Headline
CVE-2023-4945: class-wcj-general-shortcodes.php in woocommerce-jetpack/tags/7.1.0/includes/shortcodes – WordPress Plugin Repository
The Booster for WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting via multiple shortcodes in versions up to, and including, 7.1.0 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 6.0.16 * @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 3.9.0141 * @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 $result = ( isset( $atts[‘name’] ) ? wcj_get_option( $atts[‘name’], ( isset( $atts[‘default’] ) ? $atts[‘default’] : false ) ) : ‘’ );148 return ( is_array( $result ) ?149 ( isset( $atts[‘field’] ) && isset( $result[ $atts[‘field’] ] ) ? $result[ $atts[‘field’] ] : implode( ', ', $result ) ) :150 $result );151 }152153 /**154 * Wcj_shipping_costs_table.155 *156 * @version 3.9.0157 * @since 3.9.0158 * @todo [dev] sort `$table` before using159 * @todo [feature] add `volume` prop160 * @todo [feature] add `total` prop161 * @param array $atts The user defined shortcode attributes.162 */163 public function wcj_shipping_costs_table( $atts ) {164 $_cart = WC()->cart;165 if ( ! empty( $atts[‘table’] ) && ( $_cart ) ) {166 if ( ! isset( $atts[‘cmp’] ) ) {167 $atts[‘cmp’] = 'max’;168 }169 if ( ! isset( $atts[‘prop’] ) ) {170 $atts[‘prop’] = 'quantity’;171 }172 switch ( $atts[‘prop’] ) {173 case 'weight’:174 $param_value = $_cart->get_cart_contents_weight();175 break;176 default: // quantity.177 $param_value = $_cart->get_cart_contents_count();178 }179 $table = array_map( 'trim’, explode( '|’, $atts[‘table’] ) );180 if ( ‘min’ === $atts[‘cmp’] ) {181 $table = array_reverse( $table );182 }183 foreach ( $table as $row ) {184 $cells = array_map( 'trim’, explode( '-', $row ) );185 if ( 2 !== count( $cells ) ) {186 return '’;187 }188 if (189 ( ‘min’ === $atts[‘cmp’] && $param_value >= $cells[0] ) ||190 ( ‘max’ === $atts[‘cmp’] && $param_value <= $cells[0] )191 ) {192 return $cells[1];193 }194 }195 }196 return ‘’;197 }198199 /**200 * Wcj_upsell_display.201 *202 * @version 3.6.0203 * @since 3.6.0204 * @todo (maybe) move to Products shortcodes205 * @param array $atts The user defined shortcode attributes.206 */207 public function wcj_upsell_display( $atts ) {208 woocommerce_upsell_display(209 ( isset( $atts[‘limit’] ) ? $atts[‘limit’] : '-1’ ),210 ( isset( $atts[‘columns’] ) ? $atts[‘columns’] : 4 ),211 ( isset( $atts[‘orderby’] ) ? $atts[‘orderby’] : ‘rand’ ),212 ( isset( $atts[‘order’] ) ? $atts[‘order’] : ‘desc’ )213 );214 }215216 /**217 * Wcj_cross_sell_display.218 *219 * @version 3.9.1220 * @since 3.6.0221 * @param array $atts The user defined shortcode attributes.222 */223 public function wcj_cross_sell_display( $atts ) {224225 if ( ! function_exists( ‘WC’ ) || ! isset( WC()->cart ) ) {226 return '’;227 }228229 $limit = ( isset( $atts[‘limit’] ) ? $atts[‘limit’] : 2 );230 $columns = ( isset( $atts[‘columns’] ) ? $atts[‘columns’] : 2 );231 $orderby = ( isset( $atts[‘orderby’] ) ? $atts[‘orderby’] : ‘rand’ );232 $order = ( isset( $atts[‘order’] ) ? $atts[‘order’] : ‘desc’ );233234 // Get visible cross sells then sort them at random.235 $cross_sells = array_filter( array_map( 'wc_get_product’, WC()->cart->get_cross_sells() ), ‘wc_products_array_filter_visible’ );236237 wc_set_loop_prop( 'name’, ‘cross-sells’ );238 wc_set_loop_prop( 'columns’, apply_filters( 'woocommerce_cross_sells_columns’, $columns ) );239240 // Handle orderby and limit results.241 $orderby = apply_filters( 'woocommerce_cross_sells_orderby’, $orderby );242 $order = apply_filters( 'woocommerce_cross_sells_order’, $order );243 $cross_sells = wc_products_array_orderby( $cross_sells, $orderby, $order );244 $limit = apply_filters( 'woocommerce_cross_sells_total’, $limit );245 $cross_sells = $limit > 0 ? array_slice( $cross_sells, 0, $limit ) : $cross_sells;246247 ob_start();248 wc_get_template(249 'cart/cross-sells.php’,250 array(251 ‘cross_sells’ => $cross_sells,252253 // Not used now, but used in previous version of up-sells.php.254 ‘posts_per_page’ => $limit,255 ‘orderby’ => $orderby,256 ‘columns’ => $columns,257 )258 );259 return ob_get_clean();260 }261262 /**263 * Wcj_shipping_time_table.264 *265 * @version 3.5.0266 * @since 3.5.0267 * @todo `$atts[‘shipping_class_term_id’]` - class term ID is not visible anywhere for admin, so probably need to use `slug` instead268 * @param array $atts The user defined shortcode attributes.269 */270 public function wcj_shipping_time_table( $atts ) {271 $do_use_shipping_instances = ( ‘yes’ === wcj_get_option( 'wcj_shipping_time_use_shipping_instance’, ‘no’ ) );272 $do_use_shipping_classes = ( ‘yes’ === apply_filters( 'booster_option’, 'no’, wcj_get_option( 'wcj_shipping_time_use_shipping_classes’, ‘no’ ) ) );273 $shipping_class_term_id = ( isset( $atts[‘shipping_class_term_id’] ) ? $atts[‘shipping_class_term_id’] : ‘0’ );274 $option_id_shipping_class = ( $do_use_shipping_classes ? ‘_class_’ . $shipping_class_term_id : ‘’ );275 return wcj_get_shipping_time_table( $do_use_shipping_instances, $option_id_shipping_class );276 }277278 /**279 * Wcj_wc_session_value.280 *281 * @version 3.4.0282 * @since 3.4.0283 * @todo handle arrays284 * @param array $atts The user defined shortcode attributes.285 */286 public function wcj_wc_session_value( $atts ) {287 return ( ‘’ === $atts[‘key’] ? ‘’ : WC()->session->get( $atts[‘key’], ‘’ ) );288 }289290 /**291 * Wcj_session_value.292 *293 * @version 3.4.0294 * @since 3.4.0295 * @param array $atts The user defined shortcode attributes.296 */297 public function wcj_session_value( $atts ) {298 return ( ‘’ === $atts[‘key’] || ! isset( $_SESSION[ $atts[‘key’] ] ) ? ‘’ : $_SESSION[ $atts[‘key’] ] );299 }300301 /**302 * Wcj_request_value.303 *304 * @version 5.6.2305 * @since 3.4.0306 * @param array $atts The user defined shortcode attributes.307 */308 public function wcj_request_value( $atts ) {309 return ( ( ‘’ === $atts[‘key’] || ! isset( $_REQUEST[ $atts[‘key’] ] ) ) ? ‘’ : sanitize_text_field( wp_unslash( $_REQUEST[ $atts[‘key’] ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification310 }311312 /**313 * Wcj_tcpdf_rectangle.314 *315 * @version 3.4.0316 * @since 3.3.0317 * @see https://tcpdf.org/examples/example_012/318 * @todo add more atts (e.g. style, fill color etc.)319 * @todo add options to take `width` and `height` from custom source (e.g. item or order meta)320 * @todo (maybe) move all `tcpdf` shortcodes to `class-wcj-shortcodes-tcpdf.php`321 * @todo (maybe) create general `[wcj_tcpdf_method]` shortcode (not sure how to solve `$params` part though)322 * @param array $atts The user defined shortcode attributes.323 */324 public function wcj_tcpdf_rectangle( $atts ) {325326 $style = 'D’;327 $border_style = array(328 ‘all’ => array(329 ‘width’ => 0.5,330 ‘cap’ => 'round’,331 ‘join’ => 'round’,332 ‘dash’ => 0,333 ‘color’ => array( 0, 0, 0 ),334 ),335 );336 $fill_color = array();337338 $params = array(339 $atts[‘x’],340 $atts[‘y’],341 $atts[‘width’],342 $atts[‘height’],343 $style,344 $border_style,345 $fill_color,346 );347348 return wcj_tcpdf_method( 'Rect’, $params );349 }350351 /**352 * Wcj_tcpdf_barcode.353 *354 * @version 3.3.0355 * @since 3.2.4356 * @param array $atts The user defined shortcode attributes.357 */358 public function wcj_tcpdf_barcode( $atts ) {359 return wcj_tcpdf_barcode( $atts );360 }361362 /**363 * Wcj_barcode.364 *365 * @version 3.3.0366 * @since 3.2.4367 * @todo (maybe) current page url as `code`368 * @param array $atts The user defined shortcode attributes.369 */370 public function wcj_barcode( $atts ) {371 return wcj_barcode( $atts );372 }373374 /**375 * Wcj_product_category_count.376 *377 * @version 3.2.4378 * @since 3.2.4379 * @todo option to use `name` or `term_id` instead of `slug`380 * @todo `pad_counts`381 * @todo add similar `[wcj_product_tag_count]` and `[wcj_product_taxonomy_count]`382 * @param array $atts The user defined shortcode attributes.383 */384 public function wcj_product_category_count( $atts ) {385 if ( ! isset( $atts[‘slug’] ) ) {386 return '’;387 }388 $product_categories = get_categories(389 array(390 ‘hide_empty’ => 0,391 ‘hierarchical’ => 1,392 ‘taxonomy’ => 'product_cat’,393 ‘slug’ => $atts[‘slug’],394 )395 );396 return ( isset( $product_categories[0]->count ) ? $product_categories[0]->count : ‘’ );397 }398399 /**400 * Wcj_button_toggle_tax_display.401 *402 * @version 5.6.7403 * @since 3.2.4404 * @todo (dev) different style/class for different tax state405 * @todo (maybe) `get` instead of `post`406 * @param array $atts The user defined shortcode attributes.407 */408 public function wcj_button_toggle_tax_display( $atts ) {409 $session_value = wcj_session_get( ‘wcj_toggle_tax_display’ );410 $current_value = ( ( ‘’ === $session_value || null === $session_value ) ? wcj_get_option( 'woocommerce_tax_display_shop’, ‘excl’ ) : $session_value );411 $current_value = ‘’ === $current_value ? ‘excl’ : $current_value;412 $label = $atts[ ‘label_’ . $current_value ];413 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"’ .414 ' class="’ . $atts[‘class’] . ‘" style="’ . $atts[‘style’] . ‘" value="’ . $label . '"></form>’;415 }416417 /**418 * Wcj_store_address.419 *420 * @version 3.2.1421 * @since 3.2.1422 * @todo `force_country_display` - make optional423 * @todo `remove_filter` will remove all `__return_true` functions (even added elsewhere)424 * @param array $atts The user defined shortcode attributes.425 */426 public function wcj_store_address( $atts ) {427 add_filter( 'woocommerce_formatted_address_force_country_display’, ‘__return_true’ );428 $return = WC()->countries->get_formatted_address(429 array(430 ‘company’ => $atts[‘company’],431 ‘address_1’ => WC()->countries->get_base_address(),432 ‘address_2’ => WC()->countries->get_base_address_2(),433 ‘city’ => WC()->countries->get_base_city(),434 ‘state’ => WC()->countries->get_base_state(),435 ‘postcode’ => WC()->countries->get_base_postcode(),436 ‘country’ => WC()->countries->get_base_country(),437 )438 );439 remove_filter( 'woocommerce_formatted_address_force_country_display’, ‘__return_true’ );440 return $return;441 }442443 /**444 * Wcj_wp_option.445 *446 * @version 3.2.1447 * @since 3.2.1448 * @param array $atts The user defined shortcode attributes.449 */450 public function wcj_wp_option( $atts ) {451 return ( ‘’ !== $atts[‘option’] ? wcj_get_option( $atts[‘option’], $atts[‘default’] ) : ‘’ );452 }453454 /**455 * Wcj_current_currency_code.456 *457 * @version 3.1.1458 * @since 3.1.1459 * @param array $atts The user defined shortcode attributes.460 */461 public function wcj_current_currency_code( $atts ) {462 return get_woocommerce_currency();463 }464465 /**466 * Wcj_current_currency_symbol.467 *468 * @version 3.1.1469 * @since 3.1.1470 * @param array $atts The user defined shortcode attributes.471 */472 public function wcj_current_currency_symbol( $atts ) {473 return get_woocommerce_currency_symbol();474 }475476 /**477 * Wcj_selector.478 *479 * @version 6.0.0480 * @since 3.1.0481 * @todo add `default` attribute482 * @todo (maybe) add more selector types (e.g.: currency)483 * @todo (maybe) remove country switcher and currency switcher shortcodes and use this shortcode instead484 * @param array $atts The user defined shortcode attributes.485 */486 public function wcj_selector( $atts ) {487 $html = '’;488 $options = '’;489 $countries = apply_filters( 'booster_option’, 'all’, wcj_get_option( 'wcj_product_by_country_country_list_shortcode’, ‘all’ ) );490 $wpnonce = isset( $_REQUEST[ ‘wcj_’ . $atts[‘selector_type’] . ‘_selector-nonce’ ] ) ? wp_verify_nonce( sanitize_key( $_REQUEST[ ‘wcj_’ . $atts[‘selector_type’] . ‘_selector-nonce’ ] ), ‘wcj_’ . $atts[‘selector_type’] . ‘_selector’ ) : false;491 $selected_value = ( ( $wpnonce && isset( $_REQUEST[ ‘wcj_’ . $atts[‘selector_type’] . ‘_selector’ ] ) ) ?492 sanitize_text_field( wp_unslash( $_REQUEST[ ‘wcj_’ . $atts[‘selector_type’] . ‘_selector’ ] ) ) :493 wcj_session_get( ‘wcj_selected_’ . $atts[‘selector_type’] )494 );495496 switch ( $countries ) {497 case 'wc’:498 $countries = WC()->countries->get_allowed_countries();499 break;500 default: // 'all’.501 $countries = wcj_get_countries();502 break;503 }504505 switch ( $atts[‘selector_type’] ) {506 case 'product_custom_visibility’:507 $options = wcj_get_select_options( wcj_get_option( 'wcj_product_custom_visibility_options_list’, ‘’ ) );508 break;509 default: // 'country’.510 $options = $countries;511 asort( $options );512 break;513 }514 foreach ( $options as $value => $title ) {515 $html .= ‘<option value="’ . $value . '" ' . selected( $selected_value, $value, false ) . ‘>’ . $title . '</option>’;516 }517 return ‘<form method="post" action="">’ .518 ‘<select name="wcj_’ . $atts[‘selector_type’] . ‘_selector" class="wcj_’ . $atts[‘selector_type’] . ‘_selector" onchange="this.form.submit()">’ .519 $html .520 ‘</select>’ .521 wp_nonce_field( ‘wcj_’ . $atts[‘selector_type’] . '_selector’, ‘wcj_’ . $atts[‘selector_type’] . ‘_selector-nonce’ ) .522 '</form>’;523 }524525 /**526 * Wcj_site_url.527 *528 * @version 2.9.1529 * @since 2.9.1530 * @param array $atts The user defined shortcode attributes.531 */532 public function wcj_site_url( $atts ) {533 return site_url();534 }535536 /**537 * Wcj_currency_exchange_rate.538 *539 * @version 2.9.0540 * @since 2.9.0541 * @todo (maybe) add similar function542 * @param array $atts The user defined shortcode attributes.543 */544 public function wcj_currency_exchange_rate( $atts ) {545 return ( ‘’ !== $atts[‘from’] && ‘’ !== $atts[‘to’] ) ? wcj_get_option( ‘wcj_currency_exchange_rates_’ . sanitize_title( $atts[‘from’] . $atts[‘to’] ) ) : '’;546 }547548 /**549 * Wcj_currency_exchange_rate_wholesale_module.550 *551 * @version 5.4.5552 * @since 5.4.5553 * @todo (maybe) add similar function554 */555 public function wcj_currency_exchange_rate_wholesale_module() {556 $store_base_currency = strtolower( get_option( ‘woocommerce_currency’ ) );557 $store_current_currency = strtolower( get_woocommerce_currency() );558 return ( ‘’ !== $store_base_currency && ‘’ !== $store_current_currency ) ? wcj_get_option( ‘wcj_currency_exchange_rates_’ . sanitize_title( $store_base_currency . $store_current_currency ) ) : '’;559560 }561562563 /**564 * Wcj_currency_exchange_rates_table.565 *566 * @version 6.0.1567 * @since 2.9.0568 * @todo (maybe) add similar function569 * @param array $atts The user defined shortcode attributes.570 */571 public function wcj_currency_exchange_rates_table( $atts ) {572 $all_currencies = w_c_j()->all_modules[‘currency_exchange_rates’]->get_all_currencies_exchange_rates_settings();573 $table_data = array();574 foreach ( $all_currencies as $currency ) {575 $table_data[] = array( $currency[‘title’], wcj_get_option( $currency[‘id’] ) );576 }577 if ( ! empty( $table_data ) ) {578 return wcj_get_table_html(579 $table_data,580 array(581 ‘table_class’ => 'wcj_currency_exchange_rates_table’,582 ‘table_heading_type’ => 'vertical’,583 )584 );585 } else {586 return '’;587 }588 }589590 /**591 * Wcj_empty_cart_button.592 *593 * @version 2.8.0594 * @since 2.8.0595 * @param array $atts The user defined shortcode attributes.596 */597 public function wcj_empty_cart_button( $atts ) {598 if ( ! wcj_is_module_enabled( ‘empty_cart’ ) ) {599 /* translators: %s: translation added */600 return ‘<p>’ . sprintf( __( '"%s" module is not enabled!’, ‘woocommerce-jetpack’ ), __( 'Empty Cart Button’, ‘woocommerce-jetpack’ ) ) . '</p>’;601 }602 return wcj_empty_cart_button_html();603 }604605 /**606 * Wcj_current_time.607 *608 * @version 5.6.8609 * @since 2.6.0610 * @param array $atts The user defined shortcode attributes.611 */612 public function wcj_current_time( $atts ) {613 return date_i18n( $atts[‘time_format’], wcj_get_timestamp_date_from_gmt() );614 }615616 /**617 * Wcj_current_datetime.618 *619 * @version 5.6.8620 * @since 2.6.0621 * @param array $atts The user defined shortcode attributes.622 */623 public function wcj_current_datetime( $atts ) {624 return date_i18n( $atts[‘datetime_format’], wcj_get_timestamp_date_from_gmt() );625 }626627 /**628 * Wcj_current_timestamp.629 *630 * @version 5.6.8631 * @since 2.6.0632 * @param array $atts The user defined shortcode attributes.633 */634 public function wcj_current_timestamp( $atts ) {635 return wcj_get_timestamp_date_from_gmt();636 }637638 /**639 * Wcj_customer_order_count.640 *641 * @version 3.4.0642 * @since 3.4.0643 * @todo `hide_if_zero`644 * @param array $atts The user defined shortcode attributes.645 */646 public function wcj_customer_order_count( $atts ) {647 if ( is_user_logged_in() ) {648 $current_user = wp_get_current_user();649 $customer = new WC_Customer( $current_user->ID );650 return $customer->get_order_count();651 } else {652 return '’;653 }654 }655656 /**657 * Wcj_customer_total_spent.658 *659 * @version 3.4.0660 * @since 3.4.0661 * @todo `hide_if_zero`662 * @todo `hide_currency`663 * @todo (maybe) solve multicurrency issue664 * @param array $atts The user defined shortcode attributes.665 */666 public function wcj_customer_total_spent( $atts ) {667 if ( is_user_logged_in() ) {668 $current_user = wp_get_current_user();669 $customer = new WC_Customer( $current_user->ID );670 return wc_price( $customer->get_total_spent() );671 } else {672 return '’;673 }674 }675676 /**677 * Wcj_customer_billing_country.678 *679 * @version 2.5.8680 * @since 2.5.8681 * @see https://docs.woocommerce.com/wc-apidocs/class-WC_Customer.html682 * @todo move all customer shortcodes to new class `WCJ_Customers_Shortcodes` (and there `$this->the_customer = new WC_Customer( $current_user->ID )`)683 * @todo add `[wcj_customer_taxable_address]` (with `$customer->get_taxable_address()`)684 * @todo add `[wcj_customer_prop]` (with `$customer->get_{$atts[‘key’]}()`)685 * @param array $atts The user defined shortcode attributes.686 */687 public function wcj_customer_billing_country( $atts ) {688 if ( is_user_logged_in() ) {689 $current_user = wp_get_current_user();690 $meta = get_user_meta( $current_user->ID, 'billing_country’, true );691 if ( ‘’ !== ( $meta ) ) {692 return ( ‘yes’ === $atts[‘full_country_name’] ) ? wcj_get_country_name_by_code( $meta ) : $meta;693 }694 }695 return '’;696 }697698 /**699 * Wcj_customer_shipping_country.700 *701 * @version 2.5.8702 * @since 2.5.8703 * @param array $atts The user defined shortcode attributes.704 */705 public function wcj_customer_shipping_country( $atts ) {706 if ( is_user_logged_in() ) {707 $current_user = wp_get_current_user();708 $meta = get_user_meta( $current_user->ID, 'shipping_country’, true );709 if ( ‘’ !== ( $meta ) ) {710 return ( ‘yes’ === $atts[‘full_country_name’] ) ? wcj_get_country_name_by_code( $meta ) : $meta;711 }712 }713 return '’;714 }715716 /**717 * Wcj_customer_meta.718 *719 * @version 2.5.8720 * @since 2.5.8721 * @param array $atts The user defined shortcode attributes.722 */723 public function wcj_customer_meta( $atts ) {724 if ( ‘’ !== $atts[‘key’] && is_user_logged_in() ) {725 $current_user = wp_get_current_user();726 $meta = get_user_meta( $current_user->ID, $atts[‘key’], true );727 if ( ‘’ !== ( $meta ) ) {728 return $meta;729 }730 }731 return '’;732 }733734 /**735 * Get_shortcode_currencies.736 *737 * @version 2.4.5738 * @since 2.4.5739 * @param array $atts The user defined shortcode attributes.740 */741 private function get_shortcode_currencies( $atts ) {742 // Shortcode currencies.743 $shortcode_currencies = $atts[‘currencies’];744 if ( ‘’ === $shortcode_currencies ) {745 $shortcode_currencies = array();746 } else {747 $shortcode_currencies = str_replace( ' ', '’, $shortcode_currencies );748 $shortcode_currencies = trim( $shortcode_currencies, ‘,’ );749 $shortcode_currencies = explode( ',’, $shortcode_currencies );750 }751 if ( empty( $shortcode_currencies ) ) {752 $total_number = apply_filters( 'booster_option’, 2, wcj_get_option( 'wcj_multicurrency_total_number’, 2 ) );753 for ( $i = 1; $i <= $total_number; $i++ ) {754 $shortcode_currencies[] = wcj_get_option( ‘wcj_multicurrency_currency_’ . $i );755 }756 }757 return $shortcode_currencies;758 }759760 /**761 * Wcj_wholesale_price_table (global only).762 *763 * @version 3.1.0764 * @since 2.4.8765 * @param array $atts The user defined shortcode attributes.766 */767 public function wcj_wholesale_price_table( $atts ) {768769 if ( ! wcj_is_module_enabled( ‘wholesale_price’ ) ) {770 return '’;771 }772773 // Check for user role options.774 $role_option_name_addon = '’;775 $user_roles = wcj_get_option( 'wcj_wholesale_price_by_user_role_roles’, ‘’ );776 if ( ! empty( $user_roles ) ) {777 $current_user_role = wcj_get_current_user_first_role();778 foreach ( $user_roles as $user_role_key ) {779 if ( $current_user_role === $user_role_key ) {780 $role_option_name_addon = ‘_’ . $user_role_key;781 break;782 }783 }784 }785786 $wholesale_price_levels = array();787 $wcj_wholesale_price_levels_number = apply_filters( 'booster_option’, 1, wcj_get_option( ‘wcj_wholesale_price_levels_number’ . $role_option_name_addon, 1 ) );788 for ( $i = 1; $i <= $wcj_wholesale_price_levels_number; $i++ ) {789 $level_qty = wcj_get_option( ‘wcj_wholesale_price_level_min_qty’ . $role_option_name_addon . ‘_’ . $i, PHP_INT_MAX );790 $discount = wcj_get_option( ‘wcj_wholesale_price_level_discount_percent’ . $role_option_name_addon . ‘_’ . $i, 0 );791 $wholesale_price_levels[] = array(792 ‘quantity’ => $level_qty,793 ‘discount’ => $discount,794 );795 }796797 $data_qty = array();798 $data_discount = array();799 $columns_styles = array();800 $i = -1;801 foreach ( $wholesale_price_levels as $wholesale_price_level ) {802 $i++;803 if ( 0 === $wholesale_price_level[‘quantity’] && ‘yes’ === $atts[‘hide_if_zero_quantity’] ) {804 continue;805 }806 $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’];807 $data_qty[] = str_replace(808 array( '%level_qty%’, '%level_min_qty%’, ‘%level_max_qty%’ ), // %level_qty% is deprecated809 array( $wholesale_price_level[‘quantity’], $wholesale_price_level[‘quantity’], $level_max_qty ),810 $atts[‘heading_format’]811 );812 $data_discount[] = ( ‘fixed’ === wcj_get_option( 'wcj_wholesale_price_discount_type’, ‘percent’ ) )813 ? '-' . wc_price( $wholesale_price_level[‘discount’] ) : '-' . $wholesale_price_level[‘discount’] . '%’;814 $columns_styles[] = $atts[‘columns_style’];815 }816817 $table_rows = array( $data_qty, $data_discount );818819 if ( ‘vertical’ === $atts[‘table_format’] ) {820 $table_rows_modified = array();821 foreach ( $table_rows as $row_number => $table_row ) {822 foreach ( $table_row as $column_number => $cell ) {823 $table_rows_modified[ $column_number ][ $row_number ] = $cell;824 }825 }826 $table_rows = $table_rows_modified;827 }828829 return wcj_get_table_html(830 $table_rows,831 array(832 ‘table_class’ => 'wcj_wholesale_price_table’,833 ‘columns_styles’ => $columns_styles,834 ‘table_heading_type’ => $atts[‘table_format’],835 )836 );837 }838839 /**840 * Wcj_currency_select_link_list.841 *842 * @version 5.6.8843 * @since 2.4.5844 * @param array $atts The user defined shortcode attributes.845 * @param array | string $content The user defined shortcode content.846 */847 public function wcj_currency_select_link_list( $atts, $content ) {848 $html = '’;849 $shortcode_currencies = $this->get_shortcode_currencies( $atts );850 // Options.851 $currencies = get_woocommerce_currencies();852 $selected_currency = '’;853 $session_value = wcj_session_get( ‘wcj-currency’ );854 if ( null !== ( $session_value ) ) {855 $selected_currency = $session_value;856 } else {857 $module_roles = wcj_get_option( 'wcj_multicurrency_role_defaults_roles’, ‘’ );858 if ( ! empty( $module_roles ) ) {859 $current_user_role = wcj_get_current_user_first_role();860 if ( in_array( $current_user_role, $module_roles, true ) ) {861 $selected_currency = wcj_get_option( ‘wcj_multicurrency_role_defaults_’ . $current_user_role, ‘’ );862 }863 }864 }865 if ( ‘’ === $selected_currency && ‘’ !== $atts[‘default’] ) {866 $selected_currency = $atts[‘default’];867 }868 $links = array();869 $first_link = '’;870 $switcher_template = wcj_get_option( 'wcj_multicurrency_switcher_template’, '%currency_name% (%currency_symbol%)' );871 foreach ( $shortcode_currencies as $currency_code ) {872 if ( isset( $currencies[ $currency_code ] ) ) {873 $template_replaced_values = array(874 ‘%currency_name%’ => $currencies[ $currency_code ],875 ‘%currency_code%’ => $currency_code,876 ‘%currency_symbol%’ => get_woocommerce_currency_symbol( $currency_code ),877 );878 $currency_switcher_output = str_replace( array_keys( $template_replaced_values ), array_values( $template_replaced_values ), $switcher_template );879 $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>’;880 if ( $currency_code !== $selected_currency ) {881 $links[] = $the_link;882 } else {883 $first_link = $the_link;884 }885 }886 }887 if ( ‘’ !== $first_link ) {888 $links = array_merge( array( $first_link ), $links );889 }890 $html .= implode( '<br>’, $links );891 return $html;892 }893894 /**895 * Wcj_get_left_to_free_shipping.896 *897 * @version 2.5.8898 * @since 2.4.4899 * @param array $atts The user defined shortcode attributes.900 * @param array | string $content The user defined shortcode content.901 */902 public function wcj_get_left_to_free_shipping( $atts, $content ) {903 return wcj_get_left_to_free_shipping( $atts[‘content’], $atts[‘multiply_by’] );904 }905906 /**907 * Wcj_tcpdf_pagebreak.908 *909 * @version 2.3.7910 * @since 2.3.7911 * @param array $atts The user defined shortcode attributes.912 * @param array | string $content The user defined shortcode content.913 */914 public function wcj_tcpdf_pagebreak( $atts, $content ) {915 return '<tcpdf method="AddPage" />’;916 }917918 /**919 * Get_currency_selector.920 *921 * @version 5.6.8922 * @since 2.4.5923 * @param array $atts The user defined shortcode attributes.924 * @param array | string $content The user defined shortcode content.925 * @param string $type The user defined shortcode type.926 */927 private function get_currency_selector( $atts, $content, $type = ‘select’ ) {928 // Start.929 $form_method = $atts[‘form_method’];930 $class = $atts[‘class’];931 $style = $atts[‘style’];932 $html = '’;933 $html .= ‘<form action="" method="’ . $form_method . '">’;934 if ( ‘select’ === $type ) {935 $html .= ‘<select name="wcj-currency" id="wcj-currency-select" style="’ . $style . ‘" class="’ . $class . '" onchange="this.form.submit()“>’;936 }937 $shortcode_currencies = $this->get_shortcode_currencies( $atts );938 // Options.939 $currencies = get_woocommerce_currencies();940 $selected_currency = '’;941 $session_value = wcj_session_get( ‘wcj-currency’ );942 if ( null !== ( $session_value ) ) {943 $selected_currency = $session_value;944 } else {945 $module_roles = wcj_get_option( 'wcj_multicurrency_role_defaults_roles’, ‘’ );946 if ( ! empty( $module_roles ) ) {947 $current_user_role = wcj_get_current_user_first_role();948 if ( in_array( $current_user_role, $module_roles, true ) ) {949 $selected_currency = wcj_get_option( ‘wcj_multicurrency_role_defaults_’ . $current_user_role, ‘’ );950 }951 }952 }953 if ( ‘’ === $selected_currency && ‘’ !== $atts[‘default’] ) {954 wcj_session_set( 'wcj-currency’, $atts[‘default’] );955 $selected_currency = $atts[‘default’];956 }957 $switcher_template = wcj_get_option( 'wcj_multicurrency_switcher_template’, '%currency_name% (%currency_symbol%)' );958 foreach ( $shortcode_currencies as $currency_code ) {959 if ( isset( $currencies[ $currency_code ] ) ) {960 $template_replaced_values = array(961 ‘%currency_name%’ => $currencies[ $currency_code ],962 ‘%currency_code%’ => $currency_code,963 ‘%currency_symbol%’ => get_woocommerce_currency_symbol( $currency_code ),964 );965 $currency_switcher_output = str_replace( array_keys( $template_replaced_values ), array_values( $template_replaced_values ), $switcher_template );966 if ( ‘’ === $selected_currency ) {967 $selected_currency = $currency_code;968 }969 if ( ‘select’ === $type ) {970 $html .= ‘<option value="’ . $currency_code . '” ' . selected( $currency_code, $selected_currency, false ) . ‘>’ . $currency_switcher_output . '</option>’;971 } elseif ( ‘radio’ === $type ) {972 $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>’;973 }974 }975 }976 // End.977 if ( ‘select’ === $type ) {978 $html .= '</select>’;979 }980 $html .= wp_nonce_field( 'wcj-currency’, ‘wcj-currency-nonce’ );981 $html .= '</form>’;982 return $html;983 }984985 /**986 * Wcj_currency_select_radio_list.987 *988 * @version 2.4.5989 * @since 2.4.5990 * @param array $atts The user defined shortcode attributes.991 * @param array | string $content The user defined shortcode content.992 */993 public function wcj_currency_select_radio_list( $atts, $content ) {994 return $this->get_currency_selector( $atts, $content, ‘radio’ );995 }996997 /**998 * Wcj_currency_select_drop_down_list.999 *1000 * @version 2.4.51001 * @since 2.4.31002 * @param array $atts The user defined shortcode attributes.1003 * @param array | string $content The user defined shortcode content.1004 */1005 public function wcj_currency_select_drop_down_list( $atts, $content ) {1006 return $this->get_currency_selector( $atts, $content, ‘select’ );1007 }10081009 /**1010 * Wcj_country_select_drop_down_list.1011 *1012 * @version 5.6.81013 * @param array $atts The user defined shortcode attributes.1014 * @param array | string $content The user defined shortcode content.1015 */1016 public function wcj_country_select_drop_down_list( $atts, $content ) {1017 $form_method = $atts[‘form_method’];1018 $select_class = $atts[‘class’];1019 $select_style = $atts[‘style’];1020 if ( ! isset( $atts[‘force_display’] ) || ! filter_var( $atts[‘force_display’], FILTER_VALIDATE_BOOLEAN ) ) {1021 if ( ! wcj_is_module_enabled( ‘price_by_country’ ) ) {1022 return;1023 }1024 }10251026 $countries = wcj_get_countries();1027 $shortcode_countries = ( empty( $atts[‘countries’] ) ? array() : array_map( 'trim’, explode( ',’, $atts[‘countries’] ) ) );1028 $session_value = wcj_session_get( ‘wcj-country’ );1029 $selected_country = ( null !== ( $session_value ) ? $session_value : ‘’ );1030 if ( ‘yes’ === $atts[‘replace_with_currency’] ) {1031 $currencies_names_and_symbols = wcj_get_woocommerce_currencies_and_symbols();1032 }1033 $html = '’;1034 $html .= '<form action="” method="’ . $form_method . '">’;1035 $html .= ‘<select name="wcj-country" id="wcj-country" style="’ . $select_style . ‘" class="’ . $select_class . ‘" onchange="this.form.submit()">’;1036 if ( empty( $shortcode_countries ) ) {1037 foreach ( $countries as $country_code => $country_name ) {1038 $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"’ : ‘’ );1039 $option_label = ( ‘yes’ === $atts[‘replace_with_currency’] ) ? $currencies_names_and_symbols[ wcj_get_currency_by_country( $country_code ) ] : $country_name;1040 $html .= ‘<option’ . $data_icon . ' value="’ . $country_code . '" ' . selected( $country_code, $selected_country, false ) . ‘>’ . $option_label . ‘</option>’;1041 }1042 } else {1043 foreach ( $shortcode_countries as $country_code ) {1044 if ( isset( $countries[ $country_code ] ) ) {1045 $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"’ : ‘’ );1046 $option_label = ( ‘yes’ === $atts[‘replace_with_currency’] ) ? $currencies_names_and_symbols[ wcj_get_currency_by_country( $country_code ) ] : $countries[ $country_code ];1047 $html .= ‘<option’ . $data_icon . ' value="’ . $country_code . ‘" ' . selected( $country_code, $selected_country, false ) . ‘>’ . $option_label . ‘</option>’;1048 }1049 }1050 }1051 $html .= wp_nonce_field( ‘wcj-country’, ‘wcj-country-nonce’ );1052 $html .= ‘</select>’;1053 $html .= ‘</form>’;1054 return $html;1055 }10561057 /**1058 * Wcj_text.1059 *1060 * @since 2.2.91061 * @param array $atts The user defined shortcode attributes.1062 * @param array | string $content The user defined shortcode content.1063 */1064 public function wcj_text( $atts, $content ) {10651066 return $content;1067 }10681069 /**1070 * Wcj_wpml.1071 *1072 * @version 2.2.91073 * @param array $atts The user defined shortcode attributes.1074 * @param array | string $content The user defined shortcode content.1075 */1076 public function wcj_wpml( $atts, $content ) {1077 return do_shortcode( $content );1078 }10791080 /**1081 * Wcj_wpml_translate.1082 *1083 * @param array $atts The user defined shortcode attributes.1084 * @param array | string $content The user defined shortcode content.1085 */1086 public function wcj_wpml_translate( $atts, $content ) {1087 return $this->wcj_wpml( $atts, $content );1088 }10891090 /**1091 * Wcj_current_date.1092 *1093 * @version 5.6.81094 * @param array $atts The user defined shortcode attributes.1095 */1096 public function wcj_current_date( $atts ) {1097 return date_i18n( $atts[‘date_format’], wcj_get_timestamp_date_from_gmt() );1098 }10991100 /**1101 * Wcj_image.1102 *1103 * @version 3.9.01104 * @since 3.9.01105 * @param array $atts The user defined shortcode attributes.1106 */1107 public function wcj_image( $atts ) {1108 return ‘<img’ .1109 ' src="’ . ( ! empty( $atts[‘src’] ) ? $atts[‘src’] : ‘’ ) . ‘"’ .1110 ' class="’ . ( ! empty( $atts[‘class’] ) ? $atts[‘class’] : ‘’ ) . ‘"’ .1111 ' style="’ . ( ! empty( $atts[‘style’] ) ? $atts[‘style’] : ‘’ ) . ‘"’ .1112 ' width="’ . ( ! empty( $atts[‘width’] ) ? $atts[‘width’] : ‘’ ) . ‘"’ .1113 ' height="’ . ( ! empty( $atts[‘height’] ) ? $atts[‘height’] : ‘’ ) . ‘"’ .1114 '>’;1115 }1116 }11171118endif;11191120return new WCJ_General_Shortcodes();