← All changes
|
src/Addons/GlobalTieredPricing/CPT/Columns/Pricing.php
+156
-120
7.1.4
→
8.1.0
View file →
| @@ -1,140 +1,176 @@ | ||
| 1 | 1 | <?php namespace TierPricingTable\Addons\GlobalTieredPricing\CPT\Columns; |
| 2 | 2 | |
| 3 | -use ArrayIterator; | |
| 4 | 3 | use Exception; |
| 5 | 4 | use TierPricingTable\Addons\GlobalTieredPricing\GlobalPricingRule; |
| 6 | 5 | use TierPricingTable\Core\ServiceContainerTrait; |
| 7 | 6 | |
| 7 | +/** | |
| 8 | + * What the rule changes, only when set: base price, the tiers as a small table, quantity limits. | |
| 9 | + */ | |
| 8 | 10 | class Pricing { |
| 9 | - | |
| 11 | + | |
| 10 | 12 | use ServiceContainerTrait; |
| 11 | - | |
| 13 | + | |
| 12 | 14 | public function getName(): string { |
| 13 | 15 | return __( 'Pricing', 'tier-pricing-table' ); |
| 14 | 16 | } |
| 15 | - | |
| 17 | + | |
| 16 | 18 | public function render( GlobalPricingRule $rule ) { |
| 17 | 19 | try { |
| 18 | 20 | $rule->validatePricing(); |
| 19 | - | |
| 20 | - $pricingType = $rule->getTieredPricingType(); | |
| 21 | - $rules = 'percentage' === $pricingType ? $rule->getPercentageTieredPricingRules() : $rule->getFixedTieredPricingRules(); | |
| 22 | - $minimum = $rule->getMinimum() ? intval( $rule->getMinimum() ) : 1; | |
| 23 | - | |
| 24 | - $regularProductPriceString = __( 'Regular price', 'tier-pricing-table' ); | |
| 25 | - | |
| 26 | - if ( $rule->getPricingType() === 'flat' ) { | |
| 27 | - if ( $rule->getSalePrice() ) { | |
| 28 | - $regularProductPriceString = wc_price( $rule->getSalePrice() ); | |
| 29 | - } elseif ( $rule->getRegularPrice() ) { | |
| 30 | - $regularProductPriceString = wc_price( $rule->getRegularPrice() ); | |
| 31 | - } | |
| 32 | - } elseif ( $rule->getDiscount() ) { | |
| 33 | - $regularProductPriceString = $rule->getDiscount() . '% off'; | |
| 34 | - } | |
| 35 | - | |
| 21 | + } catch ( Exception $e ) { | |
| 36 | 22 | ?> |
| 37 | - | |
| 38 | - <?php | |
| 39 | - $applyingType = $rule->getApplyingType() === 'individual' ? __( '(Individual)', 'tier-pricing-table' ) : __( '(Mix and match)', 'tier-pricing-table' ); | |
| 40 | - ?> | |
| 41 | - <div style="margin-bottom: 12px;"> | |
| 42 | - <?php | |
| 43 | - $hasBasePricing = ( $rule->getPricingType() === 'flat' && ( $rule->getRegularPrice() || $rule->getSalePrice() ) ) || ( $rule->getPricingType() !== 'flat' && $rule->getDiscount() ); | |
| 44 | - if ( $hasBasePricing ) : ?> | |
| 45 | - <div style="margin-bottom: 8px;"> | |
| 46 | - <strong style="display: block; margin-bottom: 4px;"><?php esc_html_e( 'Base Pricing:', 'tier-pricing-table' ); ?></strong> | |
| 47 | - <div style="display: flex; flex-wrap: wrap; gap: 4px;"> | |
| 48 | - <?php if ( $rule->getPricingType() === 'flat' ) : ?> | |
| 49 | - <?php if ( $rule->getRegularPrice() ) : ?> | |
| 50 | - <span style="display: inline-block; padding: 2px 8px; background: #f0f0f1; border-radius: 3px; font-size: 12px; color: #3c434a; border: 1px solid #dcdcdc;"> | |
| 51 | - <?php echo wp_kses_post( __( 'Regular:', 'tier-pricing-table' ) . ' <b>' . wc_price( $rule->getRegularPrice() ) . '</b>' ); ?> | |
| 52 | - </span> | |
| 53 | - <?php endif; ?> | |
| 54 | - <?php if ( $rule->getSalePrice() ) : ?> | |
| 55 | - <span style="display: inline-block; padding: 2px 8px; background: #f0f0f1; border-radius: 3px; font-size: 12px; color: #3c434a; border: 1px solid #dcdcdc;"> | |
| 56 | - <?php echo wp_kses_post( __( 'Sale:', 'tier-pricing-table' ) . ' <b>' . wc_price( $rule->getSalePrice() ) . '</b>' ); ?> | |
| 57 | - </span> | |
| 58 | - <?php endif; ?> | |
| 59 | - <?php else : ?> | |
| 60 | - <?php if ( $rule->getDiscount() ) : ?> | |
| 61 | - <span style="display: inline-block; padding: 2px 8px; background: #f0f0f1; border-radius: 3px; font-size: 12px; color: #3c434a; border: 1px solid #dcdcdc;"> | |
| 62 | - <?php esc_html_e( 'Discount:', 'tier-pricing-table' ); ?> <b><?php echo esc_html( $rule->getDiscount() ); ?>%</b> | |
| 63 | - (<?php echo $rule->getDiscountType() === 'sale_price' ? esc_html__( 'Sale price', 'tier-pricing-table' ) : esc_html__( 'Regular price', 'tier-pricing-table' ); ?>) | |
| 64 | - </span> | |
| 65 | - <?php endif; ?> | |
| 66 | - <?php endif; ?> | |
| 67 | - </div> | |
| 68 | - </div> | |
| 69 | - <?php endif; ?> | |
| 70 | - | |
| 71 | - <?php if ( ! empty( $rules ) ) : ?> | |
| 72 | - <div> | |
| 73 | - <div style="display: flex; align-items: center; margin-bottom: 8px;"> | |
| 74 | - <strong style="display: block; color: #1d2327; margin-right: 6px;"><?php esc_html_e( 'Tiered Rules:', 'tier-pricing-table' ); ?></strong> | |
| 75 | - <span style="color: #50575e; font-size: 13px;"> | |
| 76 | - <?php echo esc_html( $applyingType ); ?> | |
| 77 | - </span> | |
| 78 | - </div> | |
| 79 | - <table style="width: 100%; border-collapse: collapse; font-size: 13px; text-align: left; margin-bottom: 8px; border: 1px solid #c3c4c7; border-radius: 4px; overflow: hidden; background: #fff;"> | |
| 80 | - <thead style="background: #f0f0f1; border-bottom: 2px solid #c3c4c7;"> | |
| 81 | - <tr> | |
| 82 | - <th style="padding: 8px 10px; font-weight: 600; color: #1d2327;"><?php esc_html_e( 'Quantity', 'tier-pricing-table' ); ?></th> | |
| 83 | - <th style="padding: 8px 10px; font-weight: 600; color: #1d2327;"><?php echo 'percentage' === $pricingType ? esc_html__( 'Discount', 'tier-pricing-table' ) : esc_html__( 'Price', 'tier-pricing-table' ); ?></th> | |
| 84 | - </tr> | |
| 85 | - </thead> | |
| 86 | - <tbody> | |
| 87 | - <?php | |
| 88 | - // Base quantity row | |
| 89 | - $baseQtyStr = ''; | |
| 90 | - if ( 1 >= array_keys( $rules )[0] - $minimum ) { | |
| 91 | - $baseQtyStr = number_format_i18n( $minimum ); | |
| 92 | - } else { | |
| 93 | - $baseQtyStr = number_format_i18n( $minimum ) . ' - ' . number_format_i18n( array_keys( $rules )[0] - 1 ); | |
| 94 | - } | |
| 95 | - ?> | |
| 96 | - <tr style="border-bottom: 1px solid #c3c4c7;"> | |
| 97 | - <td style="padding: 6px 10px; color: #1d2327; border-right: 1px solid #e2e4e7;"><?php echo esc_html( $baseQtyStr ); ?></td> | |
| 98 | - <td style="padding: 6px 10px; color: #1d2327;"><?php echo wp_kses_post( $regularProductPriceString ); ?></td> | |
| 99 | - </tr> | |
| 100 | - | |
| 101 | - <?php | |
| 102 | - $iterator = new ArrayIterator( $rules ); | |
| 103 | - while ( $iterator->valid() ) { | |
| 104 | - $currentPrice = $iterator->current(); | |
| 105 | - $currentQuantity = $iterator->key(); | |
| 106 | - $iterator->next(); | |
| 107 | - | |
| 108 | - if ( $iterator->valid() ) { | |
| 109 | - $quantity = $currentQuantity; | |
| 110 | - if ( intval( $iterator->key() - 1 != $currentQuantity ) ) { | |
| 111 | - $quantity = number_format_i18n( $quantity ); | |
| 112 | - if ( $this->getContainer()->getSettings()->get( 'quantity_type', 'range' ) === 'range' ) { | |
| 113 | - $quantity .= ' - ' . number_format_i18n( intval( $iterator->key() - 1 ) ); | |
| 114 | - } | |
| 115 | - } | |
| 116 | - } else { | |
| 117 | - $quantity = number_format_i18n( $currentQuantity ) . '+'; | |
| 118 | - } | |
| 119 | - | |
| 120 | - $priceStr = 'percentage' === $pricingType ? esc_html( $currentPrice . '%' ) : wp_kses_post( wc_price( $currentPrice ) ); | |
| 121 | - ?> | |
| 122 | - <tr style="border-bottom: 1px solid #c3c4c7;"> | |
| 123 | - <td style="padding: 6px 10px; color: #1d2327; font-weight: 600; border-right: 1px solid #e2e4e7;"><?php echo esc_html( $quantity ); ?></td> | |
| 124 | - <td style="padding: 6px 10px; color: #0070bc; font-weight: 600;"><?php echo $priceStr; ?></td> | |
| 125 | - </tr> | |
| 126 | - <?php | |
| 127 | - } | |
| 128 | - ?> | |
| 129 | - </tbody> | |
| 130 | - </table> | |
| 131 | - </div> | |
| 132 | - <?php endif; ?> | |
| 23 | + <div class="tpt-rules-list__line tpt-rules-list__warn"> | |
| 24 | + <span class="dashicons dashicons-warning"></span> | |
| 25 | + <span><?php echo esc_html( $e->getMessage() ); ?></span> | |
| 133 | 26 | </div> |
| 134 | 27 | <?php |
| 135 | - | |
| 136 | - } catch ( Exception $e ) { | |
| 137 | - echo wp_kses_post( '<div class="help_tip tpt-rule-status tpt-rule-status--invalid" data-tip="' . $e->getMessage() . '">!</div>' ); | |
| 138 | 28 | } |
| 29 | + | |
| 30 | + $this->renderBasePrice( $rule ); | |
| 31 | + $this->renderTiers( $rule ); | |
| 32 | + $this->renderQuantityLimits( $rule ); | |
| 33 | + } | |
| 34 | + | |
| 35 | + protected function renderBasePrice( GlobalPricingRule $rule ) { | |
| 36 | + $chips = array(); | |
| 37 | + | |
| 38 | + if ( 'flat' === $rule->getPricingType() ) { | |
| 39 | + if ( $rule->getRegularPrice() ) { | |
| 40 | + $chips[] = __( 'Regular', 'tier-pricing-table' ) . ' <b>' . wc_price( $rule->getRegularPrice() ) . '</b>'; | |
| 41 | + } | |
| 42 | + if ( $rule->getSalePrice() ) { | |
| 43 | + $chips[] = __( 'Sale', 'tier-pricing-table' ) . ' <b>' . wc_price( $rule->getSalePrice() ) . '</b>'; | |
| 44 | + } | |
| 45 | + } elseif ( $rule->getDiscount() ) { | |
| 46 | + $chips[] = sprintf( | |
| 47 | + /* translators: 1: percentage, 2: "sale price" or "regular price" */ | |
| 48 | + __( 'Discount <b>%1$s%%</b> off the %2$s', 'tier-pricing-table' ), | |
| 49 | + esc_html( $rule->getDiscount() ), | |
| 50 | + 'sale_price' === $rule->getDiscountType() ? __( 'sale price', 'tier-pricing-table' ) : __( 'regular price', 'tier-pricing-table' ) | |
| 51 | + ); | |
| 52 | + } | |
| 53 | + | |
| 54 | + if ( $chips ) { | |
| 55 | + $this->renderLine( __( 'Base price', 'tier-pricing-table' ), $chips ); | |
| 56 | + } | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * The tiers as a small table: quantity ranges (or thresholds, per the plugin's quantity type | |
| 61 | + * setting) and the price or discount, with a base row for the quantities below the first tier. | |
| 62 | + */ | |
| 63 | + protected function renderTiers( GlobalPricingRule $rule ) { | |
| 64 | + $percentage = 'percentage' === $rule->getTieredPricingType(); | |
| 65 | + $tiers = $percentage ? $rule->getPercentageTieredPricingRules() : $rule->getFixedTieredPricingRules(); | |
| 66 | + | |
| 67 | + if ( empty( $tiers ) ) { | |
| 68 | + return; | |
| 69 | + } | |
| 70 | + | |
| 71 | + ksort( $tiers ); | |
| 72 | + $quantities = array_map( 'intval', array_keys( $tiers ) ); | |
| 73 | + $values = array_values( $tiers ); | |
| 74 | + $minimum = $rule->getMinimum() ? (int) $rule->getMinimum() : 1; | |
| 75 | + $ranges = 'range' === $this->getContainer()->getSettings()->get( 'quantity_type', 'range' ); | |
| 76 | + | |
| 77 | + // what the customer pays below the first tier | |
| 78 | + $base = __( 'Regular price', 'tier-pricing-table' ); | |
| 79 | + if ( 'flat' === $rule->getPricingType() ) { | |
| 80 | + if ( $rule->getSalePrice() ) { | |
| 81 | + $base = wc_price( $rule->getSalePrice() ); | |
| 82 | + } elseif ( $rule->getRegularPrice() ) { | |
| 83 | + $base = wc_price( $rule->getRegularPrice() ); | |
| 84 | + } | |
| 85 | + } elseif ( $rule->getDiscount() ) { | |
| 86 | + /* translators: %s: percentage */ | |
| 87 | + $base = esc_html( sprintf( __( '%s%% off', 'tier-pricing-table' ), $rule->getDiscount() ) ); | |
| 88 | + } | |
| 89 | + | |
| 90 | + $rows = array(); | |
| 91 | + if ( $quantities[0] > $minimum ) { | |
| 92 | + $rows[] = array( $this->quantityLabel( $minimum, $quantities[0] - 1, $ranges ), $base, false ); | |
| 93 | + } | |
| 94 | + | |
| 95 | + foreach ( $quantities as $index => $quantity ) { | |
| 96 | + $next = $quantities[ $index + 1 ] ?? null; | |
| 97 | + $label = null === $next ? number_format_i18n( $quantity ) . '+' : $this->quantityLabel( $quantity, $next - 1, $ranges ); | |
| 98 | + $value = $percentage ? esc_html( $values[ $index ] . '%' ) : wc_price( $values[ $index ] ); | |
| 99 | + $rows[] = array( $label, $value, true ); | |
| 100 | + } | |
| 101 | + | |
| 102 | + $label = sprintf( | |
| 103 | + /* translators: 1: "fixed" or "percentage", 2: "individual" or "mix & match" */ | |
| 104 | + __( 'Tiers (%1$s, %2$s)', 'tier-pricing-table' ), | |
| 105 | + $percentage ? __( 'percentage', 'tier-pricing-table' ) : __( 'fixed', 'tier-pricing-table' ), | |
| 106 | + 'individual' === $rule->getApplyingType() ? __( 'individual', 'tier-pricing-table' ) : __( 'mix & match', 'tier-pricing-table' ) | |
| 107 | + ); | |
| 108 | + ?> | |
| 109 | + <div class="tpt-rules-list__line tpt-rules-list__line--chips"> | |
| 110 | + <span class="tpt-rules-list__muted"><?php echo esc_html( $label ); ?></span> | |
| 111 | + </div> | |
| 112 | + <table class="tpt-rules-list__tiers"> | |
| 113 | + <thead> | |
| 114 | + <tr> | |
| 115 | + <th><?php esc_html_e( 'Quantity', 'tier-pricing-table' ); ?></th> | |
| 116 | + <th><?php echo $percentage ? esc_html__( 'Discount', 'tier-pricing-table' ) : esc_html__( 'Price', 'tier-pricing-table' ); ?></th> | |
| 117 | + </tr> | |
| 118 | + </thead> | |
| 119 | + <tbody> | |
| 120 | + <?php foreach ( $rows as list( $quantityLabel, $value, $isTier ) ) : ?> | |
| 121 | + <tr> | |
| 122 | + <td><?php echo esc_html( $quantityLabel ); ?></td> | |
| 123 | + <td class="<?php echo $isTier ? 'is-tier' : ''; ?>"><?php echo wp_kses_post( $value ); ?></td> | |
| 124 | + </tr> | |
| 125 | + <?php endforeach; ?> | |
| 126 | + </tbody> | |
| 127 | + </table> | |
| 128 | + <?php | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * "10 - 29" with ranges on, "10" otherwise (or when the range is a single quantity). | |
| 133 | + */ | |
| 134 | + protected function quantityLabel( int $from, int $to, bool $ranges ): string { | |
| 135 | + if ( $to <= $from || ! $ranges ) { | |
| 136 | + return number_format_i18n( $from ); | |
| 137 | + } | |
| 138 | + | |
| 139 | + return number_format_i18n( $from ) . ' - ' . number_format_i18n( $to ); | |
| 140 | + } | |
| 141 | + | |
| 142 | + protected function renderQuantityLimits( GlobalPricingRule $rule ) { | |
| 143 | + $chips = array(); | |
| 144 | + | |
| 145 | + if ( $rule->getMinimum() ) { | |
| 146 | + /* translators: %s: quantity */ | |
| 147 | + $chips[] = sprintf( __( 'Min <b>%s</b>', 'tier-pricing-table' ), esc_html( number_format_i18n( $rule->getMinimum() ) ) ); | |
| 148 | + } | |
| 149 | + if ( ! empty( $rule->data['maximum_quantity'] ) ) { | |
| 150 | + /* translators: %s: quantity */ | |
| 151 | + $chips[] = sprintf( __( 'Max <b>%s</b>', 'tier-pricing-table' ), esc_html( number_format_i18n( (int) $rule->data['maximum_quantity'] ) ) ); | |
| 152 | + } | |
| 153 | + if ( ! empty( $rule->data['group_of_quantity'] ) ) { | |
| 154 | + /* translators: %s: quantity */ | |
| 155 | + $chips[] = sprintf( __( 'Step <b>%s</b>', 'tier-pricing-table' ), esc_html( number_format_i18n( (int) $rule->data['group_of_quantity'] ) ) ); | |
| 156 | + } | |
| 157 | + | |
| 158 | + if ( $chips ) { | |
| 159 | + $this->renderLine( __( 'Quantity', 'tier-pricing-table' ), $chips ); | |
| 160 | + } | |
| 161 | + } | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * @param string[] $chips Escaped HTML. | |
| 165 | + */ | |
| 166 | + protected function renderLine( string $label, array $chips ) { | |
| 167 | + ?> | |
| 168 | + <div class="tpt-rules-list__line tpt-rules-list__line--chips"> | |
| 169 | + <span class="tpt-rules-list__muted"><?php echo esc_html( $label ); ?></span> | |
| 170 | + <?php foreach ( $chips as $chip ) : ?> | |
| 171 | + <span class="tpt-rules-list__chip"><?php echo wp_kses_post( $chip ); ?></span> | |
| 172 | + <?php endforeach; ?> | |
| 173 | + </div> | |
| 174 | + <?php | |
| 139 | 175 | } |
| 140 | 176 | } |