Всего 125 685 комментариев

Дмитрий
19 минут назад
0
так же при обновлении minishop3 до версии 1.5.0-beta1 ошибка
[MiniShop3] System routes are in: core/components/minishop3/config/routes/
[MiniShop3] Scheduler not installed, skipping task registration. Install Scheduler component to enable background task processing.
PHP warning: Undefined array key "desc"
PHP warning: Undefined array key "desc"
Успешно установлен пакет minishop3-1.5.0-beta1
Дмитрий
30 минут назад
0
Добрый день! При обновлении modx 3.1.2 до 3.2.0 появились ошибки
Fatal error: Uncaught TypeError: array_diff_key(): Argument #1 ($array) must be of type array, string given in /home/setup/includes/upgrade.install.php:254 Stack trace: #0 /home/setup/includes/upgrade.install.php(254): array_diff_key('{"mscategory_sa...', Array) #1 /home/setup/includes/runner/modinstallrunnerweb.class.php(78): include('/home/hostcweb/...') #2 /home/setup/includes/runner/modinstallrunner.class.php(49): modInstallRunnerWeb->execute(1) #3 /home/setup/controllers/install.php(34): modInstallRunner->run(1) #4 /home/setup/includes/request/modinstallrequest.class.php(81): include('/home/hostcweb/...') #5 /home/setup/index.php(30): modInstallRequest->handle() #6 {main} thrown in /home/setup/includes/upgrade.install.php on line 254
, оказалось, что в modx_access_policies у modx_access_policies стоял 0 template, а в data
"{\"mscategory_save\":true,\"msproduct_save\":true,\"msproduct_publish\":true,\"msproduct_delete\":true,\"msorder_save\":true,\"msorder_view\":true,\"msorder_list\":true,\"msorder_remove\":true,\"mssetting_save\":true,\"mssetting_view\":true,\"mssetting_list\":true,\"msproductfile_save\":true,\"msproductfile_generate\":true,\"msproductfile_list\":true}"
, убрал лишние кавычки и /, поставил 8 шаблон руками, после этого modx обновился. Это баг minishop3 или я где-то напортачил?
Иван Бочкарев
Вчера в 14:45
+1
Добавил сиcтемную настройку ms3recentlyviewed.block_bots_detector и интегрировал jaybizzle/crawler-detect
Ivan K.
Вчера в 14:38
0
В следующий раз сделаю как положено)
Николай Савин
28 февраля 2026, 22:07
+1
Заранее прошу прощение за занудство, но по semver если в релизе фигурирует слово «Добавлено» — то это автоматически минорный релиз (меняем вторую цифру в версии)
Дмитрий
28 февраля 2026, 15:20
0
Всем привет!
Версия модуля 1.4.0
Необходимо обновить наименования товаров.
Выбираем Тип импорта — Обновить данные товаров
Соответствие Столбца Название — pagetitle
Запускаем импорт.
В логе запись апдейтится, но там нет поля pagetitle:

[2026-02-28 14:43:45] (INFO @ /var/sites/core/components/msimportexport/model/msimportexport/msie.class.php: 2905) Update SQL:
UPDATE `modx_ms2_products` AS msProductData SET `price`='26420',`old_price`='0',`article`='',`sklad`=0,`weight`='0',`color`='[\"\\u0414\\u0443\\u0431 \\u043a\\u0430\\u043f\\u0443\\u0447\\u0447\\u0438\\u043d\\u043e\"]',`size`='[\«2000x600\»,\«2000x700\»,\«2000x800\»,\«2000x900\»]',`made_in`='',`vendor`=4,`steklo`=0,`nestandart`=1,`garanty`=5,`available`=2,`new`=0,`favorite`=0,`popular`=0,`ms2colors_common_id`=1,`ms2colors_collection_id`=68,`mk_price_box`=5870,`mk_price_nalich`=5580,`mk_subtype`=1,`mk_kapitel`=0,`mk_material`=8,`mk_style`=2,`mk_type_open`='[\«1\»,\«2\»,\«3\»,\«4\»]' WHERE `msProductData`.`id` = 1567

Подскажите, пож-та, как поправить.
Спасибо.

