PluginProbe
Tiered Pricing Table for WooCommerce / 8.0.2
Tiered Pricing Table for WooCommerce v8.0.2
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 / Addons / CartUpsells / CartUpsellsService.php

CartUpsellsService.php in Tiered Pricing Table for WooCommerce 8.0.2, at src/Addons/CartUpsells/CartUpsellsService.php

227 lines 9.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace TierPricingTable\Addons\CartUpsells;
4
5 use ArrayIterator;
6 use TierPricingTable\Core\ServiceContainerTrait;
7 use TierPricingTable\PriceManager;
8 use TierPricingTable\PricingRule;
9 /**
10 * Class CartUpsellsService
11 *
12 * Service shows upsells for each cart item that has tiered pricing
13 *
14 * @package TierPricingTable\Addons\CartUpsells
15 */
16 class CartUpsellsService {
17 use ServiceContainerTrait;
18 /**
19 * CatalogPriceManager constructor.
20 */
21 public function __construct() {
22 }
23
24 public function showUpsell( $cartItem, $cartItemKey = '' ) {
25 if ( !$this->isCartUpsellEnabled() ) {
26 return;
27 }
28 $nextPriceData = $this->getNextPriceData( $cartItem );
29 $upsellString = $this->formatUpsellString( $cartItem, $nextPriceData, $cartItemKey );
30 if ( !$upsellString ) {
31 return;
32 }
33 // the link carries the target quantity for the cart script
34 $allowed = wp_kses_allowed_html( 'post' );
35 $allowed['a']['data-tpt-cart-item'] = true;
36 $allowed['a']['data-tpt-quantity'] = true;
37 $current = (int) $this->getTotalProductCountInCart( $cartItem );
38 $target = $current + (int) $nextPriceData['next_quantity'];
39 ?>
40 <div class="tpt-cart-upsell" style="color: <?php
41 echo esc_attr( $this->getUpsellColor() );
42 ?>">
43 <small><?php
44 echo wp_kses( $upsellString, $allowed );
45 ?></small>
46 <?php
47 if ( $this->isProgressBarEnabled() && $target > 0 ) {
48 ?>
49 <div class="tpt-cart-upsell__progress" role="progressbar" aria-valuemin="0" aria-valuemax="<?php
50 echo esc_attr( $target );
51 ?>" aria-valuenow="<?php
52 echo esc_attr( $current );
53 ?>">
54 <i style="width: <?php
55 echo esc_attr( max( 2, min( 100, round( $current / $target * 100 ) ) ) );
56 ?>%"></i>
57 </div>
58 <?php
59 }
60 ?>
61 </div>
62 <?php
63 }
64
65 public function showUpsellInBlock( $itemData, $cartItem ) {
66 if ( !$this->isCartUpsellEnabled() ) {
67 return $itemData;
68 }
69 $isStoreApi = false;
70 if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
71 $requestUri = ( isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '' );
72 if ( strpos( $requestUri, '/wc/store/' ) !== false ) {
73 $isStoreApi = true;
74 }
75 }
76 $isBlockPage = function_exists( 'has_block' ) && (has_block( 'woocommerce/cart' ) || has_block( 'woocommerce/checkout' ));
77 // If it's NOT the Store API and NOT a block page, it's the classic cart. Bail out.
78 if ( !$isStoreApi && !$isBlockPage ) {
79 return $itemData;
80 }
81 $upsellString = $this->formatUpsellString( $cartItem );
82 if ( !$upsellString ) {
83 return $itemData;
84 }
85 $itemData[] = array(
86 'key' => '',
87 'value' => wp_strip_all_tags( $upsellString ),
88 );
89 return $itemData;
90 }
91
92 /**
93 * @param array $cartItem
94 * @param array|null $nextPriceData The next tier's figures, when already computed.
95 * @param string $cartItemKey Set for the classic cart: the required quantity becomes a link that
96 * moves the line to the next tier.
97 *
98 * @return string|false
99 */
100 protected function formatUpsellString( $cartItem, $nextPriceData = null, $cartItemKey = '' ) {
101 if ( null === $nextPriceData ) {
102 $nextPriceData = $this->getNextPriceData( $cartItem );
103 }
104 if ( empty( $nextPriceData ) ) {
105 return false;
106 }
107 $template = $this->getTemplate();
108 $quantity = (string) $nextPriceData['next_quantity'];
109 if ( $cartItemKey && $this->isQuantityLinkEnabled() ) {
110 $target = (int) $cartItem['quantity'] + (int) $nextPriceData['next_quantity'];
111 $quantity = '<a href="#" class="tpt-cart-upsell__link" data-tpt-cart-item="' . esc_attr( $cartItemKey ) . '" data-tpt-quantity="' . esc_attr( $target ) . '">' . $quantity . '</a>';
112 }
113 return strtr( $template, array(
114 '{tp_required_quantity}' => $quantity,
115 '{tp_next_price}' => wc_price( $nextPriceData['next_price'] ),
116 '{tp_next_discount}' => number_format(
117 $nextPriceData['next_discount'],
118 wc_get_price_decimals(),
119 wc_get_price_decimal_separator(),
120 wc_get_price_thousand_separator()
121 ),
122 '{tp_actual_discount}' => number_format(
123 $nextPriceData['actual_discount'],
124 wc_get_price_decimals(),
125 wc_get_price_decimal_separator(),
126 wc_get_price_thousand_separator()
127 ),
128 ) );
129 }
130
131 protected function getNextPriceData( $cartItem ) {
132 $pricingRule = $this->getPricingRule( $cartItem );
133 if ( !empty( $pricingRule->getRules() ) ) {
134 $iterator = new ArrayIterator(array_reverse( $pricingRule->getRules(), true ));
135 $currentQuantity = $this->getTotalProductCountInCart( $cartItem );
136 while ( $iterator->valid() ) {
137 if ( $currentQuantity < $iterator->key() ) {
138 $prevQuantity = $iterator->key();
139 $prevPrice = $iterator->current();
140 $iterator->next();
141 if ( $iterator->valid() && $currentQuantity >= $iterator->key() ) {
142 $product = wc_get_product( $this->getProductId( $cartItem ) );
143 if ( $pricingRule->isFixed() ) {
144 $nextPrice = $prevPrice;
145 $currentPrice = $iterator->current();
146 } else {
147 $nextPrice = PriceManager::getProductPriceWithPercentageDiscount( $product, $prevPrice );
148 $currentPrice = PriceManager::getProductPriceWithPercentageDiscount( $product, $iterator->current() );
149 }
150 $currentPrice = PriceManager::getPriceToDisplay( $currentPrice, $product, 'cart' );
151 $nextPrice = PriceManager::getPriceToDisplay( $nextPrice, $product, 'cart' );
152 return array(
153 'next_price' => $nextPrice,
154 'next_discount' => PriceManager::calculateDiscount( $currentPrice, $nextPrice ),
155 'actual_discount' => ( $pricingRule->isPercentage() ? $prevPrice : PriceManager::calculateDiscount( $product->get_price( 'edit' ), $currentPrice ) ),
156 'next_quantity' => $prevQuantity - $currentQuantity,
157 );
158 } elseif ( !$iterator->valid() ) {
159 $product = wc_get_product( $this->getProductId( $cartItem ) );
160 if ( $pricingRule->isFixed() ) {
161 $nextPrice = $prevPrice;
162 $currentPrice = $product->get_price();
163 } else {
164 $nextPrice = PriceManager::getProductPriceWithPercentageDiscount( $product, $prevPrice );
165 $currentPrice = $product->get_price();
166 }
167 $nextPrice = PriceManager::getPriceToDisplay( $nextPrice, $product, 'cart' );
168 return array(
169 'next_price' => $nextPrice,
170 'next_discount' => PriceManager::calculateDiscount( $currentPrice, $nextPrice ),
171 'actual_discount' => ( $pricingRule->isPercentage() ? $prevPrice : PriceManager::calculateDiscount( $currentPrice, $product->get_price( 'edit' ) ) ),
172 'next_quantity' => $prevQuantity - $currentQuantity,
173 );
174 }
175 } else {
176 $iterator->next();
177 }
178 }
179 }
180 return array();
181 }
182
183 public function getTotalProductCountInCart( $cartItem ) {
184 return ( !empty( $cartItem['tiered_pricing_data']['total_item_quantity'] ) ? $cartItem['tiered_pricing_data']['total_item_quantity'] : $cartItem['quantity'] );
185 }
186
187 /**
188 * Get pricing rules from cart item
189 *
190 * @param array $cartItem
191 *
192 * @return PricingRule|false
193 */
194 protected function getPricingRule( $cartItem ) {
195 $productId = $this->getProductId( $cartItem );
196 if ( $productId ) {
197 return PriceManager::getPricingRule( $productId );
198 }
199 return false;
200 }
201
202 protected function getProductId( $cartItem ) {
203 return ( !empty( $cartItem['variation_id'] ) ? $cartItem['variation_id'] : $cartItem['product_id'] );
204 }
205
206 protected function getTemplate() {
207 return $this->getContainer()->getSettings()->get( 'cart_upsell_template', __( 'Add <b>{tp_required_quantity}</b> more to get <b>{tp_next_price}</b> each', 'tier-pricing-table' ) );
208 }
209
210 protected function getUpsellColor() {
211 return $this->getContainer()->getSettings()->get( 'cart_upsell_color', '#059669' );
212 }
213
214 protected function isCartUpsellEnabled() {
215 return $this->getContainer()->getSettings()->get( 'cart_upsell_enabled', 'no' ) === 'yes';
216 }
217
218 protected function isQuantityLinkEnabled() : bool {
219 return $this->getContainer()->getSettings()->get( 'cart_upsell_link', 'yes' ) !== 'no';
220 }
221
222 protected function isProgressBarEnabled() : bool {
223 return $this->getContainer()->getSettings()->get( 'cart_upsell_progress', 'no' ) === 'yes';
224 }
225
226 }
227