Недавно наткнулся на платный компонент msCustomerAutoReg (490 руб.), который позволяет регистрировать пользователей после оформления заказа. Сказать, что я удивился, это не сказать ничего. Мало того, что компонент платный, так и способ реализации задачи достаточно некорректный, с моей точки зрения. На вопрос: можно сделать лучше и штатными средствами? Я отвечу: можно! И даже нужно!
Начнем с того, что после оформления заказа miniShop2 автоматически регистрирует пользователя на сайте, только данные пользователя на почту не высылаются. В сети предлагают кучу решений данной задачи, но все они сводятся к тому, что после оформления заказа пользователю отсылается второе письмо с данными от личного кабинета. Не считаю, что два письма отсылать корректно. Поэтому делюсь своими наработками в данном направлении.
Компонент miniShop2 обладает широкими возможностями для масштабирования, за что разработчику огромное спасибо. В частности, мы можем переопределить стандартные методы классов. Что и послужит нам отличным инструментом для решения данной задачи. Нам нужно переопределить всего один метод changeOrderStatus, для этого создаем файл orderCustomHandler.class.php в директории /core/components/minishop2/custom/order/ со следующим содержимым:
<?php
class orderCustomHandler extends msOrderHandler{
/**
* Switch order status
*
* @param integer $order_id The id of msOrder
* @param integer $status_id The id of msOrderStatus
*
* @return boolean|string
*/
public function changeOrderStatus($order_id, $status_id)
{
/** @var msOrder $order */
if (!$order = $this->modx->getObject('msOrder', array('id' => $order_id), false)) {
return $this->modx->lexicon('ms2_err_order_nf');
}
$ctx = $order->get('context');
$this->modx->switchContext($ctx);
$this->initialize($ctx);
// This method could be overwritten from custom order handler
if (is_object($this->order) && method_exists($this->order, 'changeOrderStatus')) {
return $this->order->changeOrderStatus($order_id, $status_id);
}
$error = '';
/** @var msOrderStatus $status */
if (!$status = $this->modx->getObject('msOrderStatus', array('id' => $status_id, 'active' => 1))) {
$error = 'ms2_err_status_nf';
} /** @var msOrderStatus $old_status */
else {
if ($old_status = $this->modx->getObject('msOrderStatus',
array('id' => $order->get('status'), 'active' => 1))
) {
if ($old_status->get('final')) {
$error = 'ms2_err_status_final';
} else {
if ($old_status->get('fixed')) {
if ($status->get('rank') <= $old_status->get('rank')) {
$error = 'ms2_err_status_fixed';
}
}
}
}
}
if ($order->get('status') == $status_id) {
$error = 'ms2_err_status_same';
}
if (!empty($error)) {
return $this->modx->lexicon($error);
}
$response = $this->ms2->invokeEvent('msOnBeforeChangeOrderStatus', array(
'order' => $order,
'status' => $order->get('status'),
));
if (!$response['success']) {
return $response['message'];
}
$order->set('status', $status_id);
if ($order->save()) {
$this->ms2->orderLog($order->get('id'), 'status', $status_id);
$response = $this->ms2->invokeEvent('msOnChangeOrderStatus', array(
'order' => $order,
'status' => $status_id,
));
if (!$response['success']) {
return $response['message'];
}
$lang = $this->modx->getOption('cultureKey', null, 'en', true);
if ($tmp = $this->modx->getObject('modUserSetting', array('key' => 'cultureKey', 'user' => $order->get('user_id')))) {
$lang = $tmp->get('value');
}
else if ($tmp = $this->modx->getObject('modContextSetting', array('key' => 'cultureKey', 'context_key' => $order->get('context')))) {
$lang = $tmp->get('value');
}
$this->modx->setOption('cultureKey', $lang);
$this->modx->lexicon->load($lang . ':minishop2:default', $lang . ':minishop2:cart');
$pls = $order->toArray();
$pls['cost'] = $this->ms2->formatPrice($pls['cost']);
$pls['cart_cost'] = $this->ms2->formatPrice($pls['cart_cost']);
$pls['delivery_cost'] = $this->ms2->formatPrice($pls['delivery_cost']);
$pls['weight'] = $this->ms2->formatWeight($pls['weight']);
$pls['payment_link'] = '';
if ($payment = $order->getOne('Payment')) {
if ($class = $payment->get('class')) {
$this->ms2->loadCustomClasses('payment');
if (class_exists($class)) {
/** @var msPaymentHandler|PayPal $handler */
$handler = new $class($order);
if (method_exists($handler, 'getPaymentLink')) {
$link = $handler->getPaymentLink($order);
$pls['payment_link'] = $link;
}
}
}
}
$userId = $pls["user_id"];
$user = $this->modx->getObject("modUser", $userId);
if($user){
$time = time();
$newUser = 10;
$username = $user->get("username");
$createdon = strtotime($user->get("createdon")) + $newUser;
if($createdon > $time){
$length = 8;
$pass = $this->modx->user->generatePassword($length);
$user->set("password", $pass);
$user->save();
$pls["userdata"] = array(
"username" => $username,
"password" => $pass,
);
$user->addSessionContext("web");
}
}
if ($status->get('email_manager')) {
$subject = $this->ms2->pdoTools->getChunk('@INLINE ' . $status->get('subject_manager'), $pls);
$tpl = '';
if ($chunk = $this->modx->getObject('modChunk', array('id' => $status->get('body_manager')))) {
$tpl = $chunk->get('name');
}
$body = $this->modx->runSnippet('msGetOrder', array_merge($pls, array('tpl' => $tpl)));
$emails = array_map('trim', explode(',',
$this->modx->getOption('ms2_email_manager', null, $this->modx->getOption('emailsender')))
);
if (!empty($subject)) {
foreach ($emails as $email) {
if (preg_match('#.*?@.*#', $email)) {
$this->ms2->sendEmail($email, $subject, $body);
}
}
}
}
if ($status->get('email_user')) {
if ($profile = $this->modx->getObject('modUserProfile', array('internalKey' => $pls['user_id']))) {
$subject = $this->ms2->pdoTools->getChunk('@INLINE ' . $status->get('subject_user'), $pls);
$tpl = '';
if ($chunk = $this->modx->getObject('modChunk', array('id' => $status->get('body_user')))) {
$tpl = $chunk->get('name');
}
$body = $this->modx->runSnippet('msGetOrder', array_merge($pls, array('tpl' => $tpl)));
$email = $profile->get('email');
if (!empty($subject) && preg_match('#.*?@.*#', $email)) {
$this->ms2->sendEmail($email, $subject, $body);
}
}
}
}
return true;
}
}
Как видите, мы просто добавили небольшой блок, который позволяет нам вывести данные по личному кабинету прямо в письме о новом заказе. Что чертовски круто. Теперь переходим в системные настройки в разде miniShop2 и меняем значение настройки ms2_order_handler_class на orderCustomHandler.
Далее просто редактируем стандартный чанк tpl.msEmail, добавляя блок с данными о заказе (всегда мучал вопрос почему из коробки этого нет) и данными от личного кабинета:
<div style="width:90%;margin:auto;">
{if $user.fullname}<p><strong>Ф.И.О.:</strong> {$user.fullname}</p>{/if}
{if $user.email}<p><strong>E-mail:</strong> {$user.email}</p>{/if}
{if $address.phone}<p><strong>Телефон:</strong> {$address.phone}</p>{/if}
{if $address.city}<p><strong>Город:</strong> {$address.city}</p>{/if}
{if $address.street}<p><strong>Адрес:</strong> {$address.street}{/if}
{if $address.building} {$address.building}{/if}
{if $address.room} {$address.room}</p>{/if}
{if $address.comment}<p><strong>Комментарии:</strong> {$address.comment}</p>{/if}
{if $delivery.name}<p><strong>Доставка:</strong> {$delivery.name}</p>{/if}
{if $payment.name}<p><strong>Оплата:</strong> {$payment.name}</p>{/if}
{if $userdata}
<h3 style="{$style.h}{$style.h3}">Данные для входа в личный кабинет:</h3>
<div style="padding: 0 20px;">
<strong>Логин:</strong> {$userdata.username}<br/>
<strong>Пароль:</strong> {$userdata.password}
</div>
{/if}
</div>
Вот и все! Несколько минут работы, сэкономленные 490 руб. и полученные новые навыки. Неплохо правда?
[20-Aug-2021 11:40:33 Europe/Moscow] PHP Fatal error: Uncaught Error: Call to undefined method orderCustomHandler::loadCustomClasses() in /home/site/core/components/minishop2/custom/order/orderCustomHandler.class.php:92 Stack trace: #0 /home/site/core/components/minishop2/model/minishop2/minishop2.class.php(741): orderCustomHandler->changeOrderStatus(15701, 1) #1 /home/site/core/components/minishop2/model/minishop2/msorderhandler.class.php(475): miniShop2->changeOrderStatus(15701, 1) #2 /home/site/core/components/minishop2/model/minishop2/minishop2.class.php(194): msOrderHandler->submit(Array) #3 /home/site/core/cache/includes/elements/modplugin/14.include.cache.php(21): miniShop2->handleRequest('order/submit', Array) #4 /home/site/core/model/modx/modscript.class.php(76): include('/home/site/co...') #5 /home/site/core/model/modx/modx.class.php(1674): modScript->process(NULL) #6 /home/site/core/model/modx/modrequest.class.php(70): modX->invokeEvent('OnHandleRequest') #7 /home/site/core/model/modx/modx.class.php(1461): modRequest->handleRequest in /home/site/core/components/minishop2/custom/order/orderCustomHandler.class.php on line 92if ($payment = $order->getOne('Payment')) { 92-я строка: if ($class = $payment->get('class')) { $this->loadCustomClasses('payment'); if (class_exists($class)) { /** @var msPaymentHandler|PayPal $handler */ $handler = new $class($order); if (method_exists($handler, 'getPaymentLink')) { $link = $handler->getPaymentLink($order); $pls['payment_link'] = $link; } } } }$this->loadCustomClasses('payment');Нужно писать вот так:$this->ms2->loadCustomClasses('payment');Так как у orderHandler нет метода loadCustomClasses. Изначально это функция взята из другого класса. У меня в коде была опечатка.Сейчас мне надо модифицировать sendEmail в minishop.class.php, делаю так же по вашему примеру и ничего не происходит, запускается старый метод. Подскажите куда копать