Файл импорта:
ID; Название; Опубликован; Цена; Старая цена; Артикул;sklad; Вес; Цвет; Размер; Страна; Производитель;steklo;nestandart;garanty;available; Новый; Особый; Популярный;ms2colors_common_id;ms2colors_collection_id;mk_price_box;mk_price_nalich;mk_subtype;mk_kapitel;mk_material;mk_Стайл;mk_type_open;ms2colors_common_name;ms2colors_collection_name
1567; Футура 311;1;26420.00;0.00;;0;0.000; Дуб капуччино;2000x600|2000x700|2000x800|2000x900;;4;0;1;5;2;0;0;0;1;68;5870;5580;1;0;8;2;1|2|3|4; Светло коричневый; Дуб капучино
Артур Шевченко
27 февраля 2026, 21:26
0
Настройками нельзя, только написанием своего плагина, который будет проверять необходимые условия. Если сами не справитесь, могу написать его за отдельную плату.
Николай
27 февраля 2026, 15:50
0
Можно ли учитывать все товары в корзине для минимальной стоимости (даже те, для которых не настроена скидка), но исключить одну категорию из этого подсчета.
Николай
27 февраля 2026, 15:34
0
т.е. если я настроил скидку на 2 категории, то скидка будет применятся, только тогда когда я набрал минимальную сумму из этих 2-х категорий?
Артур Шевченко
27 февраля 2026, 15:27
0
В настройках скидки можно выбрать «Учитывать количество акционных товаров» тогда при подсчёте суммы будет учитываться только общая стоимость товаров удовлетворяющих остальным условиям акции
Николай Савин
25 февраля 2026, 17:49
+2
Добавлен также генератор разнообразных типов опций товара в разном количестве для разных наборов и их заполнение у товаров.
Николай Савин
25 февраля 2026, 15:21
0
Сложно сказать. Впервые про такую проблему слышу. Вы можете написать мне в телеграм доступы — вместе посмотрим
Ольга
25 февраля 2026, 15:07
0
Подскажите, никак не получается понять почему — почему вывод корзины не работает после авторизации? причем добавление товаров уже после авторизации, ничего не решает, корзины не видно, так же не видно мини корзинки, все пусто. Может ге в системе что то щелкнуть нужно? типа сессий, итд?
Дмитрий
25 февраля 2026, 09:59
0
Удалось найти решение?
Дмитрий
24 февраля 2026, 18:29
0
это сделал ИИ.
Я взял код из файла /core/components/minishop2/model/minishop2/minishop2.class.php
я скопировал этот метод function getReceiverId(), скинул ИИ и описал свои хотелки.
ИИ сгенерировал новый код, я его вставил обратно в файл /core/components/minishop2/model/minishop2/minishop2.class.php и все прекрасно заработало, но когда я расширяю хендлер, у меня перестает работать.

Поправил код по вашему мануалу — все работает, спасибо большое!
Иван Бочкарев
24 февраля 2026, 13:05
0
Привет!

Сегодня выложим — была проблема с защитой и ключами + был занят работой над minishop3 и PR к MODX github.com/modxcms/revolution/pulls/Ibochkarev

@Андрей дополнение в магазине
Михаил
23 февраля 2026, 03:33
0
Вот так отображаются поля довольно красиво! Нужно создать поля: allowed_resources, date_start, date_end в базе данных в таблице modx_user_attributes. Это плагин:
<?php
/**
 * Plugin for adding custom fields to user profile
 * Events: OnMODXInit, OnUserFormPrerender, OnUserFormSave
 */

