Кастомизация minishop'a

Доброго дня!
Стоит задача изменить исходник файла живущего по адресу:
/core/components/minishop2/model/minishop2/minishop2.class.php

По сути, что может быть проще, поменять код и дело с концом, но при первом же обновлении, все это канет в лету, а это не корпоративно!

Как можно подцепить свой файл?
Дмитрий
18 февраля 2026, 12:05
modx.pro
136
0

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

Артур Шевченко
18 февраля 2026, 14:14
0
Никак. Если расскажешь задачу, возможно, подскажут другое решение.
    Дмитрий
    18 февраля 2026, 18:18
    0
    хм… хочу что бы при формировании заказа минишоп генерировал username не email пользователя, а номер телефона
    Дмитрий
    18 февраля 2026, 18:50
    0
    Во, вот так хочу, что бы было

    public function getCustomerId() {
            $customer = null;
    
            $response = $this->invokeEvent('msOnBeforeGetOrderCustomer', [
                'order' => $this->order,
                'customer' => $customer,
            ]);
            if (!$response['success']) {
                return $response['message'];
            }
    
            if (!$customer) {
                $data = $this->order->get();
                $email = $data['email'] ?? '';
                $receiver = $data['receiver'] ?? '';
                $phone = $data['phone'] ?? '';
                
                // Функция для приведения телефона к международному формату +КодСтраныНомер
                $formatPhone = function($phone) {
                    if (empty($phone)) return '';
                    
                    // Удаляем все нецифровые символы
                    $phone = preg_replace('/[^0-9]/', '', $phone);
                    
                    // Определяем код страны по умолчанию (Россия)
                    $defaultCountryCode = '7';
                    
                    // Если номер начинается с 8 (Россия)
                    if (substr($phone, 0, 1) == '8') {
                        $phone = $defaultCountryCode . substr($phone, 1);
                    }
                    // Если номер без кода (10 цифр) - добавляем код по умолчанию
                    elseif (strlen($phone) == 10) {
                        $phone = $defaultCountryCode . $phone;
                    }
                    // Если номер начинается с 7 (уже есть код России)
                    elseif (substr($phone, 0, 1) == '7' && strlen($phone) == 11) {
                        // Оставляем как есть
                    }
                    // Если номер с другим кодом страны
                    elseif (strlen($phone) > 11 || (strlen($phone) == 11 && substr($phone, 0, 1) != '7')) {
                        // Оставляем как есть (уже содержит код страны)
                    }
                    
                    // Добавляем знак + в начало
                    return '+' . $phone;
                };
                
                // Приводим телефон к единому формату
                $formattedPhone = $formatPhone($phone);
                
                // Обновляем телефон в данных заказа
                if ($formattedPhone !== $phone) {
                    $data['phone'] = $formattedPhone;
                    $this->order->set($data);
                    $phone = $formattedPhone;
                }
                
                // Формируем receiver, если он пустой
                if (empty($receiver)) {
                    if (!empty($phone)) {
                        $receiver = preg_replace('/[^0-9]/', '', $phone);
                    } elseif (!empty($email)) {
                        $receiver = substr($email, 0, strpos($email, '@'));
                    } else {
                        $receiver = uniqid('user_', false);
                    }
                }
                
                // Формируем email, если он пустой
                if (empty($email)) {
                    if (!empty($phone)) {
                        $cleanPhone = preg_replace('/[^0-9]/', '', $phone);
                        $email = 'user_' . $cleanPhone . '@' . $this->modx->getOption('http_host');
                    } else {
                        $email = $receiver . '@' . $this->modx->getOption('http_host');
                    }
                }
    
                // Если пользователь авторизован
                if ($this->modx->user->isAuthenticated()) {
                    $profile = $this->modx->user->Profile;
                    
                    if (!$profile->get('email')) {
                        $profile->set('email', $email);
                    }
                    
                    if (!empty($phone) && $profile->get('mobilephone') != $phone) {
                        $profile->set('mobilephone', $phone);
                    }
                    
                    if (!empty($receiver) && $profile->get('fullname') != $receiver) {
                        $profile->set('fullname', $receiver);
                    }
                    
                    $profile->save();
                    $customer = $this->modx->user;
                    
                } else {
                    // Поиск существующего пользователя
                    $c = $this->modx->newQuery('modUser');
                    $c->leftJoin('modUserProfile', 'Profile');
                    
                    $filter = [];
                    
                    if (!empty($phone)) {
                        $filter['modUser.username'] = $phone;
                        $filter['OR:Profile.mobilephone:='] = $phone;
                    }
                    
                    if (!empty($email)) {
                        $filter['OR:Profile.email:='] = $email;
                    }
                    
                    $c->where($filter);
                    $c->select('modUser.id');
                    
                    // Пытаемся найти пользователя
                    if (!$customer = $this->modx->getObject('modUser', $c)) {
                        // Создаем нового пользователя
                        $userData = [
                            'username' => !empty($phone) ? $phone : $email,
                            'password' => md5(rand()),
                            'active' => 1
                        ];
                        
                        $customer = $this->modx->newObject('modUser', $userData);
                        
                        $profileData = [
                            'fullname' => $receiver,
                        ];
                        
                        if (!empty($email)) {
                            $profileData['email'] = $email;
                        }
                        
                        if (!empty($phone)) {
                            $profileData['mobilephone'] = $phone;
                        }
                        
                        $profile = $this->modx->newObject('modUserProfile', $profileData);
                        $customer->addOne($profile);
                        
                        // Добавляем настройку языка
                        $setting = $this->modx->newObject('modUserSetting');
                        $setting->fromArray([
                            'key' => 'cultureKey',
                            'value' => $this->modx->getOption('cultureKey', null, 'en', true),
                        ], '', true);
                        $customer->addMany($setting);
                        
                        if (!$customer->save()) {
                            $customer = null;
                        } elseif ($groups = $this->modx->getOption('ms2_order_user_groups', null, false)) {
                            $groupRoles = array_map('trim', explode(',', $groups));
                            foreach ($groupRoles as $groupRole) {
                                $groupRole = explode(':', $groupRole);
                                $roleId = null;
                                if (count($groupRole) > 1 && !empty($groupRole[1])) {
                                    $roleId = is_numeric($groupRole[1]) ? (int)$groupRole[1] : $groupRole[1];
                                }
                                $customer->joinGroup($groupRole[0], $roleId);
                            }
                        }
                    } else {
                        // Пользователь найден - обновляем данные
                        $profile = $customer->getOne('Profile');
                        if ($profile) {
                            $changed = false;
                            
                            if (!empty($phone) && $profile->get('mobilephone') != $phone) {
                                $profile->set('mobilephone', $phone);
                                $changed = true;
                            }
                            
                            if (!empty($email) && $profile->get('email') != $email) {
                                $profile->set('email', $email);
                                $changed = true;
                            }
                            
                            if (!empty($receiver) && $profile->get('fullname') != $receiver) {
                                $profile->set('fullname', $receiver);
                                $changed = true;
                            }
                            
                            if ($changed) {
                                $profile->save();
                            }
                        }
                    }
                }
            }
    
            $response = $this->invokeEvent('msOnGetOrderCustomer', [
                'order' => $this->order,
                'customer' => $customer,
            ]);
            if (!$response['success']) {
                return $response['message'];
            }
    
            return $customer instanceof modUser ? $customer->get('id') : 0;
        }
      Тодор
      19 февраля 2026, 19:45
      0
      • Расширяешь класс msOrderHandler (поключение)
      • Копируете из старого submit
      • Заменяешь там
        $user_id = $this->ms2->getCustomerId();
        на
        $user_id = $this->getReceiverId();
      • Добавляешь новый метод getReceiverId в новообразованный класс и меняешь его как хочешь
        Дмитрий
        20 февраля 2026, 09:44
        0
        Спасибо! Но есть ряд вопросов, в рамках того, что я сильно не сведущ…
        я уже как-то подключал свой обработчик доставки.
        имеет ли значение в какой папке будет лежать новый файл my_msOrderHandler

        метод это когда начинается с «public function»?

        Т.е. посути в новом файле должно остаться метод submit с теми изменениями что вы написали и мой метод, который я постил в предыдущем комментарии?
          Дмитрий
          20 февраля 2026, 10:59
          0
          и вот еще какой вопрос…

          в документации прописано вот так:

          if (!class_exists('msDeliveryInterface')) {
            require_once dirname(dirname(dirname(__FILE__))) . '/model/minishop2/msdeliveryhandler.class.php';
          }
          
          class msDeliveryHandlerMsk extends msDeliveryHandler implements msDeliveryInterface {
          пример подключения собственного класса доставки.

          ИИ говорит мне, что интерфейс не нужно подключать для msOrderHandler

          т.е. этот кусок получается лишний в моем случае?
          if (!class_exists('msDeliveryInterface')) {
            require_once dirname(dirname(dirname(__FILE__))) . '/model/minishop2/msdeliveryhandler.class.php';
          }
            Дмитрий
            20 февраля 2026, 19:28
            0
            В общем убил целый день, но… так у меня ничего и не вышло.
            не могу зарегистрировать класс.

            содержание самого файла my_msorderhandler.class.php:

            <?php
            if (!class_exists('msOrderHandler')) {  // проверяем интерфейс заказа
                require_once MODX_CORE_PATH . 'components/minishop2/handlers/msorderhandler.class.php';
            }
            
            class my_OrderHandler extends msOrderHandler {  // implements msOrderInterface не нужен
                public function submit($data = [])
                    {
                        
                        $response = $this->ms2->invokeEvent('msOnSubmitOrder', [
                            'data' => $data,
                            'order' => $this,
                        ]);
                        if (!$response['success']) {
                            return $this->error($response['message']);
                        }
                        if (!empty($response['data']['data'])) {
                            $this->set($response['data']['data']);
                        }
                
                        $response = $this->getDeliveryRequiresFields();
                        if ($this->ms2->config['json_response']) {
                            $response = json_decode($response, true);
                        }
                        if (!$response['success']) {
                            return $this->error($response['message']);
                        }
                        $requires = $response['data']['requires'];
                
                        $errors = [];
                        foreach ($requires as $v) {
                            if (!empty($v) && empty($this->order[$v])) {
                                $errors[] = $v;
                            }
                        }
                        if (!empty($errors)) {
                            return $this->error('ms2_order_err_requires', $errors);
                        }
                
                        $user_id = $this->getReceiverId();
                        if (empty($user_id) || !is_int($user_id)) {
                            return $this->error(is_string($user_id) ? $user_id : 'ms2_err_user_nf');
                        }
                
                        $cart_status = $this->ms2->cart->status();
                        if (empty($cart_status['total_count'])) {
                            return $this->error('ms2_order_err_empty');
                        }
                
                        $delivery_cost = $this->getCost(false, true);
                        $cart_cost = $this->getCost(true, true) - $delivery_cost;
                        $num = $this->getNewOrderNum();
                
                        /** @var msOrder $msOrder */
                        $msOrder = $this->storageHandler->getForSubmit(
                            compact('user_id', 'num', 'cart_cost', 'cart_status', 'delivery_cost')
                        );
                
                        $response = $this->ms2->invokeEvent('msOnBeforeCreateOrder', [
                            'msOrder' => $msOrder,
                            'order' => $this,
                        ]);
                        if (!$response['success']) {
                            return $this->error($response['message']);
                        }
                
                        if ($msOrder->save()) {
                            $response = $this->ms2->invokeEvent('msOnCreateOrder', [
                                'msOrder' => $msOrder,
                                'order' => $this,
                            ]);
                            if (!$response['success']) {
                                return $this->error($response['message']);
                            }
                
                            if ($this->storage === 'session') {
                                $this->ms2->cart->clean();
                                $this->clean();
                            }
                            if (empty($_SESSION['minishop2']['orders'])) {
                                $_SESSION['minishop2']['orders'] = [];
                            }
                            $_SESSION['minishop2']['orders'][] = $msOrder->get('id');
                
                            // Trying to set status "new"
                            $status_new = $this->modx->getOption('ms2_status_new', null, 1);
                            $response = $this->ms2->changeOrderStatus($msOrder->get('id'), $status_new);
                            if ($response !== true) {
                                return $this->error($response, ['msorder' => $msOrder->get('id')]);
                            }
                
                            // Reload order object after changes in changeOrderStatus method
                            /** @var msOrder $msOrder */
                            $msOrder = $this->modx->getObject('msOrder', ['id' => $msOrder->get('id')]);
                
                            /** @var msPayment $payment */
                            $payment = $this->modx->getObject(
                                'msPayment',
                                ['id' => $msOrder->get('payment'), 'active' => 1]
                            );
                            if ($payment) {
                                $response = $payment->send($msOrder);
                                if ($this->config['json_response']) {
                                    @session_write_close();
                                    echo is_array($response) ? json_encode($response) : $response;
                                    die();
                                }
                                if (!empty($response['data']['redirect'])) {
                                    $this->modx->sendRedirect($response['data']['redirect']);
                                }
                                if (!empty($response['data']['msorder'])) {
                                    $redirect = $this->modx->context->makeUrl(
                                        $this->modx->resource->id,
                                        ['msorder' => $response['data']['msorder']]
                                    );
                                    $this->modx->sendRedirect($redirect);
                                }
                                $this->modx->sendRedirect($this->modx->context->makeUrl($this->modx->resource->id));
                            } else {
                                if ($this->config['json_response']) {
                                    return $this->success('', ['msorder' => $msOrder->get('id')]);
                                }
                                $redirect = $this->modx->context->makeUrl(
                                    $this->modx->resource->id,
                                    ['msorder' => $msOrder->get('id')]
                                );
                                $this->modx->sendRedirect($redirect);
                            }
                            return $this->success();
                        }
                
                        return $this->error();
                    }
                    
                    
                    public function getCustomerId() {
                error_log("🔥🔥🔥 getCustomerId() НАЧАЛО 🔥🔥🔥");
            
                    $customer = null;
            
                    $response = $this->invokeEvent('msOnBeforeGetOrderCustomer', [
                        'order' => $this->order,
                        'customer' => $customer,
                    ]);
                    if (!$response['success']) {
                        return $response['message'];
                    }
            
                    if (!$customer) {
                        $data = $this->order->get();
                        $email = $data['email'] ?? '';
                        $receiver = $data['receiver'] ?? '';
                        $phone = $data['phone'] ?? '';
                        
                        // Функция для приведения телефона к международному формату +КодСтраныНомер
                        $formatPhone = function($phone) {
                            if (empty($phone)) return '';
                            
                            // Удаляем все нецифровые символы
                            $phone = preg_replace('/[^0-9]/', '', $phone);
                            
                            // Определяем код страны по умолчанию (Россия)
                            $defaultCountryCode = '7';
                            
                            // Если номер начинается с 8 (Россия)
                            if (substr($phone, 0, 1) == '8') {
                                $phone = $defaultCountryCode . substr($phone, 1);
                            }
                            // Если номер без кода (10 цифр) - добавляем код по умолчанию
                            elseif (strlen($phone) == 10) {
                                $phone = $defaultCountryCode . $phone;
                            }
                            // Если номер начинается с 7 (уже есть код России)
                            elseif (substr($phone, 0, 1) == '7' && strlen($phone) == 11) {
                                // Оставляем как есть
                            }
                            // Если номер с другим кодом страны
                            elseif (strlen($phone) > 11 || (strlen($phone) == 11 && substr($phone, 0, 1) != '7')) {
                                // Оставляем как есть (уже содержит код страны)
                            }
                            
                            // Добавляем знак + в начало
                            return '+' . $phone;
                        };
                        
                        // Приводим телефон к единому формату
                        $formattedPhone = $formatPhone($phone);
                        
                        // Обновляем телефон в данных заказа
                        if ($formattedPhone !== $phone) {
                            $data['phone'] = $formattedPhone;
                            $this->order->set($data);
                            $phone = $formattedPhone;
                        }
                        
                        // Формируем receiver, если он пустой
                        if (empty($receiver)) {
                            if (!empty($phone)) {
                                $receiver = preg_replace('/[^0-9]/', '', $phone);
                            } elseif (!empty($email)) {
                                $receiver = substr($email, 0, strpos($email, '@'));
                            } else {
                                $receiver = uniqid('user_', false);
                            }
                        }
                        
                        // Формируем email, если он пустой
                        if (empty($email)) {
                            if (!empty($phone)) {
                                $cleanPhone = preg_replace('/[^0-9]/', '', $phone);
                                $email = 'user_' . $cleanPhone . '@' . $this->modx->getOption('http_host');
                            } else {
                                $email = $receiver . '@' . $this->modx->getOption('http_host');
                            }
                        }
            
                        // Если пользователь авторизован
                        if ($this->modx->user->isAuthenticated()) {
                            $profile = $this->modx->user->Profile;
                            
                            if (!$profile->get('email')) {
                                $profile->set('email', $email);
                            }
                            
                            if (!empty($phone) && $profile->get('mobilephone') != $phone) {
                                $profile->set('mobilephone', $phone);
                            }
                            
                            if (!empty($receiver) && $profile->get('fullname') != $receiver) {
                                $profile->set('fullname', $receiver);
                            }
                            
                            $profile->save();
                            $customer = $this->modx->user;
                            
                        } else {
                            // Поиск существующего пользователя
                            $c = $this->modx->newQuery('modUser');
                            $c->leftJoin('modUserProfile', 'Profile');
                            
                            $filter = [];
                            
                            if (!empty($phone)) {
                                $filter['modUser.username'] = $phone;
                                $filter['OR:Profile.mobilephone:='] = $phone;
                            }
                            
                            if (!empty($email)) {
                                $filter['OR:Profile.email:='] = $email;
                            }
                            
                            $c->where($filter);
                            $c->select('modUser.id');
                            
                            // Пытаемся найти пользователя
                            if (!$customer = $this->modx->getObject('modUser', $c)) {
                                // Создаем нового пользователя
                                $userData = [
                                    'username' => !empty($phone) ? $phone : $email,
                                    'password' => md5(rand()),
                                    'active' => 1
                                ];
                                
                                $customer = $this->modx->newObject('modUser', $userData);
                                
                                $profileData = [
                                    'fullname' => $receiver,
                                ];
                                
                                if (!empty($email)) {
                                    $profileData['email'] = $email;
                                }
                                
                                if (!empty($phone)) {
                                    $profileData['mobilephone'] = $phone;
                                }
                                
                                $profile = $this->modx->newObject('modUserProfile', $profileData);
                                $customer->addOne($profile);
                                
                                // Добавляем настройку языка
                                $setting = $this->modx->newObject('modUserSetting');
                                $setting->fromArray([
                                    'key' => 'cultureKey',
                                    'value' => $this->modx->getOption('cultureKey', null, 'en', true),
                                ], '', true);
                                $customer->addMany($setting);
                                
                                if (!$customer->save()) {
                                    $customer = null;
                                } elseif ($groups = $this->modx->getOption('ms2_order_user_groups', null, false)) {
                                    $groupRoles = array_map('trim', explode(',', $groups));
                                    foreach ($groupRoles as $groupRole) {
                                        $groupRole = explode(':', $groupRole);
                                        $roleId = null;
                                        if (count($groupRole) > 1 && !empty($groupRole[1])) {
                                            $roleId = is_numeric($groupRole[1]) ? (int)$groupRole[1] : $groupRole[1];
                                        }
                                        $customer->joinGroup($groupRole[0], $roleId);
                                    }
                                }
                            } else {
                                // Пользователь найден - обновляем данные
                                $profile = $customer->getOne('Profile');
                                if ($profile) {
                                    $changed = false;
                                    
                                    if (!empty($phone) && $profile->get('mobilephone') != $phone) {
                                        $profile->set('mobilephone', $phone);
                                        $changed = true;
                                    }
                                    
                                    if (!empty($email) && $profile->get('email') != $email) {
                                        $profile->set('email', $email);
                                        $changed = true;
                                    }
                                    
                                    if (!empty($receiver) && $profile->get('fullname') != $receiver) {
                                        $profile->set('fullname', $receiver);
                                        $changed = true;
                                    }
                                    
                                    if ($changed) {
                                        $profile->save();
                                    }
                                }
                            }
                        }
                    }
            
                    $response = $this->invokeEvent('msOnGetOrderCustomer', [
                        'order' => $this->order,
                        'customer' => $customer,
                    ]);
                    if (!$response['success']) {
                        return $response['message'];
                    }
            
                    return $customer instanceof modUser ? $customer->get('id') : 0;
                }
                    
            }

            согласно священописанию в консоле делаю так:
            <?php
            if ($miniShop2 = $modx->getService('miniShop2')) {
              $miniShop2->addService('order', 'my_OrderHandler',
                  '{core_path}components/minishop2/custom/order/my_msorderhandler.class.php');
            }
            Пробую, и ничего не меняется. На пару с ИИ добрел до системной настройки, с ключем ms2_order_handler_class и там указал свой класс. Перестало работать вообще. Т.е. тыкаю на кнопку «сделать заказ» на самом сайте и ничего не происходит.
            Из чего делаю вывод, что класс мой не зарегистрировался.

            Дальше меняю настройку ms2_services.
            она у меня выглядела так:
            {«cart»:[],«order»:[«my_OrderHandler»],«payment»:[],«delivery»:{«mydelivery»:"{core_path}components\/minishop2\/custom\/delivery\/my_msdeliveryhandler.class.php"}}

            т.к. я уже ранее подрубал собственную службу доставки, и она вроде как исправно работает, делаю по образу и подобию с order, хотя ИИ визжит, что так делать нельзя, и у этой настройки должно быть только название класса.

            В логах живет вот такая ошибка:

            (ERROR @ /home/c/cz42644/test-iflower/public_html/core/components/minishop2/model/minishop2/minishop2.class.php: 484) [miniShop2] Could not load custom class at "/home/c/cz42644/test-iflower/public_html/my_OrderHandler"
            Т.е. я так понимаю, он ищет файл с моей службой почему-то не так где надо, по сути в корне. И как ему указать, где искать — не ведаю.

            Вообщем, итог такой, что либо ничего не меняется, либо не работает вовсе.

            Что и где я делаю не так?
              Тодор
              Вчера в 23:53
              0
              Етот кусок кода отвечает за то что бы менялась настройка ms2_services
              <?php
              if ($miniShop2 = $modx->getService('miniShop2')) {
                $miniShop2->addService('order', 'my_OrderHandler',
                    '{core_path}components/minishop2/custom/order/my_msorderhandler.class.php');
              }
              После чего у тебя ms2_services должен быть таким
              {"cart":[],"order":{"my_OrderHandler":"{core_path}components\/minishop2\/custom\/order\/my_msorderhandler.class.php"},"payment":[],"delivery":{"mydelivery":"{core_path}components\/minishop2\/custom\/delivery\/my_msdeliveryhandler.class.php"}}
              Тебе надо делать только одно из двух либо регистировать клас через консоль либо в сис. настройках.

              В зависимости от версии minishopа может быть разный путь к msOrderHandler, убедись что етот файл существует
              require_once MODX_CORE_PATH . 'components/minishop2/handlers/msorderhandler.class.php';
              А еще в submit ты поменял $user_id = $this->ms2->getCustomerId(); на $user_id = $this->getReceiverId(); Но новый метод ты не назвал getReceiverId
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        10