PluginProbe
Tiered Pricing Table for WooCommerce / 6.1.0
Tiered Pricing Table for WooCommerce v6.1.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.1.0, at src/Services/ProductPageService.php

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