switch ($modx->event->name) {
    case "OnMODXInit":
        // Добавляем поля в карту объектов MODX
        $map = array(
            'modUserProfile' => array(
                'fields' => array(
                    'allowed_resources' => null,
                    'date_start' => null,
                    'date_end' => null,
                ),
                'fieldMeta' => array(
                    'allowed_resources' => array(
                        'dbtype' => 'varchar',
                        'precision' => '191',
                        'phptype' => 'string',
                        'null' => true,
                        'default' => null,
                    ),
                    'date_start' => array(
                        'dbtype' => 'int',
                        'precision' => '20',
                        'phptype' => 'integer',
                        'null' => true,
                        'default' => null,
                    ),
                    'date_end' => array(
                        'dbtype' => 'int',
                        'precision' => '20',
                        'phptype' => 'integer',
                        'null' => true,
                        'default' => null,
                    ),
                ),
            ),
        );

        foreach ($map as $class => $data) {
            $modx->loadClass($class);
            foreach ($data['fields'] as $field => $default) {
                if (!isset($modx->map[$class]['fields'][$field])) {
                    $modx->map[$class]['fields'][$field] = $default;
                    if (isset($data['fieldMeta'][$field])) {
                        $modx->map[$class]['fieldMeta'][$field] = $data['fieldMeta'][$field];
                    }
                }
            }
        }
        break;
    
    case "OnUserFormPrerender":
        // Проверяем существование пользователя
        if (!isset($user) || !is_object($user) || $user->get('id') < 1) {
            return;
        }

        $profile = $user->getOne('Profile');
        if (!$profile) {
            return;
        }

        // Получаем значения полей
        $allowedResources = $profile->get('allowed_resources') ?: '';
        $dateStart = $profile->get('date_start');
        $dateEnd = $profile->get('date_end');

        // Форматируем даты
        $dateStartFormatted = (!empty($dateStart) && is_numeric($dateStart)) 
            ? date('Y-m-d', $dateStart) 
            : '';
        $dateEndFormatted = (!empty($dateEnd) && is_numeric($dateEnd)) 
            ? date('Y-m-d', $dateEnd) 
            : '';

        // Экранируем для JavaScript
        $allowedResources = htmlspecialchars($allowedResources, ENT_QUOTES, 'UTF-8');

        $js = <<<JS
<script type="text/javascript">
Ext.onReady(function() {
    Ext.ComponentMgr.onAvailable('modx-user-tabs', function(panel) {
        panel.on('beforerender', function() {
            // Находим левую колонку первой вкладки
            var tabPanel = this.items && this.items.items && this.items.items[0];
            if (!tabPanel) return;
            
            var formPanel = tabPanel.items && tabPanel.items.items && tabPanel.items.items[0];
            if (!formPanel) return;
            
            var leftCol = formPanel.items && formPanel.items.items && formPanel.items.items[0];
            if (!leftCol) return;

            // Создаем FieldSet с правильным layout
            var customFields = new Ext.form.FieldSet({
                title: 'Доступ к ресурсам',
                collapsible: true,
                collapsed: false,
                style: 'margin-top: 15px; margin-bottom: 15px;',
                autoHeight: true,
                layout: 'form',  // КЛЮЧЕВОЕ: включает отображение fieldLabel
                labelWidth: 150,
                anchor: '100%',
                defaults: {
                    anchor: '100%',
                    msgTarget: 'under'
                },
                items: [
                    {
                        xtype: 'textfield',
                        name: 'allowed_resources',
                        fieldLabel: 'Разрешенные ресурсы',
                        maxLength: 191,
                        value: '{$allowedResources}',
                        listeners: {
                            afterrender: function(cmp) {
                                if (Ext.QuickTips) {
                                    Ext.QuickTips.register({
                                        target: cmp.getEl(),
                                        text: 'ID ресурсов через запятую (например: 1,5,12,43)'
                                    });
                                }
                            }
                        }
                    },
                    {
                        xtype: 'datefield',
                        name: 'date_start',
                        fieldLabel: 'Дата начала доступа',
                        format: 'Y-m-d',
                        value: '{$dateStartFormatted}',
                        emptyText: 'Выберите дату начала'
                    },
                    {
                        xtype: 'datefield',
                        name: 'date_end',
                        fieldLabel: 'Дата окончания доступа',
                        format: 'Y-m-d',
                        value: '{$dateEndFormatted}',
                        emptyText: 'Выберите дату окончания'
                    }
                ]
            });

            // Добавляем в левую колонку
            leftCol.add(customFields);
            
            // Обновляем layout
            if (leftCol.doLayout) {
                leftCol.doLayout();
            }
            if (panel.doLayout) {
                panel.doLayout();
            }
        });
    });
});
</script>

<style type="text/css">
/* Стили для полей */
.x-fieldset {
    border: 1px solid #d0d0d0;
    padding: 10px;
    margin-bottom: 10px;
}
.x-fieldset legend {
    font-weight: bold;
    color: #333;
    padding: 0 5px;
}
.x-form-item {
    margin-bottom: 10px;
}
.x-form-item-label {
    font-weight: bold !important;
    color: #555;
    font-size: 12px;
}
.x-form-field-wrap {
    margin-bottom: 5px;
}
</style>
JS;

        $modx->controller->addHtml($js);
        break;
        
    case "OnUserFormSave":
        if (!isset($user) || !is_object($user)) {
            return;
        }
        
        $profile = $user->getOne('Profile');
        if (!$profile) {
            return;
        }
        
        $modified = false;
        
        // Сохраняем allowed_resources
        if (isset($_POST['allowed_resources'])) {
            $value = trim($_POST['allowed_resources']);
            $profile->set('allowed_resources', $value !== '' ? $value : null);
            $modified = true;
        }
        
        // Сохраняем date_start
        if (isset($_POST['date_start'])) {
            if (!empty($_POST['date_start'])) {
                $timestamp = strtotime($_POST['date_start']);
                if ($timestamp !== false) {
                    $profile->set('date_start', $timestamp);
                    $modified = true;
                }
            } else {
                $profile->set('date_start', null);
                $modified = true;
            }
        }
        
        // Сохраняем date_end
        if (isset($_POST['date_end'])) {
            if (!empty($_POST['date_end'])) {
                $timestamp = strtotime($_POST['date_end']);
                if ($timestamp !== false) {
                    $profile->set('date_end', $timestamp);
                    $modified = true;
                }
            } else {
                $profile->set('date_end', null);
                $modified = true;
            }
        }
        
        // Сохраняем профиль только если были изменения
        if ($modified) {
            $profile->save();
        }
        break;
}
Александр Туниеков
22 февраля 2026, 19:58
0
Кто реально внедрил MODX с Vue. js — каков опыт?
Опыт — реактивные переменные благословение и проклятие Vue. С ними можно делать почти мнгновенно реагирующий интерфейс и неприятность что в них не всегда оказывается то что нужно. Где то в коде именил или не изменил не так как нужно и приложение ведет себя не так как нужно. Отследить изменения тяжело особенно если меняешь чужой код или код ИИ
Александр Туниеков
22 февраля 2026, 19:33
+2
Я делаю miniERP систему на модекс. ИИ помогает значительно. Но с ИИ лучше делать когда сам понимаешь как сделать. Нейросеть не догоняет весь контекст. И сочиняет на ходу чтобы как-бы выполнить задачу. Правда у меня нейросеть хотя бы пытается что-то сделать, а люди сразу в ступор впадают :-). Непривычный контекст задач и тяжело въехать.
Я делаю систему с нейросетью используя modExtra и PVExtra, так как IDE заточены под файлы и в базу не лезут. А в MODX пользовательский код обычно в базе. То есть ставлю чистый MODX. Делаю на нем ЧПУ и делаю компоненты которые заполняют сайт. Возможно имеет смысл подключить к нейросети MCP MySQL и чтоб нейросеть напрямую редактировала страницы и шаблоны. Чанки, сниппеты и тв в последнее время не использую. Вместо сниппетов vue компоненты к которым чанки не особо прикрутишь. А вместо тв проще нужные таблицы сразу писать.
Мне проше сразу писать компоненты. Некоторые потом можно отдельно выкладывать. И проще в прод вносить изменения. Просто поставил компонент и нужные правки применились. И не надо делать деплой всего сервера. Правки по компонентам и нужно поставить лишь тот компонент в котором изменения.

С нейросеть у меня 2 метода писать код:
1. Точечное промт-програмирование. Например, пишешь промпт: здесь отсортируй массив по возрастанию ранга наряда. И нейросеть вставляет нужный код.
2. Вайб-кодинг. Есть задача которую непонятно как сделать и пишешь, например, нужно сделать дополнительные фильтры чекбоксы которые выводят список значений в таблице и при выборе которых в таблице фильтруется по этим выбранным значениям. И нейросеть сама разбирается что сделать и пишет код. Такой промпт я как-то задавал и потом 3 часа разбирался почему основные фильтры не работают. Оказалось что нейросеть решила, что если есть допфильтры, то основные не нужны :-).

3 месяц писал с Kilo Code для VSCode. Но постепенно работа через API Claude стала забирать все больше денег. Сейчас использую Claude Code для VSCode с подпиской MAX. Она втрое дешевле должна выходить. Вчера сочинял с ним план внедрения в miniERP продажи перепродоваемых товаров (вместе с товарами которые мы изготавливаем). Перед использованием вайб-кодинга лучше с ИИ сочинить план разработки.

Ну вкратце так. Более подробно пока желания писать нет. Хотя есть моменты которые хочется обсудить или написать статьи, но прям сейчас только то что написал.