От автора: в первой статье мы создали плагин Recent Products, который показывает Х количество товаров на стороне front-end’а. Количество отображаемых товаров можно настроить через back-end форму конфигураций, которую мы создали в первой части. Также мы разобрались с архитектурой плагинов в OpenCart. Данная архитектура применяется и к front-end части плагина.
Быстрый обзор
Как уже говорилось ранее, в этом уроке мы создадим файлы front-end стороны плагина. Давайте взглянем на список файлов.
catalog/language/english/module/recent_products.php: файл со статическими заголовками, которые используются на front-end стороне.
catalog/controller/module/recent_products.php: файл контроллера с логикой приложения нашего модуля.
catalog/model/module/recent_products.php: файл модели, взаимодействующий с базой данных для получения товаров.
catalog/view/theme/default/template/module/recent_products.tpl: шаблон представления с XHTML кодом.
Первым делом вы заметите, что в отличие от директории admin, тут используется папка catalog, в которой хранятся файлы плагина на front-end стороне. Также есть файл модели, который не создавался для back-end’а и хранит программный код нашего плагина, чтобы вытягивать недавние товары из базы данных.
Другая вещь, на которую нужно обратить внимание – расположение файла представления recent_products.tpl. На самом деле, на стороне front-end’а у вас может быть несколько тем, и файл будет храниться в папке темы. У нас указан путь к теме по умолчанию в OpenCart, по которому хранится большая часть файлов шаблонов. Во всем остальном структура плагина такая же, в ней есть файл языка и контроллера.
Создаем файлы плагина
Первым делом создадим файл языка catalog/language/english/module/recent_products.php с кодом.
1 2 3 4 |
<?php // catalog/language/english/module/recent_products.php // Заголовок $_['heading_title'] = 'Recent Products'; |
Файл используется для установки статичных заголовков, которые будут использоваться в файле шаблона представления. Файл почти идентичен файлу языка из админки.
Теперь давайте создадим файл контроллера, который должен находиться по адресу catalog/controller/module/recent_products.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php // catalog/controller/module/recent_products.php class ControllerModuleRecentProducts extends Controller { public function index($setting) { $this->load->language('module/recent_products'); $data['heading_title'] = $this->language->get('heading_title'); $this->load->model('module/recent_products'); $this->load->model('tool/image'); $data['products'] = array(); $results = $this->model_module_recent_products->getRecentProducts( $setting['limit'] ); if ($results) { foreach ($results as $result) { if ($result['image']) { $image = $this->model_tool_image->resize( $result['image'], 100, 100 ); } else { $image = $this->model_tool_image->resize( 'placeholder.png', 100, 100 ); } if ( ( $this->config->get('config_customer_price') && $this->customer->isLogged() ) || !$this->config->get( 'config_customer_price' ) ) { $price = $this->currency->format( $this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')) ); } else { $price = false; } if ((float)$result['special']) { $special = $this->currency->format( $this->tax->calculate( $result['special'], $result['tax_class_id'], $this->config->get('config_tax') ) ); } else { $special = false; } $data['products'][] = array( 'product_id' => $result['product_id'], 'thumb' => $image, 'name' => $result['name'], 'description' => utf8_substr( strip_tags( html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8') ), 0, $this->config->get( 'config_product_description_length' ) ) . '..', 'price' => $price, 'special' => $special, 'href' => $this->url->link('product/product', 'product_id=' . $result['product_id']) ); } if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/recent_products.tpl')) { return $this->load->view( $this->config->get('config_template') . '/template/module/recent_products.tpl', $data ); } else { return $this->load->view( 'default/template/module/recent_products.tpl', $data ); } } } } |
Опять же, в методе index хранится большая часть нашего кода. В большинстве плагинов в методе index вам встретится аргумент $setting. Вспомните форму настроек в админке из первого урока, которая нужна для настройки параметров плагина – это и есть переменная $setting. В ней в виде массива хранятся значения настроек плагина для формы.
Сокращение $this->load->language загружает файл языка с front-end стороны, который подробно мы разобрали в первом уроке. Точно так же $this->load->model загружает модель плагина, которая хранится по адресу catalog/model/module/recent_products.php. Также мы подгружаем модель Image из папки tool, в ней есть метод для изменения размера изображений.
Самый важный вызов в методе index – вызов метода getRecentProducts, который возвращает из базы данных массив недавно просмотренных товаров. Когда будем разбирать файл модели, мы разберем его более подробно. В качестве аргумента методу передается значение $setting[‘limit’], которое определяется на стороне back-end’а.
1 |
$results = $this->model_module_recent_products->getRecentProducts( $setting['limit'] ); |
Затем мы проходимся по массиву товаров и подготавливаем массив $data[‘products’], который будем использовать в файле шаблона. В процессе подготовки массива мы используем метод для изменения размера изображений из модели Image и создаем с его помощью маленькие изображения. Большие изображения на front-end’е показывать нет смысла.
Также вы заметите $this->config->get – данная строка используется для вытягивания глобальных значений настроек магазина. Изменить эти параметры можно в System > Settings.
Сокращение $this->url->link создает SEO дружелюбные ссылки на страницы товаров. И наконец, идет кусок кода, загружающий файл шаблона recent_products.tpl, в котором данные подготавливаются к выводу при помощи массива $data.
В отличие от админки, на front-end стороне есть условие загрузки файла шаблона, так как вы можете использовать тему не по умолчанию. Если у вас тем нет, всегда используется тема по умолчанию в качестве фолбэка.
1 2 3 4 5 |
if ( file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/recent_products.tpl') ) { return $this->load->view( $this->config->get('config_template') . '/template/module/recent_products.tpl', $data ); } else { return $this->load->view( 'default/template/module/recent_products.tpl', $data ); } |
С файлом контроллера закончили. Теперь давайте создадим файл модели catalog/model/module/recent_products.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php // catalog/model/module/recent_products.php class ModelModuleRecentProducts extends Model { public function getRecentProducts($limit) { $this->load->model('catalog/product'); $product_data = $this->cache->get( 'product.recent.' . (int)$this->config->get('config_language_id') . '.' . (int)$this->config->get('config_store_id') . '.' . $this->config->get('config_customer_group_id') . '.' . (int)$limit ); if (!$product_data) { $query = $this->db->query("SELECT p.product_id FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) WHERE p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "' ORDER BY p.date_added DESC LIMIT " . (int)$limit); foreach ($query->rows as $result) { $product_data[$result['product_id']] = $this->model_catalog_product->getProduct( $result['product_id'] ); } $this->cache->set( 'product.recent.' . (int)$this->config->get('config_language_id') . '.' . (int)$this->config->get('config_store_id') . '.' . $this->config->get('config_customer_group_id') . '.' . (int)$limit, $product_data ); } return $product_data; } } |
По коду видно, что класс модели начинается с ключевого слова Model, и затем указывается структура папок. Класс наследует все от класса Model, в котором хранятся объекты и методы для взаимодействия с базой данных.
Также мы загружаем модель Product из папки catalog при помощи $this->load->model(‘catalog/product’). Нам понадобятся методы из этого класса.
Есть еще пара полезных сокращений — $this->cache->set и $this->cache->get. Первое используется для записи значения в кэш, а второе получает уже записанное значение из кэша по ключу. Хорошая привычка использовать кэш для увеличения производительности магазина.
В конце мы выполняем запрос к базе данных и вытягиваем недавние товары при помощи строки $this->db->query. Строка запускает метод query класса database.
После получения товаров мы проходимся по ним в цикле и подгружаем информацию о них при помощи метода getProduct класса модели Product. В конце мы сохраняем данные из массива в кэш, чтобы в последующих запросах нам не пришлось заново делать одну и ту же работу!
Осталось создать файл шаблона recent_products.tpl. Создадим его в папке catalog/view/theme/default/template/module/recent_products.tpl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!-- catalog/view/theme/default/template/module/recent_products.tpl --> <h3><?php echo $heading_title; ?></h3> <div class="row"> <?php foreach ($products as $product) { ?> <div class="product-layout col-lg-3 col-md-3 col-sm-6 col-xs-12"> <div class="product-thumb transition"> <div class="image"><a href="<?php echo $product['href']; ?>"><img src="<?php echo $product['thumb']; ?>" alt="<?php echo $product['name']; ?>" title="<?php echo $product['name']; ?>" class="img-responsive" /></a></div> <div class="caption"> <h4><a href="<?php echo $product['href']; ?>"><?php echo $product['name']; ?></a></h4> <p><?php echo $product['description']; ?></p> <?php if ($product['price']) { ?> <p class="price"> <?php if (!$product['special']) { ?> <?php echo $product['price']; ?> <?php } else { ?> <span class="price-new"><?php echo $product['special']; ?></span> <span class="price-old"><?php echo $product['price']; ?></span> <?php } ?> </p> <?php } ?> </div> </div> </div> <?php } ?> </div> |
В файле шаблона мы просто пробегаемся по массиву $products, который был передан из контроллера и выводим список товаров в XHTML.
С front-end файлами закончили! В следующем разделе я покажу вам, как прикрепить наш плагин к макету OpenCart, чтобы он показывался на стороне front-end’а.
Прикрепляем плагин к макету
Любой плагин, который что-то показывает на front-end стороне, необходимо привязать к свободному макету. Для примера мы привяжем плагин к позиции Content Top.
Перейдите в панель администратора в System > Design > Layouts. Должны отобразиться все доступные макеты магазина. Перейдите в режим редактирования макета Home. Необходимо просто добавить новый модуль, как показано на скриншоте ниже.
Как видите, мы взяли Recent Products > My Recent Block Plugin и прикрепили его к позиции Content Top. Сохраните изменения и все!
Front-end демо
Перейдите на сторону front-end’а, должен появиться красивый блок с недавно просмотренными товарами, как на скриншоте ниже.
Вот и закончилось наше путешествие по разработке пользовательского плагина для OpenCart. Серия уроков была нацелена на начинающих разработчиков, однако мы получили довольно хороший шаблон плагина, который можно расширить под свои нужды. Покопайтесь в коде, добавьте новый функционал. Хорошее упражнение после урока!
Заключение
В этой серии уроков мы изучили разработку пользовательского плагина в OpenCart. Так как курс был для новичков, мы создали очень простой плагин со списком недавно просмотренных товаров в блоке. В предыдущем уроке мы создали форму настроек для нашего плагина.
Автор: Sajal Soni
Источник: //code.tutsplus.com/
Редакция: Команда webformyself.