суббота, 29 февраля 2020 г.

VirtueMart - автоматическое назначение категорий товарам

Если вы более-менее серьёзно работаете с интернет-магазином на связке Joomla + VirtueMart, рано или поздно у вас встаёт задача (особенно актуальная для seo целей) автоматически назначать / убирать категории (доп. категории) для нужных товаров.

Например, за счёт этого можно помещать все товары из категории "Туфли" и имеющие допполе Цвет - Красный в категорию Красные туфли. Это лишь один из множества примеров.

Так вот, хорошая новость - сделать это легче, чем кажется!

Не волнуйтесь - поделюсь решением бесплатно :)
В знак благодарности потом сможете оставить комментарий под этим постом.

Вообще, есть мысли оформить это в виде нормального расширения (компонента). Сделаю это в будущем. Но пока не до того. Пока - в виде php-скрипта. Лично меня полностью устраивает и так. И это даёт максимальную гибкость - тем, кто так или иначе дружит с PHP, разумеется.

Итак, ближе к делу:

1) Создаём в папке с сайтом (но не там где все обычные файлы сайта (например, robots.txt), а на уровень выше, то есть вне public_html или www - это чтобы с фронта сайта никто не мог запускать наши скрипты) папочку с названием, например, 'cron'.
То есть в папке сайта будет 'cron' и 'public_html' (или 'cron' и 'www').
Будем складывать туда наши скрипты запускаемые кроном по расписанию.

2) В создаём в папке 'cron' php-файл, который можно назвать, к примеру, 'set_cat.php'.

3) Помещаем в этот файл такой код и потом модифицируем его под свои нужды (ну, точнее задачи :)

<?php

ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);

$time_start = microtime(true);

// SETTING
$root_path = '/home/a/alexey/gnevyshev.ru/public_html'; // указываем путь к корню сайта (где лежит robots.txt)
$sale_cat_id = 652; // id категории Распродажа
$cf_prodazh_id = 36; // id поля Продаж за 30 дней
$debug_mode = false; // true or false

// define('END', '<br>'.PHP_EOL);
define('END', PHP_EOL);

// Подключаем фреймворк Joomla
define('_JEXEC', 1);
define('JPATH_BASE', $root_path);
require_once JPATH_BASE.'/includes/defines.php';
require_once JPATH_BASE.'/includes/framework.php';

$db = JFactory::getDBO();

// Удаляем старые записи
$query = $db->getQuery(true);
$query->delete($db->quoteName('#__virtuemart_product_categories'));
$query->where($db->quoteName('virtuemart_category_id') . " = $sale_cat_id");
$db->setQuery($query);
$result = $db->execute();
if ($debug_mode) {
    if ($result) echo 'Очистили старую принадлежность товаров к категории Распродажа. Затронутых записей: '.$db->getAffectedRows().END;
    else echo 'Не удалось очистить старую принадлежность товаров к категории Распродажа. Что-то пошло не так'.END;
}
unset($query, $result);

// Получаем список для каких товаров надо сделать новые записи
$query = '
    SELECT p.virtuemart_product_id, pc.customfield_value, p.product_in_stock
    FROM #__virtuemart_products p
    LEFT JOIN #__virtuemart_product_prices pp USING(virtuemart_product_id)
    LEFT JOIN (
        SELECT p2.virtuemart_product_id, pc2.customfield_value
        FROM #__virtuemart_products p2
        LEFT JOIN #__virtuemart_product_customfields pc2 USING(virtuemart_product_id)
        WHERE pc2.virtuemart_custom_id = '.$cf_prodazh_id.' 
    ) pc USING(virtuemart_product_id)
    WHERE
        pp.override = 1
        AND pp.product_override_price < pp.product_price
        AND p.product_in_stock > 0
    ORDER BY pc.customfield_value DESC, p.product_in_stock DESC
';
$db->setQuery($query);
$result = $db->execute();
$affected = $db->getNumRows();
$results = $db->loadObjectList();
if ($debug_mode) {
    if ($result) echo 'Получили список товаров, которые нужно поместить в категорию Распродажа. Число позиций: '.$affected.END;
    else echo 'Не удалось получить список товаров, которые нужно поместить в категорию Распродажа. Что-то пошло не так.'.END;
}
unset($query, $result, $affected);

/*
echo '<pre>';
print_r($results);
echo '</pre>';
*/

// Вставляем новые записи в БД
$i = 1;
foreach ($results as $res) {
    $record = (object) [];
    $record->virtuemart_product_id = $res->virtuemart_product_id;
    $record->virtuemart_category_id = $sale_cat_id;
    $record->ordering = $i;
    $result = $db->insertObject('#__virtuemart_product_categories', $record);
    if ($debug_mode) {
        if ($result) echo 'Товару '.$res->virtuemart_product_id.' добавили категорию '.$sale_cat_id.END;
        else echo 'Не удалось вставить запись в таблицу virtuemart_product_categories для товаара '.$res->virtuemart_product_id.END;
    }
    unset($record, $res, $result);
    $i++;
}
unset($i);

$time_end = microtime(true);
$time = round($time_end - $time_start, 2);

if ($debug_mode) echo "Скрипт выполнен. Затрачено $time сек.";

4) Настраиваем на сервере/хостинге крон-задачу по запуску этого скрипта, скажем, каждые 10 минут. Если не сталкивались с созданием крон задач, обратитесь в поддержку хостинга или погуглите / пояндексуйте :)

Для примера, в моём случае команда крон выглядит так:
/usr/bin/php ~/mkelektro/cron/set_sale_cat.php

Данный скрипт несколько специфичен, как вы понимаете. Он сделан под мою конкретную задачу - товарам, у которых есть спеццена, добавить категорию Распродажа.

Но главное - перед вами рабочая Логика. Условия запросов можно переделать под любую повседневную задачу (если не уходить в крайности понимания слова 'любую' :)

Работает 100% для VirtueMart 3 с Joomla 3.9 - под которые я писал. Но думаю, что будет работать и на других версиях. Если что, можно адаптировать.

Добавлю ещё, что в начале скрипта $debug_mode можно установить на = true;
Тогда скрипт будет выводить комментарии о выполнении своих этапов.

Можно также раскомментировать блок с print_r, чтобы посмотреть на содержание массива со списком подобранных для обработки товаров перед началом присвоения им категории.

Если будут вопросы, пишите. Чем смогу, помогу! )

Комментариев нет:

Отправить комментарий