В стандартном Opencart модули можно размещать в четырёх позициях макета: «Колонка слева», «Колонка справа», «Вверху страницы» и «Внизу страницы». Дизайн магазина часто требует других мест, например блока в шапке. Вторая частая задача - показать модуль на одной странице, а не на всех страницах с этим макетом. Ниже обе задачи для Opencart 3 и 4.

Перед правкой файлов сделайте резервную копию. Изменения в файлах ядра пропадут при обновлении Opencart, поэтому для боевого магазина их лучше оформить модификатором OCMOD (в Opencart 3) или через события и собственное расширение (в Opencart 4). Ниже показано, что именно меняется - перенести эти правки в модификатор несложно.

Как работают позиции

Схема страницы с отмеченными зонами позиций

Каждая позиция - это контроллер в catalog/controller/common/: column_left.php, column_right.php, content_top.php, content_bottom.php. Контроллер определяет макет текущей страницы, берёт из базы модули, назначенные этому макету в нужной позиции, и выводит их через шаблон. Шаблон позиции подключается в шаблонах страниц, например {{ content_top }} в шаблоне категории.

Значит, новая позиция - это три вещи: контроллер, шаблон и вывод в нужном месте, плюс пункт в форме макета в админке.

Название позиции хранится в поле position таблицы oc_layout_module, а длина этого поля ограничена (обычно 14 символов). Выбирайте короткое имя, например header_content, или увеличьте длину поля в базе.

Новая позиция в Opencart 3

Пример: позиция header_content для вывода модулей в шапке сайта.

1. Контроллер позиции

Скопируйте catalog/controller/common/content_top.php в catalog/controller/common/header_content.php. В новом файле:

  • переименуйте класс ControllerCommonContentTop в ControllerCommonHeaderContent;
  • в вызове getLayoutModules($layout_id, 'content_top') замените content_top на header_content;
  • в последней строке return $this->load->view('common/content_top', $data); замените шаблон на common/header_content.

2. Шаблон позиции

Создайте catalog/view/theme/<ваша тема>/template/common/header_content.twig:

twig
{% for module in modules %}
  {{ module }}
{% endfor %}

Можно обернуть вывод в свой div с классом для стилей.

3. Вывод в шапке

В catalog/controller/common/header.php перед строкой return $this->load->view('common/header', $data); добавьте:

php
$data['header_content'] = $this->load->controller('common/header_content');

В шаблоне common/header.twig вашей темы выведите позицию в нужном месте:

twig
{{ header_content }}

4. Пункт в форме макета

В admin/language/ru-ru/design/layout.php (и в файле английского языка) добавьте строку:

php
$_['text_header_content'] = 'Шапка сайта';

В admin/view/template/design/layout_form.twig каждая позиция оформлена отдельной таблицей: найдите блок таблицы с id="module-content-top" и скопируйте его целиком. В копии замените content-top на header-content, content_top на header_content и text_content_top на text_header_content. Функция addModule() в том же шаблоне строит имя позиции из идентификатора таблицы, поэтому кнопка добавления модуля заработает в новой таблице без отдельных правок.

Очистите кэш шаблонов («Панель управления» → значок шестерёнки → «Обновить кэш» для темы) и, если используются модификаторы, обновите их. После этого в «Дизайн» → «Макеты» появится позиция «Шапка сайта».

Новая позиция в Opencart 4

Логика та же, но код организован иначе:

  • контроллеры используют пространства имён: класс в catalog/controller/common/header_content.php объявляется как class HeaderContent extends \Opencart\System\Engine\Controller в пространстве имён Opencart\Catalog\Controller\Common;
  • путь к контроллеру расширения модуля строится с учётом расширения-владельца, поэтому копируйте именно content_top.php вашей версии и меняйте в нём только имя класса, позицию и шаблон;
  • шаблоны - Twig, как в Opencart 3; форма макета в админке - admin/view/template/design/layout_form.twig.

Правки ядра в Opencart 4 лучше не делать напрямую. Удобный путь - собственное расширение, которое через события (view/common/header/before и подобные) добавляет переменную с выводом позиции в шапку. Так магазин переживёт обновление.

Модуль только на одной странице

Четыре схемы страниц, на одной выделен модуль

Задача: модуль с блоками о компании должен выводиться на странице «О компании», но не на других информационных страницах («Доставка», «Оплата»), хотя у всех у них макет «Информация».

Без кода: свой макет для страницы

Opencart позволяет назначить отдельный макет конкретной статье, категории или товару.

  1. «Дизайн» → «Макеты» → «Добавить». Назовите макет, например, «О компании». Маршрут можно не указывать или указать information/information.
  2. В этом макете разместите нужный модуль в позиции «Вверху страницы» (или любой другой).
  3. Откройте «Каталог» → «Статьи» → «О компании», вкладка «Дизайн», и в поле «Переопределение макета» выберите «О компании».

Теперь у этой страницы свой набор модулей, а остальные информационные страницы продолжают использовать макет «Информация». Для каждой страницы со своими блоками создайте свой макет. Этот способ работает в Opencart 2.x, 3 и 4 и не ломается при обновлениях.

С кодом: условие в контроллере позиции

Если отдельные макеты неудобны (например, страниц много и модули назначаются программно), можно фильтровать вывод в контроллере позиции. В Opencart 3 в catalog/controller/common/content_top.php в цикле по модулям есть блок:

php
if (isset($part[1])) {
    $setting_info = $this->model_setting_module->getModule($part[1]);

    if ($setting_info && $setting_info['status']) {
        $output = $this->load->controller('extension/module/' . $part[0], $setting_info);

        if ($output) {
            $data['modules'][] = $output;
        }
    }
}

Здесь $part[1] - ID модуля (виден в адресе страницы редактирования модуля). Добавьте карту «модуль → страница» и проверку:

php
// ID модуля => ID информационной страницы
$only_on = array(59 => 4, 62 => 6, 63 => 8);

if ($output) {
    $module_id = (int)$part[1];

    if (isset($only_on[$module_id])) {
        $information_id = isset($this->request->get['information_id']) ? (int)$this->request->get['information_id'] : 0;

        if ($route == 'information/information' && $information_id == $only_on[$module_id]) {
            $data['modules'][] = $output;
        }
    } else {
        $data['modules'][] = $output;
    }
}

Модули из массива выводятся только на своих страницах, все остальные - как обычно. ID страницы виден в адресе редактирования статьи в админке.

Тот же приём работает в Opencart 4, только модель модулей там вызывается как $this->model_setting_module, а путь к контроллеру модуля включает код расширения. Ориентируйтесь на код content_top.php своей версии и вставляйте условие вокруг строки, которая добавляет $output в $data['modules'].

Об этих и других модулях для Opencart - в статье про бесплатные модули Opencart от logi.cc.