Товары в карусели opencart
2022-09-14
Все написанное в этой статье является продолжением предыдущих статей о модуле "карусель" в opencart 2.3
Модуль "Карусель" красивый, но бесполезный: выводит различные ссылки в виде картинок в ряд, с возможностью их перелистывать.
Модуль "Рекомендуемые" полезный, но не функциональный: отображает несколько товаров в виде отдельных блоков, можно его открыть или сразу добавить в корзину.
А хотелось бы, иметь возможность вывести в ряд много товаров, с возможностью открытия каждого, перелистывания и быстрого добавления в корзину. То есть нужно объединить функции обоих модулей.
Создавать отдельный модуль смысла нет, нужно только добавить функционал из одного модуля в другой. Для модификации я выбрал модуль "Карусель", чтобы можно было выводить не только товары, но и статичные картинки.
Готовый архив с файлами, к этой статье можно найти внизу страницы.
Дополнительное поле в БД
Сначала нужно добавить в модуль "Баннер" дополнительное поле, которое будет хранить идентификатор товара(product_id), для этого в БД, в таблице "oc_banner_image" добавляем поле product_id, числового типа(INT).
Модель
Дальше нужно переработать модель баннера, находится по адресу: /admin/model/design/banner.php.
В ней сначала нужно изменить запрос для работы с новым полем product_id в функциях addBanner и editBanner:
$this->db->query("INSERT INTO " . DB_PREFIX .
"banner_image SET banner_id = '" . (int)$banner_id . "',
language_id = '" . (int)$language_id . "',
title = '" . $this->db->escape($banner_image['title']) . "',
link = '" . $this->db->escape($banner_image['link']) . "',
image = '" . $this->db->escape($banner_image['image']) . "',
product_id = '" . (int)$banner_image['product_id'] . "',
sort_order = '" . (int)$banner_image['sort_order'] . "'");
В функции getBannerImages добавить в массив $banner_image_data новый элемент: 'product_id' => $banner_image['product_id'].
Контроллер
Далее предстоит сделать изменения в контроллере: /admin/controller/design/banner.php, но сделать их красиво:
в функцию getForm() добавить $data['entry_product_id'] = $this -> language -> get('entry_product_id');
Соответственно в файлы языка добавить entry_product_id, вот так - $_['entry_product_id'] = 'Товар:';
Потом в этой же функции(getForm) подключить модель product ($this -> load -> model('catalog/product');), нужно для получения данных товара, а затем получить товар по ид - $product_info = $this -> model_catalog_product -> getProduct($banner_image['product_id']);
Из всего массива полученных данных о товаре, нам нужно два поля name и product_id ($product_name = $product_info['name']), которое надо добавить в $data 'product_name' => $product_name, а заодно и ид товара 'product_id' => $banner_image['product_id'], но добавлять нужно с условием проверки. В итоге функция getForm() будет выглядить так:
protected function getForm() {
$data['heading_title'] = $this->language->get('heading_title');
$data['text_form'] = !isset($this->request->get['banner_id']) ? $this->language->get('text_add') : $this->language->get('text_edit');
$data['text_enabled'] = $this->language->get('text_enabled');
$data['text_disabled'] = $this->language->get('text_disabled');
$data['text_default'] = $this->language->get('text_default');
$data['entry_name'] = $this->language->get('entry_name');
$data['entry_title'] = $this->language->get('entry_title');
$data['entry_link'] = $this->language->get('entry_link');
$data['entry_image'] = $this->language->get('entry_image');
$data['entry_product_id'] = $this->language->get('entry_product_id');
$data['entry_status'] = $this->language->get('entry_status');
$data['entry_sort_order'] = $this->language->get('entry_sort_order');
$data['button_save'] = $this->language->get('button_save');
$data['button_cancel'] = $this->language->get('button_cancel');
$data['button_banner_add'] = $this->language->get('button_banner_add');
$data['button_remove'] = $this->language->get('button_remove');
if (isset($this->error['warning'])) {
$data['error_warning'] = $this->error['warning'];
} else {
$data['error_warning'] = '';
}
if (isset($this->error['name'])) {
$data['error_name'] = $this->error['name'];
} else {
$data['error_name'] = '';
}
if (isset($this->error['banner_image'])) {
$data['error_banner_image'] = $this->error['banner_image'];
} else {
$data['error_banner_image'] = array();
}
$url = '';
if (isset($this->request->get['sort'])) {
$url .= '&sort=' . $this->request->get['sort'];
}
if (isset($this->request->get['order'])) {
$url .= '&order=' . $this->request->get['order'];
}
if (isset($this->request->get['page'])) {
$url .= '&page=' . $this->request->get['page'];
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], true)
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('design/banner', 'token=' . $this->session->data['token'] . $url, true)
);
if (!isset($this->request->get['banner_id'])) {
$data['action'] = $this->url->link('design/banner/add', 'token=' . $this->session->data['token'] . $url, true);
} else {
$data['action'] = $this->url->link('design/banner/edit', 'token=' . $this->session->data['token'] . '&banner_id=' . $this->request->get['banner_id'] . $url, true);
}
$data['cancel'] = $this->url->link('design/banner', 'token=' . $this->session->data['token'] . $url, true);
if (isset($this->request->get['banner_id']) && ($this->request->server['REQUEST_METHOD'] != 'POST')) {
$banner_info = $this->model_design_banner->getBanner($this->request->get['banner_id']);
}
$data['token'] = $this->session->data['token'];
if (isset($this->request->post['name'])) {
$data['name'] = $this->request->post['name'];
} elseif (!empty($banner_info)) {
$data['name'] = $banner_info['name'];
} else {
$data['name'] = '';
}
if (isset($this->request->post['status'])) {
$data['status'] = $this->request->post['status'];
} elseif (!empty($banner_info)) {
$data['status'] = $banner_info['status'];
} else {
$data['status'] = true;
}
$this->load->model('localisation/language');
$data['languages'] = $this->model_localisation_language->getLanguages();
$this->load->model('tool/image');
if (isset($this->request->post['banner_image'])) {
$banner_images = $this->request->post['banner_image'];
} elseif (isset($this->request->get['banner_id'])) {
$banner_images = $this->model_design_banner->getBannerImages($this->request->get['banner_id']);
} else {
$banner_images = array();
}
$data['banner_images'] = array();
$this->load->model('catalog/product');
foreach ($banner_images as $key => $value) {
foreach ($value as $banner_image) {
if (is_file(DIR_IMAGE . $banner_image['image'])) {
$image = $banner_image['image'];
$thumb = $banner_image['image'];
} else {
$image = '';
$thumb = 'no_image.png';
}
$product_info = $this->model_catalog_product->getProduct($banner_image['product_id']);
$product_name = '';
if ($product_info) {
$product_name = $product_info['name'];
}
$data['banner_images'][$key][] = array(
'title' => $banner_image['title'],
'link' => $banner_image['link'],
'product_id' => $banner_image['product_id'],
'product_name' => $product_name,
'image' => $image,
'thumb' => $this->model_tool_image->resize($thumb, 100, 100),
'sort_order' => $banner_image['sort_order']
);
}
}
$data['placeholder'] = $this->model_tool_image->resize('no_image.png', 100, 100);
$data['header'] = $this->load->controller('common/header');
$data['column_left'] = $this->load->controller('common/column_left');
$data['footer'] = $this->load->controller('common/footer');
$this->response->setOutput($this->load->view('design/banner_form', $data));
}
Представление
Следующий шаг - изменения формы редактирования баннера, для этого нужно внести изменения в файл /admin/view/template/design/banner_form.tpl добавить поле, с отображнием имени товара(product_name), и скрытое поле с id-товара(product_id). Эти поля я вставил перед полем ссылки($banner_image['link']).
<input type="text" value="<?php echo $banner_image['product_name']; ?>" placeholder="<?php echo $entry_product_id; ?>" id="input-product<?php echo $image_row; ?>" class="form-control" name="product_name"/> <input type="hidden" name="banner_image[<?php echo $language['language_id']; ?>][<?php echo $image_row; ?>][product_id]" value="<?php echo $banner_image['product_id']; ?>">
А еще в этом файле, нужно подключить скрипт подбора товара. Ее можно взять из "рекомендуемого", но немного изменить:
$('input[name=\'product_name\']').autocomplete({
source: function(request, response) {
$.ajax({
url: 'index.php?route=catalog/product/autocomplete&token=&filter_name=' + encodeURIComponent(request),
dataType: 'json',
success: function(json) {
response($.map(json, function(item) {
return {
label: item['name'],
value: item['product_id']
}
}));
}
});
},
select: function(item) {
$(this).val(item['label']);
$(this).next().next().val(item['value']);
}
});
Отображение на сайте
На этом работа с административной частью окончена. Далее нужно разобраться выводом в каталог. В первую очередь идем в контроллер catalog/controller/extension/module/carousel.php в него нужно добавить загрузку модели товара $this->load->model('catalog/product'); и обработку строк баннера (взято из контроллера featured) - по условию что "$result['product_id']>0", если равно 0, то обрабатывать как картинку.
foreach ($results as $result) {
if ($result['product_id']>0) {
$product_info = $this->model_catalog_product->getProduct($result['product_id']);
if ($product_info) {
if ($product_info['image']) {
$image = $this->model_tool_image->resize($product_info['image'], $setting['width'], $setting['height']);
} else {
$image = $this->model_tool_image->resize('placeholder.png', $setting['width'], $setting['height']);
}
if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) {
$price = $this->currency->format($this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
} else {
$price = false;
}
if ((float)$product_info['special']) {
$special = $this->currency->format($this->tax->calculate($product_info['special'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
} else {
$special = false;
}
if ($this->config->get('config_tax')) {
$tax = $this->currency->format((float)$product_info['special'] ? $product_info['special'] : $product_info['price'], $this->session->data['currency']);
} else {
$tax = false;
}
if ($this->config->get('config_review_status')) {
$rating = $product_info['rating'];
} else {
$rating = false;
}
$data['banners'][] = array(
'name' => $result['name'],
'product_id' => $product_info['product_id'],
'thumb' => $image,
'product_name' => $product_info['name'],
'description' => utf8_substr(strip_tags(html_entity_decode($product_info['description'], ENT_QUOTES, 'UTF-8')), 0, $this->config->get($this->config->get('config_theme') . '_product_description_length')) . '..',
'price' => $price,
'special' => $special,
'tax' => $tax,
'rating' => $rating,
'href' => $this->url->link('product/product', 'product_id=' . $product_info['product_id'])
);
}
}
elseif (is_file(DIR_IMAGE . $result['image'])) {
$data['banners'][] = array(
'name' => $result['name'],
'title' => $result['title'],
'link' => $result['link'],
'image' => $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height'])
);
}
}
Теперь настроим отображение карусели, для это меняем шаблон вывода catalog/view/theme/default/template/extension/module/carousel.tpl. В него также добавлен кусок кода из featured, по условию , в итоге получается, что если массив данных имеет product_id, то выводится товар, а если не имеет, то выводится картинка, как и было задумано разработчиками.
Файлы для скачивания:
Архив к этой статье;
Обновлнеи карусели;
Навигация и заголовок;
