Pull to refresh

Magento, подписка на новости во время чекаута

Reading time 6 min
Views 1.8K
Оу, оказывается здесь даже есть целый один пост про разработку под Magento. Мне тоже есть что сказать. Интересно, будет ли это кому-нибудь интересно…

Итак, задача — добавить галочку «Получать новости» к одному из шагов чекаута (checkout — «проход через кассу»).



Сразу стало ясно, что придётся писать новый модуль, т.к. модификации дизайнерских файлов здесь не хватит. Как можно добавить своё поле к какому-либо шагу чекаута, можно подсмотреть у модулей Desitex Checkoutnewsletter (он добавляет галочку «подписать на новости» во второй шаг, где надо указать billing address) и у Biebersdorf CustomerOrderComment (он добавляет поле для добавления комментария в последний шаг — страницу подтверждения заказа).

Опускаю процесс копания в указанных модулях и поиска решения :) В итоге, что бы всё получилось, нужно:
  • Модифицировать дизайнерский файл, который рисует нужную страницу чекаута — добавить туда галочку;
  • Каким-либо образом подписаться на событие «сохранение страницы чекаута», что бы:
  • Запомнить состояние галочки в текущей сессии
  • Обработать событие «оформление заказа», возникающее когда пользователь уже оформил заказ, перед тем как сайт перенаправит его на сайт для оплаты (например, PayPal, AlliedWallet). Здесь надо извлечь сохранённое значение из сессии и подписать пользователя на рассылку, если он этого хочет.

Создание модуля


Прежде всего создадим модуль. Пусть он будет в пространстве имён Mage, а называться будет NewsletterSubscribe.

Сначала нужно сказать Magento, что наш модуль есть — создаём файл Mage_NewsletterSubscribe.xml в папке app/etc/modules:

<?xml version="1.0"?>
<config>
    <modules>
        <Mage_NewsletterSubscribe>
            <active>true</active>
            <codePool>local</codePool>
        </Mage_NewsletterSubscribe>
    </modules>
</config>

Согласно XML, модуль активен и находится в пуле local.

Далее создаём папку где будет находится новый модуль — app/code/local/Mage/NewsletterSubscribe, и файл конфигурации config.xml в папке app/code/local/Mage/NewsletterSubscribe/etc:

<?xml version="1.0"?>
<config>
    <global>
        <helpers>
            <newslettersubscribe>
                <class>Mage_NewsletterSubscribe_Helper</class>
            </newslettersubscribe>
        </helpers>
    </global>
</config>

Без хелпера модуль не будет работать как надо, а будет вместо этого падать. Поэтому дадим Magento хелпер, пусть и пустой — файл Data.php в папке Helper:
<?php

class Mage_NewsletterSubscribe_Helper_Data extends Mage_Core_Helper_Abstract {

}

Модификация страницы чекаута


Файл, рисующий нужную страницу чекаута — app\design\frontend\default\sunnyD\template\checkout\onepage\payment\methods.phtml. Добавляем галочку:

...
<?php /* bof Subscribe for newsletter checkbox */ ?>
<dt>Join Our Mailing List</dt>
<dd>
    <input type="checkbox" name="NewsletterSubscribe" id="NewsletterSubscribe" checked="checked" />
    <label for="NewsletterSubscribe"><?php echo Mage::helper('newslettersubscribe')->__('I would like to receive the Century Supplements newsletter') ?></label>
</dd>
<?php /* eof Subscribe for newsletter checkbox */ ?>
...

Да, теперь мы видим нашу галочку на странице выбора метода оплаты. Но почему же она неактивна? А потому что она сделана неактивной JS кодом, расположенным в конце файла:

<script type="text/javascript">payment.init();</script>

Не разбирался зачем он нужен, но в данном случае он делает неактивными все тэги <input>. Выходит, нам надо активировать нашу галочку после выполнения этого кода:

<script type="text/javascript">payment.init();</script>

<script type="text/javascript">$('NewsletterSubscribe').disabled = false;</script>

Теперь галочка стала активна, идём дальше.

Событие «сохранение страницы чекаута»


Я подсмотрел как это делает Checkoutnewsletter. В конфигурационном файле модуля есть строки, которые видимо перехватывают действия, связанные со всем чекаутом, всеми его страницами:

<?xml version="1.0"?>
<config>
    ...
    <global>
        <models>
            <checkout>
                <rewrite>
                    <type_onepage>Desitex_Checkoutnewsletter_Model_Checkout_Type_Onepage</type_onepage>
                </rewrite>
            </checkout>
    ...
</config>

Стандартный класс Mage_Checkout_Model_Type_Onepage заменяется классом модуля Desitex_Checkoutnewsletter_Model_Checkout_Type_Onepage (который наследуется от оригинального класса Mage_Checkout_Model_Type_Onepage). В этом классе переопределён всего один метод:

<?php

