PluginProbe
Tiered Pricing Table for WooCommerce / 6.5.0
Tiered Pricing Table for WooCommerce v6.5.0
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 / Services / ProductPageService.php

ProductPageService.php in Tiered Pricing Table for WooCommerce 6.5.0, at src/Services/ProductPageService.php

319 lines 9.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php namespace TierPricingTable\Services;
2
3 use Exception;
4 use TierPricingTable\Admin\ProductPage\TieredPricingTab;
5 use TierPricingTable\Core\ServiceContainerTrait;
6 use TierPricingTable\PriceManager;
7 use TierPricingTable\PricingTable;
8 use TierPricingTable\Settings\Sections\GeneralSection\Subsections\ProductPagePriceSubsection;
9 use TierPricingTable\TierPricingTablePlugin;
10 use WC_Product;
11 use WC_Product_Data_Store_CPT;
12 use WP_Post;
13
14 /**
15 * Class ProductPageHandler
16 *
17 * @package TierPricingTable\Frontend
18 */
19 class ProductPageService {
20
21 use ServiceContainerTrait;
22
23 public function __construct() {
24
25 add_action( 'woocommerce_quantity_input_classes', function ( $classes, $product ) {
26 if ( $product instanceof WC_Product ) {
27 $classes[] = 'quantity-input-product-' . $product->get_id();
28 }
29
30 return $classes;
31 }, 10, 2 );
32
33 add_filter( 'woocommerce_available_variation', function ( $data, WC_Product $product ) {
34 $data['parent_id'] = $product->get_id();
35
36 return $data;
37 }, 10, 2 );
38
39 // Wrap price
40 add_action( 'woocommerce_get_price_html', array( $this, 'wrapPrice' ), 101, 2 );
41
42 // Render price table
43 add_action( $this->getContainer()->getSettings()->get( 'position_hook',
44 'woocommerce_before_add_to_cart_button' ), array(
45 $this,
46 'renderPricingTableOnProductPage',
47 ), - 999 );
48
49 // Get table for variation
50 add_action( 'wc_ajax_get_pricing_table', array( $this, 'getVariationPricingTable' ), 10, 1 );
51
52 // Render tooltip if enabled
53 add_filter( 'woocommerce_get_price_html', array( $this, 'renderTooltip' ), 999, 2 );
54
55 add_filter( 'woocommerce_get_price_suffix', function ( $suffix, \WC_product $product, $price, $qty ) {
56
57 // Allow 3rd-party to control this
58 if ( ! apply_filters( 'tiered_pricing_table/frontend/modify_price_suffix', true, $suffix, $product, $price,
59 $qty ) ) {
60 return $suffix;
61 }
62
63 if ( empty( $suffix ) ) {
64 return $suffix;
65 }
66
67 $html = '';
68
69 $suffix = get_option( 'woocommerce_price_display_suffix' );
70
71 if ( $suffix && wc_tax_enabled() && 'taxable' === $product->get_tax_status() ) {
72
73 if ( '' === $price ) {
74 $price = $product->get_price();
75 }
76
77 $replacements = array(
78 '{price_including_tax}' => '<span class="tiered-pricing-dynamic-price__including_tax">' . wc_price( wc_get_price_including_tax( $product,
79 array(
80 'qty' => $qty,
81 'price' => $price,
82 ) ) ) . '</span>',
83 '{price_excluding_tax}' => '<span class="tiered-pricing-dynamic-price__excluding_tax">' . wc_price( wc_get_price_excluding_tax( $product,
84 array(
85 'qty' => $qty,
86 'price' => $price,
87 ) ) ) . '</span>',
88 );
89
90 $html = str_replace( array_keys( $replacements ), array_values( $replacements ),
91 ' <small class="woocommerce-price-suffix">' . wp_kses_post( $suffix ) . '</small>' );
92 }
93
94 return $html;
95
96 }, 10, 4 );
97 }
98
99 /**
100 * Wrap product price for managing it by JS
101 *
102 * @param mixed $priceHTML
103 * @param WC_Product $product
104 *
105 * @return string
106 */
107 public function wrapPrice( $priceHTML, WC_Product $product ) {
108
109 if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
110 return $priceHTML;
111 }
112
113 // Do not wrap price in quick edit and inline edit in admin
114 if ( isset( $_POST['action'] ) && in_array( $_POST['action'], [
115 'inline-save',
116 ], true ) ) {
117 return $priceHTML;
118 }
119
120 // Allow 3rd-party to control this
121 if ( ! apply_filters( 'tiered_pricing_table/frontend/wrap_price', true, $product, $priceHTML ) ) {
122 return $priceHTML;
123 }
124
125 $parentProductID = $product->get_parent_id() ? $product->get_parent_id() : $product->get_id();
126 $variationID = TierPricingTablePlugin::isVariationProductSupported( $product ) ? $product->get_id() : null;
127 $productPagePrice = get_queried_object_id() === $parentProductID && is_product();
128 $priceDisplayContext = $productPagePrice ? 'product-page' : 'shop-loop';
129
130 $priceType = apply_filters( 'tiered_pricing_table/frontend/default_price_behaviour_type', 'dynamic', $product,
131 $priceHTML, $priceDisplayContext );
132
133 if ( $productPagePrice && $product->get_type() !== 'variation' ) {
134 // Do not format prices if tiered pricing formatting enabled on the product page.
135 if ( 'same_as_catalog' === ProductPagePriceSubsection::getFormatPriceType() ) {
136 $priceType = 'static';
137 }
138 }
139
140 $isVariable = in_array( $product->get_type(), TierPricingTablePlugin::getSupportedVariableProductTypes() );
141
142 $pricingRules = PriceManager::getPricingRule( $product->get_id() );
143
144 // Do not wrap if there is no pricing rules
145 if ( ! $isVariable && empty( $pricingRules->getRules() ) ) {
146 $priceType = 'no-rules';
147 }
148
149 $supportedTypes = array_merge( TierPricingTablePlugin::getSupportedSimpleProductTypes(), array( 'variation' ) );
150
151 $wrapVariableProductPrice = apply_filters( 'tiered_pricing_table/frontend/wrap_variable_price', true,
152 $product );
153
154 // Is "show total price" is enabled, we can wrap the variable product price, or it's forced by the hook
155 if ( $wrapVariableProductPrice || $this->getContainer()->getSettings()->get( 'show_total_price',
156 'no' ) === 'yes' ) {
157 $supportedTypes = array_merge( $supportedTypes,
158 TierPricingTablePlugin::getSupportedVariableProductTypes() );
159 }
160
161 if ( in_array( $product->get_type(), $supportedTypes ) ) {
162
163 ob_start();
164
165 ?>
166 <span class="tiered-pricing-dynamic-price-wrapper<?php echo $isVariable ? ' tiered-pricing-dynamic-price-wrapper--variable' : ''; ?>"
167 data-display-context="<?php echo esc_attr( $priceDisplayContext ); ?>"
168 data-price-type="<?php echo esc_attr( $priceType ); ?>"
169 data-product-id="<?php echo esc_attr( $product->get_id() ); ?>"
170 data-parent-id="<?php echo esc_attr( $product->get_parent_id() ? $product->get_parent_id() : $product->get_id() ); ?>">
171 <?php
172 return ob_get_clean() . $priceHTML . '</span>';
173 }
174
175 return $priceHTML;
176 }
177
178 /**
179 * Render a pricing table on the product page
180 */
181 public function renderPricingTableOnProductPage() {
182
183 global $post;
184
185 if ( ! $post || ! is_product() ) {
186 return;
187 }
188
189 $variationId = $this->getVariationIdFromURL( $post->ID );
190
191 PricingTable::getInstance()->renderPricingTable( $post->ID, $variationId );
192 }
193
194 public function getVariationIdFromURL( $productId ): ?int {
195
196 $attributes = array();
197 $attributeWordLen = strlen( 'attribute_' );
198
199 foreach ( $_REQUEST as $key => $value ) {
200
201 if ( strlen( $key ) < $attributeWordLen ) {
202 continue;
203 }
204
205 $string = substr( $key, 0, $attributeWordLen );
206
207 if ( strcasecmp( $string, 'attribute_' ) === 0 ) {
208 $attributes[ $key ] = $value;
209 }
210 }
211
212 if ( empty( $attributes ) ) {
213 return null;
214 }
215
216 $product = wc_get_product( $productId );
217
218 if ( ! $product ) {
219 return null;
220 }
221
222 if ( ! TierPricingTablePlugin::isVariableProductSupported( $product ) ) {
223 return null;
224 }
225
226 return ( new WC_Product_Data_Store_CPT() )->find_matching_product_variation( $product, $attributes );
227 }
228
229 /**
230 * Render tooltip near product price if selected display type is "tooltip"
231 *
232 * @param ?string $price
233 * @param WC_Product $_product
234 *
235 * @return string
236 */
237 public function renderTooltip( ?string $price, WC_Product $_product ): ?string {
238
239 // Do not render if not display
240 if ( 'yes' !== $this->getContainer()->getSettings()->get( 'display', 'yes' ) ) {
241 return $price;
242 }
243
244 $displayType = TieredPricingTab::getProductTemplate( $_product->get_parent_id() ? $_product->get_parent_id() : $_product->get_id() );
245 $displayType = 'default' === $displayType ? $this->getContainer()->getSettings()->get( 'display_type',
246 'table' ) : $displayType;
247
248 // Do not display if display type is not the tooltip
249 if ( 'tooltip' !== $displayType ) {
250 return $price;
251 }
252
253 if ( is_product() ) {
254 $addTooltip = false;
255 $page_product_id = get_queried_object_id();
256
257 if ( $_product->is_type( 'variation' ) && $_product->get_parent_id() === $page_product_id ) {
258 $addTooltip = true;
259 } elseif ( $_product->get_id() === $page_product_id && TierPricingTablePlugin::isSimpleProductSupported( $_product ) ) {
260 $addTooltip = true;
261 }
262
263 if ( ! $addTooltip ) {
264 return $price;
265 }
266
267 $pricingRule = PriceManager::getPricingRule( $_product->get_id() );
268
269 if ( ! empty( $pricingRule->getRules() ) ) {
270
271 return $price . $this->getContainer()->getFileManager()->renderTemplate( 'frontend/tooltip.php', array(
272 'color' => $this->getContainer()->getSettings()->get( 'tooltip_color', '#3858e9' ),
273 'size' => $this->getContainer()->getSettings()->get( 'tooltip_size', 15 ) . 'px',
274 ) );
275 }
276
277 }
278
279 return $price;
280 }
281
282 /**
283 * Fired when user chooses a variation. Renders tiered pricing table for the variation
284 *
285 * @throws Exception
286 * @global WP_Post $post .
287 */
288 public function getVariationPricingTable() {
289
290 $product_id = isset( $_POST['variation_id'] ) ? sanitize_text_field( $_POST['variation_id'] ) : false;
291 $nonce = isset( $_POST['nonce'] ) ? sanitize_key( $_POST['nonce'] ) : false;
292 $displayContext = isset( $_POST['display_context'] ) ? sanitize_text_field( $_POST['display_context'] ) : 'product-page';
293
294 $renderSettings = apply_filters( 'tiered_pricing_table/frontend/variation_render_settings', array(),
295 $product_id, $displayContext );
296
297 // Some cache plugins may cache the nonce, so we need to leave the ability to disable nonce verification.
298 // Checking nonce is not critical here.
299 $verifyNonce = apply_filters( 'tiered_pricing_table/frontend/load_variation/verify_nonce', false, $nonce,
300 'get_pricing_table' );
301
302 if ( $verifyNonce && ! wp_verify_nonce( $nonce, 'get_pricing_table' ) ) {
303 return;
304 }
305
306 $product = wc_get_product( $product_id );
307
308 if ( $product ) {
309 $parentProduct = wc_get_product( $product->get_parent_id() );
310
311 if ( $parentProduct ) {
312 PricingTable::getInstance()->renderPricingTableHTML( $parentProduct, $product, $renderSettings );
313 }
314
315 }
316
317 }
318 }
319