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 / ProductCatalogLoop / Settings / ProductCatalogLoopSettingsSection.php

ProductCatalogLoopSettingsSection.php in Tiered Pricing Table for WooCommerce 8.0.2, at src/Addons/ProductCatalogLoop/Settings/ProductCatalogLoopSettingsSection.php

806 lines 31.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php namespace TierPricingTable\Addons\ProductCatalogLoop\Settings;
2
3 use TierPricingTable\Settings\CustomOptions\TPTDisplayType;
4 use TierPricingTable\Settings\CustomOptions\TPTQuantityMeasurementField;
5 use TierPricingTable\Settings\CustomOptions\TPTCheckboxListOption;
6 use TierPricingTable\Settings\CustomOptions\TPTSwitchOption;
7 use TierPricingTable\Settings\CustomOptions\TPTTextTemplate;
8 use TierPricingTable\Settings\Sections\GeneralSection\GeneralSection;
9 use TierPricingTable\Settings\Sections\SectionAbstract;
10 use TierPricingTable\Settings\Settings;
11 use TierPricingTable\TierPricingTablePlugin;
12
13 class ProductCatalogLoopSettingsSection extends SectionAbstract {
14
15 public static function getOptionID( $option ): string {
16 return self::getSettingsPrefix() . $option;
17 }
18
19 public static function getSettingsPrefix(): string {
20 return Settings::SETTINGS_PREFIX . 'shop_loop_display_';
21 }
22
23 public function getName(): string {
24 return __( 'Shop & Categories', 'tier-pricing-table' );
25 }
26
27 public function getSlug(): string {
28 return 'shop-loop-display';
29 }
30
31 public function getSettings(): array {
32
33 $availableLayouts = TierPricingTablePlugin::getAvailablePricingLayouts();
34 unset( $availableLayouts['tooltip'] );
35
36 return array(
37 array(
38 'title' => __( 'Tiered Pricing on Shop & Category Pages', 'tier-pricing-table' ),
39 'desc' => __( 'Control how tiered pricing appears on shop and category pages.',
40 'tier-pricing-table' ),
41 'type' => 'title',
42 ),
43 array(
44 'title' => __( 'Enable on Shop & Categories', 'tier-pricing-table' ),
45 'id' => self::getOptionID( 'enabled' ),
46 'type' => TPTSwitchOption::FIELD_TYPE,
47 'default' => 'no',
48 'extended_description' => ( function () {
49 ob_start();
50 ?>
51 <p>
52 <?php
53 esc_html_e( 'Turn this on to display tiered pricing directly within your shop and category pages.',
54 'tier-pricing-table' );
55 ?>
56 </p>
57 <p>
58 <b><?php esc_html_e( 'Note:', 'tier-pricing-table' ); ?></b>
59 <?php esc_html_e( 'Depending on your theme, you may need minor CSS adjustments for optimal display.', 'tier-pricing-table' ); ?>
60 </p>
61 <?php
62 return ob_get_clean();
63 } )(),
64 'desc' => __( 'Display tiered pricing tables on shop and category pages.',
65 'tier-pricing-table' ),
66 'desc_tip' => true,
67 ),
68 array(
69 'title' => __( 'Position on product grid item', 'tier-pricing-table' ),
70 'id' => self::getOptionID( 'position' ),
71 'type' => 'select',
72 'default' => 'woocommerce_after_shop_loop_item__6',
73 'options' => array(
74 'woocommerce_after_shop_loop_item__6' => __( 'Above add-to-cart button', 'tier-pricing-table' ),
75 'woocommerce_after_shop_loop_item__15' => __( 'Below add-to-cart button', 'tier-pricing-table' ),
76 'woocommerce_shop_loop_item_title__5' => __( 'Above product title', 'tier-pricing-table' ),
77 'woocommerce_shop_loop_item_title__15' => __( 'Below product title', 'tier-pricing-table' ),
78 ),
79 'desc' => __( 'Choose where the tiered pricing table appears relative to the product image and details.',
80 'tier-pricing-table' ),
81 'desc_tip' => true,
82 ),
83 array(
84 'title' => __( 'Where it shows', 'tier-pricing-table' ),
85 'id' => self::getOptionID( 'scope' ),
86 'type' => TPTDisplayType::FIELD_TYPE,
87 'options' => self::getScopeOptions(),
88 'descriptions' => array(
89 'everywhere' => __( 'Every product list', 'tier-pricing-table' ),
90 'selected' => __( 'Chosen lists and categories', 'tier-pricing-table' ),
91 ),
92 'default' => 'everywhere',
93 ),
94 array(
95 'title' => __( 'Product lists', 'tier-pricing-table' ),
96 'id' => self::getOptionID( 'contexts' ),
97 'type' => TPTCheckboxListOption::FIELD_TYPE,
98 'options' => self::getContextOptions(),
99 'default' => '',
100 'desc' => __( 'The product lists that show tiered pricing. Leave every box unticked for all lists.', 'tier-pricing-table' ),
101 ),
102 array(
103 'title' => __( 'Only for products in categories', 'tier-pricing-table' ),
104 'id' => self::getOptionID( 'categories' ),
105 'type' => TPTCheckboxListOption::FIELD_TYPE,
106 'display' => 'category-search',
107 'placeholder' => __( 'All categories', 'tier-pricing-table' ),
108 'default' => '',
109 'desc' => __( 'Leave empty to show tiered pricing for every product. A category covers its child categories.', 'tier-pricing-table' ),
110 ),
111 array(
112 'title' => __( 'Tiers per grid item', 'tier-pricing-table' ),
113 'id' => self::getOptionID( 'tiers_limit' ),
114 'type' => 'number',
115 'default' => '',
116 'css' => 'width: 6em;',
117 'custom_attributes' => array( 'min' => 1, 'max' => 20, 'step' => 1, 'placeholder' => __( 'All', 'tier-pricing-table' ) ),
118 'desc' => __( 'How many tiers a grid item lists; the rest sit behind a "+N more" link to the product page. Leave empty to list them all.', 'tier-pricing-table' ),
119 ),
120 array(
121 'title' => __( 'Bulk savings badge', 'tier-pricing-table' ),
122 'id' => self::getOptionID( 'badge_enabled' ),
123 'type' => TPTSwitchOption::FIELD_TYPE,
124 'default' => 'no',
125 'desc' => __( 'A badge on the product image with the biggest discount the product\'s tiers give.', 'tier-pricing-table' ),
126 ),
127 array(
128 'title' => __( 'Badge text', 'tier-pricing-table' ),
129 'id' => self::getOptionID( 'badge_template' ),
130 'type' => TPTTextTemplate::FIELD_TYPE,
131 'placeholders' => self::getBadgePlaceholders(),
132 'default' => self::getDefaultBadgeTemplate(),
133 ),
134 array(
135 'title' => __( 'Badge position', 'tier-pricing-table' ),
136 'id' => self::getOptionID( 'badge_position' ),
137 'type' => 'select',
138 'default' => 'top-left',
139 'options' => self::getBadgePositionOptions(),
140 ),
141 array(
142 'title' => __( 'Badge color', 'tier-pricing-table' ),
143 'id' => self::getOptionID( 'badge_color' ),
144 'type' => 'color',
145 'default' => '',
146 'css' => 'width:6em;',
147 'desc' => __( 'Leave empty to use the active tier color.', 'tier-pricing-table' ),
148 ),
149 array(
150 'title' => __( 'Add quantity selector to grids', 'tier-pricing-table' ),
151 'id' => self::getOptionID( 'show_quantity_field' ),
152 'type' => TPTSwitchOption::FIELD_TYPE,
153 'default' => 'no',
154 'extended_description' => ( function () {
155 ob_start();
156 ?>
157 <p>
158 <?php
159 esc_html_e( 'Add a quantity input field directly to items on the shop and category pages.', 'tier-pricing-table' );
160 ?>
161 </p>
162 <p>
163 <b>
164 <?php
165 esc_html_e( 'Only enable this if your theme doesn\'t already provide quantity selectors on the shop page.',
166 'tier-pricing-table' );
167 ?>
168 </b>
169 </p>
170 <?php
171 return ob_get_clean();
172 } )(),
173 'custom_attributes' => [ 'data-tiered-pricing-premium-option' => true ],
174 ),
175 array(
176 'title' => __( 'Dynamic price', 'tier-pricing-table' ),
177 'id' => self::getOptionID( 'dynamic_price' ),
178 'type' => TPTSwitchOption::FIELD_TYPE,
179 'default' => 'yes',
180 'extended_description' => ( function () {
181 ob_start();
182 ?>
183 <p>
184 <?php
185 esc_html_e( 'Update the displayed price to the tier price when the customer changes the quantity in the grid. Needs a quantity field on the grid item, from this plugin, the theme or another plugin.',
186 'tier-pricing-table' );
187 ?>
188 </p>
189 <?php
190 return ob_get_clean();
191 } )(),
192 'desc_tip' => true,
193 ),
194 array(
195 'title' => __( 'Compact layout', 'tier-pricing-table' ),
196 'id' => self::getOptionID( 'use_reduced_styles' ),
197 'type' => TPTSwitchOption::FIELD_TYPE,
198 'default' => 'yes',
199 'desc' => __( 'Apply minimal styling to pricing tables to better fit the constrained space of catalog grids.',
200 'tier-pricing-table' ),
201 'desc_tip' => true,
202 ),
203 array(
204 'type' => 'sectionend',
205 ),
206
207 array(
208 'title' => __( 'Pricing Layout Settings', 'tier-pricing-table' ),
209 'desc' => __( 'Customize the appearance and behavior of tiered pricing on catalog pages.',
210 'tier-pricing-table' ),
211 'id' => self::getOptionId( 'layout_settings' ),
212 'type' => 'title',
213 ),
214
215 array(
216 'title' => __( 'Layout source', 'tier-pricing-table' ),
217 'id' => self::getOptionID( 'layout_settings' ),
218 'type' => TPTDisplayType::FIELD_TYPE,
219 'options' => array(
220 'default' => __( 'Same as product page', 'tier-pricing-table' ),
221 'custom' => __( 'Custom', 'tier-pricing-table' ),
222 ),
223 'desc' => __( 'Choose whether to inherit the layout from the product page or use a custom layout for catalogs.',
224 'tier-pricing-table' ),
225 'desc_tip' => true,
226 'default' => 'default',
227 ),
228 array(
229 'title' => __( 'Catalog layout', 'tier-pricing-table' ),
230 'id' => self::getOptionID( 'layout' ),
231 'type' => TPTDisplayType::FIELD_TYPE,
232 'options' => $availableLayouts,
233
234 'desc' => __( 'Select the specific visual template for the catalog page.', 'tier-pricing-table' ),
235 'desc_tip' => true,
236 'default' => 'table',
237 ),
238 array(
239 'title' => __( 'Table design style', 'tier-pricing-table' ),
240 'id' => self::getOptionID( 'pricing_table_style' ),
241 'type' => TPTDisplayType::FIELD_TYPE,
242 'options' => GeneralSection::getStyleOptions( true )['table'],
243 'default' => 'default',
244 'value' => self::getTableStyle(),
245 'desc_tip' => true,
246 ),
247 array(
248 'title' => __( 'Blocks design style', 'tier-pricing-table' ),
249 'id' => self::getOptionID( 'pricing_blocks_style' ),
250 'type' => TPTDisplayType::FIELD_TYPE,
251 'options' => GeneralSection::getStyleOptions( true )['blocks'],
252 'default' => 'default',
253 'value' => self::getBlocksStyle(),
254 'desc_tip' => true,
255 ),
256 array(
257 'title' => __( 'Options design style', 'tier-pricing-table' ),
258 'id' => self::getOptionID( 'pricing_options_style' ),
259 'type' => TPTDisplayType::FIELD_TYPE,
260 'options' => GeneralSection::getStyleOptions( true )['options'],
261 'default' => 'default',
262 'value' => self::getOptionsStyle(),
263 'desc_tip' => true,
264 ),
265 array(
266 'title' => __( 'Dropdown design style', 'tier-pricing-table' ),
267 'id' => self::getOptionID( 'pricing_dropdown_style' ),
268 'type' => TPTDisplayType::FIELD_TYPE,
269 'options' => GeneralSection::getStyleOptions( true )['dropdown'],
270 'default' => 'default',
271 'value' => self::getDropdownStyle(),
272 'desc_tip' => true,
273 ),
274 array(
275 'title' => __( 'Plain text design style', 'tier-pricing-table' ),
276 'id' => self::getOptionID( 'pricing_plain_text_style' ),
277 'type' => TPTDisplayType::FIELD_TYPE,
278 'options' => GeneralSection::getStyleOptions( true )['plain-text'],
279 'default' => 'default',
280 'value' => self::getPlainTextStyle(),
281 'desc_tip' => true,
282 ),
283 array(
284 'title' => __( 'Pricing title', 'tier-pricing-table' ),
285 'id' => self::getOptionID( 'title' ),
286 'type' => 'text',
287 'default' => '',
288 'desc' => __( 'Text displayed above the tiered pricing block.',
289 'tier-pricing-table' ),
290 ),
291 array(
292 'title' => __( 'Quantity display type', 'tier-pricing-table' ),
293 'id' => self::getOptionID( 'quantity_type' ),
294 'type' => TPTDisplayType::FIELD_TYPE,
295 'options' => array(
296 'range' => __( 'Range', 'tier-pricing-table' ),
297 'static' => __( 'Static values', 'tier-pricing-table' ),
298 ),
299 'descriptions' => array(
300 'range' => __( 'e.g. 10 - 24 pieces', 'tier-pricing-table' ),
301 'static' => __( 'e.g. 10+ pieces', 'tier-pricing-table' ),
302 ),
303 'default' => 'range',
304 ),
305 array(
306 'title' => __( 'Spacing', 'tier-pricing-table' ),
307 'id' => self::getOptionID( 'layout_spacing' ),
308 'type' => 'number',
309 'default' => '',
310 'css' => 'width: 6em;',
311 'custom_attributes' => array( 'min' => 0, 'max' => 40, 'step' => 1, 'placeholder' => __( 'Auto', 'tier-pricing-table' ) ),
312 'desc' => __( 'Gap between the pricing blocks, options or card rows, in pixels. Leave empty to keep each design style\'s own spacing.', 'tier-pricing-table' ),
313 ),
314 array(
315 'title' => __( 'Cell padding', 'tier-pricing-table' ),
316 'id' => self::getOptionID( 'cell_padding' ),
317 'type' => 'number',
318 'default' => '',
319 'css' => 'width: 6em;',
320 'custom_attributes' => array( 'min' => 0, 'max' => 30, 'step' => 1, 'placeholder' => __( 'Auto', 'tier-pricing-table' ) ),
321 'desc' => __( 'Padding inside the cells of the table and horizontal table layouts, in pixels. Leave empty to keep each design style\'s own padding; a value also overrides the theme\'s cell padding.', 'tier-pricing-table' ),
322 ),
323 array(
324 'title' => __( 'Tier order', 'tier-pricing-table' ),
325 'id' => self::getOptionID( 'tiers_order' ),
326 'type' => TPTDisplayType::FIELD_TYPE,
327 'options' => array(
328 'asc' => __( 'Ascending', 'tier-pricing-table' ),
329 'desc' => __( 'Descending', 'tier-pricing-table' ),
330 ),
331 'descriptions' => array(
332 'asc' => __( 'Smallest quantity first', 'tier-pricing-table' ),
333 'desc' => __( 'Biggest discount first', 'tier-pricing-table' ),
334 ),
335 'default' => 'asc',
336 ),
337 array(
338 'title' => __( 'Active pricing tier color', 'tier-pricing-table' ),
339 'id' => self::getOptionID( 'selected_quantity_color' ),
340 'type' => 'color',
341 'css' => 'width:6em;',
342 'default' => '#3858e9',
343 ),
344 array(
345 'title' => __( 'Discount badge color', 'tier-pricing-table' ),
346 'id' => self::getOptionID( 'discount_badge_color' ),
347 'type' => 'color',
348 'css' => 'width:6em;',
349 'default' => '',
350 'desc' => __( 'The discount badge of table styles #2 to #6. Styles #2 and #6 show a light tint of this color behind text in this color, styles #3 and #4 a solid badge with white text, style #5 colors its savings bar and percentage. Leave empty to keep the style\'s own colors (the active tier color on styles #3 to #5).', 'tier-pricing-table' ),
351 ),
352 array(
353 'title' => __( 'Active tier left border', 'tier-pricing-table' ),
354 'id' => self::getOptionID( 'table_active_border' ),
355 'type' => TPTSwitchOption::FIELD_TYPE,
356 'default' => 'yes',
357 'desc' => __( 'Table styles #1, #5 and #6 mark the active tier with a left border in the active tier color. Switch it off to keep the row highlight only.', 'tier-pricing-table' ),
358 ),
359 array(
360 'title' => __( 'Unit label', 'tier-pricing-table' ),
361 'id' => self::getOptionID( 'table_quantity_measurement' ),
362 'type' => TPTQuantityMeasurementField::FIELD_TYPE,
363 'default' => array(
364 'singular' => '',
365 'plural' => '',
366 ),
367 'desc' => __( 'For example: pieces, boxes, bottles, packs, etc. This will be shown next to quantity values. Leave blank to skip adding a unit label.',
368 'tier-pricing-table' ),
369 ),
370 array(
371 'title' => __( 'Unit label', 'tier-pricing-table' ),
372 'id' => self::getOptionID( 'blocks_quantity_measurement' ),
373 'type' => TPTQuantityMeasurementField::FIELD_TYPE,
374 'default' => array(
375 'singular' => _n( 'piece', 'pieces', 1, 'tier-pricing-table' ),
376 'plural' => _n( 'piece', 'pieces', 2, 'tier-pricing-table' ),
377 ),
378 'desc' => __( 'For example: pieces, boxes, bottles, packs, etc. This will be shown next to quantity values. Leave blank to skip adding a unit label.',
379 'tier-pricing-table' ),
380 ),
381 array(
382 'title' => __( 'Quantity column title', 'tier-pricing-table' ),
383 'default' => __( 'Quantity', 'tier-pricing-table' ),
384 'id' => self::getOptionID( 'quantity_column_title' ),
385 'desc' => __( 'Leave empty to not show this column.', 'tier-pricing-table' ),
386 'type' => 'text',
387 ),
388 array(
389 'title' => __( 'Discount column title', 'tier-pricing-table' ),
390 'default' => __( 'Discount', 'tier-pricing-table' ),
391 'id' => self::getOptionID( 'discount_column_title' ),
392 'desc' => __( 'Leave empty to not show this column.', 'tier-pricing-table' ),
393 'type' => 'text',
394 ),
395 array(
396 'title' => __( 'Price column title', 'tier-pricing-table' ),
397 'default' => __( 'Price', 'tier-pricing-table' ),
398 'id' => self::getOptionID( 'price_column_title' ),
399 'desc' => __( 'Leave empty to not show this column.', 'tier-pricing-table' ),
400 'type' => 'text',
401 ),
402 array(
403 'title' => __( 'Show discount', 'tier-pricing-table' ),
404 'id' => self::getOptionID( 'blocks_show_discount' ),
405 'type' => TPTSwitchOption::FIELD_TYPE,
406 'default' => 'yes',
407 ),
408 array(
409 'title' => __( 'Discount format', 'tier-pricing-table' ),
410 'id' => self::getOptionID( 'discount_format' ),
411 'type' => TPTDisplayType::FIELD_TYPE,
412 'options' => array(
413 'percentage' => __( 'Percentage', 'tier-pricing-table' ),
414 'amount' => __( 'Amount saved', 'tier-pricing-table' ),
415 'both' => __( 'Both', 'tier-pricing-table' ),
416 ),
417 'descriptions' => array(
418 'percentage' => __( 'e.g. 10%', 'tier-pricing-table' ),
419 'amount' => __( 'e.g. $4.50', 'tier-pricing-table' ),
420 'both' => __( 'e.g. 10% ($4.50)', 'tier-pricing-table' ),
421 ),
422 'default' => 'percentage',
423 ),
424 array(
425 'title' => __( 'Show regular product price', 'tier-pricing-table' ),
426 'id' => self::getOptionID( 'options_show_original_product_price' ),
427 'type' => TPTSwitchOption::FIELD_TYPE,
428 'default' => 'yes',
429 'desc' => __( 'Show the crossed out regular price in options.', 'tier-pricing-table' ),
430 ),
431 array(
432 'title' => __( 'Show total pricing in option', 'tier-pricing-table' ),
433 'id' => self::getOptionID( 'options_show_total' ),
434 'type' => TPTSwitchOption::FIELD_TYPE,
435 'default' => 'yes',
436 'desc' => __( 'Show the total price in an active option.', 'tier-pricing-table' ),
437 'custom_attributes' => [ 'data-tiered-pricing-premium-option' => true ],
438 ),
439 array(
440 'title' => __( 'Option template', 'tier-pricing-table' ),
441 'id' => self::getOptionID( 'options_option_text' ),
442 'default' => __( '<strong>Buy {tp_quantity} pieces and save {tp_rounded_discount}%</strong>',
443 'tier-pricing-table' ),
444 'placeholders' => array(
445 'tp_quantity',
446 'tp_discount',
447 'tp_rounded_discount',
448 ),
449 'type' => TPTTextTemplate::FIELD_TYPE,
450 ),
451 array(
452 'title' => __( 'Show the "no discount" option', 'tier-pricing-table' ),
453 'id' => self::getOptionID( 'options_show_default_option' ),
454 'type' => TPTSwitchOption::FIELD_TYPE,
455 'default' => 'yes',
456 'desc' => __( 'Show the option with a regular product price.', 'tier-pricing-table' ),
457 ),
458 array(
459 'title' => __( '"No discount" option template', 'tier-pricing-table' ),
460 'id' => self::getOptionID( 'options_default_option_text' ),
461 'default' => __( '<strong>Buy {tp_quantity} pieces</strong>', 'tier-pricing-table' ),
462 'placeholders' => array(
463 'tp_quantity',
464 ),
465 'type' => TPTTextTemplate::FIELD_TYPE,
466 ),
467 array(
468 'title' => __( 'Template', 'tier-pricing-table' ),
469 'id' => self::getOptionID( 'plain_text_template' ),
470 'default' => __( '<strong>Buy {tp_quantity} pieces for {tp_price} each and save {tp_rounded_discount}%</strong>',
471 'tier-pricing-table' ),
472 'placeholders' => array(
473 'tp_quantity',
474 'tp_discount',
475 'tp_price',
476 'tp_rounded_discount',
477 ),
478 'type' => TPTTextTemplate::FIELD_TYPE,
479 ),
480
481 array(
482 'title' => __( 'Show the "no discount" tier', 'tier-pricing-table' ),
483 'id' => self::getOptionID( 'plain_text_show_first_tier' ),
484 'type' => TPTSwitchOption::FIELD_TYPE,
485 'default' => 'yes',
486 'desc' => __( 'Show the tier with a regular product price.', 'tier-pricing-table' ),
487 ),
488
489 array(
490 'title' => __( '"No discount" template', 'tier-pricing-table' ),
491 'id' => self::getOptionID( 'plain_text_first_tier_template' ),
492 'default' => __( '<strong>Buy {tp_quantity} pieces for {tp_price} each</strong>',
493 'tier-pricing-table' ),
494 'placeholders' => array(
495 'tp_quantity',
496 'tp_price',
497 ),
498 'type' => TPTTextTemplate::FIELD_TYPE,
499 ),
500 array(
501 'title' => __( 'Clickable tiered pricing', 'tier-pricing-table' ),
502 'id' => self::getOptionID( 'clickable_table_rows' ),
503 'type' => TPTSwitchOption::FIELD_TYPE,
504 'default' => 'yes',
505 'desc' => __( 'Makes tiered pricing (table rows, blocks, options, etc) clickable.',
506 'tier-pricing-table' ),
507 'custom_attributes' => [ 'data-tiered-pricing-premium-option' => true ],
508 ),
509 array(
510 'type' => 'sectionend',
511 ),
512 );
513 }
514
515 /**
516 * The product lists tiered pricing can show in, keyed by the value stored in the "contexts" option.
517 */
518 public static function getContextOptions(): array {
519 return array(
520 'shop' => __( 'Shop page', 'tier-pricing-table' ),
521 'category' => __( 'Category pages', 'tier-pricing-table' ),
522 'tag' => __( 'Tag and attribute pages', 'tier-pricing-table' ),
523 'search' => __( 'Search results', 'tier-pricing-table' ),
524 'related' => __( 'Related products', 'tier-pricing-table' ),
525 'upsells' => __( 'Upsells', 'tier-pricing-table' ),
526 'cross_sells' => __( 'Cross-sells in the cart', 'tier-pricing-table' ),
527 'shortcode' => __( 'Product shortcodes and other lists', 'tier-pricing-table' ),
528 'blocks' => __( 'Product Collection block', 'tier-pricing-table' ),
529 );
530 }
531
532 public static function getScopeOptions(): array {
533 return array(
534 'everywhere' => __( 'Everywhere', 'tier-pricing-table' ),
535 'selected' => __( 'Selected places', 'tier-pricing-table' ),
536 );
537 }
538
539 /**
540 * Whether the display is limited to chosen lists and categories.
541 */
542 public static function isScopeSelected(): bool {
543 return 'selected' === get_option( self::getOptionID( 'scope' ), 'everywhere' );
544 }
545
546 /**
547 * The enabled contexts; nothing stored, or the "everywhere" scope, means all of them.
548 */
549 public static function getContexts(): array {
550 $known = array_keys( self::getContextOptions() );
551
552 if ( ! self::isScopeSelected() ) {
553 return $known;
554 }
555
556 $chosen = array_values( array_intersect( TPTCheckboxListOption::toArray( get_option( self::getOptionID( 'contexts' ), '' ) ), $known ) );
557
558 return $chosen ? $chosen : $known;
559 }
560
561 /**
562 * Product category ids the display is limited to; empty means every product.
563 */
564 public static function getCategories(): array {
565 if ( ! self::isScopeSelected() ) {
566 return array();
567 }
568
569 return array_values( array_filter( array_map( 'intval', TPTCheckboxListOption::toArray( get_option( self::getOptionID( 'categories' ), '' ) ) ) ) );
570 }
571
572 /**
573 * Names of the chosen categories, keyed by id (for the pickers; the full list is never loaded).
574 */
575 public static function getCategoryNames( array $ids ): array {
576 $names = array();
577
578 foreach ( $ids as $id ) {
579 $term = get_term( (int) $id, 'product_cat' );
580 if ( $term && ! is_wp_error( $term ) ) {
581 $path = array();
582 foreach ( array_reverse( get_ancestors( $term->term_id, 'product_cat' ) ) as $ancestorId ) {
583 $ancestor = get_term( $ancestorId, 'product_cat' );
584 if ( $ancestor && ! is_wp_error( $ancestor ) ) {
585 $path[] = $ancestor->name;
586 }
587 }
588 $path[] = $term->name;
589 $names[ (int) $id ] = implode( ' > ', $path );
590 }
591 }
592
593 return $names;
594 }
595
596 public static function getTiersLimit(): int {
597 return max( 0, (int) get_option( self::getOptionID( 'tiers_limit' ), '' ) );
598 }
599
600 public static function isBadgeEnabled(): bool {
601 return 'yes' === get_option( self::getOptionID( 'badge_enabled' ), 'no' );
602 }
603
604 public static function getDefaultBadgeTemplate(): string {
605 return __( 'Save up to {tp_max_discount}', 'tier-pricing-table' );
606 }
607
608 public static function getBadgeTemplate(): string {
609 $template = (string) get_option( self::getOptionID( 'badge_template' ), '' );
610
611 return '' !== trim( $template ) ? $template : self::getDefaultBadgeTemplate();
612 }
613
614 public static function getBadgePlaceholders(): array {
615 return array( 'tp_max_discount', 'tp_lowest_price', 'tp_lowest_quantity', 'tp_max_saving' );
616 }
617
618 public static function getBadgePositionOptions(): array {
619 return array(
620 'top-left' => __( 'Top left', 'tier-pricing-table' ),
621 'top-right' => __( 'Top right', 'tier-pricing-table' ),
622 );
623 }
624
625 public static function getBadgePosition(): string {
626 return 'top-right' === get_option( self::getOptionID( 'badge_position' ), 'top-left' ) ? 'top-right' : 'top-left';
627 }
628
629 public static function getBadgeColor(): string {
630 return (string) get_option( self::getOptionID( 'badge_color' ), '' );
631 }
632
633 public static function isEnabled(): bool {
634 return 'yes' === get_option( self::getOptionID( 'enabled' ), 'no' );
635 }
636
637 public static function getPosition(): array {
638 $hook = get_option( self::getOptionID( 'position' ), 'woocommerce_after_shop_loop_item__6' );
639
640 $hook = explode( '__', $hook );
641
642 return array(
643 'hook' => ! empty( $hook[0] ) ? $hook[0] : '__none__',
644 'priority' => ! empty( $hook[1] ) ? $hook[1] : 15,
645 );
646 }
647
648 public static function isCustomLayoutSettings(): bool {
649 return 'custom' === get_option( self::getOptionID( 'layout_settings' ), 'default' );
650 }
651
652 public static function getLayoutType(): string {
653 return get_option( self::getOptionID( 'layout' ), 'table' );
654 }
655
656 /**
657 * Catalog design styles. Until a catalog style is saved, the product page style applies (that is how
658 * catalogs always rendered before they had their own style options).
659 */
660 public static function getTableStyle(): string {
661 return self::catalogStyle( 'table', (string) get_option( self::getOptionID( 'pricing_table_style' ), '' ) ?: GeneralSection::getPricingTableStyle() );
662 }
663
664 public static function getBlocksStyle(): string {
665 return self::catalogStyle( 'blocks', (string) get_option( self::getOptionID( 'pricing_blocks_style' ), '' ) ?: GeneralSection::getPricingBlocksStyle() );
666 }
667
668 public static function getOptionsStyle(): string {
669 return self::catalogStyle( 'options', (string) get_option( self::getOptionID( 'pricing_options_style' ), '' ) ?: GeneralSection::getPricingOptionsStyle() );
670 }
671
672 public static function getDropdownStyle(): string {
673 return self::catalogStyle( 'dropdown', (string) get_option( self::getOptionID( 'pricing_dropdown_style' ), '' ) ?: GeneralSection::getPricingDropdownStyle() );
674 }
675
676 public static function getPlainTextStyle(): string {
677 return self::catalogStyle( 'plain-text', (string) get_option( self::getOptionID( 'pricing_plain_text_style' ), '' ) ?: GeneralSection::getPricingPlainTextStyle() );
678 }
679
680 /**
681 * A style withheld from shop and category pages falls back to the default one there.
682 */
683 protected static function catalogStyle( string $layout, string $style ): string {
684 $excluded = GeneralSection::getCatalogExcludedStyles();
685
686 return in_array( $style, (array) ( $excluded[ $layout ] ?? array() ), true ) ? 'default' : $style;
687 }
688
689 public static function getTitle(): string {
690 return get_option( self::getOptionID( 'title' ), '' );
691 }
692
693 public static function getQuantityType(): string {
694 return get_option( self::getOptionID( 'quantity_type' ), 'range' );
695 }
696
697 public static function getLayoutSpacing(): string {
698 return (string) get_option( self::getOptionID( 'layout_spacing' ), '' );
699 }
700
701 public static function getCellPadding(): string {
702 return (string) get_option( self::getOptionID( 'cell_padding' ), '' );
703 }
704
705 public static function getTiersOrder(): string {
706 return (string) get_option( self::getOptionID( 'tiers_order' ), 'asc' );
707 }
708
709 public static function getDiscountFormat(): string {
710 return (string) get_option( self::getOptionID( 'discount_format' ), 'percentage' );
711 }
712
713 public static function getSelectedQuantityColor(): string {
714 return get_option( self::getOptionID( 'selected_quantity_color' ), '#3858e9' );
715 }
716
717 public static function getDiscountBadgeColor(): string {
718 return (string) get_option( self::getOptionID( 'discount_badge_color' ), '' );
719 }
720
721 public static function getActiveTierBorder(): string {
722 return 'no' === get_option( self::getOptionID( 'table_active_border' ), 'yes' ) ? 'no' : 'yes';
723 }
724
725 public static function getTableQuantityMeasurement(): array {
726 return get_option( self::getOptionID( 'table_quantity_measurement' ), array(
727 'singular' => '',
728 'plural' => '',
729 ) );
730 }
731
732 public static function getBlocksQuantityMeasurement(): array {
733 return get_option( self::getOptionID( 'blocks_quantity_measurement' ), array(
734 'singular' => _n( 'piece', 'pieces', 1, 'tier-pricing-table' ),
735 'plural' => _n( 'piece', 'pieces', 2, 'tier-pricing-table' ),
736 ) );
737 }
738
739 public static function getTableColumnsTitles(): array {
740 return array(
741 'head_quantity_text' => get_option( self::getOptionID( 'quantity_column_title' ),
742 __( 'Quantity', 'tier-pricing-table' ) ),
743 'head_discount_text' => get_option( self::getOptionID( 'discount_column_title' ),
744 __( 'Discount', 'tier-pricing-table' ) ),
745 'head_price_text' => get_option( self::getOptionID( 'price_column_title' ),
746 __( 'Price', 'tier-pricing-table' ) ),
747 );
748 }
749
750 public static function blocksShowDiscount(): bool {
751 return 'yes' === get_option( self::getOptionID( 'blocks_show_discount' ), 'yes' );
752 }
753
754 public static function isShowOriginalProductPriceInOptions(): bool {
755 return 'yes' === get_option( self::getOptionID( 'options_show_original_product_price' ), 'yes' );
756 }
757
758 public static function isShowTotalInOptions(): bool {
759 return 'yes' === get_option( self::getOptionID( 'options_show_total' ), 'yes' );
760 }
761
762 public static function getOptionText(): string {
763 return get_option( self::getOptionID( 'options_option_text' ),
764 '<strong>Buy {tp_quantity} pieces and save {tp_rounded_discount}%</strong>' );
765 }
766
767 public static function isShowDefaultOption(): bool {
768 return 'yes' === get_option( self::getOptionID( 'options_show_default_option' ), 'yes' );
769 }
770
771 public static function getDefaultOptionText(): string {
772 return get_option( self::getOptionID( 'options_default_option_text' ),
773 '<strong>Buy {tp_quantity} pieces</strong>' );
774 }
775
776 public static function getPlainTextTemplate(): string {
777 return get_option( self::getOptionID( 'plain_text_template' ),
778 '<strong>Buy {tp_quantity} pieces for {tp_price} each and save {tp_rounded_discount}%</strong>' );
779 }
780
781 public static function isShowFirstPlainTextTier(): bool {
782 return 'yes' === get_option( self::getOptionID( 'plain_text_show_first_tier' ), 'yes' );
783 }
784
785 public static function getFirstTierPlainTextTemplate(): string {
786 return get_option( self::getOptionID( 'plain_text_first_tier_template' ),
787 '<strong>Buy {tp_quantity} pieces for {tp_price} each</strong>' );
788 }
789
790 public static function isClickableTableRows(): bool {
791 return 'yes' === get_option( self::getOptionID( 'clickable_table_rows' ), 'yes' );
792 }
793
794 public static function useReducedStyles(): bool {
795 return 'yes' === get_option( self::getOptionID( 'use_reduced_styles' ), 'yes' );
796 }
797
798 public static function isDynamicPrice(): bool {
799 return 'yes' === get_option( self::getOptionID( 'dynamic_price' ), 'yes' );
800 }
801
802 public static function showQuantityField(): bool {
803 return 'yes' === get_option( self::getOptionID( 'show_quantity_field' ), 'no' );
804 }
805
806 }