PluginProbe
Tiered Pricing Table for WooCommerce / 7.1.4
Tiered Pricing Table for WooCommerce v7.1.4
8.0.2 7.1.7 7.1.5 7.1.4 7.1.1 6.5.0 6.4.0 6.1.0 trunk 1.0 1.1 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0 2.3.1 2.3.2 2.3.3 All 91 releases
tier-pricing-table / src / Integrations / Plugins / WooCommerceSubscriptions.php

WooCommerceSubscriptions.php in Tiered Pricing Table for WooCommerce 7.1.4, at src/Integrations/Plugins/WooCommerceSubscriptions.php

112 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php namespace TierPricingTable\Integrations\Plugins;
2
3 use TierPricingTable\PriceManager;
4 use WC_Product;
5
6 /**
7 * Compatibility with WooCommerce Subscriptions "All Products for Subscriptions" (APFS) plans.
8 *
9 * APFS applies a subscription plan's price/discount to a product purely through view-context
10 * `woocommerce_product_get_price` filters (it never writes the price prop). WooCommerce Subscriptions
11 * additionally filters non-subscription product prices to 0 during its "recurring totals" pass. Both
12 * are `view`-context filters, so reading `get_price('edit')` returns the raw, unmodified price.
13 *
14 * This integration keeps tiered pricing correct on plan items without changing behaviour for any other
15 * store:
16 *
17 * - Charging: it recomputes a plan item's tiered price in the "edit" context, so a percentage tier is
18 * based on the raw price rather than the plan-discounted (and, in the recurring pass, zeroed) "view"
19 * price. The plan discount is then applied exactly once — by Subscriptions, when the stored tier
20 * price is read during totals — and the tier no longer collapses to false on renewals.
21 * - Display: it defers a plan item's cart price/subtotal to WooCommerce, which already reflects the
22 * plan discount, instead of the plugin rebuilding it from a fresh (plan-unaware) product instance.
23 *
24 * Everything is scoped to items actually purchased on a plan and is a no-op unless APFS is active.
25 */
26 class WooCommerceSubscriptions extends PluginIntegrationAbstract {
27
28 public function run() {
29
30 // These hooks are registered unconditionally: run() executes at plugin-include time, before
31 // WooCommerce Subscriptions lazily loads its "All Products for Subscriptions" cart API on
32 // plugins_loaded. Availability is instead checked inside each callback (isSubscriptionPlanItem),
33 // which runs at cart-calculation time, so the callbacks are safe no-ops when APFS is absent.
34
35 // Charging: recompute plan items in the "edit" context (raw price base). Runs even when the
36 // incoming price is false — during the recurring pass getTierPrice() returns false because the
37 // product's "view" price has been filtered to 0.
38 add_filter( 'tiered_pricing_table/cart/product_cart_price',
39 function ( $price, $cartItem, $cartItemKey, $totalQuantity ) {
40
41 if ( ! $this->isSubscriptionPlanItem( $cartItem ) ) {
42 return $price;
43 }
44
45 return PriceManager::getPriceByRules( $totalQuantity, $cartItem['data']->get_id(), 'edit', 'cart',
46 false );
47 }, 10, 4 );
48
49 // Display: defer the subtotal column to WooCommerce for plan items so it matches the charge.
50 add_filter( 'tiered_pricing_table/cart/recalculate_cart_item_subtotal',
51 function ( $state, $cartItem ) {
52 return $this->isSubscriptionPlanItem( $cartItem ) ? false : $state;
53 }, 10, 2 );
54
55 // Display: defer the price column to WooCommerce for plan items.
56 add_filter( 'tiered_pricing_table/cart/need_price_recalculation/item',
57 function ( $state, $cartItem ) {
58 return $this->isSubscriptionPlanItem( $cartItem ) ? false : $state;
59 }, 10, 2 );
60 }
61
62 /**
63 * Whether a cart item is currently purchased on a subscription plan (APFS).
64 *
65 * Reads the scheme stored on the cart item itself, which survives the cloned recurring cart, rather
66 * than the product object's runtime state.
67 *
68 * @param array $cartItem
69 *
70 * @return bool
71 */
72 protected function isSubscriptionPlanItem( $cartItem ): bool {
73
74 if ( ! class_exists( '\WCS_ATT_Cart' ) ) {
75 return false;
76 }
77
78 if ( empty( $cartItem['data'] ) || ! ( $cartItem['data'] instanceof WC_Product ) ) {
79 return false;
80 }
81
82 $scheme = \WCS_ATT_Cart::get_subscription_scheme( $cartItem );
83
84 // A non-empty, non-'0' scheme key means the item is on a plan; '0'/null means a one-time purchase.
85 return ! empty( $scheme ) && '0' !== (string) $scheme;
86 }
87
88 public function getTitle(): string {
89 return 'WooCommerce Subscriptions';
90 }
91
92 public function getDescription(): string {
93 return __( 'Apply tiered pricing correctly to products purchased on a WooCommerce Subscriptions plan, in both the initial and recurring totals.', 'tier-pricing-table' );
94 }
95
96 public function getSlug(): string {
97 return 'woocommerce-subscriptions';
98 }
99
100 public function getAuthorURL(): string {
101 return 'https://woocommerce.com/products/woocommerce-subscriptions/';
102 }
103
104 public function getIconURL(): string {
105 return $this->getContainer()->getFileManager()->locateAsset( 'admin/integrations/woocommerce-develop.jpeg' );
106 }
107
108 public function getIntegrationCategory(): string {
109 return 'custom_product_types';
110 }
111 }
112