Наумов Алексей

Наумов Алексей

Был в сети 28 июля 2026, 14:21
Заказы принимаю
Компонент считает рейтинг по 2-м алгоритмам: по Вильсону и среднее арифметическое.
По-умолчанию вильсон, отсюда и такой средний бал.
Чтобы было среднее арифметическое — в используемых чанках поменяйте постфикс "_wilson" на "_simple".
Берем нужный нам сниппет (pdoResources, msProducts).
К выборке присоединяем цепочку и выбираем кол-во отзывов:
&leftJoin=`{
        "ecThread": {
    		"class": "ecThread",
    		"on": " CONCAT('resource-', modResource.id) = ecThread.name"
    	}
    }`
    &select=`{
    	"modResource": "*",
    	"ecThread": "ecThreadRating.count AS reviews_count",
    }`
После сортируем по полю reviews_count
Не совсем. OnEcMessagePublish сработает когда в админке будет выбран пункт меню «Опубликовать». Но если просто отредактировать сообщение, проставив галочку «Опубликован», то будет событие OnEcMessageSave.

Если нужно отслеживать, что поменялся список отзывов, то надо ловить все события: OnEcMessageSave, OnEcMessagePublish, OnEcMessageUnpublish, OnEcMessageDelete, OnEcMessageUndelete, OnEcMessageRemove.

плагин один, код один, события несколько. Уже в плагине смотрите, что произошло.
Получить id вроде как, если не путаюсь:
$id = $object->get('id');
По событиям документации нет.

Список:
// ecThread events
OnBeforeEcThreadRemove
OnEcThreadRemove
// ecMessage events
OnBeforeEcMessageSave
OnEcMessageSave
OnBeforeEcMessagePublish
OnEcMessagePublish
OnBeforeEcMessageUnpublish
OnEcMessageUnpublish
OnBeforeEcMessageDelete
OnEcMessageDelete
OnBeforeEcMessageUndelete
OnEcMessageUndelete
OnBeforeEcMessageRemove
OnEcMessageRemove

В событии как правило доступен $object (ecMessage или ecThread).
Нашел в интернате вот эту функцию
miniShop2.Callbacks.Cart.add.response.success = function() {}
Вешаю ее на странице карточки товара. Но в консоль выводится это:
Uncaught ReferenceError: miniShop2 is not defined
Ваш скрипт должен быть подключен после всех скриптов минишоп.
Насколько я помню по своему опыту, главный трабл был в том, что были затерты js файлы.

Примерный сценарий:
1. Разворачиваем сайт
2. Устанавливаем поверх свежий (или не очень свежий) MODX
3. Обновляем все компоненты, задача — переустановить их с заменой файлов
4. Удаляем старые версии компонентов, чтобы уменьшить кол-во файлов
5. Тщательно ищем упоминания вирусов во всех файлах, сверяемся с исходниками modx и компонентов, используем антивирусы.
6. Кстати. Вот перед всем этим, хорошо бы проанализировать даты изменения файлов. Возможно, вам получится выяснить список файлов, модернизированных вирусом.
7. Недостающие файлы пытаемся найти через webarchive или свои старые бекапы. Это единственное место, где я смог найти js файлы.
bootstrap + возможно MobileDetect
Актуально)
Каталог с поддержкой фильтрации, значит MS2
Да, miniShop2 + mFilter2 (mSearch2).
Что-то удобное по загрузке фотографий для MS2 — ms2Gallery
Если нужно дополнительно, то да. Хотя и штатная галерея вроде ничего.
Отзывы — Tickets
Вполне. Или советую свой компонент easyComm.

Избранное к каталогу
msFavorites
modstore.pro/packages/ecommerce/msfavorites
И возможно предзаказ
Или штатную корзину от минишопа, где покупка и будет «предзаказом», или вообще «Купить в 1 клик» в виде простейшей формы.

Office — если нужен кабинет. Авторизацию вроде он поддерживает штатно через HybridAuth.
Кнопками управлять так.
При объявлении окна, внутри
Ext.applyIf(config, {
после
fields: this.getFields(config)
добавляем еще кнопки (по умолчанию их 2 штуки, а вот вам пример на 4 штуки)
buttons: [
            {
                text: 'Моя кнопка',
                scope: this,
                handler: function () {
                    alert("Работает");
                }
            },
            {
                text: config.cancelBtnText || _('cancel'),
                scope: this,
                handler: function () {
                    config.closeAction !== 'close' ? this.hide() : this.close();
                }
            },
            {
                text: config.saveBtnText || _('save'),
                scope: this,
                handler: function () {
                    this.submit(false);
                }
            },
            {
                text: config.saveBtnText || _('save_and_close'),
                cls: 'primary-button',
                scope: this,
                handler: function () {
                    this.submit(true);
                }
            }
        ]
Сугубо индивидуальная задача.
Как вариант «попроще» — создать неопубликованный ресурс «Меню», а внутри шпарить уже ресурсами-ссылками, вывод через pdoMenu.

Вариант через MIGX тоже можно, почему нет.
Да хоть в чанке пункты прописывайте, а своим сниппетом на вывод.
Чет много кода))

Смотри, пример процессора, который выдает список категорий из Tickets. При этом они фильтруются по введенному пользователю значению (поиск по pagetitle).

<?php

class boardAdvertCategoryGetListProcessor extends modObjectGetListProcessor
{
    public $classKey = 'TicketsSection';
    public $languageTopics = array('resource');
    public $defaultSortField = 'pagetitle';

    /** {@inheritDoc} */
    public function prepareQueryBeforeCount(xPDOQuery $c) {

        if ($this->getProperty('combo')) {
            $c->leftJoin('modResource','Rubric','`TicketsSection`.`parent` = `Rubric`.`id`');
            $c->select($this->modx->getSelectColumns($this->classKey, $this->classKey, ''));
            $c->select('`Rubric`.`pagetitle` as `rubric`');
        }
        else {
            $c->select($this->modx->getSelectColumns($this->classKey, $this->classKey, ''));
        }
        $query = $this->getProperty('query');
        $c->where(array('class_key' => 'TicketsSection'));
        if (!empty($query)) {
            $c->where(array('pagetitle:LIKE' => '%'.$query.'%'));
        }

        $id = $this->getProperty('id');
        if (!empty($id)) {
            $c->where(array('id' => $id));
        }
        return $c;
    }
    /** {@inheritDoc} */
    public function prepareRow(xPDOObject $object) {
        if ($this->getProperty('combo')) {
            $array = array(
                'id' => $object->get('id'),
                'pagetitle' => $object->get('pagetitle'),
                'rubric' => $object->get('rubric'),
            );
        }
        else {
            $array = $object->toArray();
        }
        return $array;
    }
}

return 'boardAdvertCategoryGetListProcessor';
Если мы откроем процессор modResourceCreateProcessor, то видим, что нужный permission это new_document.

А если мы откроем (к примеру) modObjectGetProcessor, то видим некий checkViewPermission и checkPolicy('view').

Короче для создания ресурса нужен new_document, для для просмотра объекта view.
Поизучайте код процессоров, посмотрите как они наследуются.