Любой "движок" требует соблюдения определенных правил при создании новых конструкций или модернизации существующих. Как правило никто эти нормы подробно не расписывает. И, чтобы встроить свой код в чужой движок иногда приходится много копать этого самого чужого кода. Данная статья написана в стиле As is - т.е. я не объясняю почему здесь должен быть этот div или за что отвечает этот метод. Если интересно - копайте код сами :)
Здесь предлагается набор конструкций (паззлов) из которых однозначно и достаточно быстро можно создать необходимый функционал
Достало меня каждый раз оформлять футер - выискивание модулей где располагаются ссылки, невозможно изменять название, количество блоков. Как-то все криво, нелогично и не в одном месте. Да и с мультиязычностью как всегда не все в порядке.
Футер, по моему глубокому разумению, должен содержать несколько колонок нужных ссылок и колонку с реквизитами.
Предлагаю совместить приятное с полезным и научиться создавать собственные модули с нуля на примере создания полезной конструкции :). К тому же создать модуль для Prestashop версии 1,5 совершенно не сложно.
Мы не будем создавать свою таблицу в БД сайта. Воспользуемся замечательной, по моему мнению, возможностью PrestaShop создавать и использовать переменные конфигурации. Они размещаются в базе автоматом.
Назовем модуль: realfooter.
Задача: Заменить стандартные ссылки футера. Ссылки будут располагаться в 4 колонках. Каждая колонка имеет свое название. Пятая колонка будет содержать контакную информацию.
Все языкозависимо (во какое слово :) )
В принципе, поняв суть, каждый в последствие сможет создавать свой уникальный футер (и не только футер) под свои потребности. Поэтому описывать создание я буду несколько шире, чем того требует наша конкретная задача.
1. Создаем скелет нашего модуля
В каталоге www/modules создаем подкаталог realfooter.В нем создаем следующие подкаталоги и файлы:
- cjs - подкаталог. Здесь будут располагаться файлы css и js если их много. Если у вас планируется один js и один css файл - тогда положите их в корне realfooter и в дополнительном подкаталоге cjs просто нет смысла
- img - подкаталог. Здесь будут располагаться картинки, опять же, если их много и в этом подкаталоге есть смысл.
- translations - подкаталог. Это обязательный подкаталог, если у вас многоязычный сайт. Название подкаталога стандартное и изменять его нельзя.
- realfooter.php - файл. Это основной класс нашего модуля: инсталляция/деинсталляция и вся математика в т.ч. работа с БД. Создайте пока пустой файл.
- realfooter.tpl - файл. Это представление (вьюха, отображение) - HTML код со вставками Smarty для вывода нашего модуля во фронт.. Создайте пока пустой файл. Что такое язык разметки Smarty и как им пользоваться - велкам ту соответствующий замечательный сайт (не забудьте там включить русский язык ;))
- logo.gif - файл. Иконка, которая появится в админке и будет сопровождать наш новый модуль
2. Файл realfooter.php
Как уже было сказано, это основной/главный файл нашего модуля.
Ниже мы указываем название нашего модуля человеческим языком и краткое описание. Все это будет отображаться в админке
Этих действий вполне достаточно для инсталляции и деинсталляции нашего модуля. Если Вы собираетесь использовать собственную таблицу в БД - просто посмотрите как инициализируемый, создается и удаляется таблица на примере модулей, что в папке modules. Там ничего сложного.
Пару слов о страшилке под названием HOOK. На самом деле ничего страшного нет. В интернете полно описаний, но, честно говоря они не совсем понятны. Поэтому я скажу грубо, но метко: хук - это поле (место, позиция) в шаблоне, в которое помещается модуль, а точнее TPL -файл модуля. В Prestashop есть правда еще другие типы хуков, но нам сейчас они не важны.
Как вы уже догадались у нашего модуля будет админка (кто жил до этого момента в счастливом неведении - может "сделать глаза" и воскликнуть "Да ладно!" ;) ).
Стандартом (если так можно выразиться) PrestaShop предусмотрено два метода: displayForm() и getContent(). Первый содержит код формы в админке, второй выводит форму и обрабатывает ее.
hnc_panname_x_lang, hnc_strname_x_s_lang, hnc_strlink_x_s, hnc_contname_lang, hnc_text_lang
Теперь разберемся с блоками формы. Для вывода обычного блока используем такую конструкцию:
Мультиязычный блок выводим так:
Вывод загруженной картинки и поля для загрузки:
Кнопки:
Метод Tools::isSubmit() проверяет, что кнопка нажималась.
Метод Tools::getValue() - выдает переменную пришедшую в $_POST
Метод Configuration::updateValue() - обновляет нашу переменную или создает новую, в случае ее отсутствия
В переменную $out_msg собираем сообщения или ошибки
Да, для обработки картинок такой код:
Также подключаем таблицу стилей realfooter.css, которую расположим в корне папки модуля.
Если модуль предполагает расположение еще в каких-либо хуках, это надо явно указать:
Таким образом модулю будет разрешено располагаться в хуке Home в том же виде, что и в хуке Footer. Однако Вы можете указать здесь другой шаблон, вывести другие данные и т.п.
Остальное все понятно без комментариев
На этом разрешите закончить. Надеюсь кому-то сэкономил время :)
<?php if( !defined( '_PS_VERSION_' ) ) exit; class realfooter extends Module { private $_html = ''; private $_postErrors = array(); public function __construct() { $this->name = 'realfooter'; $this->tab = 'front_office_features'; $this->version = '1.0'; $this->author = 'HowKnowCoder'; parent::__construct(); $this->displayName = $this->l( 'Main page Footer module' ); $this->description = $this->l( 'Main page Footer HowKnowCoder module' ); }В конструкторе мы указываем название нашего модуля, принадлежность к группе ('front_office_features'), версию и автора. Если Вы намерены делать несколько модулей, то рекомендую указвать автора, т.к. в админке есть фильтр по автору модуля, что очень удобно.
Ниже мы указываем название нашего модуля человеческим языком и краткое описание. Все это будет отображаться в админке
function install() { $this->_clearCache( 'realfooter.tpl' ); if( Shop::isFeatureActive() ) Shop::setContext( Shop::CONTEXT_ALL ); return parent::install() && $this->registerHook( 'footer' ) && Configuration::updateValue( 'realfooter', 'settings' ); } public function uninstall() { $this->_clearCache( 'realfooter.tpl' ); if( !parent::uninstall() || !Configuration::deleteByName( 'realfooter' ) ) return false; return true; }Методы install и uninstall говорят сами за себя. Мы размещаемся в хуке Footer ($this->registerHook ...) и у нас будет админка (Configuration::updateValue ...)
Этих действий вполне достаточно для инсталляции и деинсталляции нашего модуля. Если Вы собираетесь использовать собственную таблицу в БД - просто посмотрите как инициализируемый, создается и удаляется таблица на примере модулей, что в папке modules. Там ничего сложного.
Пару слов о страшилке под названием HOOK. На самом деле ничего страшного нет. В интернете полно описаний, но, честно говоря они не совсем понятны. Поэтому я скажу грубо, но метко: хук - это поле (место, позиция) в шаблоне, в которое помещается модуль, а точнее TPL -файл модуля. В Prestashop есть правда еще другие типы хуков, но нам сейчас они не важны.
Как вы уже догадались у нашего модуля будет админка (кто жил до этого момента в счастливом неведении - может "сделать глаза" и воскликнуть "Да ладно!" ;) ).
Стандартом (если так можно выразиться) PrestaShop предусмотрено два метода: displayForm() и getContent(). Первый содержит код формы в админке, второй выводит форму и обрабатывает ее.
Создаем форму:
public function displayForm() { // Get default Language $languages = Language::getLanguages( false ); $deflang_id = (int)( Configuration::get( 'PS_LANG_DEFAULT' ) ); $lang_value = array(); //Создаем форму и выводим шапку $form = '<form action="' . Tools::safeOutput( $_SERVER[ 'REQUEST_URI' ] ) . '" 'method="post" method="post">'; $form .= '<fieldset><legend>'; $form .= '<img src="' . $this->_path . 'logo.png" alt="" title="" />'; $form .= $this->l( 'HowKnowCoder Footer Page Settings' ) . '</legend>'; // Цикл вывода панелей. По условиям у нас 4 панели // Panels for( $i = 1; $i <= 4; $i++ ) { $form .= '<div style="clear: both;">'; $form .= '<label style="font-weight: bold; border: 1px solid #AAA; padding: 10px; background-color: #DDD;">'; $form .= sprintf( $this->l( '%s panel' ), $i ) . '</label>'; $form .= '<hr style="width: 80%; height: 1px; background-color: #AAA;" /></div>'; $form .= '<div style="width: 100%; clear: both;"></div>'; // Выводим название блока. Название зависит от языка, поэтому выводим стандартную панель языков с флагами // Title $form .= '<label > ' . $this->l( 'Panel name:' ) . ' </label > '; $form .= '<div class="margin-form" > '; $form .= '<div class="translatable" > '; foreach( $languages as $language ) { $lang_value[ $language[ 'id_lang' ] ][ 'hnc_panname_' . $i ] = Configuration::get( 'HNC_PANNAME_' . $i . '_' . $language[ 'id_lang' ] ); $form .= ' <div id = "hnc_panname_' . $i . '_' . (int)$language[ 'id_lang' ] . '" class="lang_' . (int)$language[ 'id_lang' ] . '" style = "display: ' . ( $language[ 'id_lang' ] == $deflang_id ? 'block' : 'none' ) .'; float: left;">'; $form .= ' <input size = "50" type = "text" name = "hnc_panname_' . $i . '_' . $language[ 'id_lang' ] . '" value = "'. Tools::safeOutput( @$lang_value[ $language[ 'id_lang' ] ][ 'hnc_panname_' . $i ], true ) . '" />'; $form .= ' </div > '; } $form .= $this->displayFlags( $languages, $deflang_id, 'hnc_panname_' . $i, 'hnc_panname_' . $i, true ); $form .= ' </div ></div ><div style="clear: both;padding-bottom: 10px;"> </div>'; // Выводим 6 ссылок внутри блока. Ссылка состоит из поля Названия и поля собственно ссылки // Strings for( $s = 1; $s <= 6; $s++ ) { // String Title $form .= '<label > ' . $this->l( 'String:' ) . $s . ' </label > '; $form .= '<div class="margin-form" > '; $form .= '<div class="translatable" > '; foreach( $languages as $language ) { $lang_value[ $language[ 'id_lang' ] ][ 'hnc_strname_' . $i . '_' . $s ] = Configuration::get( 'HNC_STRNAME_' . $i . '_' . $s . '_' . $language[ 'id_lang' ] ); $form .= ' <div id = "hnc_strname_' . $i . '_' . $s . '_' . (int)$language[ 'id_lang' ] . '" class="lang_' . (int)$language[ 'id_lang' ] . '" style = "display: ' . ( $language[ 'id_lang' ] == $deflang_id ? 'block' : 'none' ) .'; float: left;">'; $form .= ' <input size = "50" type = "text" name = "hnc_strname_' . $i . '_' . $s . '_' . $language[ 'id_lang' ] . '" value = "'. Tools::safeOutput( @$lang_value[ $language[ 'id_lang' ] ][ 'gc_strname_' . $i . '_' . $s ], true ) . '" />'; $form .= ' </div>'; } $form .= $this->displayFlags( $languages, $deflang_id, 'hnc_strname_' . $i . '_' . $s, 'hnc_strname_' . $i . '_' . $s, true ); $form .= ' </div></div>'; // Ссылка не зависит от языка, поэтому код проще // Link $form .= '<label > ' . $this->l( 'Link:' ) . ' </label > '; $form .= '<div class="margin-form" > '; $form .= '<input type = "text" size = "50" name = "hnc_strlink_' . $i . '_' . $s . '" value = "' . Configuration::get( 'HNC_STRLINK_' . $i . '_' . $s ) . '" />'; $form .= '<p style = "clear: both" > '. sprintf( $this->l( 'URL like this: %s' ), '/index.php?id_category=6&controller=category' ). ' </p ></div > '; } // Здесь выводим пятую панель. Оба поля мультиязычны // Contacts Title $form .= '<div style="clear: both;">'; $form .= '<label style="font-weight: bold; border: 1px solid #AAA; padding: 10px; background-color: #DDD;"> '. sprintf( $this->l( 'Contact panel' ), $i ) . '</label>'; $form .= '<hr style="width: 80%; height: 1px; background-color: #AAA;" /></div>'; $form .= '<div style="width: 100%; clear: both;"></div>'; $form .= '<label > ' . $this->l( 'Contact Title:' ) . ' </label > '; $form .= '<div class="margin-form" > '; $form .= '<div class="translatable" > '; foreach( $languages as $language ) { $lang_value[ $language[ 'id_lang' ] ][ 'hnc_contname' ] = Configuration::get( 'HNC_CONTNAME_' . $language[ 'id_lang' ] ); $form .= ' <div id = "hnc_contname_' . (int)$language[ 'id_lang' ] . '" class="lang_' . (int)$language[ 'id_lang' ] . '" style = "display: ' . ( $language[ 'id_lang' ] == $deflang_id ? 'block' : 'none' ).'; float: left;">'; $form .= ' <input size = "50" type = "text" name = "hnc_contname_' . $language[ 'id_lang' ] . '" value = "' .= Tools::safeOutput( @$lang_value[ $language[ 'id_lang' ] ][ 'mbf_contname' ], true ) . '" />'; $form .= ' </div > '; } $form .= $this->displayFlags( $languages, $deflang_id, 'hnc_contname', 'hnc_contname', true ); $form .= ' </div ></div >'; // Contacts $form .= '<label style = "clear:both;" > ' . $this->l( 'Contacts:' ) . ' </label > '; $form .= '<div class="margin-form" > '; $form .= '<div class="translatable" > '; foreach( $languages as $language ) { $lang_value[ $language[ 'id_lang' ] ][ 'hnc_text' ] = Configuration::get( 'HNC_TEXT_' . $language[ 'id_lang' ] ); $form .= ' <div id = "hnc_text_' . (int)$language[ 'id_lang' ] . '" class="lang_' . (int)$language[ 'id_lang' ] . '" style = "display: ' . ( $language[ 'id_lang' ] == $deflang_id ? 'block' : 'none' ).'; float: left;">'; $form .= ' <textarea rows = "5" cols = "60" type = "text" name = "hnc_text_' . $language[ 'id_lang' ] . '">'. Tools::safeOutput( @$lang_value[ $language[ 'id_lang' ] ][ 'mbf_text' ], true ). '</textarea ></div > '; } $form .= $this->displayFlags( $languages, $deflang_id, 'hnc_text', 'hnc_text', true ); $form .= ' </div ></div > '; $form .= '<div style = "clear: both;width: 100%;" ></div > '; $form .= '<input type = "submit" name = "submitHNCPage" value = "' . $this->l( 'Save' ) . '" class="button" />'; $form .= '</fieldset ></form > '; return $form; }Страшно? Сам боюсь ... А если присмотреться - да все просто. Прежде всего надо определиться с названиями полей и названиями соответствующих переменных. Переменным очень желательно дать префикс, чтобы их можно было отличить от другого "хлама" и чтобы ваши переменные не переписали существующие!!! в таблице ps_configuration.
- HNC_PANNAME_x_lang - название блока, где x: номер блока, lang: язык текста
- HNC_STRNAME_x_s_lang - название ссылки, где x: номер блока, s: номер строки в блоке, lang: язык текста
- HNC_STRLINK_x_s - ссылка, где x: номер блока, s: номер строки в блоке
- HNC_CONTNAME_lang - название 5 панели, где lang: язык текста
- HNC_TEXT_lang - текст 5 панели, где lang: язык текста
hnc_panname_x_lang, hnc_strname_x_s_lang, hnc_strlink_x_s, hnc_contname_lang, hnc_text_lang
Теперь разберемся с блоками формы. Для вывода обычного блока используем такую конструкцию:
<label >Название поля</label > <div class="margin-form" > <input type = "text" size = "50" name = "hnc_имя" value = "<?php echo Configuration::get( 'HNC_ИМЯ ) ?>" /> <p style = "clear: both" > Подсказка если необходима </p >
Мультиязычный блок выводим так:
<label style = "clear:both;" >Название поля</label > <div class="margin-form" > <div class="translatable" > <?php foreach( $languages as $language ) { $lang_value[ $language[ 'id_lang' ] ][ 'hnc_имя' ] = Configuration::get( 'HNC_ИМЯ_' . $language[ 'id_lang' ] ); $form .= ' <div id = "hnc_имя_' . (int)$language[ 'id_lang' ] . '" class="lang_' . (int)$language[ 'id_lang' ] . '" style = "display: ' . ( $language[ 'id_lang' ] == $deflang_id ? 'block' : 'none' ).'; float: left;">'; $form .= ' <textarea rows = "5" cols = "60" type = "text" name = "hnc_имя_' . $language[ 'id_lang' ] . '">'. Tools::safeOutput( @$lang_value[ $language[ 'id_lang' ] ][ 'hnc_имя' ], true ). '</textarea > </div>'; } $form .= $this->displayFlags( $languages, $deflang_id, 'hnc_имя', 'hnc_имя', true ); ?> </div > </div >
Вывод загруженной картинки и поля для загрузки:
<div class="over" > <div class="margin-form" > <img src = "<?php echo Tools::getProtocol() . Tools::getMediaServer( $this->name ) . _MODULE_DIR_ . $this->name . '/files/' . Configuration::get( 'HNC_ИМЯ' ) ?>" alt = "" style = "height:120px;margin-left: 100px;" /> </div > <label> Название </label > <div class="margin-form" > <input id = "hnc_имя" type = "file" name = "hnc_имя" /> <p style = "clear: both" >Подсказка если необходима </p > </div > </div >Не забываем про enctype="multipart/form-data" при загрузке картинок
Кнопки:
<div style = "clear: both;width: 100%;" ></div > <input type = "submit" name = "submitHNCPage" value = "Сохранить" class="button" />Теперь вы можете создать любую форму
Обработчик формы
Обработчиком служит метод getContent(). Он же и выводит форму.public function getContent() { $out_msg = ''; $languages = Language::getLanguages( false ); $output = '<h2>' . $this->displayName . '</h2>'; if( Tools::isSubmit( 'submitHNCPage' ) ) { $deflang_id = (int)( Configuration::get( 'PS_LANG_DEFAULT' ) ); // Panels for( $i = 1; $i <= 4; $i++ ) { foreach( $languages as $language ) { if( Tools::getValue( 'hnc_panname_' . $i . '_' . $language[ 'id_lang' ] ) ) Configuration::updateValue( 'HNC_PANNAME_' . $i . '_' . $language[ 'id_lang' ], Tools::getValue( 'hnc_panname_' . $i . '_' . $language[ 'id_lang' ] ) ); else Configuration::updateValue( 'HNC_PANNAME_' . $i . '_' . $language[ 'id_lang' ], '' ); } // Strings for( $s = 1; $s <= 6; $s++ ) { foreach( $languages as $language ) { if( Tools::getValue( 'hnc_strname_' . $i . '_' . $s . '_' . $language[ 'id_lang' ] ) ) Configuration::updateValue( 'HNC_STRNAME_' . $i . '_' . $s . '_' . $language[ 'id_lang' ], Tools::getValue( 'hnc_strname_' . $i . '_' . $s . '_' . $language[ 'id_lang' ] ) ); else Configuration::updateValue( 'HNC_STRNAME_' . $i . '_' . $s . '_' . $language[ 'id_lang' ], '' ); } if( Tools::getValue( 'hnc_strlink_' . $i . '_' . $s ) ) Configuration::updateValue( 'HNC_STRLINK_' . $i . '_' . $s, Tools::getValue( 'hnc_strlink_' . $i . '_' . $s ) ); else Configuration::updateValue( 'HNC_STRLINK_' . $i . '_' . $s, '' ); } } foreach( $languages as $language ) { if( Tools::getValue( 'hnc_contname_' . $language[ 'id_lang' ] ) ) Configuration::updateValue( 'HNC_CONTNAME_' . $language[ 'id_lang' ], Tools::getValue( 'hnc_contname_' . $language[ 'id_lang' ] ) ); else Configuration::updateValue( 'HNC_CONTNAME_' . $language[ 'id_lang' ], '' ); if( Tools::getValue( 'hnc_text_' . $language[ 'id_lang' ] ) ) Configuration::updateValue( 'HNC_TEXT_' . $language[ 'id_lang' ], Tools::getValue( 'hnc_text_' . $language[ 'id_lang' ] ) ); else Configuration::updateValue( 'HNC_TEXT_' . $language[ 'id_lang' ], '' ); } $this->_clearCache( 'realfooter.tpl' ); $out_msg .= '<div class="conf confirm">'.$this->l('Settings updated').'</div>'; } return $out_msg . $this->displayForm(); }Ну здесь совсем все просто. Главное, чтобы name 'submitHNCPage' кнопки в форме:
<input type = "submit" name = "submitHNCPage" value = "Сохранить" class="button" />совпал с
if( Tools::isSubmit( 'submitHNCPage' ) )
Метод Tools::isSubmit() проверяет, что кнопка нажималась.
Метод Tools::getValue() - выдает переменную пришедшую в $_POST
Метод Configuration::updateValue() - обновляет нашу переменную или создает новую, в случае ее отсутствия
В переменную $out_msg собираем сообщения или ошибки
Да, для обработки картинок такой код:
if( isset( $_FILES[ 'hnc_имя' ] ) && isset( $_FILES[ 'hnc_имя' ][ 'tmp_name' ] ) && !empty( $_FILES[ 'hnc_имя' ][ 'tmp_name' ] ) ) { if( $error = ImageManager::validateUpload( $_FILES[ 'hnc_имя' ], 4000000 ) ) return $this->displayError( $this->l( 'Invalid image' ) ); else { $ext = mb_substr( $_FILES[ 'hnc_имя' ][ 'name' ], mb_strrpos( $_FILES[ 'hnc_имя' ][ 'name' ], '.' ) + 1 ); $file_name = md5( $_FILES[ 'hnc_имя' ][ 'name' ] ) . '.' . $ext; if( !move_uploaded_file( $_FILES[ 'hnc_имя'][ 'tmp_name' ], dirname( __FILE__ ) . '/files/' . $file_name ) ) return $this->displayError( $this->l( 'An error occurred while attempting to upload the file.' ) ); else { if( Configuration::hasContext( 'HNC_ИМЯ', null, Shop::getContext() ) && Configuration::get( 'HNC_ИМЯ' ) != $file_name ) @unlink( dirname( __FILE__ ) . '/files/' . Configuration::get( 'HNC_ИМЯ' ) ); Configuration::updateValue( 'HNC_ИМЯ' . $i, $file_name ); $this->_clearCache( 'realfooter.tpl' ); } } }Для файлов необходимо создать папку files в корне модуля
Подготовка и вывод данных в шаблон
В нашем примере данные выводятся в хук Footer.public function hookFooter( $params ) { $deflang_id = (int)( Configuration::get( 'PS_LANG_DEFAULT' ) ); $tmp = array(); for( $i = 1; $i <= 4; $i++ ) { $tmp[ $i ][ 'hnc_panname' ] = Configuration::get( 'HNC_PANNAME_' . $i . '_' . $this->context->language->id ); for( $s = 1; $s <= 6; $s++ ) { $tmp[ $i ][ $s ][ 'hnc_strname' ] = Configuration::get( 'HNC_STRNAME_' . $i . '_' . $s . '_' . $this->context->language->id ); $tmp[ $i ][ $s ][ 'hnc_strlink' ] = Configuration::get( 'HNC_STRLINK_' . $i . '_' . $s ); } } if( !$this->isCached( 'mbrosfooter.tpl', $this->getCacheId( 'realfooter' ) ) ) { $this->smarty->assign( array( 'hnc_contname' => Configuration::get( 'HNC_CONTNAME_' . $this->context->language->id ), 'hnc_text' => Configuration::get( 'HNC_TEXT_' . $this->context->language->id ), 'data' => $tmp ) ); } $this->context->controller->addCSS( ( $this->_path ) . 'realfooter.css', 'all' ); return $this->display( __FILE__, 'realfooter.tpl', $this->getCacheId( 'realfooter' ) ); }Здесь также ничего сложного. Мультиязычные данные мы выводим в зависимости от текущего языка $this->context->language->id. Все динамичесике данные запоминаем в массив $tmp. Передаем в шаблон как переменную $data.
Также подключаем таблицу стилей realfooter.css, которую расположим в корне папки модуля.
Если модуль предполагает расположение еще в каких-либо хуках, это надо явно указать:
function hookDisplayTop( $params ) { return $this->hookDisplayHome( $params ); }
Таким образом модулю будет разрешено располагаться в хуке Home в том же виде, что и в хуке Footer. Однако Вы можете указать здесь другой шаблон, вывести другие данные и т.п.
3. Шаблон
Ну и наконец то, собственно ради чего все танцевалось: шаблон.<!-- HowKnowCoder Footer module --> <div id="foot-wrapper"> {assign var="flag" value="false"} {foreach from=$data item=d name=frd} <div class="foot-panel">
<h4>{$d.hnc_panname|upper}</h4> <ul> {section name="i" loop=$d} {if $d[i].hnc_strname|mb_strlen > 0 } <li><a href="{$d[i].hnc_strlink}">{$d[i].hnc_strname}</a></li> {/if} {/section} </ul> </div> {/foreach}
<div class="foot-panel-contact"> <h4>{$hnc_contname|upper}</h4> <p>{$hnc_text|nl2br}</p> </div> </div>Очень желательно указывать <!-- HowKnowCoder Footer module --> - так гораздо проще ориентироваться в коде. Кроме того, это чуть ли не стандарт PrestaShop.
Остальное все понятно без комментариев
4. Размещение
Тут все стандартно. Модуль инсталлируется и автоматом размещается в футере. Далее надо зайти в меню Модули и удалить из футера все модули кроме нашего.На этом разрешите закончить. Надеюсь кому-то сэкономил время :)
Комментариев нет :
Отправить комментарий
Есть что сказать - скажи