Создание модуля PrestaShop: инструкция

Модули — это идеальный способ выразить свой талант и воображение, а также проявить себя, поскольку они дают много возможностей.

Создание модуля PrestaShop: инструкция

Привет, ребята!

Учусь разрабатывать модули Престашоп. И хочу поделиться с вами накопленными знаниями и материалами. Кстати, огромная благодарность всем авторам, которые уделяли свое время написанию обучающих статей и публикации советов по разработке! Сегодня в блоге веб-мастерской MAKE-WEBSITE.ru проведем общий анализ структуры модуля PrestaShop и разработаем простой модуль, выводящий на сайт интернет-магазина небольшой текстовый блок. Пусть это будет своеобразным конспектом по написанию модуля. Но прежде чем приступим к разбору модуля и его кода, давайте вначале рассмотрим несколько понятий, с которыми сталкивается разработчик на Престашоп. Поговорим про хуки, smarty и работу с базой данных.

Про хуки

Хуки – это способ связать ваш код с некоторыми конкретными событиями PrestaShop. Есть 2 типа хуков:

  1. Display (дисплей). Эти хуки приводят к тому, что что-то отображается либо в фронт-офисе, либо в бэк-офисе. Другими словами хуки используются для вывода результатов работы модуля в определенном месте страницы. Это могут быть: номер телефона в шапке сайта или блок «Популярные товары» в левой колонке.

    Примеры: displayHeader, displayFooter, displayLeftColumn.
  2. Action (действие). Эти хуки запускаются конкретными событиями, которые происходят в PrestaShop. Например, фиксировать заход посетителя на главную страницу.

    Примеры: actionObjectProductAddAfter, actionObjectProductDeleteBefore, actionCarrierUpdate.

Примеры хуков типа Display:

Хуки движка Престашоп

Использование хуков в модуле

Для этого в классе модуля создается публичный метод, начинающийся с “hook” и содержащий имя хука. Например, для вывода информации в левом столбце код будет выглядеть так:

public function hookDisplayNameOfHook($params)
{
// Код хука.
}

В метод передается только одна переменная, содержащая массив параметров, отправляемых хуку. Чтобы метод вызывался в хуке, необходимо зарегистрировать его, используя registerHook(). Регистрация обычно делается во время установки модуля.

public function install()
{
  return parent::install() && $this->registerHook('NameOfHook');
}

При удалении модуля PrestaShop самостоятельно удалит эту регистрацию.

Полезные ссылки по теме хуков:

Документация:
https://devdocs.prestashop.com/1.7/modules/concepts/hooks/

Механизм "хуков"
http://prestalab.ru/wiki/mexanizm-xukov?s%5b%5d=хуки

Классная статья про Хуки на английском:
https://belvg.com/blog/hooks-in-prestashop.html

Smarty шаблоны .tpl

Шаблонизатор Smarty – это обработчик шаблонов PHP. Это один из инструментов, который позволяет отделить визуальную часть от серверной части сайта.

Ниже приведен пример файла шаблона news.tpl. Фактически это обычный html с вставками переменных и конструкций циклов. Все переменные заключены в фигурные скобки.

<html>
{foreach from=$news item=item}
Заголовок: {$item.title}
Текст новости:
{item.description}
<a href="index.php?id={$item.id}" mce_href="index.php?id={$item.id}">Подробнее...</a>
{/foreach}
</html>

Этот пример выводит 10 извлечённых из базы данных новостей.

Почитать о Smarty:

Руководство по Smarty
https://www.smarty.net/docsv2/ru/

How to Use Smarty Template Engine in PrestaShop 1.7
https://belvg.com/blog/smarty-template-engine-in-prestashop-1-7-basics-examples-functions.html

Configuration: работа без создания таблицы в базе данных

Данные могут быть сохранены в БД магазина без создания отдельной таблицы для конкретного модуля. В этом случае используется таблица ps_configuration. Таблица Конфигурации содержит список свойств key => value (s), к которым можно обращаться из любого места, в том числе в модуле.
Класс Configuration – это интерфейс, позволяющий каждому разработчику модуля получать или хранить данные в таблице конфигурации.

