PluginProbe
Tiered Pricing Table for WooCommerce / 8.1.0
Tiered Pricing Table for WooCommerce v8.1.0
8.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 All 92 releases
← All changes | src/Addons/GlobalTieredPricing/CPT/Form/Form.php +124 -186 6.1.0 → 8.1.0 View file →
@@ -6,8 +6,9 @@
6 6 use TierPricingTable\Addons\GlobalTieredPricing\CPT\Form\Tabs\Settings;
7 7 use TierPricingTable\Addons\GlobalTieredPricing\CPT\Form\Tabs\UsersAndRoles;
8 8 use TierPricingTable\Addons\GlobalTieredPricing\CPT\GlobalTieredPricingCPT;
9 9 use TierPricingTable\Addons\GlobalTieredPricing\GlobalPricingRule;
10 +use TierPricingTable\Addons\GlobalTieredPricing\RuleOverlaps;
10 11 use TierPricingTable\Core\ServiceContainerTrait;
11 12 use WP_Post;
12 13
13 14 class Form {
@@ -24,18 +25,28 @@
24 25 protected $defaultTab = 'pricing';
25 26
26 27 protected $pricingRuleInstance = null;
27 28
29 + /**
30 + * @var Guide
31 + */
32 + protected $guide;
33 +
28 34 public function __construct() {
29 35
36 + $this->guide = new Guide();
37 +
30 38 add_action( 'init', function () {
31 - $this->tabs = apply_filters( 'tiered_pricing_table/global_pricing/form_tabs', array(
39 + $tabs = array(
32 40 new Pricing( $this ),
33 41 new ProductAndCategories( $this ),
34 42 new UsersAndRoles( $this ),
35 43 new Quantity( $this ),
36 - new Settings( $this ),
37 - ) );
44 + );
45 +
46 + $tabs[] = new Settings( $this );
47 +
48 + $this->tabs = apply_filters( 'tiered_pricing_table/global_pricing/form_tabs', $tabs, $this );
38 49 } );
39 50
40 51 add_action( 'edit_form_after_title', function ( WP_Post $post ) {
41 52 if ( GlobalTieredPricingCPT::SLUG !== $post->post_type ) {
@@ -62,16 +73,15 @@
62 73 .tpt-global-pricing-rule-form .woocommerce-help-tip {
63 74 margin-left: 5px;
64 75 }
65 76
66 - /* tab hint */
67 77 .tpt-global-pricing-rule-hint {
68 78 display: flex;
69 79 align-items: center;
70 - padding: 10px 10px;
71 - border: 1px solid #eee5ed;
72 - background: #faf6f9;
73 - color: #814c77 !important;
80 + padding: 10px;
81 + border-left: 3px solid var(--wp-admin-theme-color, #2271b1);
82 + background: #f6f7f7;
83 + color: var(--wp-admin-theme-color, #2271b1) !important;
74 84 margin-bottom: 20px;
75 85 }
76 86
77 87 .tpt-global-pricing-rule-hint--top-level {
@@ -78,8 +88,18 @@
78 88 margin-top: 10px;
79 89 border: 1px solid #888;
80 90 }
81 91
92 + .tpt-global-pricing-rule-hint--warning {
93 + border-left-color: #dba617;
94 + background: #fcf9e8;
95 + color: #6d4f00 !important;
96 + }
97 +
98 + .tpt-global-pricing-rule-hint--top-level + .tpt-global-pricing-rule-hint--top-level {
99 + margin-top: -10px;
100 + }
101 +
82 102 .tpt-global-pricing-rule-hint__icon {
83 103 margin-right: 10px;
84 104 }
85 105
@@ -117,9 +137,9 @@
117 137 }
118 138
119 139 .tpt-global-pricing-rule-form-tab--active {
120 140 cursor: default;
121 - background: #faf6f9;
141 + background: #f6f7f7;
122 142 }
123 143
124 144 .tpt-global-pricing-rule-form-tab__icon {
125 145 transition: all .1s;
@@ -126,11 +146,11 @@
126 146 margin-right: 10px;
127 147 height: 40px;
128 148 aspect-ratio: 1/1;
129 149 border-radius: 50%;
130 - background: #faf6f9;
150 + background: #f6f7f7;
131 151 text-align: center;
132 - color: #814c77;
152 + color: var(--wp-admin-theme-color, #2271b1);
133 153 font-size: 20px;
134 154 font-weight: bold;
135 155 display: flex;
136 156 justify-content: center;
@@ -138,9 +158,9 @@
138 158 }
139 159
140 160 .tpt-global-pricing-rule-form-tab--active h3,
141 161 .tpt-global-pricing-rule-form-tab--active div {
142 - color: #814c77 !important;
162 + color: var(--wp-admin-theme-color, #2271b1) !important;
143 163 }
144 164
145 165 .tpt-global-pricing-rule-form-tab--active .tpt-global-pricing-rule-form-tab__icon {
146 166 background: #fff;
@@ -212,9 +232,9 @@
212 232 display: none;
213 233 }
214 234
215 235 .tpt-global-pricing-rule-form-tab--active {
216 - border-bottom: 3px solid #814c77;
236 + border-bottom: 3px solid var(--wp-admin-theme-color, #2271b1);
217 237 }
218 238 }
219 239
220 240 @media screen and (max-width: 500px) {
@@ -221,8 +241,59 @@
221 241 .tiered-pricing-form-block {
222 242 padding: 5px 20px !important;
223 243 }
224 244 }
245 +
246 + /* Accordion styles */
247 + .tpt-exclusions-accordion {
248 + margin-top: 20px;
249 + background: #fff;
250 + }
251 +
252 + .tpt-exclusions-accordion summary {
253 + cursor: pointer;
254 + list-style: none;
255 + display: flex;
256 + align-items: center;
257 + justify-content: space-between;
258 + padding: 12px 15px;
259 + background: #f6f7f7;
260 + border: 1px solid #e8e8e8;
261 + font-size: 14px;
262 + font-weight: 600;
263 + color: #1d2327;
264 + transition: background-color 0.2s ease;
265 + }
266 +
267 + .tpt-exclusions-accordion summary::-webkit-details-marker {
268 + display: none;
269 + }
270 +
271 + .tpt-exclusions-accordion summary:hover {
272 + background: #f0f0f1;
273 + }
274 +
275 + .tpt-exclusions-accordion[open] summary {
276 + border-bottom-left-radius: 0;
277 + border-bottom-right-radius: 0;
278 + border-bottom: 1px solid #e8e8e8;
279 + }
280 +
281 + .tpt-exclusions-accordion[open] summary .tpt-accordion-icon {
282 + transform: rotate(180deg);
283 + }
284 +
285 + .tpt-accordion-icon {
286 + transition: transform 0.3s ease;
287 + color: #787c82;
288 + }
289 +
290 + .tpt-exclusions-accordion-content {
291 + padding: 15px 0;
292 + border: 1px solid #e8e8e8;
293 + border-top: none;
294 + border-radius: 0 0 4px 4px;
295 + }
225 296 </style>
226 297 <script>
227 298 jQuery(document).ready(function () {
228 299 let tabs = jQuery('.tpt-global-pricing-rule-form-tab');
@@ -248,19 +319,15 @@
248 319 protected function render( WP_Post $post ) {
249 320
250 321 $this->includeAssets();
251 322
252 - $rulesCount = (int) wp_count_posts( GlobalTieredPricingCPT::SLUG )->publish;
323 + $this->guide->render();
253 324
254 - if ( $this->isNewRule() && $rulesCount < 1 ) {
255 - $this->renderHelpingSteps();
325 + // a rule that changes nothing is flagged as "Skipped" by the Rule status box; no second notice here
326 + if ( ! $this->isNewRule() ) {
327 + $this->renderStatusHints( $this->getPricingRuleInstance( $post ) );
256 328 }
257 329
258 - if ( ! $this->isNewRule() && ! $this->getPricingRuleInstance( $post )->isValidPricing() ) {
259 - $this->tabs[0]->renderHint( __( 'The pricing rule does not affect either prices or product quantity limits. The rule will be skipped.',
260 - 'tier-pricing-table' ), array( 'custom_class' => 'tpt-global-pricing-rule-hint--top-level' ) );
261 - }
262 -
263 330 ?>
264 331 <div class="tpt-global-pricing-rule-form">
265 332
266 333 <nav class="tpt-global-pricing-rule-form__tabs">
@@ -265,15 +332,15 @@
265 332
266 333 <nav class="tpt-global-pricing-rule-form__tabs">
267 334 <?php foreach ( $this->tabs as $tab ) : ?>
268 335 <div class="tpt-global-pricing-rule-form-tab <?php echo esc_attr( $tab->getId() === $this->defaultTab ? 'tpt-global-pricing-rule-form-tab--active' : '' ); ?>"
269 - data-target="tpt-global-pricing-rule-form-tab-<?php echo esc_attr( $tab->getId() ); ?>">
336 + data-target="tpt-global-pricing-rule-form-tab-<?php echo esc_attr( $tab->getId() ); ?>">
270 337
271 338 <div class="tpt-global-pricing-rule-form-tab__icon" style="">
272 - <?php if ( $tab->getIcon() === '$' ) : ?>
273 - <span>$</span>
339 + <?php if ( strpos( $tab->getIcon(), 'dashicons-' ) === 0 ) : ?>
340 + <span class="dashicons <?php echo esc_attr( $tab->getIcon() ); ?>"></span>
274 341 <?php else : ?>
275 - <span class="dashicons <?php echo esc_attr( $tab->getIcon() ); ?>"></span>
342 + <span><?php echo esc_html( $tab->getIcon() ); ?></span>
276 343 <?php endif; ?>
277 344 </div>
278 345
279 346 <div class="tpt-global-pricing-rule-form-tab__title">
@@ -288,9 +355,9 @@
288 355
289 356 <section class="tpt-global-pricing-rule-form__content woocommerce_options_panel">
290 357 <?php foreach ( $this->tabs as $tab ) : ?>
291 358 <div class="tpt-global-pricing-rule-form-tab-content <?php echo esc_attr( $tab->getId() === $this->defaultTab ? 'tpt-global-pricing-rule-form-tab-content--active' : '' ); ?>"
292 - id="tpt-global-pricing-rule-form-tab-<?php echo esc_attr( $tab->getId() ); ?>">
359 + id="tpt-global-pricing-rule-form-tab-<?php echo esc_attr( $tab->getId() ); ?>">
293 360 <?php
294 361 $tab->render( $this->getPricingRuleInstance( $post ) );
295 362
296 363 do_action( 'tiered_pricing_table/global_pricing/form/tab_end', $tab,
@@ -303,8 +370,39 @@
303 370 <?php
304 371 }
305 372
306 373 /**
374 + * What the admin should know before editing: other rules have a higher priority for products and
375 + * customers they share, so this rule is skipped there. The Rule status box lists them.
376 + */
377 + protected function renderStatusHints( GlobalPricingRule $rule ) {
378 + // a suspended, expired or skipped rule is not applied anyway, so nothing overrides it
379 + if ( 'publish' !== get_post_status( $rule->getId() ) || ! $rule->canBeOverridden() ) {
380 + return;
381 + }
382 +
383 + $overriding = ( new RuleOverlaps() )->findOverriding( $rule, GlobalTieredPricingCPT::getGlobalRules( true, false ) );
384 +
385 + if ( ! $overriding ) {
386 + return;
387 + }
388 +
389 + $this->tabs[0]->renderHint(
390 + sprintf(
391 + /* translators: %d: number of rules */
392 + _n(
393 + '%d other rule has a higher priority and is applied instead of this rule for the products and customers they both match. See "Overridden by" in the Rule status box.',
394 + '%d other rules have a higher priority and are applied instead of this rule for the products and customers they both match. See "Overridden by" in the Rule status box.',
395 + count( $overriding ),
396 + 'tier-pricing-table'
397 + ),
398 + count( $overriding )
399 + ),
400 + array( 'custom_class' => 'tpt-global-pricing-rule-hint--top-level tpt-global-pricing-rule-hint--warning' )
401 + );
402 + }
403 +
404 + /**
307 405 * Get pricing rule instance
308 406 *
309 407 * @param WP_Post $post
310 408 *
@@ -315,168 +413,8 @@
315 413 $this->pricingRuleInstance = GlobalPricingRule::build( $post->ID );
316 414 }
317 415
318 416 return $this->pricingRuleInstance;
319 - }
320 -
321 - public function renderHelpingSteps() {
322 - ?>
323 - <style>
324 - .tpt-global-pricing-rule-helping {
325 - background: #fff;
326 - border: 1px solid #e8e8e8;
327 - padding: 20px;
328 - position: relative;
329 - text-align: center;
330 - margin: 20px 0;
331 - }
332 -
333 - .tpt-global-pricing-rule-helping__close {
334 - position: absolute;
335 - top: 10px;
336 - width: 26px;
337 - height: 26px;
338 - background: #faf6f9;
339 - color: #814c77;
340 - text-align: center;
341 - line-height: 24px;
342 - right: 10px;
343 - font-weight: bold;
344 - border-radius: 50%;
345 - }
346 -
347 - .tpt-global-pricing-rule-helping__close:hover {
348 - background: #f3ddee;
349 - cursor: pointer;
350 - }
351 -
352 - .tpt-global-pricing-rule-helping__title {
353 - font-size: 1.5em;
354 - font-weight: bold;
355 - margin-bottom: 15px;
356 - }
357 -
358 - .tpt-global-pricing-rule-helping__steps {
359 - justify-content: center;
360 - gap: 20px;
361 - display: flex;
362 - align-items: center;
363 - margin-top: 30px
364 - }
365 -
366 - .tpt-global-pricing-rule-helping-step--arrow {
367 - padding: 5px;
368 - border-radius: 50%;
369 - background: #faf6f9;
370 - color: #814c77;
371 - }
372 -
373 - .tpt-global-pricing-rule-helping-step__title {
374 - font-size: 1.4em;
375 - font-weight: 600;
376 - }
377 -
378 - .tpt-global-pricing-rule-helping-step__description {
379 - margin-top: 10px;
380 - }
381 -
382 - .tpt-global-pricing-rule-helping-step__icon,
383 - .tpt-global-pricing-rule-helping-step__icon span {
384 - width: 50px;
385 - height: 50px;
386 - border-radius: 50%;
387 - background: #faf6f9;
388 - margin: 0 auto 15px;
389 - text-align: center;
390 - color: #814c77;
391 - font-size: 25px;
392 - font-weight: bold;
393 - line-height: 50px;
394 - }
395 - </style>
396 - <script>
397 - jQuery(document).ready(function () {
398 - jQuery('.tpt-global-pricing-rule-helping__close').click(function () {
399 - jQuery(this).parent().hide();
400 - })
401 - })
402 - </script>
403 - <?php
404 - $steps = array(
405 - array(
406 - 'title' => 'Add pricing',
407 - 'description' => 'Set up custom regular and/or tiered pricing.',
408 - 'icon' => '$',
409 - 'has_next_step' => true,
410 - ),
411 - array(
412 - 'title' => 'Select products',
413 - 'description' => 'Select products or product categories that the rule will apply to.',
414 - 'icon' => '<span class="dashicons dashicons-archive"></span>',
415 - 'has_next_step' => true,
416 - ),
417 - array(
418 - 'title' => 'Select users',
419 - 'description' => 'Select users or user roles that the rule will apply to.',
420 - 'icon' => '<span class="dashicons dashicons-admin-users"></span>',
421 - 'has_next_step' => true,
422 - ),
423 - array(
424 - 'title' => 'Specify quantity',
425 - 'description' => 'Specify the minimum, maximum, and quantity step for products.',
426 - 'icon' => '<span class="dashicons dashicons-database"></span>',
427 - 'has_next_step' => false,
428 - ),
429 - )
430 - ?>
431 - <div class="tpt-global-pricing-rule-helping">
432 - <div class="tpt-global-pricing-rule-helping__title">
433 - <?php esc_html_e( 'How global pricing rules work', 'tier-pricing-table' ); ?>
434 - </div>
435 - <p>
436 - <?php
437 - esc_html_e( 'Global rules are useful when you need to set custom pricing for multiple products and apply it to a specific group of users.',
438 - 'tier-pricing-table' );
439 - ?>
440 - </p>
441 -
442 - <p>
443 - <?php
444 - esc_html_e( 'Please note that depending on the priority settings, the global pricing rule may override product-level tiered pricing or quantity limits.',
445 - 'tier-pricing-table' );
446 - ?>
447 - </p>
448 -
449 - <div class="tpt-global-pricing-rule-helping__steps">
450 -
451 - <?php foreach ( $steps as $step ) : ?>
452 -
453 - <div class="tpt-global-pricing-rule-helping-step">
454 - <div class="tpt-global-pricing-rule-helping-step__icon">
455 - <?php echo wp_kses_post( $step['icon'] ); ?>
456 - </div>
457 -
458 - <div class="tpt-global-pricing-rule-helping-step__title">
459 - <?php echo esc_html( $step['title'] ); ?>
460 - </div>
461 -
462 - <div class="tpt-global-pricing-rule-helping-step__description">
463 - <?php echo esc_html( $step['description'] ); ?>
464 - </div>
465 - </div>
466 -
467 - <?php if ( $step['has_next_step'] ) : ?>
468 - <div class="tpt-global-pricing-rule-helping-step tpt-global-pricing-rule-helping-step--arrow">
469 - <span class="dashicons dashicons-arrow-right-alt"></span>
470 - </div>
471 - <?php endif; ?>
472 - <?php endforeach; ?>
473 - </div>
474 - <div class="tpt-global-pricing-rule-helping__close">
475 - &times;
476 - </div>
477 - </div>
478 - <?php
479 417 }
480 418
481 419 public function isNewRule(): bool {
482 420 global $pagenow;