epic

epic

С нами с 16 марта 2024; Место в рейтинге пользователей: #9564
vectorserver
03 июля 2025, 11:09
1
+1
Вот тебе решение, тут я использую сниппет phpThumbOn и проверяю файлы которые весят более 1мб и делаю ресайз по ширине 1024px, создай файл в корне сайта msproducts_resizer.php и запусти его, в журнале все сообщения!

<?php
// Ресайзер оригиналов изображений msProduct по быстрому
// Определяем режим API MODX
define('MODX_API_MODE', true);
require 'index.php';

// Инициализация MODX
/** @var modX $modx */
$modx->getService('error', 'error.modError');
$modx->setLogLevel(modX::LOG_LEVEL_FATAL);
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

// Путь к папке с продуктами
$basePath = MODX_BASE_PATH . 'assets/images/products/';

// Размер файла в байтах (1 МБ = 1048576 байт)
$maxFileSize = 1048576;

// Максимальная ширина после ресайза
$maxWidth = 1024;

// Логика поиска и ресайза изображений
function resizeImagesWithPhpThumb($basePath, $maxFileSize, $maxWidth)
{
    global $modx;

    // Получаем список всех подпапок в директории products
    $directories = glob($basePath . '*', GLOB_ONLYDIR);

    foreach ($directories as $dir) {
        // Получаем все файлы изображений в текущей подпапке
        $images = glob($dir . '/*.{jpg,jpeg,png,gif}', GLOB_BRACE);

        foreach ($images as $imagePath) {
            // Проверяем размер файла
            if (filesize($imagePath) > $maxFileSize) {
                try {
                    // Генерируем URL для ресайза с помощью phpThumbOn
                    $relativePath = str_replace(MODX_BASE_PATH, '', $imagePath); // Относительный путь
                    $thumbUrl = $modx->runSnippet('phpThumbOn', [
                        'input' => $relativePath,
                        'options' => "w={$maxWidth}&zc=1", // Ширина 1024px, сохранение пропорций
                    ]);

                    // Путь к новому изображению
                    $newImagePath = MODX_BASE_PATH . ltrim($thumbUrl, '/');

                    // Заменяем оригинальное изображение на новое
                    if (file_exists($newImagePath)) {
                        unlink($imagePath); // Удаляем старое изображение
                        rename($newImagePath, $imagePath); // Переименовываем новое изображение
                    }

                    // Логируем успешное изменение
                    $modx->log(modX::LOG_LEVEL_INFO, "Изображение {$imagePath} успешно изменено.");
                } catch (\Exception $e) {
                    // Логируем ошибку при обработке изображения
                    $modx->log(modX::LOG_LEVEL_ERROR, "Ошибка при обработке изображения {$imagePath}: " . $e->getMessage());
                }
            } else {
                // Логируем, если размер файла меньше порогового значения
                $modx->log(modX::LOG_LEVEL_INFO, "Изображение {$imagePath} меньше 1 МБ, пропускаем.");
            }
        }
    }
}

// Запуск логики
resizeImagesWithPhpThumb($basePath, $maxFileSize, $maxWidth);
Артур Шевченко
29 июля 2022, 00:19
1
+1
Думаю ntt нужно переписать вот эту функцию
// Функция включения моделей
    enableModel: function() {
        // Получаем марку автомобиля
        var marka = this.marka.find(':selected').text().replace(/\(.*?\)$/, '').replace(/\s+$/, '');
        var re = new RegExp('^' + marka);
        // Пробегаем по всем моделям и проверяем имя
        $this.model.find('option').each(function() {
            var $this = $(this);
            // Имя не совпадает - нужно отключить эту модель
            if (!$this.text().match(re) && $this.prop('value') != '') {
                $this.attr('disabled', true);
                $this.hide();
            }
            // В противном случае - включить
            else {
                $this.attr('disabled', false);
                $this.show();
            }
        });
        // И показываем весь блок с моделями
        $this.model.show();
    },
}
тут проверяется есть ли в названии модели марка
if (!$this.text().match(re) && $this.prop('value') != '')
в твоём случае надо выводить каждой модели в дата атрибут название марки и проверять есть ли у текущей опции дата атрибут с такой маркой. Как вариант.
Ivan
06 июня 2022, 14:50
2
0
В общем решение не самое красивое, но рабочее.
1) Копируем файл
/assets/components/msearch2/js/web/default.js
и называем его
/assets/components/msearch2/js/web/custom.js
.
2) В этом файле везде
mse2Config['actionUrl']
заменяем на
'/assets/components/msearch2/actionCustom.php'
3) Копируем файл
/assets/components/msearch2/action.php
и называем его
/assets/components/msearch2/actionCustom.php
4) В html коде сортировки указываем
<a href="#" data-sort="ms|price" data-dir="[[+mse2_sort:is=`ms|price:desc`:then=`desc`]]" data-default="desc" class="sort">По цене <span></span></a>
5) В файле
actionCustom.php
на 76 строчке меняем
$paginatorProperties['sortby'] = !empty($sort)
            ? $mSearch2->getSortFields($sort)
            : '';
на
$sorting = '';
            if (!empty($sort)) {
            $sorting = $mSearch2->getSortFields($sort);
            if ($sorting == '`Data`.`price` desc') {
                $sorting = 'IF (`Data`.`price` > 0, 1, 0) desc, `Data`.`price` desc';
            } elseif ($sorting == '`Data`.`price` asc') {
                $sorting = 'IF (`Data`.`price` > 0, 1, 0) desc, `Data`.`price` asc';
            }
        }
        $paginatorProperties['sortby'] = $sorting;
Радуемся
Валерий
21 ноября 2021, 20:20
1
0
Проблему решил. Добавил в вызов фильтра:
&leftJoin=`{"Remains":{"class":"msprRemains","on":"msProduct.id = Remains.product_id AND Remains.remains > 0"}}`
&loadModels=`msproductremains`
&groupby=`msProduct.id`
&select=`{"msProduct":"*","Remains":"SUM(Remains.remains) as remains"}`
Илья
14 июля 2020, 13:15
2
0
Сделал так:
{'!pdoNeighbors' | snippet : [
    'class' => 'modResource',
        'loadModels' => 'ms2gallery',
        'leftJoin' => [
            'Image' => [
                'class' => 'msResourceFile',
                'on' => 'modResource.id = Image.resource_id AND Image.parent = 0 AND Image.rank = 0',
            ],
            'Thumb' => [
                'class' => 'msResourceFile',
                'on' => 'Image.id = Thumb.parent AND Thumb.path LIKE "%small%"',
            ]
        ],
        'select' => [
            'modResource' => '*',
            'Thumb' => 'Thumb.url as small',
        ],
    'tplWrapper' => '@INLINE {$prev}{$next}',
    'tplPrev' => '@INLINE <a href="/{$uri}"><img src="{$small}">туда</a>',
    'tplNext' => '@INLINE <a href="/{$uri}"><img src="{$small}">сюда</a>',
]}
В результате выводится первая миниатюра {$small} в pdoNeighbors
Может кому-то будет полезно.

Не дадим modxУ погибнуть!!!
Сергей Фещуков
20 июня 2019, 06:55
1
0
Попробуйте вот так:
[[!msProducts?
  &leftJoin=`{"Remains":{"class":"msprRemains","on":"msProduct.id = Remains.product_id AND Remains.remains > 0"}}`
  &groupby=`msProduct.id`
  &select=`{"msProduct":"*","Remains":"IF (Remains.remains > 0, 1, 0) as remains"}`
  &sortby=`Remains.remains`
  &sortdir=`DESC`
]]
Степан Прищепенко
27 марта 2019, 00:20
1
0
Приветствую, хороший компонент, но хотел отметить несколько вещей:
1. в папке модели должен быть metadata.mysql.php, хотя бы
с таким содержимым:
$xpdo_meta_map = array();
Иначе ловим ошибку.

2. В основном классе, метод инициализации есть, но не вызывается,
и там же pdo подключается, но не получает конфиг, следует
параметры в него не передашь, можно исправить вот так:

if ($this->pdoTools = $this->modx->getService('pdoTools')){
	  $this->pdoTools->setConfig($this->config, false);
	}
3. Ключ (хеш) конфигурации корзины, при ajax запросе передается,
но нинциализация не происходит, это значит как минимум pdo не получит конфиг из пункта 2.
Для этого инициализация может быть такой:

protected $initialized = false;
	public function initialize($config = array())
    {
        if ($this->initialized) return true;

        $this->config = array_merge($this->config, $config);

        if ($this->miniShop2 = $this->modx->getService('miniShop2')) {
            $this->miniShop2->initialize($this->ctx);
        }
        if ($this->pdoTools = $this->modx->getService('pdoTools')){
            $this->pdoTools->setConfig($this->config, false);
        }

        $this->initialized = true;
    }
А в handleRequest:

$tmp = $this->getSessionData();
    $tmp = is_array($tmp) ? $tmp : array();
    $this->initialize($tmp);
Ну и в сниппеты и плагины после успешной подгрузки класса:
$msMCD->initialize();
4. Чанк элемента в корзине содержит:
<input type="hidden" name="msmcd_id" value="{$item.id}">
Ошибкой было называть имя msmcd_id вместо id, так как это может сломать
работу других компонентов
, висящих на событиях изменения
товаров в корзине. Да и префикс msmcd_ не используется ни где.

5. При удалении товара вместо Cart.remove.response.success
нужно использовать:
miniShop2.Callbacks.add('Cart.remove.ajax.always', 'msmcd_remove', function(response) {
            var cur_responce = response.responseJSON || {}
            // console.log ("done args",cur_responce);
            // debugger;
            if (cur_responce && cur_responce.success){
                if ($('.ms2_product .msmcd-count').length) {
                    $(msMCDMiniCart.formId + k + ' ' + msMCDCount.msmcdCount).val(0);
                    $(msMCDMiniCart.formId + k + ' ' + msMCDCount.msmcdAction).val('cart/add');
                }

                var sendData = {
                    action: 'msmcd/chunk',
                    ctx: msMCDMiniCart.ctx
                };
                msMCDMiniCart.send(sendData);
            }
        });
Тогда будет правильно удалять товары.

Вроде после такого напильника, стало работать как нужно. Желаю творческих успехов!
Илья
30 мая 2017, 18:22
1
0
Спасибо за разъяснения. Очень помогли. В доках оказывается есть подобное, но не сразу было понятно.
Может кому пригодится, если нужно сделать сортировку по опциям товара miniShop2:
2 поля size_h и color_id, которые нам надо отсортировать
&leftJoin=`
	{
            "size_h":{
                "class":"msProductOption",
                "on":"size_h.product_id = msProduct.id AND size_h.key = 'size_h'"
            },
            "color":{
                "class":"msProductOption",
                "on":"color.product_id = msProduct.id AND color.key = 'color_id'" 
            }
        }`
&sortAliases=`{"size_h":"size_h","color":"color"}` // добавляем псевдоним
&sort=`size_w|value:desc,color|value:asc`
Prihod
13 января 2017, 13:59
2
+1
1) т/к нужно для всех товаров не попавших в обновление поменять значение availability то возможно целесообразней использовать в качестве условия для получения всех товаров class_key == msProduct
2) т/к availability (из инфы от автора вопроса) для товара добавлено через систему плагинов minishop2 которую также в удобной форме реализует дополнение msFieldsManager то код примет следующий вид
<?php
/** @var modX $modx */
switch ($modx->event->name) {
    case 'msieOnCompleteImportProduct':

        // Получаем id всех импортированных товаров
        $currentIDs = explode(",", $modx->event->params['data']);

        // Получаем id ВСЕХ товаров в магазине
        $q = $modx->newQuery('msProduct', array('class_key' => 'msProduct'));
        $q->prepare();
        $q->stmt->execute();
        $oldIDs = $q->stmt->fetchAll(PDO::FETCH_COLUMN, 0);

        // Вычисляем id товаров которые есть на сайте, но нет в файле импорта
        $oldIDs = array_diff($oldIDs, $currentIDs);

        if (!empty($oldIDs)) {
            $oldIDs = implode(',', $oldIDs);
            $sql = "UPDATE {$modx->getTableName('msProductData')} SET availability = 0 WHERE id IN  ({$oldIDs});";
            $modx->exec($sql);
        }
        break;
}
Дмитрий Кондаков
13 января 2017, 12:40
3
+1
Создаете плагин на событие msieOnCompleteImportProduct:
<?php
/** @var modX $modx */
switch ($modx->event->name) {
	case 'msieOnCompleteImportProduct':

		// Получаем id всех импортированных товаров
		$currentIDs = explode(",", $modx->event->params['data']);

		// Получаем id ВСЕХ товаров в магазине
		$q = $modx->newQuery('msProduct', array('parent' => 7, 'template' => 8)); // тут свои условия
		$q->prepare();
		$q->stmt->execute();
		$oldIDs = $q->stmt->fetchAll(PDO::FETCH_COLUMN, 0);

		// Вычисляем id товаров которые есть на сайте, но нет в файле импорта
		$oldIDs = array_diff($oldIDs, $currentIDs);

		if ($toRemoveIDs) {
		  foreach ($toRemoveIDs as $cur) {
		    // и тут делаем с ними что угодно
		  }
		}
	break;
}
PS. на всякий случай сделайте бэкап БД перед тестированием плагина