Методы

  • Configuration::get('myVariable'): извлекает определенное значение из базы данных.
  • Configuration::getMultiple(array('myFirstVariable', 'mySecondVariable', 'myThirdVariable')): извлекает несколько значений из базы данных и возвращает массив PHP.
  • Configuration::updateValue('myVariable', $value): обновляет существующую переменную базы данных с новым значением. Если переменная еще не существует, она создает ее с этим значением.
  • Configuration::deleteByName('myVariable'): удаляет переменную базы данных.

Получение внешних значений из таблицы данных ps_configuration

Вы не ограничены своими собственными переменными. PrestaShop сохраняет все свои собственные настройки конфигурации в таблице ps_configuration. Есть буквально сотни настроек, и вы можете получить к ним доступ так же легко, как и доступ к своим собственным. Покопайтесь в этой таблице, чтобы обнаружить множество других настроек! В сегодняшнем уроке вдобавок к переменным нашего модуля мы воспользуемся значением BLOCKCONTACTINFOS_PHONE.

Статья в Документации:
https://devdocs.prestashop.com/1.7/modules/concepts/configuration/ 

Что такое модуль PrestaShop?

Модули представляют собой небольшие программы, которые используют функциональность движка, меняя или расширяя ее. С помощью модулей легко можно настроить любой требующийся функционал и преобразить внешний вид сайта.

Итак, модули предназначены для изменения отображаемого контента или реакции на события. Они выполняют множество задач: пакетное обновление, импорт, экспорт, взаимодействуют с другими программами и многое другое.

Структура папки модуля

Структура папки модуля Престашоп

На рисунке представлено примерное содержимое модуля. Каких-то папок может не быть, все зависит от конкретной ситуации. Как видим, модуль включает в себя:

  1. controllers – папка содержит сontroller файлы.
  2. translations – папка для файлов перевода.
  3. upgrade – папка для файлов обновления.
  4. views– папка, содержащая файлы шаблонов .tpl:
    • /templates/admin/ – отображение чего-либо в бэк-офисе
    • /templates/hook/ – отображение чего-либо в фронт-офисе
  5. config.xml – файл конфигурации кэша. Если он еще не существует, этот файл автоматически генерируется PrestaShop, когда модуль будет установлен впервые.
  6. my_module.php – основной PHP файл.
  7. index.php – индексный файл.
  8. logo.png – файл логотипа, представляющего этот модуль в бэк-офисе.


Кроме того модуль может содержать следующие папки:

  • classes
  • config
  • controllers
  • override
  • src
  • themes

Подробнее об этом:
https://devdocs.prestashop.com/1.7/modules/creation/module-file-structure/

Основной PHP файл

Имя файла

Имя должно являться названием класса модуля в нижнем регистре. Например: mws_contentbox.

Варианты конструкций:

  1. block + название
    Например: blockreassurance, blockcontactinfos.
  2. аббревиатура автора модуля + нижнее подчеркивание + название
    Напимер: ps_contactinfo (prestashop_contactinfo), mws_contentbox (make-website_contentbox – наш сегодняшний модуль, разработанный в веб-мастерской MAKE-WEBSITE.ru).

Основной PHP файл должен иметь то же имя, что и корневая папка модуля. Так же назовите файл шаблона вывода модуля в фронт-офис. В нашем случае: mws_contentbox\views\templates\hook\mws_contentbox.tpl.

Mws_contentbox – модуль сегодняшнего урока

В этом туториале мы создадим модуль, который выводит на сайт текстовый блок с телефоном, временем работы и каким-нибудь сообщением для покупателей.

Интернет-магазин на Престашоп

Главный файл отвечает за инсталляцию модуля, настройку и привязку к системе посредством хуков. Сущность модуля в PrestaShop реализуется классом, наследованным от системного класса Module. В нашем случае это class Mws_contentbox.

