Headline
CVE-2023-5638: class-wcj-general-shortcodes.php in woocommerce-jetpack/tags/7.1.3/includes/shortcodes – WordPress Plugin Repository
The Booster for WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ‘wcj_image’ shortcode in versions up to, and including, 7.1.2 due to insufficient input sanitization and output escaping on user supplied attributes. This makes it possible for authenticated attackers with contributor-level and above permissions to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
1<?php2/**3 * Booster for WooCommerce - Shortcodes - General4 *5 * @version 7.1.36 * @author Pluggabl LLC.7 * @package Booster_For_WooCommerce/shortcodes8 */910if ( ! defined( ‘ABSPATH’ ) ) {11 exit;12}1314if ( ! class_exists( ‘WCJ_General_Shortcodes’ ) ) :1516 /**17 * WCJ_General_Shortcodes.18 *19 * @version 4.1.020 */21 class WCJ_General_Shortcodes extends WCJ_Shortcodes {2223 /**24 * Constructor.25 *26 * @version 4.1.027 */28 public function __construct() {2930 $this->the_shortcodes = array(31 'wcj_barcode’,32 'wcj_button_toggle_tax_display’,33 'wcj_country_select_drop_down_list’,34 'wcj_cross_sell_display’,35 'wcj_currency_exchange_rate’,36 'wcj_currency_exchange_rate_wholesale_module’,37 'wcj_currency_exchange_rates_table’,38 'wcj_currency_select_drop_down_list’,39 'wcj_currency_select_link_list’,40 'wcj_currency_select_radio_list’,41 'wcj_current_currency_code’,42 'wcj_current_currency_symbol’,43 'wcj_current_date’,44 'wcj_current_datetime’,45 'wcj_current_time’,46 'wcj_current_timestamp’,47 'wcj_customer_billing_country’,48 'wcj_customer_meta’,49 'wcj_customer_order_count’,50 'wcj_customer_shipping_country’,51 'wcj_customer_total_spent’,52 'wcj_empty_cart_button’,53 'wcj_get_left_to_free_shipping’,54 'wcj_get_option’,55 'wcj_image’,56 'wcj_post_meta_sum’,57 'wcj_product_category_count’,58 'wcj_request_value’,59 'wcj_selector’,60 'wcj_session_value’,61 'wcj_shipping_costs_table’,62 'wcj_shipping_time_table’,63 'wcj_site_url’,64 'wcj_store_address’,65 'wcj_tcpdf_barcode’,66 'wcj_tcpdf_pagebreak’,67 'wcj_tcpdf_rectangle’,68 'wcj_text’,69 'wcj_upsell_display’,70 'wcj_wc_session_value’,71 'wcj_wholesale_price_table’,72 'wcj_wp_option’,73 'wcj_wpml’,74 'wcj_wpml_translate’,75 );7677 $this->the_atts = array(78 ‘date_format’ => wcj_get_option( ‘date_format’ ),79 ‘time_format’ => wcj_get_option( ‘time_format’ ),80 ‘datetime_format’ => wcj_get_option( ‘date_format’ ) . ' ' . wcj_get_option( ‘time_format’ ),81 ‘lang’ => '’,82 ‘form_method’ => 'post’,83 ‘class’ => '’,84 ‘style’ => '’,85 ‘countries’ => '’,86 ‘currencies’ => '’,87 ‘content’ => '’,88 ‘heading_format’ => 'from %level_min_qty% pcs.’,89 ‘before_level_max_qty’ => '-',90 ‘last_level_max_qty’ => '+’,91 ‘replace_with_currency’ => 'no’,92 ‘hide_if_zero_quantity’ => 'no’,93 ‘table_format’ => 'horizontal’,94 ‘key’ => '’,95 ‘full_country_name’ => 'yes’,96 ‘multiply_by’ => 1,97 ‘default’ => '’,98 ‘from’ => '’,99 ‘to’ => '’,100 ‘columns_style’ => 'text-align: center;’,101 ‘selector_type’ => 'country’,102 ‘option’ => '’,103 ‘company’ => '’,104 ‘label_incl’ => __( 'Tax toggle (incl.)', ‘woocommerce-jetpack’ ),105 ‘label_excl’ => __( 'Tax toggle (excl.)', ‘woocommerce-jetpack’ ),106 ‘slug’ => '’,107 ‘code’ => '’,108 ‘type’ => '’,109 ‘dimension’ => '2D’,110 ‘width’ => 0,111 ‘height’ => 0,112 ‘color’ => 'black’,113 ‘x’ => 0,114 ‘y’ => 0,115 );116117 parent::__construct();118119 }120121 /**122 * Wcj_post_meta_sum.123 *124 * @version 6.0.0125 * @since 4.1.0126 * @param array $atts defined shortcode attributes.127 */128 public function wcj_post_meta_sum( $atts ) {129 if ( ‘’ === $atts[‘key’] ) {130 return ‘’;131 }132 global $wpdb;133 $sum = $wpdb->get_var( $wpdb->prepare( “SELECT sum(meta_value) FROM $wpdb->postmeta WHERE meta_key = %s", $atts[‘key’] ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching134 return ( ! empty( $atts[‘offset’] ) ? $sum + $atts[‘offset’] : $sum );135 }136137 /**138 * Wcj_get_option.139 *140 * @version 7.1.2141 * @since 3.9.0142 * @todo [dev] handle multidimensional arrays143 * @todo [dev] maybe also add `get_site_option()`144 * @param array $atts The user defined shortcode attributes.145 */146 public function wcj_get_option( $atts ) {147 if ( isset( $atts[‘name’] ) && str_contains( $atts[‘name’], ‘wcj’ ) ) {148 $result = ( isset( $atts[‘name’] ) ? wcj_get_option( $atts[‘name’], ( isset( $atts[‘default’] ) ? $atts[‘default’] : false ) ) : ‘’ );149 return ( is_array( $result ) ?150 ( isset( $atts[‘field’] ) && isset( $result[ $atts[‘field’] ] ) ? $result[ $atts[‘field’] ] : implode( ', ', $result ) ) :151 $result );152 } else {153 return '’;154 }155 }156157 /**158 * Wcj_shipping_costs_table.159 *160 * @version 3.9.0161 * @since 3.9.0162 * @todo [dev] sort `$table` before using163 * @todo [feature] add `volume` prop164 * @todo [feature] add `total` prop165 * @param array $atts The user defined shortcode attributes.166 */167 public function wcj_shipping_costs_table( $atts ) {168 $_cart = WC()->cart;169 if ( ! empty( $atts[‘table’] ) && ( $_cart ) ) {170 if ( ! isset( $atts[‘cmp’] ) ) {171 $atts[‘cmp’] = 'max’;172 }173 if ( ! isset( $atts[‘prop’] ) ) {174 $atts[‘prop’] = 'quantity’;175 }176 switch ( $atts[‘prop’] ) {177 case 'weight’:178 $param_value = $_cart->get_cart_contents_weight();179 break;180 default: // quantity.181 $param_value = $_cart->get_cart_contents_count();182 }183 $table = array_map( 'trim’, explode( '|’, $atts[‘table’] ) );184 if ( ‘min’ === $atts[‘cmp’] ) {185 $table = array_reverse( $table );186 }187 foreach ( $table as $row ) {188 $cells = array_map( 'trim’, explode( '-', $row ) );189 if ( 2 !== count( $cells ) ) {190 return '’;191 }192 if (193 ( ‘min’ === $atts[‘cmp’] && $param_value >= $cells[0] ) ||194 ( ‘max’ === $atts[‘cmp’] && $param_value <= $cells[0] )195 ) {196 return $cells[1];197 }198 }199 }200 return ‘’;201 }202203 /**204 * Wcj_upsell_display.205 *206 * @version 3.6.0207 * @since 3.6.0208 * @todo (maybe) move to Products shortcodes209 * @param array $atts The user defined shortcode attributes.210 */211 public function wcj_upsell_display( $atts ) {212 woocommerce_upsell_display(213 ( isset( $atts[‘limit’] ) ? $atts[‘limit’] : '-1’ ),214 ( isset( $atts[‘columns’] ) ? $atts[‘columns’] : 4 ),215 ( isset( $atts[‘orderby’] ) ? $atts[‘orderby’] : ‘rand’ ),216 ( isset( $atts[‘order’] ) ? $atts[‘order’] : ‘desc’ )217 );218 }219220 /**221 * Wcj_cross_sell_display.222 *223 * @version 3.9.1224 * @since 3.6.0225 * @param array $atts The user defined shortcode attributes.226 */227 public function wcj_cross_sell_display( $atts ) {228229 if ( ! function_exists( ‘WC’ ) || ! isset( WC()->cart ) ) {230 return '’;231 }232233 $limit = ( isset( $atts[‘limit’] ) ? $atts[‘limit’] : 2 );234 $columns = ( isset( $atts[‘columns’] ) ? $atts[‘columns’] : 2 );235 $orderby = ( isset( $atts[‘orderby’] ) ? $atts[‘orderby’] : ‘rand’ );236 $order = ( isset( $atts[‘order’] ) ? $atts[‘order’] : ‘desc’ );237238 // Get visible cross sells then sort them at random.239 $cross_sells = array_filter( array_map( 'wc_get_product’, WC()->cart->get_cross_sells() ), ‘wc_products_array_filter_visible’ );240241 wc_set_loop_prop( 'name’, ‘cross-sells’ );242 wc_set_loop_prop( 'columns’, apply_filters( 'woocommerce_cross_sells_columns’, $columns ) );243244 // Handle orderby and limit results.245 $orderby = apply_filters( 'woocommerce_cross_sells_orderby’, $orderby );246 $order = apply_filters( 'woocommerce_cross_sells_order’, $order );247 $cross_sells = wc_products_array_orderby( $cross_sells, $orderby, $order );248 $limit = apply_filters( 'woocommerce_cross_sells_total’, $limit );249 $cross_sells = $limit > 0 ? array_slice( $cross_sells, 0, $limit ) : $cross_sells;250251 ob_start();252 wc_get_template(253 'cart/cross-sells.php’,254 array(255 ‘cross_sells’ => $cross_sells,256257 // Not used now, but used in previous version of up-sells.php.258 ‘posts_per_page’ => $limit,259 ‘orderby’ => $orderby,260 ‘columns’ => $columns,261 )262 );263 return ob_get_clean();264 }265266 /**267 * Wcj_shipping_time_table.268 *269 * @version 3.5.0270 * @since 3.5.0271 * @todo `$atts[‘shipping_class_term_id’]` - class term ID is not visible anywhere for admin, so probably need to use `slug` instead272 * @param array $atts The user defined shortcode attributes.273 */274 public function wcj_shipping_time_table( $atts ) {275 $do_use_shipping_instances = ( ‘yes’ === wcj_get_option( 'wcj_shipping_time_use_shipping_instance’, ‘no’ ) );276 $do_use_shipping_classes = ( ‘yes’ === apply_filters( 'booster_option’, 'no’, wcj_get_option( 'wcj_shipping_time_use_shipping_classes’, ‘no’ ) ) );277 $shipping_class_term_id = ( isset( $atts[‘shipping_class_term_id’] ) ? $atts[‘shipping_class_term_id’] : ‘0’ );278 $option_id_shipping_class = ( $do_use_shipping_classes ? ‘_class_’ . $shipping_class_term_id : ‘’ );279 return wcj_get_shipping_time_table( $do_use_shipping_instances, $option_id_shipping_class );280 }281282 /**283 * Wcj_wc_session_value.284 *285 * @version 3.4.0286 * @since 3.4.0287 * @todo handle arrays288 * @param array $atts The user defined shortcode attributes.289 */290 public function wcj_wc_session_value( $atts ) {291 return ( ‘’ === $atts[‘key’] ? ‘’ : WC()->session->get( $atts[‘key’], ‘’ ) );292 }293294 /**295 * Wcj_session_value.296 *297 * @version 3.4.0298 * @since 3.4.0299 * @param array $atts The user defined shortcode attributes.300 */301 public function wcj_session_value( $atts ) {302 return ( ‘’ === $atts[‘key’] || ! isset( $_SESSION[ $atts[‘key’] ] ) ? ‘’ : $_SESSION[ $atts[‘key’] ] );303 }304305 /**306 * Wcj_request_value.307 *308 * @version 5.6.2309 * @since 3.4.0310 * @param array $atts The user defined shortcode attributes.311 */312 public function wcj_request_value( $atts ) {313 return ( ( ‘’ === $atts[‘key’] || ! isset( $_REQUEST[ $atts[‘key’] ] ) ) ? ‘’ : sanitize_text_field( wp_unslash( $_REQUEST[ $atts[‘key’] ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification314 }315316 /**317 * Wcj_tcpdf_rectangle.318 *319 * @version 7.1.1320 * @since 3.3.0321 * @see https://tcpdf.org/examples/example_012/322 * @todo add more atts (e.g. style, fill color etc.)323 * @todo add options to take `width` and `height` from custom source (e.g. item or order meta)324 * @todo (maybe) move all `tcpdf` shortcodes to `class-wcj-shortcodes-tcpdf.php`325 * @todo (maybe) create general `[wcj_tcpdf_method]` shortcode (not sure how to solve `$params` part though)326 * @param array $atts The user defined shortcode attributes.327 */328 public function wcj_tcpdf_rectangle( $atts ) {329330 $style = 'D’;331 $border_style = array(332 ‘all’ => array(333 ‘width’ => 0.5,334 ‘cap’ => 'round’,335 ‘join’ => 'round’,336 ‘dash’ => 0,337 ‘color’ => array( 0, 0, 0 ),338 ),339 );340 $fill_color = array();341342 $width = wcj_sanitize_input_attribute_values( $atts[‘width’] );343 $height = wcj_sanitize_input_attribute_values( $atts[‘height’] );344 $params = array(345 $atts[‘x’],346 $atts[‘y’],347 $width,348 $height,349 $style,350 $border_style,351 $fill_color,352 );353354 return wcj_tcpdf_method( 'Rect’, $params );355 }356357 /**358 * Wcj_tcpdf_barcode.359 *360 * @version 3.3.0361 * @since 3.2.4362 * @param array $atts The user defined shortcode attributes.363 */364 public function wcj_tcpdf_barcode( $atts ) {365 return wcj_tcpdf_barcode( $atts );366 }367368 /**369 * Wcj_barcode.370 *371 * @version 3.3.0372 * @since 3.2.4373 * @todo (maybe) current page url as `code`374 * @param array $atts The user defined shortcode attributes.375 */376 public function wcj_barcode( $atts ) {377 return wcj_barcode( $atts );378 }379380 /**381 * Wcj_product_category_count.382 *383 * @version 3.2.4384 * @since 3.2.4385 * @todo option to use `name` or `term_id` instead of `slug`386 * @todo `pad_counts`387 * @todo add similar `[wcj_product_tag_count]` and `[wcj_product_taxonomy_count]`388 * @param array $atts The user defined shortcode attributes.389 */390 public function wcj_product_category_count( $atts ) {391 if ( ! isset( $atts[‘slug’] ) ) {392 return '’;393 }394 $product_categories = get_categories(395 array(396 ‘hide_empty’ => 0,397 ‘hierarchical’ => 1,398 ‘taxonomy’ => 'product_cat’,399 ‘slug’ => $atts[‘slug’],400 )401 );402 return ( isset( $product_categories[0]->count ) ? $product_categories[0]->count : ‘’ );403 }404405 /**406 * Wcj_button_toggle_tax_display.407 *408 * @version 7.1.1409 * @since 3.2.4410 * @todo (dev) different style/class for different tax state411 * @todo (maybe) `get` instead of `post`412 * @param array $atts The user defined shortcode attributes.413 */414 public function wcj_button_toggle_tax_display( $atts ) {415 $session_value = wcj_session_get( ‘wcj_toggle_tax_display’ );416 $current_value = ( ( ‘’ === $session_value || null === $session_value ) ? wcj_get_option( 'woocommerce_tax_display_shop’, ‘excl’ ) : $session_value );417 $current_value = ‘’ === $current_value ? ‘excl’ : $current_value;418 $label = wcj_sanitize_input_attribute_values( $atts[ ‘label_’ . $current_value ] );419 $class = wcj_sanitize_input_attribute_values( $atts[‘class’] );420 $style = wcj_sanitize_input_attribute_values( $atts[‘style’], ‘style’ );421 return '<form method="post” action="">’ . wp_nonce_field( ‘wcj_button_toggle_tax_display’, ‘wcj-button-toggle-tax-display-nonce’ ) . ‘<input type="submit" name="wcj_button_toggle_tax_display"’ .422 ' class="’ . $class . ‘" style="’ . $style . ‘" value="’ . $label . '"></form>’;423 }424425 /**426 * Wcj_store_address.427 *428 * @version 3.2.1429 * @since 3.2.1430 * @todo `force_country_display` - make optional431 * @todo `remove_filter` will remove all `__return_true` functions (even added elsewhere)432 * @param array $atts The user defined shortcode attributes.433 */434 public function wcj_store_address( $atts ) {435 add_filter( 'woocommerce_formatted_address_force_country_display’, ‘__return_true’ );436 $return = WC()->countries->get_formatted_address(437 array(438 ‘company’ => $atts[‘company’],439 ‘address_1’ => WC()->countries->get_base_address(),440 ‘address_2’ => WC()->countries->get_base_address_2(),441 ‘city’ => WC()->countries->get_base_city(),442 ‘state’ => WC()->countries->get_base_state(),443 ‘postcode’ => WC()->countries->get_base_postcode(),444 ‘country’ => WC()->countries->get_base_country(),445 )446 );447 remove_filter( 'woocommerce_formatted_address_force_country_display’, ‘__return_true’ );448 return $return;449 }450451 /**452 * Wcj_wp_option.453 *454 * @version 7.1.1455 * @since 3.2.1456 * @param array $atts The user defined shortcode attributes.457 */458 public function wcj_wp_option( $atts ) {459 if ( isset( $atts[‘option’] ) && str_contains( $atts[‘option’], ‘wcj’ ) ) {460 return ( ‘’ !== $atts[‘option’] ? wcj_get_option( $atts[‘option’], $atts[‘default’] ) : ‘’ );461 } else {462 return '’;463 }464 }465466 /**467 * Wcj_current_currency_code.468 *469 * @version 3.1.1470 * @since 3.1.1471 * @param array $atts The user defined shortcode attributes.472 */473 public function wcj_current_currency_code( $atts ) {474 return get_woocommerce_currency();475 }476477 /**478 * Wcj_current_currency_symbol.479 *480 * @version 3.1.1481 * @since 3.1.1482 * @param array $atts The user defined shortcode attributes.483 */484 public function wcj_current_currency_symbol( $atts ) {485 return get_woocommerce_currency_symbol();486 }487488 /**489 * Wcj_selector.490 *491 * @version 7.1.1492 * @since 3.1.0493 * @todo add `default` attribute494 * @todo (maybe) add more selector types (e.g.: currency)495 * @todo (maybe) remove country switcher and currency switcher shortcodes and use this shortcode instead496 * @param array $atts The user defined shortcode attributes.497 */498 public function wcj_selector( $atts ) {499 $html = '’;500 $options = '’;501 $countries = apply_filters( 'booster_option’, 'all’, wcj_get_option( 'wcj_product_by_country_country_list_shortcode’, ‘all’ ) );502 $selector_type = wcj_sanitize_input_attribute_values( $atts[‘selector_type’] );503 $wpnonce = isset( $_REQUEST[ ‘wcj_’ . $selector_type . ‘_selector-nonce’ ] ) ? wp_verify_nonce( sanitize_key( $_REQUEST[ ‘wcj_’ . $selector_type . ‘_selector-nonce’ ] ), ‘wcj_’ . $selector_type . ‘_selector’ ) : false;504 $selected_value = ( ( $wpnonce && isset( $_REQUEST[ ‘wcj_’ . $selector_type . ‘_selector’ ] ) ) ?505 sanitize_text_field( wp_unslash( $_REQUEST[ ‘wcj_’ . $selector_type . ‘_selector’ ] ) ) :506 wcj_session_get( ‘wcj_selected_’ . $selector_type )507 );508509 switch ( $countries ) {510 case 'wc’:511 $countries = WC()->countries->get_allowed_countries();512 break;513 default: // 'all’.514 $countries = wcj_get_countries();515 break;516 }517518 switch ( $selector_type ) {519 case 'product_custom_visibility’:520 $options = wcj_get_select_options( wcj_get_option( 'wcj_product_custom_visibility_options_list’, ‘’ ) );521 break;522 default: // 'country’.523 $options = $countries;524 asort( $options );525 break;526 }527 foreach ( $options as $value => $title ) {528 $html .= ‘<option value="’ . $value . '" ' . selected( $selected_value, $value, false ) . ‘>’ . $title . '</option>’;529 }530 return ‘<form method="post" action="">’ .531 ‘<select name="wcj_’ . $selector_type . ‘_selector" class="wcj_’ . $selector_type . ‘_selector" onchange="this.form.submit()">’ .532 $html .533 ‘</select>’ .534 wp_nonce_field( ‘wcj_’ . $selector_type . '_selector’, ‘wcj_’ . $selector_type . ‘_selector-nonce’ ) .535 '</form>’;536 }537538 /**539 * Wcj_site_url.540 *541 * @version 2.9.1542 * @since 2.9.1543 * @param array $atts The user defined shortcode attributes.544 */545 public function wcj_site_url( $atts ) {546 return site_url();547 }548549 /**550 * Wcj_currency_exchange_rate.551 *552 * @version 2.9.0553 * @since 2.9.0554 * @todo (maybe) add similar function555 * @param array $atts The user defined shortcode attributes.556 */557 public function wcj_currency_exchange_rate( $atts ) {558 return ( ‘’ !== $atts[‘from’] && ‘’ !== $atts[‘to’] ) ? wcj_get_option( ‘wcj_currency_exchange_rates_’ . sanitize_title( $atts[‘from’] . $atts[‘to’] ) ) : '’;559 }560561 /**562 * Wcj_currency_exchange_rate_wholesale_module.563 *564 * @version 5.4.5565 * @since 5.4.5566 * @todo (maybe) add similar function567 */568 public function wcj_currency_exchange_rate_wholesale_module() {569 $store_base_currency = strtolower( get_option( ‘woocommerce_currency’ ) );570 $store_current_currency = strtolower( get_woocommerce_currency() );571 return ( ‘’ !== $store_base_currency && ‘’ !== $store_current_currency ) ? wcj_get_option( ‘wcj_currency_exchange_rates_’ . sanitize_title( $store_base_currency . $store_current_currency ) ) : '’;572573 }574575576 /**577 * Wcj_currency_exchange_rates_table.578 *579 * @version 6.0.1580 * @since 2.9.0581 * @todo (maybe) add similar function582 * @param array $atts The user defined shortcode attributes.583 */584 public function wcj_currency_exchange_rates_table( $atts ) {585 $all_currencies = w_c_j()->all_modules[‘currency_exchange_rates’]->get_all_currencies_exchange_rates_settings();586 $table_data = array();587 foreach ( $all_currencies as $currency ) {588 $table_data[] = array( $currency[‘title’], wcj_get_option( $currency[‘id’] ) );589 }590 if ( ! empty( $table_data ) ) {591 return wcj_get_table_html(592 $table_data,593 array(594 ‘table_class’ => 'wcj_currency_exchange_rates_table’,595 ‘table_heading_type’ => 'vertical’,596 )597 );598 } else {599 return '’;600 }601 }602603 /**604 * Wcj_empty_cart_button.605 *606 * @version 2.8.0607 * @since 2.8.0608 * @param array $atts The user defined shortcode attributes.609 */610 public function wcj_empty_cart_button( $atts ) {611 if ( ! wcj_is_module_enabled( ‘empty_cart’ ) ) {612 /* translators: %s: translation added */613 return ‘<p>’ . sprintf( __( '"%s" module is not enabled!’, ‘woocommerce-jetpack’ ), __( 'Empty Cart Button’, ‘woocommerce-jetpack’ ) ) . '</p>’;614 }615 return wcj_empty_cart_button_html();616 }617618 /**619 * Wcj_current_time.620 *621 * @version 5.6.8622 * @since 2.6.0623 * @param array $atts The user defined shortcode attributes.624 */625 public function wcj_current_time( $atts ) {626 return date_i18n( $atts[‘time_format’], wcj_get_timestamp_date_from_gmt() );627 }628629 /**630 * Wcj_current_datetime.631 *632 * @version 5.6.8633 * @since 2.6.0634 * @param array $atts The user defined shortcode attributes.635 */636 public function wcj_current_datetime( $atts ) {637 return date_i18n( $atts[‘datetime_format’], wcj_get_timestamp_date_from_gmt() );638 }639640 /**641 * Wcj_current_timestamp.642 *643 * @version 5.6.8644 * @since 2.6.0645 * @param array $atts The user defined shortcode attributes.646 */647 public function wcj_current_timestamp( $atts ) {648 return wcj_get_timestamp_date_from_gmt();649 }650651 /**652 * Wcj_customer_order_count.653 *654 * @version 3.4.0655 * @since 3.4.0656 * @todo `hide_if_zero`657 * @param array $atts The user defined shortcode attributes.658 */659 public function wcj_customer_order_count( $atts ) {660 if ( is_user_logged_in() ) {661 $current_user = wp_get_current_user();662 $customer = new WC_Customer( $current_user->ID );663 return $customer->get_order_count();664 } else {665 return '’;666 }667 }668669 /**670 * Wcj_customer_total_spent.671 *672 * @version 3.4.0673 * @since 3.4.0674 * @todo `hide_if_zero`675 * @todo `hide_currency`676 * @todo (maybe) solve multicurrency issue677 * @param array $atts The user defined shortcode attributes.678 */679 public function wcj_customer_total_spent( $atts ) {680 if ( is_user_logged_in() ) {681 $current_user = wp_get_current_user();682 $customer = new WC_Customer( $current_user->ID );683 return wc_price( $customer->get_total_spent() );684 } else {685 return '’;686 }687 }688689 /**690 * Wcj_customer_billing_country.691 *692 * @version 2.5.8693 * @since 2.5.8694 * @see https://docs.woocommerce.com/wc-apidocs/class-WC_Customer.html695 * @todo move all customer shortcodes to new class `WCJ_Customers_Shortcodes` (and there `$this->the_customer = new WC_Customer( $current_user->ID )`)696 * @todo add `[wcj_customer_taxable_address]` (with `$customer->get_taxable_address()`)697 * @todo add `[wcj_customer_prop]` (with `$customer->get_{$atts[‘key’]}()`)698 * @param array $atts The user defined shortcode attributes.699 */700 public function wcj_customer_billing_country( $atts ) {701 if ( is_user_logged_in() ) {702 $current_user = wp_get_current_user();703 $meta = get_user_meta( $current_user->ID, 'billing_country’, true );704 if ( ‘’ !== ( $meta ) ) {705 return ( ‘yes’ === $atts[‘full_country_name’] ) ? wcj_get_country_name_by_code( $meta ) : $meta;706 }707 }708 return '’;709 }710711 /**712 * Wcj_customer_shipping_country.713 *714 * @version 2.5.8715 * @since 2.5.8716 * @param array $atts The user defined shortcode attributes.717 */718 public function wcj_customer_shipping_country( $atts ) {719 if ( is_user_logged_in() ) {720 $current_user = wp_get_current_user();721 $meta = get_user_meta( $current_user->ID, 'shipping_country’, true );722 if ( ‘’ !== ( $meta ) ) {723 return ( ‘yes’ === $atts[‘full_country_name’] ) ? wcj_get_country_name_by_code( $meta ) : $meta;724 }725 }726 return '’;727 }728729 /**730 * Wcj_customer_meta.731 *732 * @version 2.5.8733 * @since 2.5.8734 * @param array $atts The user defined shortcode attributes.735 */736 public function wcj_customer_meta( $atts ) {737 if ( ‘’ !== $atts[‘key’] && is_user_logged_in() ) {738 $current_user = wp_get_current_user();739 $meta = get_user_meta( $current_user->ID, $atts[‘key’], true );740 if ( ‘’ !== ( $meta ) ) {741 return $meta;742 }743 }744 return '’;745 }746747 /**748 * Get_shortcode_currencies.749 *750 * @version 2.4.5751 * @since 2.4.5752 * @param array $atts The user defined shortcode attributes.753 */754 private function get_shortcode_currencies( $atts ) {755 // Shortcode currencies.756 $shortcode_currencies = $atts[‘currencies’];757 if ( ‘’ === $shortcode_currencies ) {758 $shortcode_currencies = array();759 } else {760 $shortcode_currencies = str_replace( ' ', '’, $shortcode_currencies );761 $shortcode_currencies = trim( $shortcode_currencies, ‘,’ );762 $shortcode_currencies = explode( ',’, $shortcode_currencies );763 }764 if ( empty( $shortcode_currencies ) ) {765 $total_number = apply_filters( 'booster_option’, 2, wcj_get_option( 'wcj_multicurrency_total_number’, 2 ) );766 for ( $i = 1; $i <= $total_number; $i++ ) {767 $shortcode_currencies[] = wcj_get_option( ‘wcj_multicurrency_currency_’ . $i );768 }769 }770 return $shortcode_currencies;771 }772773 /**774 * Wcj_wholesale_price_table (global only).775 *776 * @version 3.1.0777 * @since 2.4.8778 * @param array $atts The user defined shortcode attributes.779 */780 public function wcj_wholesale_price_table( $atts ) {781782 if ( ! wcj_is_module_enabled( ‘wholesale_price’ ) ) {783 return '’;784 }785786 // Check for user role options.787 $role_option_name_addon = '’;788 $user_roles = wcj_get_option( 'wcj_wholesale_price_by_user_role_roles’, ‘’ );789 if ( ! empty( $user_roles ) ) {790 $current_user_role = wcj_get_current_user_first_role();791 foreach ( $user_roles as $user_role_key ) {792 if ( $current_user_role === $user_role_key ) {793 $role_option_name_addon = ‘_’ . $user_role_key;794 break;795 }796 }797 }798799 $wholesale_price_levels = array();800 $wcj_wholesale_price_levels_number = apply_filters( 'booster_option’, 1, wcj_get_option( ‘wcj_wholesale_price_levels_number’ . $role_option_name_addon, 1 ) );801 for ( $i = 1; $i <= $wcj_wholesale_price_levels_number; $i++ ) {802 $level_qty = wcj_get_option( ‘wcj_wholesale_price_level_min_qty’ . $role_option_name_addon . ‘_’ . $i, PHP_INT_MAX );803 $discount = wcj_get_option( ‘wcj_wholesale_price_level_discount_percent’ . $role_option_name_addon . ‘_’ . $i, 0 );804 $wholesale_price_levels[] = array(805 ‘quantity’ => $level_qty,806 ‘discount’ => $discount,807 );808 }809810 $data_qty = array();811 $data_discount = array();812 $columns_styles = array();813 $i = -1;814 foreach ( $wholesale_price_levels as $wholesale_price_level ) {815 $i++;816 if ( 0 === $wholesale_price_level[‘quantity’] && ‘yes’ === $atts[‘hide_if_zero_quantity’] ) {817 continue;818 }819 $level_max_qty = ( isset( $wholesale_price_levels[ $i + 1 ][‘quantity’] ) ) ? $atts[‘before_level_max_qty’] . ( $wholesale_price_levels[ $i + 1 ][‘quantity’] - 1 ) : $atts[‘last_level_max_qty’];820 $data_qty[] = str_replace(821 array( '%level_qty%’, '%level_min_qty%’, ‘%level_max_qty%’ ), // %level_qty% is deprecated822 array( $wholesale_price_level[‘quantity’], $wholesale_price_level[‘quantity’], $level_max_qty ),823 $atts[‘heading_format’]824 );825 $data_discount[] = ( ‘fixed’ === wcj_get_option( 'wcj_wholesale_price_discount_type’, ‘percent’ ) )826 ? '-' . wc_price( $wholesale_price_level[‘discount’] ) : '-' . $wholesale_price_level[‘discount’] . '%’;827 $columns_styles[] = $atts[‘columns_style’];828 }829830 $table_rows = array( $data_qty, $data_discount );831832 if ( ‘vertical’ === $atts[‘table_format’] ) {833 $table_rows_modified = array();834 foreach ( $table_rows as $row_number => $table_row ) {835 foreach ( $table_row as $column_number => $cell ) {836 $table_rows_modified[ $column_number ][ $row_number ] = $cell;837 }838 }839 $table_rows = $table_rows_modified;840 }841842 return wcj_get_table_html(843 $table_rows,844 array(845 ‘table_class’ => 'wcj_wholesale_price_table’,846 ‘columns_styles’ => $columns_styles,847 ‘table_heading_type’ => $atts[‘table_format’],848 )849 );850 }851852 /**853 * Wcj_currency_select_link_list.854 *855 * @version 5.6.8856 * @since 2.4.5857 * @param array $atts The user defined shortcode attributes.858 * @param array | string $content The user defined shortcode content.859 */860 public function wcj_currency_select_link_list( $atts, $content ) {861 $html = '’;862 $shortcode_currencies = $this->get_shortcode_currencies( $atts );863 // Options.864 $currencies = get_woocommerce_currencies();865 $selected_currency = '’;866 $session_value = wcj_session_get( ‘wcj-currency’ );867 if ( null !== ( $session_value ) ) {868 $selected_currency = $session_value;869 } else {870 $module_roles = wcj_get_option( 'wcj_multicurrency_role_defaults_roles’, ‘’ );871 if ( ! empty( $module_roles ) ) {872 $current_user_role = wcj_get_current_user_first_role();873 if ( in_array( $current_user_role, $module_roles, true ) ) {874 $selected_currency = wcj_get_option( ‘wcj_multicurrency_role_defaults_’ . $current_user_role, ‘’ );875 }876 }877 }878 if ( ‘’ === $selected_currency && ‘’ !== $atts[‘default’] ) {879 $selected_currency = $atts[‘default’];880 }881 $links = array();882 $first_link = '’;883 $switcher_template = wcj_get_option( 'wcj_multicurrency_switcher_template’, '%currency_name% (%currency_symbol%)' );884 foreach ( $shortcode_currencies as $currency_code ) {885 if ( isset( $currencies[ $currency_code ] ) ) {886 $template_replaced_values = array(887 ‘%currency_name%’ => $currencies[ $currency_code ],888 ‘%currency_code%’ => $currency_code,889 ‘%currency_symbol%’ => get_woocommerce_currency_symbol( $currency_code ),890 );891 $currency_switcher_output = str_replace( array_keys( $template_replaced_values ), array_values( $template_replaced_values ), $switcher_template );892 $the_link = ‘<a href="’ . esc_url( wp_nonce_url( add_query_arg( 'wcj-currency’, $currency_code ), 'wcj-currency’, ‘wcj-currency-nonce’ ) ) . ‘">’ . $currency_switcher_output . '</a>’;893 if ( $currency_code !== $selected_currency ) {894 $links[] = $the_link;895 } else {896 $first_link = $the_link;897 }898 }899 }900 if ( ‘’ !== $first_link ) {901 $links = array_merge( array( $first_link ), $links );902 }903 $html .= implode( '<br>’, $links );904 return $html;905 }906907 /**908 * Wcj_get_left_to_free_shipping.909 *910 * @version 2.5.8911 * @since 2.4.4912 * @param array $atts The user defined shortcode attributes.913 * @param array | string $content The user defined shortcode content.914 */915 public function wcj_get_left_to_free_shipping( $atts, $content ) {916 return wcj_get_left_to_free_shipping( $atts[‘content’], $atts[‘multiply_by’] );917 }918919 /**920 * Wcj_tcpdf_pagebreak.921 *922 * @version 2.3.7923 * @since 2.3.7924 * @param array $atts The user defined shortcode attributes.925 * @param array | string $content The user defined shortcode content.926 */927 public function wcj_tcpdf_pagebreak( $atts, $content ) {928 return '<tcpdf method="AddPage" />’;929 }930931 /**932 * Get_currency_selector.933 *934 * @version 7.1.1935 * @since 2.4.5936 * @param array $atts The user defined shortcode attributes.937 * @param array | string $content The user defined shortcode content.938 * @param string $type The user defined shortcode type.939 */940 private function get_currency_selector( $atts, $content, $type = ‘select’ ) {941 // Start.942 $form_method = wcj_sanitize_input_attribute_values( $atts[‘form_method’] );943 $class = wcj_sanitize_input_attribute_values( $atts[‘class’] );944 $style = wcj_sanitize_input_attribute_values( $atts[‘style’], ‘style’ );945 $html = '’;946 $html .= ‘<form action="" method="’ . $form_method . '">’;947 if ( ‘select’ === $type ) {948 $html .= ‘<select name="wcj-currency" id="wcj-currency-select" style="’ . $style . ‘" class="’ . $class . '" onchange="this.form.submit()“>’;949 }950 $shortcode_currencies = $this->get_shortcode_currencies( $atts );951 // Options.952 $currencies = get_woocommerce_currencies();953 $selected_currency = '’;954 $session_value = wcj_session_get( ‘wcj-currency’ );955 if ( null !== ( $session_value ) ) {956 $selected_currency = $session_value;957 } else {958 $module_roles = wcj_get_option( 'wcj_multicurrency_role_defaults_roles’, ‘’ );959 if ( ! empty( $module_roles ) ) {960 $current_user_role = wcj_get_current_user_first_role();961 if ( in_array( $current_user_role, $module_roles, true ) ) {962 $selected_currency = wcj_get_option( ‘wcj_multicurrency_role_defaults_’ . $current_user_role, ‘’ );963 }964 }965 }966 if ( ‘’ === $selected_currency && ‘’ !== $atts[‘default’] ) {967 wcj_session_set( 'wcj-currency’, $atts[‘default’] );968 $selected_currency = $atts[‘default’];969 }970 $switcher_template = wcj_get_option( 'wcj_multicurrency_switcher_template’, '%currency_name% (%currency_symbol%)' );971 foreach ( $shortcode_currencies as $currency_code ) {972 if ( isset( $currencies[ $currency_code ] ) ) {973 $template_replaced_values = array(974 ‘%currency_name%’ => $currencies[ $currency_code ],975 ‘%currency_code%’ => $currency_code,976 ‘%currency_symbol%’ => get_woocommerce_currency_symbol( $currency_code ),977 );978 $currency_switcher_output = str_replace( array_keys( $template_replaced_values ), array_values( $template_replaced_values ), $switcher_template );979 if ( ‘’ === $selected_currency ) {980 $selected_currency = $currency_code;981 }982 if ( ‘select’ === $type ) {983 $html .= ‘<option value="’ . $currency_code . '” ' . selected( $currency_code, $selected_currency, false ) . ‘>’ . $currency_switcher_output . '</option>’;984 } elseif ( ‘radio’ === $type ) {985 $html .= ‘<input type="radio" name="wcj-currency" id="wcj-currency-radio" value="’ . $currency_code . ‘" ' . checked( $currency_code, $selected_currency, false ) . ' onclick="this.form.submit()“> ' . $currency_switcher_output . '<br>’;986 }987 }988 }989 // End.990 if ( ‘select’ === $type ) {991 $html .= '</select>’;992 }993 $html .= wp_nonce_field( 'wcj-currency’, ‘wcj-currency-nonce’ );994 $html .= '</form>’;995 return $html;996 }997998 /**999 * Wcj_currency_select_radio_list.1000 *1001 * @version 2.4.51002 * @since 2.4.51003 * @param array $atts The user defined shortcode attributes.1004 * @param array | string $content The user defined shortcode content.1005 */1006 public function wcj_currency_select_radio_list( $atts, $content ) {1007 return $this->get_currency_selector( $atts, $content, ‘radio’ );1008 }10091010 /**1011 * Wcj_currency_select_drop_down_list.1012 *1013 * @version 2.4.51014 * @since 2.4.31015 * @param array $atts The user defined shortcode attributes.1016 * @param array | string $content The user defined shortcode content.1017 */1018 public function wcj_currency_select_drop_down_list( $atts, $content ) {1019 return $this->get_currency_selector( $atts, $content, ‘select’ );1020 }10211022 /**1023 * Wcj_country_select_drop_down_list.1024 *1025 * @version 7.1.11026 * @param array $atts The user defined shortcode attributes.1027 * @param array | string $content The user defined shortcode content.1028 */1029 public function wcj_country_select_drop_down_list( $atts, $content ) {1030 $form_method = wcj_sanitize_input_attribute_values( $atts[‘form_method’] );1031 $select_class = wcj_sanitize_input_attribute_values( $atts[‘class’] );1032 $select_style = wcj_sanitize_input_attribute_values( $atts[‘style’], ‘style’ );10331034 if ( ! isset( $atts[‘force_display’] ) || ! filter_var( $atts[‘force_display’], FILTER_VALIDATE_BOOLEAN ) ) {1035 if ( ! wcj_is_module_enabled( ‘price_by_country’ ) ) {1036 return;1037 }1038 }10391040 $countries = wcj_get_countries();1041 $shortcode_countries = ( empty( $atts[‘countries’] ) ? array() : array_map( 'trim’, explode( ',’, $atts[‘countries’] ) ) );1042 $session_value = wcj_session_get( ‘wcj-country’ );1043 $selected_country = ( null !== ( $session_value ) ? $session_value : ‘’ );1044 if ( ‘yes’ === $atts[‘replace_with_currency’] ) {1045 $currencies_names_and_symbols = wcj_get_woocommerce_currencies_and_symbols();1046 }1047 $html = '’;1048 $html .= '<form action="” method="’ . $form_method . '">’;1049 $html .= ‘<select name="wcj-country" id="wcj-country" style="’ . $select_style . ‘" class="’ . $select_class . ‘" onchange="this.form.submit()">’;1050 if ( empty( $shortcode_countries ) ) {1051 foreach ( $countries as $country_code => $country_name ) {1052 $data_icon = ( ‘yes’ === wcj_get_option( ‘wcj_price_by_country_jquery_wselect_enabled’, ‘no’ ) ? ' data-icon="’ . wcj_plugin_url() . ‘/assets/images/flag-icons/’ . strtolower( $country_code ) . ‘.png"’ : ‘’ );1053 $option_label = ( ‘yes’ === $atts[‘replace_with_currency’] ) ? $currencies_names_and_symbols[ wcj_get_currency_by_country( $country_code ) ] : $country_name;1054 $html .= ‘<option’ . $data_icon . ' value="’ . $country_code . '" ' . selected( $country_code, $selected_country, false ) . ‘>’ . $option_label . ‘</option>’;1055 }1056 } else {1057 foreach ( $shortcode_countries as $country_code ) {1058 if ( isset( $countries[ $country_code ] ) ) {1059 $data_icon = ( ‘yes’ === wcj_get_option( ‘wcj_price_by_country_jquery_wselect_enabled’, ‘no’ ) ? ' data-icon="’ . wcj_plugin_url() . ‘/assets/images/flag-icons/’ . strtolower( $country_code ) . ‘.png"’ : ‘’ );1060 $option_label = ( ‘yes’ === $atts[‘replace_with_currency’] ) ? $currencies_names_and_symbols[ wcj_get_currency_by_country( $country_code ) ] : $countries[ $country_code ];1061 $html .= ‘<option’ . $data_icon . ' value="’ . $country_code . ‘" ' . selected( $country_code, $selected_country, false ) . ‘>’ . $option_label . ‘</option>’;1062 }1063 }1064 }1065 $html .= wp_nonce_field( ‘wcj-country’, ‘wcj-country-nonce’ );1066 $html .= ‘</select>’;1067 $html .= ‘</form>’;1068 return $html;1069 }10701071 /**1072 * Wcj_text.1073 *1074 * @since 2.2.91075 * @param array $atts The user defined shortcode attributes.1076 * @param array | string $content The user defined shortcode content.1077 */1078 public function wcj_text( $atts, $content ) {10791080 return $content;1081 }10821083 /**1084 * Wcj_wpml.1085 *1086 * @version 2.2.91087 * @param array $atts The user defined shortcode attributes.1088 * @param array | string $content The user defined shortcode content.1089 */1090 public function wcj_wpml( $atts, $content ) {1091 return do_shortcode( $content );1092 }10931094 /**1095 * Wcj_wpml_translate.1096 *1097 * @param array $atts The user defined shortcode attributes.1098 * @param array | string $content The user defined shortcode content.1099 */1100 public function wcj_wpml_translate( $atts, $content ) {1101 return $this->wcj_wpml( $atts, $content );1102 }11031104 /**1105 * Wcj_current_date.1106 *1107 * @version 5.6.81108 * @param array $atts The user defined shortcode attributes.1109 */1110 public function wcj_current_date( $atts ) {1111 return date_i18n( $atts[‘date_format’], wcj_get_timestamp_date_from_gmt() );1112 }11131114 /**1115 * Wcj_image.1116 *1117 * @version 7.1.31118 * @since 3.9.01119 * @param array $atts The user defined shortcode attributes.1120 */1121 public function wcj_image( $atts ) {1122 $src = wcj_sanitize_input_attribute_values( $atts[‘src’], ‘src’ );1123 $class = wcj_sanitize_input_attribute_values( $atts[‘class’] );1124 $style = wcj_sanitize_input_attribute_values( $atts[‘style’], ‘style’ );1125 $width = wcj_sanitize_input_attribute_values( $atts[‘width’] );1126 $height = wcj_sanitize_input_attribute_values( $atts[‘height’] );11271128 return ‘<img’ .1129 ' src="’ . ( ! empty( $src ) ? $src : ‘’ ) . ‘"’ .1130 ' class="’ . ( ! empty( $class ) ? $class : ‘’ ) . ‘"’ .1131 ' style="’ . ( ! empty( $style ) ? $style : ‘’ ) . ‘"’ .1132 ' width="’ . ( ! empty( $width ) ? $width : ‘’ ) . ‘"’ .1133 ' height="’ . ( ! empty( $height ) ? $height : ‘’ ) . ‘"’ .1134 '>’;1135 }1136 }11371138endif;11391140return new WCJ_General_Shortcodes();