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
← All changes | src/Addons/ProductCatalogLoop/Settings/ProductCatalogLoopSettingsSection.php +386 -33 6.1.0 → 8.0.2 View file →
@@ -1,10 +1,12 @@
1 1 <?php namespace TierPricingTable\Addons\ProductCatalogLoop\Settings;
2 2
3 3 use TierPricingTable\Settings\CustomOptions\TPTDisplayType;
4 4 use TierPricingTable\Settings\CustomOptions\TPTQuantityMeasurementField;
5 +use TierPricingTable\Settings\CustomOptions\TPTCheckboxListOption;
5 6 use TierPricingTable\Settings\CustomOptions\TPTSwitchOption;
6 7 use TierPricingTable\Settings\CustomOptions\TPTTextTemplate;
8 +use TierPricingTable\Settings\Sections\GeneralSection\GeneralSection;
7 9 use TierPricingTable\Settings\Sections\SectionAbstract;
8 10 use TierPricingTable\Settings\Settings;
9 11 use TierPricingTable\TierPricingTablePlugin;
10 12
@@ -18,9 +20,9 @@
18 20 return Settings::SETTINGS_PREFIX . 'shop_loop_display_';
19 21 }
20 22
21 23 public function getName(): string {
22 - return __( 'Product Catalog', 'tier-pricing-table' );
24 + return __( 'Shop & Categories', 'tier-pricing-table' );
23 25 }
24 26
25 27 public function getSlug(): string {
26 28 return 'shop-loop-display';
@@ -32,15 +34,15 @@
32 34 unset( $availableLayouts['tooltip'] );
33 35
34 36 return array(
35 37 array(
36 - 'title' => __( 'Tiered Pricing on the shop page', 'tier-pricing-table' ),
37 - 'desc' => __( 'This section controls how tiered pricing works for product catalog.',
38 + 'title' => __( 'Tiered Pricing on Shop & Category Pages', 'tier-pricing-table' ),
39 + 'desc' => __( 'Control how tiered pricing appears on shop and category pages.',
38 40 'tier-pricing-table' ),
39 41 'type' => 'title',
40 42 ),
41 43 array(
42 - 'title' => __( 'Enabled', 'tier-pricing-table' ),
44 + 'title' => __( 'Enable on Shop & Categories', 'tier-pricing-table' ),
43 45 'id' => self::getOptionID( 'enabled' ),
44 46 'type' => TPTSwitchOption::FIELD_TYPE,
45 47 'default' => 'no',
46 48 'extended_description' => ( function () {
@@ -47,26 +49,25 @@
47 49 ob_start();
48 50 ?>
49 51 <p>
50 52 <?php
51 - esc_html_e( 'Enable this option to show tiered pricing in the products catalog.',
53 + esc_html_e( 'Turn this on to display tiered pricing directly within your shop and category pages.',
52 54 'tier-pricing-table' );
53 55 ?>
54 - <br>
55 - <br>
56 + </p>
57 + <p>
56 58 <b><?php esc_html_e( 'Note:', 'tier-pricing-table' ); ?></b>
57 - <br>
58 - <?php esc_html_e( 'Some themes could display it incorrectly.', 'tier-pricing-table' ); ?>
59 + <?php esc_html_e( 'Depending on your theme, you may need minor CSS adjustments for optimal display.', 'tier-pricing-table' ); ?>
59 60 </p>
60 61 <?php
61 62 return ob_get_clean();
62 63 } )(),
63 - 'desc' => __( 'Show tiered pricing in the product loop (product catalog page)',
64 + 'desc' => __( 'Display tiered pricing tables on shop and category pages.',
64 65 'tier-pricing-table' ),
65 66 'desc_tip' => true,
66 67 ),
67 68 array(
68 - 'title' => __( 'Position on a product item', 'tier-pricing-table' ),
69 + 'title' => __( 'Position on product grid item', 'tier-pricing-table' ),
69 70 'id' => self::getOptionID( 'position' ),
70 71 'type' => 'select',
71 72 'default' => 'woocommerce_after_shop_loop_item__6',
72 73 'options' => array(
@@ -74,14 +75,80 @@
74 75 'woocommerce_after_shop_loop_item__15' => __( 'Below add-to-cart button', 'tier-pricing-table' ),
75 76 'woocommerce_shop_loop_item_title__5' => __( 'Above product title', 'tier-pricing-table' ),
76 77 'woocommerce_shop_loop_item_title__15' => __( 'Below product title', 'tier-pricing-table' ),
77 78 ),
78 - 'desc' => __( 'Where tiered pricing should be displayed on the product page.',
79 + 'desc' => __( 'Choose where the tiered pricing table appears relative to the product image and details.',
79 80 'tier-pricing-table' ),
80 81 'desc_tip' => true,
81 82 ),
82 83 array(
83 - 'title' => __( 'Show quantity field', 'tier-pricing-table' ),
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' ),
84 151 'id' => self::getOptionID( 'show_quantity_field' ),
85 152 'type' => TPTSwitchOption::FIELD_TYPE,
86 153 'default' => 'no',
87 154 'extended_description' => ( function () {
@@ -88,15 +155,15 @@
88 155 ob_start();
89 156 ?>
90 157 <p>
91 158 <?php
92 - esc_html_e( 'Show a quantity field on the product catalog items.', 'tier-pricing-table' );
159 + esc_html_e( 'Add a quantity input field directly to items on the shop and category pages.', 'tier-pricing-table' );
93 160 ?>
94 - <br>
95 - <br>
161 + </p>
162 + <p>
96 163 <b>
97 164 <?php
98 - esc_html_e( 'Enable this only if your theme does not show the quantity field already.',
165 + esc_html_e( 'Only enable this if your theme doesn\'t already provide quantity selectors on the shop page.',
99 166 'tier-pricing-table' );
100 167 ?>
101 168 </b>
102 169 </p>
@@ -114,9 +181,9 @@
114 181 ob_start();
115 182 ?>
116 183 <p>
117 184 <?php
118 - esc_html_e( 'Similar to the product page, the price will be updated dynamically when the user changes the quantity of a specific item.',
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.',
119 186 'tier-pricing-table' );
120 187 ?>
121 188 </p>
122 189 <?php
@@ -124,13 +191,13 @@
124 191 } )(),
125 192 'desc_tip' => true,
126 193 ),
127 194 array(
128 - 'title' => __( 'Use reduced styles', 'tier-pricing-table' ),
195 + 'title' => __( 'Compact layout', 'tier-pricing-table' ),
129 196 'id' => self::getOptionID( 'use_reduced_styles' ),
130 197 'type' => TPTSwitchOption::FIELD_TYPE,
131 198 'default' => 'yes',
132 - 'desc' => __( 'The plugin will apply additional CSS styles to the pricing layouts displayed in the product catalog to make them compact.',
199 + 'desc' => __( 'Apply minimal styling to pricing tables to better fit the constrained space of catalog grids.',
133 200 'tier-pricing-table' ),
134 201 'desc_tip' => true,
135 202 ),
136 203 array(
@@ -137,10 +204,10 @@
137 204 'type' => 'sectionend',
138 205 ),
139 206
140 207 array(
141 - 'title' => __( 'Template options', 'tier-pricing-table' ),
142 - 'desc' => __( 'Choose a tiered pricing template and customize its look and behavior.',
208 + 'title' => __( 'Pricing Layout Settings', 'tier-pricing-table' ),
209 + 'desc' => __( 'Customize the appearance and behavior of tiered pricing on catalog pages.',
143 210 'tier-pricing-table' ),
144 211 'id' => self::getOptionId( 'layout_settings' ),
145 212 'type' => 'title',
146 213 ),
@@ -145,35 +212,81 @@
145 212 'type' => 'title',
146 213 ),
147 214
148 215 array(
149 - 'title' => __( 'Layout settings', 'tier-pricing-table' ),
216 + 'title' => __( 'Layout source', 'tier-pricing-table' ),
150 217 'id' => self::getOptionID( 'layout_settings' ),
151 218 'type' => TPTDisplayType::FIELD_TYPE,
152 219 'options' => array(
153 - 'default' => __( 'Same as for product page', 'tier-pricing-table' ),
220 + 'default' => __( 'Same as product page', 'tier-pricing-table' ),
154 221 'custom' => __( 'Custom', 'tier-pricing-table' ),
155 222 ),
156 - 'desc' => __( 'The template for tiered pricing for the catalog page. You can use the same template settings as for the product page or choose a different one.',
223 + 'desc' => __( 'Choose whether to inherit the layout from the product page or use a custom layout for catalogs.',
157 224 'tier-pricing-table' ),
158 225 'desc_tip' => true,
159 226 'default' => 'default',
160 227 ),
161 228 array(
162 - 'title' => __( 'Layout', 'tier-pricing-table' ),
229 + 'title' => __( 'Catalog layout', 'tier-pricing-table' ),
163 230 'id' => self::getOptionID( 'layout' ),
164 231 'type' => TPTDisplayType::FIELD_TYPE,
165 232 'options' => $availableLayouts,
166 - 'desc' => __( 'Template for tiered pricing on the catalog page.', 'tier-pricing-table' ),
233 +
234 + 'desc' => __( 'Select the specific visual template for the catalog page.', 'tier-pricing-table' ),
167 235 'desc_tip' => true,
168 236 'default' => 'table',
169 237 ),
170 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(
171 284 'title' => __( 'Pricing title', 'tier-pricing-table' ),
172 285 'id' => self::getOptionID( 'title' ),
173 286 'type' => 'text',
174 287 'default' => '',
175 - 'desc' => __( 'The pricing title that is displayed above the tiered pricing.',
288 + 'desc' => __( 'Text displayed above the tiered pricing block.',
176 289 'tier-pricing-table' ),
177 290 ),
178 291 array(
179 292 'title' => __( 'Quantity display type', 'tier-pricing-table' ),
@@ -182,20 +295,69 @@
182 295 'options' => array(
183 296 'range' => __( 'Range', 'tier-pricing-table' ),
184 297 'static' => __( 'Static values', 'tier-pricing-table' ),
185 298 ),
186 - 'desc' => __( '"Range" displays the quantity range a tier applies to. "Static" displays only the minimum quantity required.',
187 - 'tier-pricing-table' ),
299 + 'descriptions' => array(
300 + 'range' => __( 'e.g. 10 - 24 pieces', 'tier-pricing-table' ),
301 + 'static' => __( 'e.g. 10+ pieces', 'tier-pricing-table' ),
302 + ),
188 303 'default' => 'range',
189 304 ),
190 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(
191 338 'title' => __( 'Active pricing tier color', 'tier-pricing-table' ),
192 339 'id' => self::getOptionID( 'selected_quantity_color' ),
193 340 'type' => 'color',
194 341 'css' => 'width:6em;',
195 - 'default' => '#96598A',
342 + 'default' => '#3858e9',
196 343 ),
197 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(
198 360 'title' => __( 'Unit label', 'tier-pricing-table' ),
199 361 'id' => self::getOptionID( 'table_quantity_measurement' ),
200 362 'type' => TPTQuantityMeasurementField::FIELD_TYPE,
201 363 'default' => array(
@@ -237,14 +399,30 @@
237 399 'desc' => __( 'Leave empty to not show this column.', 'tier-pricing-table' ),
238 400 'type' => 'text',
239 401 ),
240 402 array(
241 - 'title' => __( 'Show percentage discount', 'tier-pricing-table' ),
403 + 'title' => __( 'Show discount', 'tier-pricing-table' ),
242 404 'id' => self::getOptionID( 'blocks_show_discount' ),
243 405 'type' => TPTSwitchOption::FIELD_TYPE,
244 406 'default' => 'yes',
245 407 ),
246 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(
247 425 'title' => __( 'Show regular product price', 'tier-pricing-table' ),
248 426 'id' => self::getOptionID( 'options_show_original_product_price' ),
249 427 'type' => TPTSwitchOption::FIELD_TYPE,
250 428 'default' => 'yes',
@@ -333,8 +511,126 @@
333 511 ),
334 512 );
335 513 }
336 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 +
337 633 public static function isEnabled(): bool {
338 634 return 'yes' === get_option( self::getOptionID( 'enabled' ), 'no' );
339 635 }
340 636
@@ -356,8 +652,41 @@
356 652 public static function getLayoutType(): string {
357 653 return get_option( self::getOptionID( 'layout' ), 'table' );
358 654 }
359 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 +
360 689 public static function getTitle(): string {
361 690 return get_option( self::getOptionID( 'title' ), '' );
362 691 }
363 692
@@ -364,10 +693,34 @@
364 693 public static function getQuantityType(): string {
365 694 return get_option( self::getOptionID( 'quantity_type' ), 'range' );
366 695 }
367 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 +
368 713 public static function getSelectedQuantityColor(): string {
369 - return get_option( self::getOptionID( 'selected_quantity_color' ), '#96598A' );
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';
370 723 }
371 724
372 725 public static function getTableQuantityMeasurement(): array {
373 726 return get_option( self::getOptionID( 'table_quantity_measurement' ), array(