Код основного PHP файла модуля mws_contentbox

<?php 
/**
* 2007-2019 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author    PrestaShop SA <contact@prestashop.com
*  @copyright 2007-2019 PrestaShop SA
*  @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
*  International Registered Trademark & Property of PrestaShop SA
*/

if (!defined('_PS_VERSION_')) {
    exit;
}

class Mws_contentbox extends Module
{
    protected $config_form = false;

    public function __construct()
    {
        $this->name = 'mws_contentbox';
        $this->tab = 'front_office_features';
        $this->version = '1.0.0';
        $this->author = 'make-website.ru';
        $this->need_instance = 1;

        /**
         * Set $this->bootstrap to true if your module is compliant with bootstrap (PrestaShop 1.6)
         */
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('Content box');
        $this->description = $this->l('Place your content everywhere!');

        $this->confirmUninstall = $this->l('Are you sure you want to uninstall?');

        $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
    }

    /**
     * Don't forget to create update methods if needed:
     * http://doc.prestashop.com/display/PS16/Enabling+the+Auto-Update
     */
    public function install()
    {
        Configuration::updateValue('MWS_CONTENTBOX_SCHEDULE', null);
        Configuration::updateValue('MWS_CONTENTBOX_SOME_MESSAGE', null);

        return parent::install() &&
            $this->registerHook('header') &&
            $this->registerHook('displayNav1');
    }

    public function uninstall()
    {
        Configuration::deleteByName('MWS_CONTENTBOX_SCHEDULE');
        Configuration::deleteByName('MWS_CONTENTBOX_SOME_MESSAGE');

        return parent::uninstall();
    }

    /**
     * Load the configuration form
     */
    public function getContent()
    {
        /**
         * If values have been submitted in the form, process.
         */
        if (((bool)Tools::isSubmit('submitMws_contentboxModule')) == true) {
            $this->postProcess();
        }

        $this->context->smarty->assign('module_dir', $this->_path);

        $output = $this->context->smarty->fetch($this->local_path.'views/templates/admin/configure.tpl');

        return $output.$this->renderForm();
    }

    /**
     * Create the form that will be displayed in the configuration of your module.
     */
    protected function renderForm()
    {
        $helper = new HelperForm();

        $helper->show_toolbar = false;
        $helper->table = $this->table;
        $helper->module = $this;
        $helper->default_form_language = $this->context->language->id;
        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);

        $helper->identifier = $this->identifier;
        $helper->submit_action = 'submitMws_contentboxModule';
        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
            .'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');

        $helper->tpl_vars = array(
            'fields_value' => $this->getConfigFormValues(), /* Add values for your inputs */
            'languages' => $this->context->controller->getLanguages(),
            'id_language' => $this->context->language->id,
        );

        return $helper->generateForm(array($this->getConfigForm()));
    }

    /**
     * Create the structure of your form.
     */
    protected function getConfigForm()
    {
        return array(
            'form' => array(
                'legend' => array(
                'title' => $this->l('Settings'),
                'icon' => 'icon-cogs',
                ),
                'input' => array(
                    array(
                        'col' => 3,
                        'type' => 'text',
                        'prefix' => '',
                        'desc' => $this->l('For example: 10:00 - 20:00 daily'),
                        'name' => 'MWS_CONTENTBOX_SCHEDULE',
                        'label' => $this->l('Schedule'),
                    ),
                    array(
                        'col' => 3,
                        'type' => 'text',
                        'prefix' => '',
                        'desc' => $this->l('For example: March 8 is a day off!'),
                        'name' => 'MWS_CONTENTBOX_SOME_MESSAGE',
                        'label' => $this->l('Some message'),
                    ),
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                ),
            ),
        );
    }

    /**
     * Set values for the inputs.
     */
    protected function getConfigFormValues()
    {
        return array(
            'MWS_CONTENTBOX_SCHEDULE' => Configuration::get('MWS_CONTENTBOX_SCHEDULE', null),
            'MWS_CONTENTBOX_SOME_MESSAGE' => Configuration::get('MWS_CONTENTBOX_SOME_MESSAGE', null),
        );
    }

    /**
     * Save form data.
     */
    protected function postProcess()
    {
        $form_values = $this->getConfigFormValues();

        foreach (array_keys($form_values) as $key) {
            Configuration::updateValue($key, Tools::getValue($key));
        }
    }

    /**
     * Add the CSS & JavaScript files you want to be added on the FO.
     */
    public function hookHeader()
    {
        // Здесь можно добавить стили и скрипты
        // $this->context->controller->addJS($this->_path.'/views/js/front.js');
        // $this->context->controller->addCSS($this->_path.'/views/css/front.css');
    }

    public function hookDisplayNav1()
    {
      // Назначаем переменные для шаблона smarty
      $this->context->smarty->assign([
          'MWS_CONTENTBOX_SCHEDULE' => Configuration::get('MWS_CONTENTBOX_SCHEDULE'),
          'MWS_CONTENTBOX_SOME_MESSAGE' => Configuration::get('MWS_CONTENTBOX_SOME_MESSAGE'),
          // Добавим из таблицы БД ps_configuration телефон:
          'BLOCKCONTACTINFOS_PHONE' => Configuration::get('BLOCKCONTACTINFOS_PHONE')
        ]);

        return $this->display(__FILE__, 'mws_contentbox.tpl');
    }
}

