Skip to content
MiniShop3
MiniShop3
Современный компонент интернет-магазина для MODX 3
  1. Компоненты
  2. MiniShop3
  3. Разработка
  4. События
  5. Товар

События товаров (каталог)

События для модификации цены, веса и полей товаров при выводе в каталоге.

Особенность

Эти события поддерживают цепочку плагинов — каждый плагин может прочитать результат предыдущего через $modx->eventData и передать свой результат следующему.

msOnGetProductPrice

Вызывается при получении цены товара. Позволяет модифицировать цену на лету.

Параметры

ПараметрТипОписание
dataarrayДанные товара — по умолчанию toArray() объекта msProductData (core-поля: price, article, weight, stock, vendor_id, tags, color, size и т.д.), либо расширенный row, если вызывающий код передал свой $data (например, ms3_products.php передаёт весь row листинга, включая extra fields)
pricefloatТекущая цена

Модификация данных (с поддержкой цепочки)

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductPrice':
        // Получаем цену (может быть уже изменена другим плагином)
        $price = $modx->eventData['msOnGetProductPrice']['price']
            ?? $scriptProperties['price'];
        $data = $scriptProperties['data'];

        // Скидка 15% для категории 5
        if ($data['parent'] == 5) {
            $price = $price * 0.85;
        }

        // Сохраняем для следующих плагинов
        $modx->eventData['msOnGetProductPrice']['price'] = $price;

        // Возвращаем результат
        $values = &$modx->event->returnedValues;
        $values['price'] = $price;
        break;
}

Персональные цены

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductPrice':
        $price = $modx->eventData['msOnGetProductPrice']['price']
            ?? $scriptProperties['price'];
        $data = $scriptProperties['data'];

        // VIP-скидка
        if ($modx->user->isMember('VIP')) {
            $price = $price * 0.8; // -20%
        }

        // Оптовая цена для оптовиков (если добавлен extra field wholesale_price)
        if ($modx->user->isMember('Wholesale')) {
            $wholesalePrice = $data['wholesale_price'] ?? 0;
            if ($wholesalePrice > 0) {
                $price = $wholesalePrice;
            }
        }

        $modx->eventData['msOnGetProductPrice']['price'] = $price;
        $values = &$modx->event->returnedValues;
        $values['price'] = $price;
        break;
}

Динамическая наценка по курсу валюты

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductPrice':
        $price = $modx->eventData['msOnGetProductPrice']['price']
            ?? $scriptProperties['price'];

        // Получаем курс из кэша или API
        $rate = $modx->cacheManager->get('usd_rate') ?? 90;

        // Товар в долларах — конвертируем (если добавлен extra field currency)
        $data = $scriptProperties['data'];
        if (($data['currency'] ?? null) === 'USD') {
            $price = $price * $rate;
        }

        $modx->eventData['msOnGetProductPrice']['price'] = $price;
        $values = &$modx->event->returnedValues;
        $values['price'] = round($price, 2);
        break;
}

msOnGetProductWeight

Вызывается при получении веса товара. Позволяет модифицировать вес на лету.

Параметры

ПараметрТипОписание
dataarrayДанные товара — по умолчанию toArray() объекта msProductData, либо расширенный row, если вызывающий код передал свой $data
weightfloatТекущий вес

Модификация данных

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductWeight':
        $weight = $modx->eventData['msOnGetProductWeight']['weight']
            ?? $scriptProperties['weight'];
        $data = $scriptProperties['data'];

        // Добавляем вес упаковки (500г)
        $packagingWeight = 0.5;
        $weight = $weight + $packagingWeight;

        $modx->eventData['msOnGetProductWeight']['weight'] = $weight;
        $values = &$modx->event->returnedValues;
        $values['weight'] = $weight;
        break;
}

Расчёт объёмного веса

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductWeight':
        $weight = $modx->eventData['msOnGetProductWeight']['weight']
            ?? $scriptProperties['weight'];
        $data = $scriptProperties['data'];

        // Получаем габариты (если добавлены extra fields length/width/height)
        $length = $data['length'] ?? 0;
        $width = $data['width'] ?? 0;
        $height = $data['height'] ?? 0;

        // Объёмный вес (делитель 5000 — стандарт для курьерских служб)
        if ($length > 0 && $width > 0 && $height > 0) {
            $volumeWeight = ($length * $width * $height) / 5000;

            // Используем больший из весов
            $weight = max($weight, $volumeWeight);
        }

        $modx->eventData['msOnGetProductWeight']['weight'] = $weight;
        $values = &$modx->event->returnedValues;
        $values['weight'] = $weight;
        break;
}

msOnGetProductFields

