PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.0.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.0.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 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
subscription / includes / Frontend / Cart.php

Cart.php in Subscriptions for WooCommerce with Stripe Recurring Payments 2.0.0, at includes/Frontend/Cart.php

666 lines 22.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Cart handling for subscription products.
4 *
5 * @package SpringDevs\Subscription
6 */
7
8 namespace SpringDevs\Subscription\Frontend;
9
10 use SpringDevs\Subscription\Illuminate\Helper;
11 use Automattic\WooCommerce\Blocks\Package;
12 use Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi;
13 use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;
14 use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
15 use SpringDevs\Subscription\Illuminate\Subscription\Subscription;
16
17 /**
18 * Cart class
19 */
20 class Cart {
21
22 /**
23 * Initialize the class
24 */
25 public function __construct() {
26 add_filter( 'woocommerce_add_cart_item_data', array( $this, 'add_to_cart_item_data' ), 10, 2 );
27 add_action( 'woocommerce_blocks_loaded', array( $this, 'define_custom_schema' ) );
28 add_filter( 'woocommerce_cart_item_price', array( $this, 'change_price_cart_html' ), 10, 2 );
29 add_filter( 'woocommerce_cart_item_subtotal', array( $this, 'change_price_cart_html' ), 10, 2 );
30 add_action( 'woocommerce_cart_totals_after_order_total', array( $this, 'add_rows_order_total' ) );
31 add_action( 'woocommerce_review_order_after_order_total', array( $this, 'add_rows_order_total' ) );
32 add_filter( 'woocommerce_add_cart_item_data', array( $this, 'set_renew_status' ), 10, 2 );
33 add_action( 'woocommerce_check_cart_items', array( $this, 'check_cart_items' ) );
34 add_filter( 'woocommerce_get_item_data', array( $this, 'set_line_item_meta' ), 10, 2 );
35 add_action( 'woocommerce_before_calculate_totals', array( $this, 'add_calculation_price_filter' ) );
36 add_action( 'woocommerce_calculate_totals', array( $this, 'remove_calculation_price_filter' ) );
37 add_action( 'woocommerce_after_calculate_totals', array( $this, 'remove_calculation_price_filter' ) );
38
39 add_filter( 'woocommerce_add_to_cart_validation', array( $this, 'add_to_cart_validation' ), 10, 4 );
40 add_action( 'woocommerce_store_api_validate_add_to_cart', array( $this, 'add_to_cart_validation_store_api' ), 10, 1 );
41 }
42
43 /**
44 * Add to cart validation.
45 *
46 * @param bool $passed Passed ?.
47 * @param int $product_id Product Id.
48 * @param int $quantity Quantity.
49 * @param int $variation_id Variation Id.
50 *
51 * @return bool
52 */
53 public function add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = 0 ) {
54 $product_id = (int) $variation_id > 0 ? (int) $variation_id : (int) $product_id;
55 $validation = $this->validate_cart_items( $product_id );
56
57 if ( $validation['failed'] ) {
58 $error_notice = empty( $validation['error_notice'] ) ? __( 'This product cannot be added to the cart.', 'subscription' ) : $validation['error_notice'];
59 wc_add_notice( $error_notice, 'error' );
60 return false;
61 }
62
63 // Validation passed.
64 return $passed;
65 }
66
67 /**
68 * Add to cart validation.
69 *
70 * @param \WC_Product $product Product.
71 * @throws \Exception If validation fails.
72 */
73 public function add_to_cart_validation_store_api( $product ) {
74 $product_id = $product->get_id();
75 $validation = $this->validate_cart_items( $product_id );
76
77 if ( $validation['failed'] ) {
78 $error_notice = empty( $validation['error_notice'] ) ? __( 'This product cannot be added to the cart.', 'subscription' ) : $validation['error_notice'];
79 throw new \Exception( esc_html( $error_notice ) );
80 }
81 }
82
83 /**
84 * Validate cart items.
85 *
86 * @param int $product_id Product Id.
87 * @return array
88 */
89 public function validate_cart_items( $product_id ) {
90 $cart_items = WC()->cart->cart_contents;
91
92 $product = Subscription::get_subs_product( $product_id );
93
94 $error_notice = null;
95 $failed = false;
96 // A tied plan counts as a subscription even without classic `_subscrpt_enabled`.
97 $enabled = $product->is_enabled() || subscrpt_plan_offered( $product_id );
98
99 foreach ( $cart_items as $key => $cart_item ) {
100 if ( isset( $cart_item['subscription'] ) ) {
101 if ( $enabled ) {
102 $error_notice = __( 'You cannot purchase multiple subscriptions at the same time.', 'subscription' );
103 } else {
104 $error_notice = __( 'You cannot purchase a subscription and a non-subscription product at the same time.', 'subscription' );
105 }
106 $failed = true;
107 } elseif ( $enabled ) {
108 $error_notice = __( 'You cannot purchase a subscription along with other products. Please remove other products from your cart first.', 'subscription' );
109 $failed = true;
110 }
111 }
112
113 return [
114 'failed' => (bool) $failed,
115 'error_notice' => $error_notice,
116 ];
117 }
118
119 /**
120 * Add filter before cart calculation.
121 *
122 * @return void
123 */
124 public function add_calculation_price_filter() {
125 add_filter( 'woocommerce_product_get_price', array( $this, 'set_prices_for_calculation' ), 100, 2 );
126 }
127
128 /**
129 * Return 0 if product has trial.
130 *
131 * @param float $price Price.
132 * @param \WC_Product $product Product object.
133 *
134 * @return float
135 */
136 public function set_prices_for_calculation( $price, $product ) {
137 $product = Subscription::get_subs_product( $product );
138 if ( $product->is_enabled() && $product->is_type( 'simple' ) ) {
139 $trial_time_per = $product->get_meta( '_subscrpt_trial_timing_per' );
140 if ( ! empty( $trial_time_per ) && $trial_time_per > 0 && Helper::check_trial( $product->get_id() ) ) {
141 return 0;
142 }
143 }
144
145 return $price;
146 }
147
148 /**
149 * Remove filter after calculate calculation.
150 *
151 * @return void
152 */
153 public function remove_calculation_price_filter() {
154 remove_filter( 'woocommerce_product_get_price', array( $this, 'set_prices_for_calculation' ), 100 );
155 }
156
157 /**
158 * Set line item for display meta details.
159 *
160 * @param array $cart_item_data Cart Item Data.
161 * @param array $cart_item Cart Item.
162 *
163 * @return array
164 */
165 public function set_line_item_meta( $cart_item_data, $cart_item ) {
166 if ( isset( $cart_item['subscription'] ) ) {
167 if ( $cart_item['subscription']['trial'] ) {
168 $cart_item_data[] = array(
169 'key' => __( 'Free Trial', 'subscription' ),
170 'value' => $cart_item['subscription']['trial'],
171 'hidden' => true,
172 '__experimental_woocommerce_blocks_hidden' => false,
173 );
174 }
175 }
176
177 return $cart_item_data;
178 }
179
180 /**
181 * Check cart items if it's valid or not?
182 *
183 * @return void
184 */
185 public function check_cart_items() {
186 if ( subscrpt_pro_activated() ) {
187 return;
188 }
189 $cart_items = WC()->cart->cart_contents;
190 if ( is_array( $cart_items ) ) {
191 foreach ( $cart_items as $key => $value ) {
192 // Plan items were validated against the plan by the resolver at
193 // add-to-cart; their `subscription` snapshot intentionally differs
194 // from the product's classic meta, so skip the classic re-check
195 // (which would otherwise drop them from the cart).
196 if ( ! empty( $value['subscrpt_plan_id'] ) ) {
197 continue;
198 }
199
200 /**
201 * Product Object.
202 *
203 * @var \WC_Product $product
204 */
205 $product = $value['data'];
206 $product = Subscription::get_subs_product( $product );
207 if ( isset( $value['subscription'] ) ) {
208 if ( $product->is_type( 'simple' ) ) {
209 if ( Helper::get_typos( 1, $product->get_meta( '_subscrpt_timing_option' ) ) !== $value['subscription']['type'] || $product->get_trial() !== $value['subscription']['trial'] ) {
210 // remove the item.
211 wc_add_notice( __( 'An item which is no longer available was removed from your cart.', 'subscription' ), 'error' );
212 WC()->cart->remove_cart_item( $key );
213 }
214 } else {
215 // remove the item.
216 wc_add_notice( __( 'An item which is no longer available was removed from your cart.', 'subscription' ), 'error' );
217 WC()->cart->remove_cart_item( $key );
218 }
219 } elseif ( $product->is_enabled() ) {
220 // remove the item.
221 wc_add_notice( __( 'An item which is no longer available was removed from your cart.', 'subscription' ), 'error' );
222 WC()->cart->remove_cart_item( $key );
223 }
224 }
225 }
226 }
227
228 /**
229 * Define custom schema.
230 *
231 * @return void
232 */
233 public function define_custom_schema() {
234 $this->register_endpoint_data(
235 array(
236 'endpoint' => CartItemSchema::IDENTIFIER,
237 'namespace' => 'sdevs_subscription',
238 'data_callback' => array( $this, 'extend_cart_item_data' ),
239 'schema_callback' => array( $this, 'extend_cart_item_schema' ),
240 'schema_type' => ARRAY_A,
241 )
242 );
243 $this->register_endpoint_data(
244 array(
245 'endpoint' => CartSchema::IDENTIFIER,
246 'namespace' => 'sdevs_subscription',
247 'data_callback' => array( $this, 'extend_cart_data' ),
248 'schema_callback' => array( $this, 'extend_cart_schema' ),
249 'schema_type' => ARRAY_A,
250 )
251 );
252 }
253
254 /**
255 * Register subscription product schema into cart/items endpoint.
256 *
257 * @return array Registered schema.
258 */
259 public function extend_cart_schema() {
260 return array(
261 'recurring_totals' => array(
262 'description' => __( 'List of recurring totals in cart.', 'subscription' ),
263 'type' => 'array',
264 'readonly' => true,
265 'recurring_totals' => array(
266 'price' => array(
267 'description' => __( 'price of the subscription, after any discount that applies to renewals.', 'subscription' ),
268 'type' => array( 'string' ),
269 'readonly' => true,
270 ),
271 'full_price' => array(
272 'description' => __( 'price of the subscription before any discount.', 'subscription' ),
273 'type' => array( 'string' ),
274 'readonly' => true,
275 ),
276 'first_price' => array(
277 'description' => __( 'amount charged today, after all discounts.', 'subscription' ),
278 'type' => array( 'string' ),
279 'readonly' => true,
280 ),
281 'has_recurring_discount' => array(
282 'description' => __( 'Whether a discount applies to renewals.', 'subscription' ),
283 'type' => array( 'boolean' ),
284 'readonly' => true,
285 ),
286 'has_one_time_discount' => array(
287 'description' => __( 'Whether a discount applies to the first payment only.', 'subscription' ),
288 'type' => array( 'boolean' ),
289 'readonly' => true,
290 ),
291 'recurring_limit' => array(
292 'description' => __( 'Number of payments the recurring discount covers. 0 means unlimited.', 'subscription' ),
293 'type' => array( 'number' ),
294 'readonly' => true,
295 ),
296 'time' => array(
297 'description' => __( 'time of the subscription.', 'subscription' ),
298 'type' => array( 'number' ),
299 'readonly' => true,
300 ),
301 'type' => array(
302 'description' => __( 'type of the subscription.', 'subscription' ),
303 'type' => array( 'string' ),
304 'readonly' => true,
305 ),
306 'description' => array(
307 'description' => __( 'price of the subscription description.', 'subscription' ),
308 'type' => array( 'string' ),
309 'readonly' => true,
310 ),
311 'can_user_cancel' => array(
312 'description' => __( 'Allow User Cancellation?', 'subscription' ),
313 'type' => array( 'string' ),
314 'readonly' => true,
315 ),
316 'max_no_payment' => array(
317 'description' => __( 'Maximum Total Payments', 'subscription' ),
318 'type' => array( 'number' ),
319 'readonly' => true,
320 ),
321 'split_total' => array(
322 'description' => __( 'Total price for a split-payment plan (entered plan price).', 'subscription' ),
323 'type' => array( 'number', 'null' ),
324 'readonly' => true,
325 ),
326 ),
327 ),
328 );
329 }
330
331 /**
332 * Register subscription product data into cart/items endpoint.
333 *
334 * @return array $item_data Registered data or empty array if condition is not satisfied.
335 */
336 public function extend_cart_data() {
337 $cart_items = WC()->cart->cart_contents;
338 $recurrings = array();
339 if ( $cart_items ) {
340 foreach ( $cart_items as $cart_item_key => $cart_item ) {
341 if ( isset( $cart_item['subscription'] ) && $cart_item['subscription']['type'] ) {
342 $cart_subscription = $cart_item['subscription'];
343 $start_date = Helper::start_date( $cart_subscription['trial'] );
344 $next_date = Helper::next_date(
345 ( $cart_subscription['time'] ?? 1 ) . ' ' . $cart_subscription['type'],
346 $cart_subscription['trial']
347 );
348
349 // Subscription timing & type
350 $time = $cart_subscription['time'];
351 $type = Helper::get_typos( $time, $cart_subscription['type'], true );
352
353 // Discount-aware totals, shared with the classic cart.
354 $price_data = Helper::build_cart_recurring_price_data( $cart_item, $cart_item_key, $type );
355
356 // Description
357 $description = empty( $cart_subscription['trial'] )
358 ? __( 'Next billing on', 'subscription' ) . ': ' . $next_date
359 : __( 'First billing on', 'subscription' ) . ': ' . $start_date;
360
361 $recurrings[] = apply_filters(
362 'subscrpt_cart_recurring_data',
363 array(
364 'price' => $price_data['total'],
365 'full_price' => $price_data['full_total'],
366 'first_price' => $price_data['first_total'],
367 'has_recurring_discount' => $price_data['has_recurring_discount'],
368 'has_one_time_discount' => $price_data['has_one_time_discount'],
369 'recurring_limit' => $price_data['recurring_limit'],
370 'time' => $time,
371 'type' => $type,
372 'description' => $description,
373 'can_user_cancel' => $cart_item['data']->get_meta( '_subscrpt_user_cancel' ),
374 'max_no_payment' => ! empty( $cart_item['subscrpt_max_no_payment'] )
375 ? (int) $cart_item['subscrpt_max_no_payment']
376 : $cart_item['data']->get_meta( '_subscrpt_max_no_payment' ),
377 'split_total' => isset( $cart_item['subscrpt_split_total'] ) ? (float) $cart_item['subscrpt_split_total'] : null,
378 ),
379 $cart_item
380 );
381 }
382 }
383 }
384
385 return $recurrings;
386 }
387
388 /**
389 * Register subscription product schema into cart/items endpoint.
390 *
391 * @return array Registered schema.
392 */
393 public function extend_cart_item_schema() {
394 return array(
395 'time' => array(
396 'description' => __( 'time of the subscription type.', 'subscription' ),
397 'type' => array( 'number', 'null' ),
398 'readonly' => true,
399 ),
400 'type' => array(
401 'description' => __( 'the subscription type.', 'subscription' ),
402 'type' => array( 'string', 'null' ),
403 'readonly' => true,
404 ),
405 'trial' => array(
406 'description' => __( 'the subscription trial.', 'subscription' ),
407 'type' => array( 'string', 'null' ),
408 'readonly' => true,
409 ),
410 'signup_fee' => array(
411 'description' => __( 'Signup Fee amount.', 'subscription' ),
412 'type' => array( 'string', 'null' ),
413 'readonly' => true,
414 ),
415 'cost' => array(
416 'description' => __( 'Recurring amount.', 'subscription' ),
417 'type' => array( 'string', 'null' ),
418 'readonly' => true,
419 ),
420 'max_no_payment' => array(
421 'description' => __( 'Maximum Total Payments', 'subscription' ),
422 'type' => array( 'number' ),
423 'readonly' => true,
424 ),
425 );
426 }
427
428 /**
429 * Register subscription product data into cart/items endpoint.
430 *
431 * @param array $cart_item Current cart item data.
432 *
433 * @return array $item_data Registered data or empty array if condition is not satisfied.
434 */
435 public function extend_cart_item_data( $cart_item ) {
436 $item_data = array(
437 'time' => null,
438 'type' => null,
439 'trial' => null,
440 'signup_fee' => null,
441 'cost' => null,
442 'max_no_payment' => null,
443 );
444
445 if ( isset( $cart_item['subscription'] ) ) {
446 $item_data = $cart_item['subscription'];
447 unset( $item_data['per_cost'] );
448 $item_data['cost'] = (float) $cart_item['subscription']['per_cost'] * $cart_item['quantity'];
449
450 // Plan items don't stamp the installment count into the subscription
451 // array (it rides the cart item as subscrpt_max_no_payment); classic
452 // products carry it on the product meta.
453 if ( ! isset( $item_data['max_no_payment'] ) ) {
454 $item_data['max_no_payment'] = ! empty( $cart_item['subscrpt_max_no_payment'] )
455 ? (int) $cart_item['subscrpt_max_no_payment']
456 : $cart_item['data']->get_meta( '_subscrpt_max_no_payment' );
457 }
458
459 // Normalise the cadence word to singular/plural by frequency for the
460 // blocks (Store API) cart — plan items store the raw plural interval
461 // (e.g. "months"), which the block would otherwise render as-is.
462 if ( ! empty( $item_data['type'] ) ) {
463 $sub_time = max( 1, (int) ( $item_data['time'] ?? 1 ) );
464 $item_data['type'] = Helper::get_typos( $sub_time, $item_data['type'] );
465 }
466 }
467 if ( ! subscrpt_pro_activated() ) {
468 $item_data['time'] = null;
469 $item_data['signup_fee'] = null;
470 }
471
472 return $item_data;
473 }
474
475 /**
476 * Add product meta on cart item.
477 *
478 * @param array $cart_item_data cart_item_data.
479 * @param int $product_id Product ID.
480 *
481 * @return array
482 */
483 public function add_to_cart_item_data( array $cart_item_data, int $product_id ): array {
484 $product = Subscription::get_subs_product( $product_id );
485 if ( ! $product->is_type( 'simple' ) ) {
486 return $cart_item_data;
487 }
488 // Plan products stamp their subscription snapshot in the plan checkout
489 // (Frontend\PlanCheckout / Pro), gated on the chosen plan id — so a One-Time
490 // purchase of a plan product is not wrongly tagged as a subscription here
491 // (which would show a cadence + list it under "Recurring totals").
492 if ( subscrpt_product_has_plan( $product_id ) ) {
493 return $cart_item_data;
494 }
495 if ( $product->is_enabled() ) :
496 $subscription_data = array();
497 $subscription_data['time'] = null;
498 $subscription_data['type'] = $product->get_timing_option();
499 $subscription_data['trial'] = null;
500 if ( $product->has_trial() ) {
501 $subscription_data['trial'] = $product->get_trial();
502 }
503 $subscription_data['signup_fee'] = null;
504 $subscription_data['per_cost'] = $product->get_price();
505 $cart_item_data['subscription'] = apply_filters( 'subscrpt_block_simple_cart_item_data', $subscription_data, $product, $cart_item_data );
506 $cart_item_data['subscription']['max_no_payment'] = $product->get_meta( '_subscrpt_max_no_payment' );
507 endif;
508
509 return $cart_item_data;
510 }
511
512 /**
513 * Register endpoint data with the API.
514 *
515 * @param array $args Endpoint data to register.
516 */
517 protected function register_endpoint_data( $args ) {
518 if ( function_exists( 'woocommerce_store_api_register_endpoint_data' ) ) {
519 woocommerce_store_api_register_endpoint_data( $args );
520 } else {
521 Package::container()->get( ExtendRestApi::class )->register_endpoint_data( $args );
522 }
523 }
524
525 /**
526 * Display formatted price on cart.
527 *
528 * @param string $price price.
529 * @param array $cart_item cart item.
530 *
531 * @return string
532 */
533 public function change_price_cart_html( $price, $cart_item ) {
534 $product = Subscription::get_subs_product( $cart_item['product_id'] );
535 if ( ! $product->is_type( 'simple' ) ) {
536 return $price;
537 }
538
539 // A tied plan makes it a subscription even without classic `_subscrpt_enabled`;
540 // get_price_html() already resolves to the plan line (Frontend\Plans), so this
541 // shows the plan cadence on the cart line without doubling.
542 if ( $product->is_enabled() || subscrpt_plan_offered( $product->get_id() ) ) {
543 return $product->get_price_html();
544 }
545
546 return $price;
547 }
548
549 /**
550 * Display "Recurring totals" on cart
551 *
552 * @return void
553 */
554 public function add_rows_order_total() {
555 $cart_items = WC()->cart->get_cart_contents();
556 $recurrs = Helper::get_recurrs_from_cart( $cart_items );
557 if ( 0 === count( $recurrs ) ) {
558 return;
559 }
560 ?>
561 <tr class="recurring-total">
562 <th><?php esc_html_e( 'Recurring totals', 'subscription' ); ?></th>
563 <td data-title="<?php esc_attr_e( 'Recurring totals', 'subscription' ); ?>">
564 <?php foreach ( $recurrs as $recurr ) : ?>
565 <p>
566 <span><?php echo wp_kses_post( $recurr['price_html'] ); ?></span>
567 <?php if ( $recurr['max_no_payment'] > 0 ) : ?>
568 <span>x <?php echo esc_html( $recurr['max_no_payment'] ); ?></span>
569 <?php endif; ?>
570 <br />
571
572 <small>
573 <?php
574 $billing_text = $recurr['trial_status']
575 ? __( 'First billing on', 'subscription' )
576 : __( 'Next billing on', 'subscription' );
577
578 echo esc_html( $billing_text . ': ' );
579 echo esc_html( $recurr['trial_status'] ? $recurr['start_date'] : $recurr['next_date'] );
580 ?>
581 </small>
582
583 <?php if ( ! empty( $recurr['has_one_time_discount'] ) ) : ?>
584 <br />
585 <small>
586 <?php
587 echo wp_kses_post(
588 sprintf(
589 // translators: 1: amount paid today, 2: amount charged on each renewal.
590 __( 'You pay %1$s today. %2$s will be charged from the next renewal.', 'subscription' ),
591 wc_price( $recurr['first_total'] ?? 0 ),
592 wc_price( $recurr['total'] ?? 0 )
593 )
594 );
595 ?>
596 </small>
597 <?php endif; ?>
598
599 <?php if ( ! empty( $recurr['has_recurring_discount'] ) && (int) ( $recurr['recurring_limit'] ?? 0 ) > 1 ) : ?>
600 <br />
601 <small>
602 <?php
603 echo wp_kses_post(
604 sprintf(
605 // translators: 1: number of discounted payments, 2: full price charged afterwards.
606 __( 'Discount applies to your first %1$s payments. After that, %2$s.', 'subscription' ),
607 number_format_i18n( (int) $recurr['recurring_limit'] ),
608 $recurr['full_price_html'] ?? ''
609 )
610 );
611 ?>
612 </small>
613 <?php endif; ?>
614
615 <?php if ( 'yes' === $recurr['can_user_cancel'] && 0 === (int) $recurr['max_no_payment'] ) : ?>
616 <br />
617 <small><?php esc_html_e( 'You can cancel subscription at any time!', 'subscription' ); ?></small>
618 <?php endif; ?>
619
620 <!-- add how many times will be build if _subscrpt_renewal_limit is not 0 -->
621 <?php if ( (int) $recurr['max_no_payment'] > 0 ) : ?>
622 <br>
623 <small>
624 <?php
625 echo wp_kses_post(
626 sprintf(
627 // translators: 1: number of installments, 2: total amount.
628 __( 'This subscription will be billed in %1$s installments, for a total of %2$s.', 'subscription' ),
629 esc_html( $recurr['max_no_payment'] ),
630 wc_price( isset( $recurr['split_total'] ) && null !== $recurr['split_total'] ? $recurr['split_total'] : $recurr['price'] * (int) $recurr['max_no_payment'] )
631 )
632 );
633 ?>
634 </small>
635 <?php endif; ?>
636 </p>
637 <?php endforeach; ?>
638 </td>
639 </tr>
640 <?php
641 }
642
643 /**
644 * Add renew status.
645 *
646 * @param array $cart_item_data cart_item_data.
647 * @param int $product_id Product ID.
648 *
649 * @return array
650 */
651 public function set_renew_status( $cart_item_data, $product_id ) {
652 $expired = Helper::subscription_exists( $product_id, 'expired' );
653 if ( $expired ) {
654 // Check if maximum payment limit has been reached
655 if ( subscrpt_is_max_payments_reached( $expired ) ) {
656 wc_add_notice( __( 'This subscription has reached its maximum payment limit and cannot be renewed further.', 'subscription' ), 'error' );
657 return $cart_item_data; // Don't add renew status
658 }
659
660 $cart_item_data['renew_subscrpt'] = true;
661 }
662
663 return $cart_item_data;
664 }
665 }
666