Last active
January 21, 2026 11:42
-
-
Save Kodzhesyan/2cbc88a845cdd3fdc5cd7e8a5dd4296f to your computer and use it in GitHub Desktop.
Динамічне ціноутворення: Купуйте більше — платіть менше!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Динамічне ціноутворення: керування через адмінку, вивід на сторінці товару та підтримка шорткоду. | |
| */ | |
| namespace WPWC_QuantityPricing; | |
| if (!defined('ABSPATH')) exit; | |
| /** | |
| * Клас для керування оптовими цінами | |
| */ | |
| class App { | |
| private static $meta_key = '_wpwc_qty_pricing_rules'; | |
| public static function init() { | |
| if (!class_exists('WooCommerce')) return; | |
| // Адмінка: додавання полів | |
| add_action('add_meta_boxes', [self::class, 'add_meta_box']); | |
| add_action('save_post', [self::class, 'save_meta_box_data']); | |
| // Фронтенд: автоматичний вивід таблиці ціни | |
| add_action('woocommerce_before_add_to_cart_form', [self::class, 'display_pricing_table']); | |
| // Реєстрація шорткоду: [qty_pricing_table id="123"] | |
| add_shortcode('qty_pricing_table', [self::class, 'shortcode_handler']); | |
| // Логіка: розрахунок ціни в кошику | |
| add_action('woocommerce_before_calculate_totals', [self::class, 'apply_quantity_discounts'], 10, 1); | |
| } | |
| /** | |
| * Додає метабокс у редактор товару | |
| */ | |
| public static function add_meta_box() { | |
| add_meta_box( | |
| 'wpwc_qty_pricing', | |
| 'Налаштування гуртових цін', | |
| [self::class, 'render_meta_box'], | |
| 'product', | |
| 'side' | |
| ); | |
| } | |
| /** | |
| * Відображає інтерфейс для введення правил | |
| */ | |
| public static function render_meta_box($post) { | |
| wp_nonce_field('wpwc_save_qty_pricing', 'wpwc_qty_pricing_nonce'); | |
| $rules = get_post_meta($post->ID, self::$meta_key, true) ?: []; | |
| echo '<div id="wpwc-pricing-rows">'; | |
| if (!empty($rules)) { | |
| foreach ($rules as $qty => $price) { | |
| echo '<div style="margin-bottom: 5px;">'; | |
| echo '<input type="number" name="wpwc_qty[]" value="'.esc_attr($qty).'" placeholder="К-сть" style="width: 60px;"> '; | |
| echo '<input type="text" name="wpwc_price[]" value="'.esc_attr($price).'" placeholder="Ціна" style="width: 80px;">'; | |
| echo '</div>'; | |
| } | |
| } | |
| echo '<div>'; | |
| echo '<input type="number" name="wpwc_qty[]" placeholder="К-сть" style="width: 60px;"> '; | |
| echo '<input type="text" name="wpwc_price[]" placeholder="Ціна" style="width: 80px;">'; | |
| echo '</div>'; | |
| echo '</div>'; | |
| echo '<p class="description">Вкажіть мінімальну кількість та нову ціну за одиницю.</p>'; | |
| } | |
| /** | |
| * Зберігає дані метабоксу | |
| */ | |
| public static function save_meta_box_data($post_id) { | |
| if (!isset($_POST['wpwc_qty_pricing_nonce']) || !wp_verify_nonce($_POST['wpwc_qty_pricing_nonce'], 'wpwc_save_qty_pricing')) return; | |
| if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; | |
| if (!current_user_can('edit_post', $post_id)) return; | |
| $qtys = $_POST['wpwc_qty'] ?? []; | |
| $prices = $_POST['wpwc_price'] ?? []; | |
| $rules = []; | |
| foreach ($qtys as $index => $qty) { | |
| $price = str_replace(',', '.', $prices[$index]); | |
| if (!empty($qty) && is_numeric($price)) { | |
| $rules[intval($qty)] = floatval($price); | |
| } | |
| } | |
| if (!empty($rules)) { | |
| ksort($rules); | |
| update_post_meta($post_id, self::$meta_key, $rules); | |
| } else { | |
| delete_post_meta($post_id, self::$meta_key); | |
| } | |
| } | |
| /** | |
| * Генерація HTML коду таблиці (універсальний метод) | |
| */ | |
| private static function get_pricing_table_html($product_id) { | |
| $rules = get_post_meta($product_id, self::$meta_key, true); | |
| if (!$rules) return ''; | |
| ob_start(); | |
| ?> | |
| <div class="wpwc-pricing-table" style="margin: 20px 0; padding: 15px; border: 1px solid #eee; border-radius: 8px; background: #fafafa;"> | |
| <h4 style="margin-top:0;">Купуйте більше — платіть менше:</h4> | |
| <ul style="list-style:none; padding:0; margin:0;"> | |
| <?php foreach ($rules as $qty => $price) : ?> | |
| <li style="margin-bottom:5px;"> | |
| ✅ Від <strong><?php echo esc_html($qty); ?> шт.</strong> — всього <strong><?php echo wc_price($price); ?></strong> за одиницю | |
| </li> | |
| <?php endforeach; ?> | |
| </ul> | |
| </div> | |
| <?php | |
| return ob_get_clean(); | |
| } | |
| /** | |
| * Автоматичний вивід через хук | |
| */ | |
| public static function display_pricing_table() { | |
| global $product; | |
| if ($product) { | |
| echo self::get_pricing_table_html($product->get_id()); | |
| } | |
| } | |
| /** | |
| * Обробник шорткоду [qty_pricing_table id=""] | |
| */ | |
| public static function shortcode_handler($atts) { | |
| $atts = shortcode_atts([ | |
| 'id' => get_the_ID(), | |
| ], $atts, 'qty_pricing_table'); | |
| return self::get_pricing_table_html($atts['id']); | |
| } | |
| /** | |
| * Застосовує ціну в кошику на основі кількості | |
| */ | |
| public static function apply_quantity_discounts($cart) { | |
| if (is_admin() && !defined('DOING_AJAX')) return; | |
| if (did_action('woocommerce_before_calculate_totals') >= 2) return; | |
| foreach ($cart->get_cart() as $cart_item) { | |
| /** @var \WC_Product $product */ | |
| $product = $cart_item['data']; | |
| $rules = get_post_meta($product->get_id(), self::$meta_key, true); | |
| if ($rules && is_array($rules)) { | |
| krsort($rules); | |
| foreach ($rules as $min_qty => $new_price) { | |
| if ($cart_item['quantity'] >= $min_qty) { | |
| $product->set_price($new_price); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // Запуск модуля | |
| App::init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment