Skip to content

Instantly share code, notes, and snippets.

@Kodzhesyan
Last active January 21, 2026 11:42
Show Gist options
  • Select an option

  • Save Kodzhesyan/2cbc88a845cdd3fdc5cd7e8a5dd4296f to your computer and use it in GitHub Desktop.

Select an option

Save Kodzhesyan/2cbc88a845cdd3fdc5cd7e8a5dd4296f to your computer and use it in GitHub Desktop.
Динамічне ціноутворення: Купуйте більше — платіть менше!
/**
* Динамічне ціноутворення: керування через адмінку, вивід на сторінці товару та підтримка шорткоду.
*/
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