Располагаться наш модуль будет в хуке displayNav1. Скриншот страницы Дизайн/Расположение блоков:

Расположение блоков в админке Престашоп

Давайте разберем код основного файла нашего модуля.

В самом начале проверяем наличие константы PrestaShop (номер версии). Если она не существует, то останавливаем загрузку модуля. Единственная цель этого — не допустить, чтобы злоумышленники загружали этот файл напрямую.

<?php

if (!defined('_PS_VERSION_')) {
exit;
}

Конструктор

Этот обязательный метод класса определяет наименование модуля, вкладку для его отображения в Админке, название в списке модулей, описание, версию и любые другие константы, которые могут пригодиться в работе. И не забываем про родительский конструктор.

Конструктор модуля

Методы install() и uninstall()

Метод инсталляции осуществляет создание таблиц в базе данных, если нужно, или добавление записей в уже имеющуюся таблицу, а также регистрацию хуков. Метод uninstall() удаляет записи из БД и деинсталлирует модуль. 

Методы инсталл и деинсталляции

После установки модуля в таблице БД ps_configuration появятся строки с нашими переменными:

Работа с базой данных в Престашоп

Страница настройки модуля в Админке:

Страница конфигурации модуля PrestaShop

Метод getContent()

Отвечает за настройку модуля в Админке. То есть, если метод с таким названием есть, то на странице управления модулями автоматически создается ссылка "Настроить" для данного модуля. Метод должен обеспечить вывод формы на странице настройки модуля в бэк-офисе и обработать пришедшие от админа данные настроек, сохранив их в базу данных (метод postProcess()).

Method getContent

Подробно об этом можно почитать в Документации:
Добавление страницы конфигурации
https://devdocs.prestashop.com/1.7/modules/creation/adding-configuration-page/

Метод renderForm()

Здесь происходит создание формы, которая будет отображаться на странице конфигурации нашего модуля.

HelperForm – это вспомогательный класс, который позволяет генерировать стандартные элементы HTML для бэк-офиса, а также для страниц конфигурации модуля.

Метод getConfigForm()

Возвращает массив, включающий заголовок, поля формы и кнопку Сохранить - все то, что мы увидим на странице конфигурации модуля в Админке. Вызывается эта функция в методе отрисовки формы renderForm().

Метод getConfigFormValues()

protected function getConfigFormValues()
{
return array(
'MWS_CONTENTBOX_SCHEDULE' => Configuration::get('MWS_CONTENTBOX_SCHEDULE', null),
'MWS_CONTENTBOX_SOME_MESSAGE' => Configuration::get('MWS_CONTENTBOX_SOME_MESSAGE', null),
);
}

Здесь устанавливаем значения полей формы конфигурации. В дальнейшем мы можем использовать массив, который возвращает этот метод, перебрав его с помощью цикла foreach и обновив значения наших переменных. Происходит это в методе postProcess():

protected function postProcess()
{
$form_values = $this->getConfigFormValues();
foreach (array_keys($form_values) as $key) {
Configuration::updateValue($key, Tools::getValue($key));
}
}

Метод hookDisplayNav1() и шаблон mws_contentbox.tpl

Выводим результат работы модуля в конкретный хук. Здесь происходит вывод содержимого (например выборки из БД) в массив и передача этого массива в шаблон smarty.

Функция отображения модуля на страницах сайта

Переводы строк на русский язык

Все строки, предназначенные для прочтения человеком, рекомендуется оборачивать в функцию Module::l(). Это делает возможным их перевод на любой язык. После установки модуля на странице Админки Интернационализация/Переводы вы можете перевести все строки на русский язык.

Переводы модуля в Админке

Переводы на русский язык в Престашоп

Об этом еще можно почитать тут:

Локализация собственных модулей
https://ida-freewares.ru/prestashop-1-6-lokalizatsiya-sobstvennykh-modulej-dlya-novichkov.html

Готовый модуль Content box: результат урока

Итак, мы добавили в хедер интернет-магазина номер телефона, график работы и короткое сообщение для покупателей. У нас получился вполне рабочий модуль для одноязычного сайта. На его базе можно разработать модули для вывода любого небольшого контента на ваш сайт.

Скачать архив с модулем Content box (Скачиваний: 229)
Модуль разработан в веб-мастерской MAKE-WEBSITE.ru. Тестировался на PrestaShop 1.7.6.3.

 

Интернет магазин на движке PrestaShop

Совет:

Чтобы получить начальный каркас модуля, воспользуйтесь Module Generator. В посте Заготовка PrestaShop модуля при помощи Генератора описана последовательность действий при генерации собственного модуля.

Полезные ссылки по разработке Престашоп модуля

Документация: Понимание вашего первого модуля
https://devdocs.prestashop.com/1.7/modules/creation/

Русская документация PrestaShop 1.6
https://bestprogrammer.xyz/sozdanie-pervogo-modulya/

PrestaShop 1.6 - памятка для авторов модулей (для новичков)
https://ida-freewares.ru/prestashop-1-6-pamyatka-dlya-avtorov-modulej-dlya-novichkov.html

Еще хорошие статьи по созданию модуля:
http://kupreev.com/page/prestashop-shopbyprice-module-fix
http://hncoder.blogspot.com/2013/11/prestashop-v15.html
http://webnewbie.ru/modules/blogwp/wordpress/prestashop/detalnyj-analiz-modulya-prestashop-1-5.html

Пишите вопросы в комментариях. И буду благодарен за ваши мнения и отзывы!

Веб разработчик MAKE-WEBSITE.ru
Автор
Подробнее
Геннадий Егупов

Создаю современные
высококонверсионные сайты

Кроссбраузернаяверстка
Созданиедизайнов
Интеграция с cmsMODx и PrestaShop
Разработка Vue.jsприложений
Прочитайте еще посты:

Оставьте свой комментарий!


Разрешённые теги: <b><i><br>


Комментарии (3)

  1. avyazovoi: Май 12, 2021г. в 10:34

    Благодарю, получил ответы на все вопросы при создании своего первого модуля на престе :)

    Ответить
  2. PrestaNoob: Январь 06, 2023г. в 20:07

    Благодарю за данный урок, по больше уроков на PrestaShop, это отличный опенсорс магазин

    Ответить
  3. kvant08: Январь 15, 2023г. в 18:27

    Очень хорошая статья. У меня такой вопрос: престашоп 8 как убрать поле доставка в модуле корзина?

    Ответить
 

Давайте общаться

Я хотел бы поговорить о вашем бизнесе, отправьте мне письмо на make.website.info@gmail.com.