Pull to refresh

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

Reading time6 min
Views1.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:
Total votes 8: ↑7 and ↓1+6
Comments10

Articles