PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.6.2
WooCommerce v10.6.2
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / class-wc-shortcodes.php
woocommerce / includes Last commit date
abstracts 2 months ago admin 2 months ago blocks 2 months ago cli 2 months ago customizer 2 months ago data-stores 2 months ago emails 2 months ago export 2 months ago gateways 2 months ago import 2 months ago integrations 2 months ago interfaces 2 months ago legacy 2 months ago libraries 2 months ago log-handlers 2 months ago payment-tokens 2 months ago product-usage 2 months ago queue 2 months ago react-admin 2 months ago rest-api 2 months ago shipping 2 months ago shortcodes 2 months ago theme-support 2 months ago tracks 2 months ago traits 2 months ago walkers 2 months ago wccom-site 2 months ago widgets 2 months ago class-wc-ajax.php 2 months ago class-wc-auth.php 2 months ago class-wc-autoloader.php 2 months ago class-wc-background-emailer.php 2 months ago class-wc-background-updater.php 2 months ago class-wc-brands-brand-settings-manager.php 2 months ago class-wc-brands-coupons.php 2 months ago class-wc-brands.php 2 months ago class-wc-breadcrumb.php 2 months ago class-wc-cache-helper.php 2 months ago class-wc-cart-fees.php 2 months ago class-wc-cart-session.php 2 months ago class-wc-cart-totals.php 2 months ago class-wc-cart.php 2 months ago class-wc-checkout.php 2 months ago class-wc-cli.php 2 months ago class-wc-comments.php 2 months ago class-wc-countries.php 2 months ago class-wc-coupon.php 2 months ago class-wc-customer-download-log.php 2 months ago class-wc-customer-download.php 2 months ago class-wc-customer.php 2 months ago class-wc-data-exception.php 2 months ago class-wc-data-store.php 2 months ago class-wc-datetime.php 2 months ago class-wc-deprecated-action-hooks.php 2 months ago class-wc-deprecated-filter-hooks.php 2 months ago class-wc-discounts.php 2 months ago class-wc-download-handler.php 2 months ago class-wc-emails.php 2 months ago class-wc-embed.php 2 months ago class-wc-form-handler.php 2 months ago class-wc-frontend-scripts.php 2 months ago class-wc-geo-ip.php 2 months ago class-wc-geolite-integration.php 2 months ago class-wc-geolocation.php 2 months ago class-wc-https.php 2 months ago class-wc-install.php 2 months ago class-wc-integrations.php 2 months ago class-wc-log-levels.php 2 months ago class-wc-logger.php 2 months ago class-wc-meta-data.php 2 months ago class-wc-order-factory.php 2 months ago class-wc-order-item-coupon.php 2 months ago class-wc-order-item-fee.php 2 months ago class-wc-order-item-meta.php 2 months ago class-wc-order-item-product.php 2 months ago class-wc-order-item-shipping.php 2 months ago class-wc-order-item-tax.php 2 months ago class-wc-order-item.php 2 months ago class-wc-order-query.php 2 months ago class-wc-order-refund.php 2 months ago class-wc-order.php 2 months ago class-wc-payment-gateways.php 2 months ago class-wc-payment-tokens.php 2 months ago class-wc-post-data.php 2 months ago class-wc-post-types.php 2 months ago class-wc-privacy-background-process.php 2 months ago class-wc-privacy-erasers.php 2 months ago class-wc-privacy-exporters.php 2 months ago class-wc-privacy.php 2 months ago class-wc-product-attribute.php 2 months ago class-wc-product-download.php 2 months ago class-wc-product-external.php 2 months ago class-wc-product-factory.php 2 months ago class-wc-product-grouped.php 2 months ago class-wc-product-query.php 2 months ago class-wc-product-simple.php 2 months ago class-wc-product-variable.php 2 months ago class-wc-product-variation.php 2 months ago class-wc-query.php 2 months ago class-wc-rate-limiter.php 2 months ago class-wc-regenerate-images-request.php 2 months ago class-wc-regenerate-images.php 2 months ago class-wc-register-wp-admin-settings.php 2 months ago class-wc-rest-authentication.php 2 months ago class-wc-rest-exception.php 2 months ago class-wc-session-handler.php 2 months ago class-wc-shipping-rate.php 2 months ago class-wc-shipping-zone.php 2 months ago class-wc-shipping-zones.php 2 months ago class-wc-shipping.php 2 months ago class-wc-shortcodes.php 2 months ago class-wc-structured-data.php 2 months ago class-wc-tax.php 2 months ago class-wc-template-loader.php 2 months ago class-wc-tracker.php 2 months ago class-wc-validation.php 2 months ago class-wc-webhook.php 2 months ago class-woocommerce.php 2 months ago wc-account-functions.php 2 months ago wc-attribute-functions.php 2 months ago wc-brands-functions.php 2 months ago wc-cart-functions.php 2 months ago wc-conditional-functions.php 2 months ago wc-core-functions.php 2 months ago wc-coupon-functions.php 2 months ago wc-deprecated-functions.php 2 months ago wc-formatting-functions.php 2 months ago wc-interactivity-api-functions.php 2 months ago wc-notice-functions.php 2 months ago wc-order-functions.php 2 months ago wc-order-item-functions.php 2 months ago wc-order-step-logger-functions.php 2 months ago wc-page-functions.php 2 months ago wc-product-functions.php 2 months ago wc-rest-functions.php 2 months ago wc-stock-functions.php 2 months ago wc-template-functions.php 2 months ago wc-template-hooks.php 2 months ago wc-term-functions.php 2 months ago wc-update-functions.php 2 months ago wc-user-functions.php 2 months ago wc-webhook-functions.php 2 months ago wc-widget-functions.php 2 months ago
class-wc-shortcodes.php
743 lines
1 <?php
2 /**
3 * Shortcodes
4 *
5 * @package WooCommerce\Classes
6 * @version 3.2.0
7 */
8
9 use Automattic\WooCommerce\Enums\ProductStatus;
10 use Automattic\WooCommerce\Enums\ProductType;
11
12 defined( 'ABSPATH' ) || exit;
13
14 /**
15 * WooCommerce Shortcodes class.
16 */
17 class WC_Shortcodes {
18
19 /**
20 * Init shortcodes.
21 */
22 public static function init() {
23 $shortcodes = array(
24 'product' => __CLASS__ . '::product',
25 'product_page' => __CLASS__ . '::product_page',
26 'product_category' => __CLASS__ . '::product_category',
27 'product_categories' => __CLASS__ . '::product_categories',
28 'add_to_cart' => __CLASS__ . '::product_add_to_cart',
29 'add_to_cart_url' => __CLASS__ . '::product_add_to_cart_url',
30 'products' => __CLASS__ . '::products',
31 'recent_products' => __CLASS__ . '::recent_products',
32 'sale_products' => __CLASS__ . '::sale_products',
33 'best_selling_products' => __CLASS__ . '::best_selling_products',
34 'top_rated_products' => __CLASS__ . '::top_rated_products',
35 'featured_products' => __CLASS__ . '::featured_products',
36 'product_attribute' => __CLASS__ . '::product_attribute',
37 'related_products' => __CLASS__ . '::related_products',
38 'shop_messages' => __CLASS__ . '::shop_messages',
39 'woocommerce_order_tracking' => __CLASS__ . '::order_tracking',
40 'woocommerce_cart' => __CLASS__ . '::cart',
41 'woocommerce_checkout' => __CLASS__ . '::checkout',
42 'woocommerce_my_account' => __CLASS__ . '::my_account',
43 );
44
45 foreach ( $shortcodes as $shortcode => $function ) {
46 add_shortcode( apply_filters( "{$shortcode}_shortcode_tag", $shortcode ), $function );
47 }
48
49 // Alias for pre 2.1 compatibility.
50 add_shortcode( 'woocommerce_messages', __CLASS__ . '::shop_messages' );
51 }
52
53 /**
54 * Shortcode Wrapper.
55 *
56 * @param string[] $function Callback function.
57 * @param array $atts Attributes. Default to empty array.
58 * @param array $wrapper Customer wrapper data.
59 *
60 * @return string
61 */
62 public static function shortcode_wrapper(
63 $function,
64 $atts = array(),
65 $wrapper = array(
66 'class' => 'woocommerce',
67 'before' => null,
68 'after' => null,
69 )
70 ) {
71 ob_start();
72
73 // @codingStandardsIgnoreStart
74 echo empty( $wrapper['before'] ) ? '<div class="' . esc_attr( $wrapper['class'] ) . '">' : $wrapper['before'];
75 call_user_func( $function, $atts );
76 echo empty( $wrapper['after'] ) ? '</div>' : $wrapper['after'];
77 // @codingStandardsIgnoreEnd
78
79 return ob_get_clean();
80 }
81
82 /**
83 * Cart page shortcode.
84 *
85 * @return string
86 */
87 public static function cart() {
88 return is_null( WC()->cart ) ? '' : self::shortcode_wrapper( array( 'WC_Shortcode_Cart', 'output' ) );
89 }
90
91 /**
92 * Checkout page shortcode.
93 *
94 * @param array $atts Attributes.
95 * @return string
96 */
97 public static function checkout( $atts ) {
98 return self::shortcode_wrapper( array( 'WC_Shortcode_Checkout', 'output' ), $atts );
99 }
100
101 /**
102 * Order tracking page shortcode.
103 *
104 * @param array $atts Attributes.
105 * @return string
106 */
107 public static function order_tracking( $atts ) {
108 return self::shortcode_wrapper( array( 'WC_Shortcode_Order_Tracking', 'output' ), $atts );
109 }
110
111 /**
112 * My account page shortcode.
113 *
114 * @param array $atts Attributes.
115 * @return string
116 */
117 public static function my_account( $atts ) {
118 return self::shortcode_wrapper( array( 'WC_Shortcode_My_Account', 'output' ), $atts );
119 }
120
121 /**
122 * List products in a category shortcode.
123 *
124 * @param array $atts Attributes.
125 * @return string
126 */
127 public static function product_category( $atts ) {
128 if ( empty( $atts['category'] ) ) {
129 return '';
130 }
131
132 $atts = array_merge(
133 array(
134 'limit' => '12',
135 'columns' => '4',
136 'orderby' => 'menu_order title',
137 'order' => 'ASC',
138 'category' => '',
139 'cat_operator' => 'IN',
140 ),
141 (array) $atts
142 );
143
144 $shortcode = new WC_Shortcode_Products( $atts, 'product_category' );
145
146 return $shortcode->get_content();
147 }
148
149 /**
150 * List all (or limited) product categories.
151 *
152 * @param array $atts Attributes.
153 * @return string
154 */
155 public static function product_categories( $atts ) {
156 if ( isset( $atts['number'] ) ) {
157 $atts['limit'] = $atts['number'];
158 }
159
160 $atts = shortcode_atts(
161 array(
162 'limit' => '-1',
163 'orderby' => 'name',
164 'order' => 'ASC',
165 'columns' => '4',
166 'hide_empty' => 1,
167 'parent' => '',
168 'ids' => '',
169 ),
170 $atts,
171 'product_categories'
172 );
173
174 $ids = array_filter( array_map( 'trim', explode( ',', $atts['ids'] ) ) );
175 $hide_empty = ( true === $atts['hide_empty'] || 'true' === $atts['hide_empty'] || 1 === $atts['hide_empty'] || '1' === $atts['hide_empty'] ) ? 1 : 0;
176
177 // Get terms and workaround WP bug with parents/pad counts.
178 $args = array(
179 'orderby' => $atts['orderby'],
180 'order' => $atts['order'],
181 'hide_empty' => $hide_empty,
182 'include' => $ids,
183 'pad_counts' => true,
184 'child_of' => $atts['parent'],
185 );
186
187 $product_categories = apply_filters(
188 'woocommerce_product_categories',
189 get_terms( 'product_cat', $args )
190 );
191
192 if ( '' !== $atts['parent'] ) {
193 $product_categories = wp_list_filter(
194 $product_categories,
195 array(
196 'parent' => $atts['parent'],
197 )
198 );
199 }
200
201 if ( $hide_empty ) {
202 foreach ( $product_categories as $key => $category ) {
203 if ( 0 === $category->count ) {
204 unset( $product_categories[ $key ] );
205 }
206 }
207 }
208
209 $atts['limit'] = '-1' === $atts['limit'] ? null : intval( $atts['limit'] );
210 if ( $atts['limit'] ) {
211 $product_categories = array_slice( $product_categories, 0, $atts['limit'] );
212 }
213
214 $columns = absint( $atts['columns'] );
215
216 wc_set_loop_prop( 'columns', $columns );
217 wc_set_loop_prop( 'is_shortcode', true );
218
219 ob_start();
220
221 if ( $product_categories ) {
222 woocommerce_product_loop_start();
223
224 foreach ( $product_categories as $category ) {
225 wc_get_template(
226 'content-product_cat.php',
227 array(
228 'category' => $category,
229 )
230 );
231 }
232
233 woocommerce_product_loop_end();
234 }
235
236 wc_reset_loop();
237
238 return '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
239 }
240
241 /**
242 * Recent Products shortcode.
243 *
244 * @param array $atts Attributes.
245 * @return string
246 */
247 public static function recent_products( $atts ) {
248 $atts = array_merge(
249 array(
250 'limit' => '12',
251 'columns' => '4',
252 'orderby' => 'date',
253 'order' => 'DESC',
254 'category' => '',
255 'cat_operator' => 'IN',
256 ),
257 (array) $atts
258 );
259
260 $shortcode = new WC_Shortcode_Products( $atts, 'recent_products' );
261
262 return $shortcode->get_content();
263 }
264
265 /**
266 * List multiple products shortcode.
267 *
268 * @param array $atts Attributes.
269 * @return string
270 */
271 public static function products( $atts ) {
272 $atts = (array) $atts;
273 $type = 'products';
274
275 // Allow list product based on specific cases.
276 if ( isset( $atts['on_sale'] ) && wc_string_to_bool( $atts['on_sale'] ) ) {
277 $type = 'sale_products';
278 } elseif ( isset( $atts['best_selling'] ) && wc_string_to_bool( $atts['best_selling'] ) ) {
279 $type = 'best_selling_products';
280 } elseif ( isset( $atts['top_rated'] ) && wc_string_to_bool( $atts['top_rated'] ) ) {
281 $type = 'top_rated_products';
282 }
283
284 $shortcode = new WC_Shortcode_Products( $atts, $type );
285
286 return $shortcode->get_content();
287 }
288
289 /**
290 * Display a single product.
291 *
292 * @param array $atts Attributes.
293 * @return string
294 */
295 public static function product( $atts ) {
296 if ( empty( $atts ) ) {
297 return '';
298 }
299
300 $atts['skus'] = isset( $atts['sku'] ) ? $atts['sku'] : '';
301 $atts['ids'] = isset( $atts['id'] ) ? $atts['id'] : '';
302 $atts['limit'] = '1';
303 $shortcode = new WC_Shortcode_Products( (array) $atts, 'product' );
304
305 return $shortcode->get_content();
306 }
307
308 /**
309 * Display a single product price + cart button.
310 *
311 * @param array $atts Attributes.
312 * @return string
313 */
314 public static function product_add_to_cart( $atts ) {
315 global $post;
316
317 if ( empty( $atts ) ) {
318 return '';
319 }
320
321 $atts = shortcode_atts(
322 array(
323 'id' => '',
324 'class' => '',
325 'quantity' => '1',
326 'sku' => '',
327 'style' => 'border:4px solid #ccc; padding: 12px;',
328 'show_price' => 'true',
329 ),
330 $atts,
331 'product_add_to_cart'
332 );
333
334 if ( ! empty( $atts['id'] ) ) {
335 $product_data = get_post( $atts['id'] );
336 } elseif ( ! empty( $atts['sku'] ) ) {
337 $product_id = wc_get_product_id_by_sku( $atts['sku'] );
338 $product_data = get_post( $product_id );
339 } else {
340 return '';
341 }
342
343 $product = is_object( $product_data ) && in_array( $product_data->post_type, array( 'product', 'product_variation' ), true ) ? wc_setup_product_data( $product_data ) : false;
344
345 if ( ! $product ) {
346 return '';
347 }
348
349 ob_start();
350
351 echo '<p class="product woocommerce add_to_cart_inline ' . esc_attr( $atts['class'] ) . '" style="' . ( empty( $atts['style'] ) ? '' : esc_attr( $atts['style'] ) ) . '">';
352
353 if ( wc_string_to_bool( $atts['show_price'] ) ) {
354 // @codingStandardsIgnoreStart
355 echo $product->get_price_html();
356 // @codingStandardsIgnoreEnd
357 }
358
359 woocommerce_template_loop_add_to_cart(
360 array(
361 'quantity' => $atts['quantity'],
362 )
363 );
364
365 echo '</p>';
366
367 // Restore Product global in case this is shown inside a product post.
368 wc_setup_product_data( $post );
369
370 return ob_get_clean();
371 }
372
373 /**
374 * Get the add to cart URL for a product.
375 *
376 * @param array $atts Attributes.
377 * @return string
378 */
379 public static function product_add_to_cart_url( $atts ) {
380 if ( empty( $atts ) ) {
381 return '';
382 }
383
384 if ( isset( $atts['id'] ) ) {
385 $product_data = get_post( $atts['id'] );
386 } elseif ( isset( $atts['sku'] ) ) {
387 $product_id = wc_get_product_id_by_sku( $atts['sku'] );
388 $product_data = get_post( $product_id );
389 } else {
390 return '';
391 }
392
393 $product = is_object( $product_data ) && in_array( $product_data->post_type, array( 'product', 'product_variation' ), true ) ? wc_setup_product_data( $product_data ) : false;
394
395 if ( ! $product ) {
396 return '';
397 }
398
399 $_product = wc_get_product( $product_data );
400
401 return esc_url( $_product->add_to_cart_url() );
402 }
403
404 /**
405 * List all products on sale.
406 *
407 * @param array $atts Attributes.
408 * @return string
409 */
410 public static function sale_products( $atts ) {
411 $atts = array_merge(
412 array(
413 'limit' => '12',
414 'columns' => '4',
415 'orderby' => 'title',
416 'order' => 'ASC',
417 'category' => '',
418 'cat_operator' => 'IN',
419 ),
420 (array) $atts
421 );
422
423 $shortcode = new WC_Shortcode_Products( $atts, 'sale_products' );
424
425 return $shortcode->get_content();
426 }
427
428 /**
429 * List best selling products on sale.
430 *
431 * @param array $atts Attributes.
432 * @return string
433 */
434 public static function best_selling_products( $atts ) {
435 $atts = array_merge(
436 array(
437 'limit' => '12',
438 'columns' => '4',
439 'category' => '',
440 'cat_operator' => 'IN',
441 ),
442 (array) $atts
443 );
444
445 $shortcode = new WC_Shortcode_Products( $atts, 'best_selling_products' );
446
447 return $shortcode->get_content();
448 }
449
450 /**
451 * List top rated products on sale.
452 *
453 * @param array $atts Attributes.
454 * @return string
455 */
456 public static function top_rated_products( $atts ) {
457 $atts = array_merge(
458 array(
459 'limit' => '12',
460 'columns' => '4',
461 'orderby' => 'title',
462 'order' => 'ASC',
463 'category' => '',
464 'cat_operator' => 'IN',
465 ),
466 (array) $atts
467 );
468
469 $shortcode = new WC_Shortcode_Products( $atts, 'top_rated_products' );
470
471 return $shortcode->get_content();
472 }
473
474 /**
475 * Output featured products.
476 *
477 * @param array $atts Attributes.
478 * @return string
479 */
480 public static function featured_products( $atts ) {
481 $atts = array_merge(
482 array(
483 'limit' => '12',
484 'columns' => '4',
485 'orderby' => 'date',
486 'order' => 'DESC',
487 'category' => '',
488 'cat_operator' => 'IN',
489 ),
490 (array) $atts
491 );
492
493 $atts['visibility'] = 'featured';
494
495 $shortcode = new WC_Shortcode_Products( $atts, 'featured_products' );
496
497 return $shortcode->get_content();
498 }
499
500 /**
501 * Show a single product page.
502 *
503 * @param array $atts Attributes.
504 * @return string
505 */
506 public static function product_page( $atts ) {
507 if ( empty( $atts ) ) {
508 return '';
509 }
510
511 if ( ! isset( $atts['id'] ) && ! isset( $atts['sku'] ) ) {
512 return '';
513 }
514
515 $product_id = isset( $atts['id'] ) ? absint( $atts['id'] ) : 0;
516 if ( ! $product_id && isset( $atts['sku'] ) ) {
517 $product_id = wc_get_product_id_by_sku( $atts['sku'] );
518 }
519
520 $product_status = empty( $atts['status'] ) ? ProductStatus::PUBLISH : $atts['status'];
521 /**
522 * Filters the list of invalid statuses for the `product_page` shortcode.
523 *
524 * @since 8.6.0
525 * @param array $invalid_statuses List of invalid statuses.
526 * @param int $product_id Product ID.
527 * @return array
528 */
529 $invalid_statuses = apply_filters( 'woocommerce_shortcode_product_page_invalid_statuses', array( ProductStatus::TRASH ), $product_id );
530 if ( in_array( $product_status, $invalid_statuses, true ) ) {
531 return '';
532 }
533 /**
534 * Filters whether to override read permissions for unpublished products.
535 *
536 * @since 8.6.0
537 * @param bool $force_rendering Whether to override read permissions for unpublished products. `true` to force rendering the product page, `false` to block rendering, or `null` to use the default behavior.
538 * @param int $product_id Product ID.
539 * @return bool
540 */
541 $force_rendering = apply_filters( 'woocommerce_shortcode_product_page_force_rendering', null, $product_id );
542 if ( isset( $force_rendering ) && ! $force_rendering ) {
543 return '';
544 }
545
546 $args = array(
547 'posts_per_page' => 1,
548 'post_type' => 'product',
549 'post_status' => $product_status,
550 'ignore_sticky_posts' => 1,
551 'no_found_rows' => 1,
552 );
553
554 if ( isset( $atts['sku'] ) ) {
555 $args['meta_query'][] = array(
556 'key' => '_sku',
557 'value' => sanitize_text_field( $atts['sku'] ),
558 'compare' => '=',
559 );
560
561 $args['post_type'] = array( 'product', 'product_variation' );
562 }
563
564 if ( isset( $atts['id'] ) ) {
565 $args['p'] = absint( $atts['id'] );
566 }
567
568 // Don't render titles if desired.
569 if ( isset( $atts['show_title'] ) && ! $atts['show_title'] ) {
570 remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
571 }
572
573 // Change form action to avoid redirect.
574 add_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' );
575
576 $single_product = new WP_Query( $args );
577
578 if (
579 ! isset( $force_rendering ) &&
580 $single_product->have_posts() &&
581 ProductStatus::PUBLISH !== $single_product->post->post_status &&
582 ! current_user_can( 'read_product', $single_product->post->ID )
583 ) {
584 return '';
585 }
586
587 $preselected_id = '0';
588
589 // Check if sku is a variation.
590 if ( isset( $atts['sku'] ) && $single_product->have_posts() && 'product_variation' === $single_product->post->post_type ) {
591
592 $variation = wc_get_product_object( ProductType::VARIATION, $single_product->post->ID );
593 $attributes = $variation->get_attributes();
594
595 // Set preselected id to be used by JS to provide context.
596 $preselected_id = $single_product->post->ID;
597
598 // Get the parent product object.
599 $args = array(
600 'posts_per_page' => 1,
601 'post_type' => 'product',
602 'post_status' => ProductStatus::PUBLISH,
603 'ignore_sticky_posts' => 1,
604 'no_found_rows' => 1,
605 'p' => $single_product->post->post_parent,
606 );
607
608 $single_product = new WP_Query( $args );
609 ?>
610 <script type="text/javascript">
611 jQuery( function( $ ) {
612 var $variations_form = $( '[data-product-page-preselected-id="<?php echo esc_attr( $preselected_id ); ?>"]' ).find( 'form.variations_form' );
613
614 <?php foreach ( $attributes as $attr => $value ) { ?>
615 $variations_form.find( 'select[name="<?php echo esc_attr( $attr ); ?>"]' ).val( '<?php echo esc_js( $value ); ?>' );
616 <?php } ?>
617 });
618 </script>
619 <?php
620 }
621
622 // For "is_single" to always make load comments_template() for reviews.
623 $single_product->is_single = true;
624
625 ob_start();
626
627 global $wp_query;
628
629 // Backup query object so following loops think this is a product page.
630 $previous_wp_query = $wp_query;
631 // @codingStandardsIgnoreStart
632 $wp_query = $single_product;
633 // @codingStandardsIgnoreEnd
634
635 wp_enqueue_script( 'wc-single-product' );
636
637 while ( $single_product->have_posts() ) {
638 $single_product->the_post()
639 ?>
640 <div class="single-product" data-product-page-preselected-id="<?php echo esc_attr( $preselected_id ); ?>">
641 <?php wc_get_template_part( 'content', 'single-product' ); ?>
642 </div>
643 <?php
644 }
645
646 // Restore $previous_wp_query and reset post data.
647 // @codingStandardsIgnoreStart
648 $wp_query = $previous_wp_query;
649 // @codingStandardsIgnoreEnd
650 wp_reset_postdata();
651
652 // Re-enable titles if they were removed.
653 if ( isset( $atts['show_title'] ) && ! $atts['show_title'] ) {
654 add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
655 }
656
657 remove_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' );
658
659 return '<div class="woocommerce">' . ob_get_clean() . '</div>';
660 }
661
662 /**
663 * Show messages.
664 *
665 * @return string
666 */
667 public static function shop_messages() {
668 if ( ! function_exists( 'wc_print_notices' ) ) {
669 return '';
670 }
671 return '<div class="woocommerce">' . wc_print_notices( true ) . '</div>';
672 }
673
674 /**
675 * Order by rating.
676 *
677 * @deprecated 3.2.0 Use WC_Shortcode_Products::order_by_rating_post_clauses().
678 * @param array $args Query args.
679 * @return array
680 */
681 public static function order_by_rating_post_clauses( $args ) {
682 return WC_Shortcode_Products::order_by_rating_post_clauses( $args );
683 }
684
685 /**
686 * List products with an attribute shortcode.
687 * Example [product_attribute attribute="color" filter="black"].
688 *
689 * @param array $atts Attributes.
690 * @return string
691 */
692 public static function product_attribute( $atts ) {
693 $atts = array_merge(
694 array(
695 'limit' => '12',
696 'columns' => '4',
697 'orderby' => 'title',
698 'order' => 'ASC',
699 'attribute' => '',
700 'terms' => '',
701 ),
702 (array) $atts
703 );
704
705 if ( empty( $atts['attribute'] ) ) {
706 return '';
707 }
708
709 $shortcode = new WC_Shortcode_Products( $atts, 'product_attribute' );
710
711 return $shortcode->get_content();
712 }
713
714 /**
715 * List related products.
716 *
717 * @param array $atts Attributes.
718 * @return string
719 */
720 public static function related_products( $atts ) {
721 if ( isset( $atts['per_page'] ) ) {
722 $atts['limit'] = $atts['per_page'];
723 }
724
725 // @codingStandardsIgnoreStart
726 $atts = shortcode_atts( array(
727 'limit' => '4',
728 'columns' => '4',
729 'orderby' => 'rand',
730 ), $atts, 'related_products' );
731 // @codingStandardsIgnoreEnd
732
733 ob_start();
734
735 // Rename arg.
736 $atts['posts_per_page'] = absint( $atts['limit'] );
737
738 woocommerce_related_products( $atts );
739
740 return ob_get_clean();
741 }
742 }
743