PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.4.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.4.0
2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 All 65 releases
← All changes | includes/Frontend/Product.php +104 -17 1.3.2 → 2.4.0 View file →
@@ -1,10 +1,21 @@
1 1 <?php
2 +/**
3 + * Storefront product handling for subscriptions.
4 + *
5 + * @package SpringDevs\Subscription
6 + */
2 7
3 8 namespace SpringDevs\Subscription\Frontend;
4 9
5 10 use SpringDevs\Subscription\Illuminate\Helper;
11 +use SpringDevs\Subscription\Illuminate\Subscription\Subscription;
6 12
13 +// HPOS: This file is compatible with WooCommerce High-Performance Order Storage (HPOS).
14 +// All WooCommerce order data is accessed via WooCommerce CRUD methods (wc_get_order, wc_get_order_item_meta, etc.).
15 +// All direct post meta access is for subscription data only, not WooCommerce order data.
16 +// If you add new order data access, use WooCommerce CRUD for HPOS compatibility.
17 +
7 18 /**
8 19 * Product class
9 20 * control single product page
10 21 */
@@ -22,9 +33,15 @@
22 33 ),
23 34 10,
24 35 2
25 36 );
26 - add_filter( 'woocommerce_product_add_to_cart_text', array( $this, 'change_single_add_to_cart_text' ), 10, 2 );
37 + add_filter( 'woocommerce_product_add_to_cart_text', array( $this, 'change_loop_add_to_cart_text' ), 10, 2 );
38 + // Plan-tied simple products behave like a variable product on the shop /
39 + // Product Collection loops: a "Select options" link to the product page (so
40 + // the customer picks a plan), never a direct/ajax add-to-cart. These native
41 + // product-method filters drive both the classic loop and the block button.
42 + add_filter( 'woocommerce_product_add_to_cart_url', array( $this, 'plan_loop_add_to_cart_url' ), 10, 2 );
43 + add_filter( 'woocommerce_product_supports', array( $this, 'plan_loop_disable_ajax' ), 10, 3 );
27 44 add_filter( 'woocommerce_get_price_html', array( $this, 'change_price_html' ), 10, 2 );
28 45 add_filter( 'woocommerce_quantity_input_args', array( $this, 'update_input_args' ), 10, 2 );
29 46 add_filter( 'woocommerce_add_to_cart', array( $this, 'update_cart_quantity' ), 10, 3 );
30 47 add_filter(
@@ -67,9 +84,9 @@
67 84 *
68 85 * @return mixed
69 86 */
70 87 public function remove_button_active_products( $button, $product ) {
71 - $product = sdevs_get_subscription_product( $product );
88 + $product = Subscription::get_subs_product( $product );
72 89 if ( ! $product->is_type( 'simple' ) ) {
73 90 return $button;
74 91 }
75 92
@@ -92,9 +109,9 @@
92 109 * Display notice if already purchased.
93 110 */
94 111 public function text_if_active() {
95 112 global $product;
96 - $sdevs_product = sdevs_get_subscription_product( $product );
113 + $sdevs_product = Subscription::get_subs_product( $product );
97 114 if ( ! $sdevs_product->is_type( 'simple' ) ) {
98 115 return;
99 116 }
100 117
@@ -103,18 +120,18 @@
103 120 if ( 'unlimited' === $limit ) {
104 121 return;
105 122 }
106 123 if ( 'one' === $limit ) {
107 - $unexpired = Helper::subscription_exists( $product->get_id(), array( 'active', 'pending' ) );
124 + $unexpired = Helper::subscription_exists( $sdevs_product->get_id(), array( 'active', 'pending' ) );
108 125 if ( ! $unexpired ) {
109 126 return false;
110 127 } else {
111 - echo '<strong>' . esc_html_e( 'You Already Subscribed These Product!', 'sdevs_subscrpt' ) . '</strong>';
128 + echo '<strong>' . esc_html_e( 'You Already Subscribed These Product!', 'subscription' ) . '</strong>';
112 129 }
113 130 }
114 131 if ( 'only_one' === $limit ) {
115 - if ( ! Helper::check_trial( $product->get_id() ) ) {
116 - echo '<strong>' . esc_html_e( 'You Already Subscribed These Product!', 'sdevs_subscrpt' ) . '</strong>';
132 + if ( ! Helper::check_trial( $sdevs_product->get_id() ) ) {
133 + echo '<strong>' . esc_html_e( 'You Already Subscribed These Product!', 'subscription' ) . '</strong>';
117 134 }
118 135 }
119 136 }
120 137 }
@@ -127,9 +144,9 @@
127 144 *
128 145 * @return boolean
129 146 */
130 147 public function check_if_purchasable( $is_purchasable, $product ) {
131 - $product = sdevs_get_subscription_product( $product );
148 + $product = Subscription::get_subs_product( $product );
132 149 if ( $product->is_enabled() ) {
133 150 $limit = $product->get_limit();
134 151 if ( 'unlimited' === $limit ) {
135 152 return true;
@@ -158,9 +175,10 @@
158 175 $order_item_id = get_post_meta( $expired, '_subscrpt_order_item_id', true );
159 176 $item_quantity = (int) wc_get_order_item_meta( $order_item_id, '_qty', true );
160 177 if ( $item_quantity !== $quantity ) {
161 178 WC()->cart->set_quantity( $cart_item_key, $item_quantity );
162 - wc_add_notice( 'You can only add ' . $item_quantity . ' ' . ( $item_quantity > 1 ? 'items' : 'item' ) . ' on cart!', 'error' );
179 + /* translators: %d: the number of items allowed in the cart. */
180 + wc_add_notice( sprintf( _n( 'You can only add %d item to the cart.', 'You can only add %d items to the cart.', $item_quantity, 'subscription' ), $item_quantity ), 'error' );
163 181 }
164 182 }
165 183 }
166 184
@@ -199,9 +217,10 @@
199 217 $order_item_id = get_post_meta( $expired, '_subscrpt_order_item_id', true );
200 218 $item_quantity = (int) wc_get_order_item_meta( $order_item_id, '_qty', true );
201 219 if ( $item_quantity !== $quantity ) {
202 220 WC()->cart->set_quantity( $cart_item_key, $item_quantity );
203 - wc_add_notice( 'You can only add ' . $item_quantity . ' ' . ( $item_quantity > 1 ? 'items' : 'item' ) . ' on cart!', 'error' );
221 + /* translators: %d: the number of items allowed in the cart. */
222 + wc_add_notice( sprintf( _n( 'You can only add %d item to the cart.', 'You can only add %d items to the cart.', $item_quantity, 'subscription' ), $item_quantity ), 'error' );
204 223 }
205 224 }
206 225 }
207 226
@@ -233,9 +252,9 @@
233 252 * @param string $text Add-to-cart button Text.
234 253 * @param \WC_Product $product Product Object.
235 254 */
236 255 public function change_single_add_to_cart_text( $text, $product ) {
237 - $product = sdevs_get_subscription_product( $product );
256 + $product = Subscription::get_subs_product( $product );
238 257 if ( $product->is_type( 'variable' ) || '' === $product->get_price() ) {
239 258 return $text;
240 259 }
241 260 $cart_btn_label = $product->get_button_label();
@@ -240,9 +259,9 @@
240 259 }
241 260 $cart_btn_label = $product->get_button_label();
242 261 $expired = Helper::subscription_exists( $product->get_id(), 'expired' );
243 262 if ( $expired ) {
244 - $text = __( 'Renew', 'sdevs_subscrpt' );
263 + $text = __( 'Renew', 'subscription' );
245 264 } elseif ( $product->is_enabled() && $cart_btn_label ) {
246 265 $text = $cart_btn_label;
247 266 }
248 267
@@ -249,8 +268,71 @@
249 268 return $text;
250 269 }
251 270
252 271 /**
272 + * Whether this is a plan-tied simple product that should behave like a
273 + * variable product on the shop / Product Collection loops.
274 + *
275 + * @param mixed $product Product object.
276 + *
277 + * @return bool
278 + */
279 + private function is_plan_loop_product( $product ) {
280 + return $product instanceof \WC_Product
281 + && $product->is_type( 'simple' )
282 + && subscrpt_plan_offered( $product->get_id() );
283 + }
284 +
285 + /**
286 + * Loop / block add-to-cart button text: "Select options" for plan products,
287 + * otherwise the classic label logic.
288 + *
289 + * @param string $text Add-to-cart button text.
290 + * @param \WC_Product $product Product object.
291 + *
292 + * @return string
293 + */
294 + public function change_loop_add_to_cart_text( $text, $product ) {
295 + if ( $this->is_plan_loop_product( $product ) ) {
296 + return __( 'Select options', 'subscription' );
297 + }
298 +
299 + return $this->change_single_add_to_cart_text( $text, $product );
300 + }
301 +
302 + /**
303 + * Loop / block add-to-cart URL: the product page for plan products, so the
304 + * customer lands on the plan selector instead of a bare add-to-cart.
305 + *
306 + * @param string $url Add-to-cart URL.
307 + * @param \WC_Product $product Product object.
308 + *
309 + * @return string
310 + */
311 + public function plan_loop_add_to_cart_url( $url, $product ) {
312 + return $this->is_plan_loop_product( $product ) ? $product->get_permalink() : $url;
313 + }
314 +
315 + /**
316 + * Disable ajax add-to-cart for plan products so their loop / block button
317 + * renders as a "Select options" link (navigates to the product page) rather
318 + * than an ajax add.
319 + *
320 + * @param bool $supports Whether the feature is supported.
321 + * @param string $feature Feature name.
322 + * @param \WC_Product $product Product object.
323 + *
324 + * @return bool
325 + */
326 + public function plan_loop_disable_ajax( $supports, $feature, $product ) {
327 + if ( 'ajax_add_to_cart' === $feature && $this->is_plan_loop_product( $product ) ) {
328 + return false;
329 + }
330 +
331 + return $supports;
332 + }
333 +
334 + /**
253 335 * Add trial, signup fee etc. with product price.
254 336 *
255 337 * @param mixed $price Price.
256 338 * @param \WC_Product $product Product.
@@ -257,9 +339,9 @@
257 339 *
258 340 * @return mixed
259 341 */
260 342 public function change_price_html( $price, $product ) {
261 - $product = sdevs_get_subscription_product( $product );
343 + $product = Subscription::get_subs_product( $product );
262 344 if ( ! $product->is_type( 'simple' ) || '' === $price ) {
263 345 return $price;
264 346 }
265 347
@@ -264,16 +346,21 @@
264 346 }
265 347
266 348 if ( $product->is_enabled() ) :
267 349 $timing_option = $product->get_timing_option();
268 - $type = Helper::get_typos( 1, $timing_option );
269 - $trial = null;
350 + $type = ucfirst( Helper::get_typos( 1, $timing_option, true ) );
351 +
352 + $trial = null;
270 353 if ( $product->has_trial() ) {
271 354 $meta_trial_time = $product->get_trial_timing_per();
272 - $trial = '<br/><small> + Get ' . $meta_trial_time . ' ' . Helper::get_typos( $meta_trial_time, $product->get_trial_timing_option() ) . ' free trial!</small>';
355 + $trial_type = Helper::get_typos( $meta_trial_time, $product->get_trial_timing_option(), true );
356 + $trial = '<br/><small> + Get ' . $meta_trial_time . ' ' . ucfirst( $trial_type ) . ' free trial!</small>';
273 357 }
274 358
275 - return apply_filters( 'subscrpt_simple_price_html', ( $price . ' / ' . $type . $trial ), $product, $price, $trial );
359 + $timing_html = "<span class='wpsubs-subscription-timing'>&nbsp;/&nbsp;{$type}</span>";
360 + $price_html = $price . $timing_html . $trial;
361 +
362 + return apply_filters( 'subscrpt_simple_price_html', $price_html, $product, $price, $trial );
276 363 else :
277 364 return $price;
278 365 endif;
279 366 }