Вызывается при получении полей товара. Позволяет добавить или модифицировать любые поля.

Параметры

ПараметрТипОписание
dataarrayДанные товара — по умолчанию toArray() объекта msProductData, либо расширенный row, если вызывающий код передал свой $data

Модификация данных

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductFields':
        $data = $modx->eventData['msOnGetProductFields']['data']
            ?? $scriptProperties['data'];

        // Добавить расчётные поля
        $data['discount_percent'] = 0;
        if ($data['old_price'] > 0 && $data['price'] > 0) {
            $data['discount_percent'] = round(
                (($data['old_price'] - $data['price']) / $data['old_price']) * 100
            );
        }

        // Добавить статус наличия
        $stock = $data['stock'] ?? 0;
        if ($stock <= 0) {
            $data['availability'] = 'out_of_stock';
            $data['availability_text'] = 'Нет в наличии';
        } elseif ($stock < 5) {
            $data['availability'] = 'low_stock';
            $data['availability_text'] = 'Заканчивается';
        } else {
            $data['availability'] = 'in_stock';
            $data['availability_text'] = 'В наличии';
        }

        $modx->eventData['msOnGetProductFields']['data'] = $data;
        $values = &$modx->event->returnedValues;
        $values['data'] = $data;
        break;
}

Добавление связанных данных

php
<?php
switch ($modx->event->name) {
    case 'msOnGetProductFields':
        $data = $modx->eventData['msOnGetProductFields']['data']
            ?? $scriptProperties['data'];

        // Добавить количество отзывов
        $reviewCount = $modx->getCount('msProductReview', [
            'product_id' => $data['id'],
            'published' => 1,
        ]);
        $data['review_count'] = $reviewCount;

        // Добавить средний рейтинг
        $c = $modx->newQuery('msProductReview');
        $c->where(['product_id' => $data['id'], 'published' => 1]);
        $c->select('AVG(rating) as avg_rating');
        if ($c->prepare() && $c->stmt->execute()) {
            $data['avg_rating'] = round($c->stmt->fetchColumn(), 1);
        }

        $modx->eventData['msOnGetProductFields']['data'] = $data;
        $values = &$modx->event->returnedValues;
        $values['data'] = $data;
        break;
}

Полный пример: система скидок и акций

php
<?php
/**
 * Плагин: Система скидок и акций
 * События: msOnGetProductPrice, msOnGetProductFields
 */

switch ($modx->event->name) {

    case 'msOnGetProductPrice':
        $price = $modx->eventData['msOnGetProductPrice']['price']
            ?? $scriptProperties['price'];
        $data = $scriptProperties['data'];

        $discounts = [];

        // 1. Скидка по категории
        $categoryDiscounts = [
            5 => 10,  // Категория 5 — скидка 10%
            10 => 15, // Категория 10 — скидка 15%
        ];
        if (isset($categoryDiscounts[$data['parent']])) {
            $discount = $categoryDiscounts[$data['parent']];
            $price = $price * (1 - $discount / 100);
            $discounts['category'] = $discount;
        }

        // 2. Скидка для авторизованных
        if ($modx->user->isAuthenticated()) {
            $price = $price * 0.95; // -5%
            $discounts['member'] = 5;
        }

        // 3. VIP-скидка
        if ($modx->user->isMember('VIP')) {
            $price = $price * 0.9; // -10%
            $discounts['vip'] = 10;
        }

        // Сохраняем информацию о скидках для использования в msOnGetProductFields
        $modx->eventData['discounts'] = $discounts;
        $modx->eventData['msOnGetProductPrice']['price'] = $price;

        $values = &$modx->event->returnedValues;
        $values['price'] = round($price, 2);
        break;

    case 'msOnGetProductFields':
        $data = $modx->eventData['msOnGetProductFields']['data']
            ?? $scriptProperties['data'];

        // Добавляем информацию о скидках
        $discounts = $modx->eventData['discounts'] ?? [];
        if (!empty($discounts)) {
            $data['applied_discounts'] = $discounts;
            $data['total_discount'] = array_sum($discounts);
        }

        // Добавляем бейджи
        $badges = [];
        if ($data['new']) {
            $badges[] = ['type' => 'new', 'text' => 'Новинка'];
        }
        if ($data['popular']) {
            $badges[] = ['type' => 'popular', 'text' => 'Хит'];
        }
        if (!empty($data['total_discount'])) {
            $badges[] = [
                'type' => 'sale',
                'text' => '-' . $data['total_discount'] . '%',
            ];
        }
        $data['badges'] = $badges;

        $modx->eventData['msOnGetProductFields']['data'] = $data;
        $values = &$modx->event->returnedValues;
        $values['data'] = $data;
        break;
}