Товары в карусели 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, то выводится товар, а если не имеет, то выводится картинка, как и было задумано разработчиками.
Файлы для скачивания:
Архив к этой статье;
Обновлнеи карусели;
Навигация и заголовок;