class Desitex_Checkoutnewsletter_Model_Checkout_Type_Onepage extends Mage_Checkout_Model_Type_Onepage
{
    public function saveBilling($data, $customerAddressId)
    {
        if (isset($data['is_subscribed']) && !empty($data['is_subscribed'])){
            $this->getCheckout()->setCustomerIsSubscribed(1);
        }
        else {
            $this->getCheckout()->setCustomerIsSubscribed(0);
        }
        return parent::saveBilling($data, $customerAddressId);
    }
}

Очевидно, действие saveBilling возникает когда пользователь переходит со страницы ввода billing address (нажимает кнопку Continue). Здесь модуль сохраняет значение своей галочки «подписываться ли на новости» в текущей сессии (или чекауте...). После этого вызывает оригинальный метод стандартного класса.

Мы поступим подобным образом — сделаем класс, отнаследуем его от стандартного, и переопределяем только один метод, возникающий при сохранении формы на нашей странице. Метод будет сохранять значение нашей галочки. Класс поместим в файл Model/Onepage.php.:

<?php

class Mage_NewsletterSubscribe_Model_Onepage extends Mage_Checkout_Model_Type_Onepage {
    public function savePayment($data) {
        if (isset($_POST['NewsletterSubscribe'])){
            $this->getCheckout()->setNewsletterSubscribe((bool) $_POST['NewsletterSubscribe']);
        }
        else {
            $this->getCheckout()->setNewsletterSubscribe(false);
        }
        return parent::savePayment($data);
    }
}

Здесь меня немного настиг ступор. Значение галочки находится среди значений формы, но из текущего места у меня нет доступа к этим переменным. Т.е. доступа к объекту Magento Request, хранящему все GET и POST переменные. Доступны разные интересные объекты типа Quote, Checkout и т.д., с разным интересными данными, но не значениями формы. Я почти отчаялся, соображая что переписывать код ядра очень плохо, но потом вспомнил, что это Php, а значит в любом месте доступны переменные $_GET и $_POST :) Проблема была решена.

Теперь скажем Magento, что бы вместо стандартного класса брал наш. Редактируем etc/config.xml:

<?xml version="1.0"?>
<config>
    <global>
        <models>
            <checkout>
                <rewrite>
                    <type_onepage>Mage_NewsletterSubscribe_Model_Onepage</type_onepage>
                </rewrite>
            </checkout>
        </models>
    ...
</config>

Здесь готово. Только видимо есть одно ограничение — переопределить стандартный класс может только один модуль. Мой метод не вызывался, пока я не убрал переопределение у модуля Checkoutnewsletter. Т.е. это не обычное событие, на которое может подписаться произвольное количество слушателей. Потенциальные трудноотлаживаемые проблемы в будущем :(

Событие «оформление заказа»


В отличии от предыдущего «события», оформление заказа это «настоящее» событие checkout_type_onepage_save_order. Что бы подписаться на него нужно изменить конфиг модуля etc/config.xml:

<?xml version="1.0"?>
<config>
    <global>
        ...
        <events>
            <checkout_type_onepage_save_order>
                <observers>
                    <mage_newslettersubscribe_observer>
                        <type>singleton</type>
                        <class>newslettersubscribe/observer</class>
                        <method>onOrderSave</method>
                    </mage_newslettersubscribe_observer>
                </observers>
            </checkout_type_onepage_save_order>
        </events>
    </global>
</config>

Здесь мы указали какой метод у какого класса вызвать (Mage_NewsletterSubscribe_Model_Observer::onOrderSave), когда пользователь оформит заказ. Теперь создадим этот класс и метод — файл /Model/Observer.php:

<?php
class Mage_NewsletterSubscribe_Model_Observer extends Mage_Core_Helper_Abstract {
    public function onOrderSave($observer) {
        $isCustomerSubscribed = (bool) Mage::getSingleton('checkout/session')->getNewsletterSubscribe();
        if ($isCustomerSubscribed) {
            $quote = $observer->getEvent()->getQuote();
            $session = Mage::getSingleton('core/session');
            try {
                $status = Mage::getModel('newsletter/subscriber')->subscribe($quote->getBillingAddress()->getEmail());
                if ($status == Mage_Newsletter_Model_Subscriber::STATUS_NOT_ACTIVE){
                    $session->addSuccess(Mage::helper('checkoutnewsletter')->__('Confirmation request has been sent regarding your newsletter subscription'));
                }
            }
            catch (Mage_Core_Exception $e) {
                $session->addException($e, Mage::helper('checkoutnewsletter')->__('There was a problem with the newsletter subscription: %s', $e->getMessage()));
            }
            catch (Exception $e) {
                $session->addException($e, Mage::helper('checkoutnewsletter')->__('There was a problem with the newsletter subscription'));
            }
        }

        return $this;
    }
}

Этот код я взял из модуля Checkoutnewsletter, только переделал его что бы он работал. К счастью в Magento есть класс, позволяющий подписывать пользователей на новости. По-сути всё что нужно сделать — вызвать Mage::getModel('newsletter/subscriber')->subscribe(<user email>);

Итог


В итоге получился небольшой модуль, выполняющий поставленную задачу.
Tags:
Hubs:
+6
Comments 10
Comments Comments 10

Articles