Доповнення (розширення)
Створення власних доповнень#
ocStore підтримує доповнення (розширення), які додають або змінюють функціональність без редагування файлів ядра. Доповненнями можуть бути модулі (наприклад, слайдери чи аналітика), платіжні шлюзи, способи доставки, теми, звіти тощо. В ocStore 3 доповнення побудовані за шаблоном MVC-L (Model-View-Controller-Language), використовують систему подій (Events) як хуки та OCMOD для модифікацій. У цьому посібнику крок за кроком описано, як створити, запакувати й установити доповнення на прикладі модуля — найпоширенішого типу.
Що потрібно#
- Робоча інсталяція ocStore 3.0.4.1.
- Базові знання PHP, HTML, CSS, JavaScript і шаблону MVC.
- Знайомство з шаблонізатором Twig (використовується для представлень).
- Доступ до адмінки й файлової системи (через FTP або на сервері).
- Редактор коду (наприклад, VS Code, Notepad++) та ZIP-архіватор.
Дотримуйтеся правил найменування: пакет для встановлення має бути ZIP-архівом із назвою, що закінчується на .ocmod.zip. Розмір файлу обмежено налаштуваннями PHP сервера (upload_max_filesize, post_max_size).
Типи доповнень#
Можливі типи доповнень:
- Модулі: банери, каруселі, додаткові блоки тощо.
- Канали просування: товарні фіди (наприклад, Google Merchant), карта сайту.
- Оплата / Доставка: інтеграція платіжних шлюзів (наприклад, PayPal) або служб доставки.
- Шаблони (теми): оформлення вітрини.
- Звіти / Аналітикс: звіти в адмінці або інтеграція з сервісами на кшталт Google Analytics.
- Інші: антифрод, капча, враховувати в замовленні (order totals), валюти, панель стану тощо.
Усі доповнення керуються в адмінці в розділі Доповнення → Доповнення (тип вибирається у списку «Оберіть тип доповнення»).
Структура каталогів#
В ocStore 3 файли доповнення розміщуються безпосередньо у стандартних каталогах ядра, у підтеці extension/ відповідного типу. Наприклад, для модуля test_module:
- admin/ — файли адмінки:
controller/extension/module/test_module.php— контролер адмінки.language/uk-ua/extension/module/test_module.php— мовні рядки (а такожen-gb/...та інші мови).view/template/extension/module/test_module.twig— представлення адмінки.model/extension/module/test_module.php— необов'язкова модель для власних операцій із БД.
- catalog/ — файли вітрини:
controller/extension/module/test_module.php— контролер вітрини.language/uk-ua/extension/module/test_module.php— мовні рядки.view/theme/default/template/extension/module/test_module.twig— представлення вітрини (defaultабо назва вашої теми).model/extension/module/test_module.php— необов'язкова модель.
Для встановлення через адмінку ці файли пакуються в архів test_module.ocmod.zip такої структури:
- upload/ — файли, які буде скопійовано в корінь магазину зі збереженням шляхів (
upload/admin/...,upload/catalog/...). - install.xml — необов'язковий OCMOD-модифікатор.
Стандартні доповнення розташовані в тих самих каталогах (admin/controller/extension/module/ тощо). Використовуйте унікальну назву модуля (наприклад, з префіксом вашого бренду), щоб уникнути конфліктів з іншими доповненнями.
Покроково: створення простого модуля#
Створимо демонстраційний модуль «Test Module», який за допомогою події виконує дію під час додавання товару в кошик.
Створіть теку#
Створіть теку test_module/, а в ній — підтеку upload/. Усередині upload/ створіть файли, описані нижче (шляхи вказано відносно upload/).
1. Контролер адмінки#
Файл: admin/controller/extension/module/test_module.php
Він відповідає за сторінку налаштувань в адмінці, збереження форми та реєстрацію події під час встановлення.
<?php
class ControllerExtensionModuleTestModule extends Controller {
private $error = array();
public function index() {
$this->load->language('extension/module/test_module');
$this->document->setTitle($this->language->get('heading_title'));
$this->load->model('setting/setting');
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->model_setting_setting->editSetting('module_test_module', $this->request->post);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=module', true));
}
if (isset($this->error['warning'])) {
$data['error_warning'] = $this->error['warning'];
} else {
$data['error_warning'] = '';
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true)
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_extension'),
'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=module', true)
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('extension/module/test_module', 'user_token=' . $this->session->data['user_token'], true)
);
$data['action'] = $this->url->link('extension/module/test_module', 'user_token=' . $this->session->data['user_token'], true);
$data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=module', true);
if (isset($this->request->post['module_test_module_status'])) {
$data['module_test_module_status'] = $this->request->post['module_test_module_status'];
} else {
$data['module_test_module_status'] = $this->config->get('module_test_module_status');
}
$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('extension/module/test_module', $data));
}
protected function validate() {
if (!$this->user->hasPermission('modify', 'extension/module/test_module')) {
$this->error['warning'] = $this->language->get('error_permission');
}
return !$this->error;
}
public function install() {
// Завантажуємо модель подій
$this->load->model('setting/event');
// Реєструємо подію: code, trigger, action, status, sort_order
$this->model_setting_event->addEvent(
'test_module_cart_add_before', // Код події (унікальний ідентифікатор)
'catalog/controller/checkout/cart/add/before', // Тригер події
'extension/module/test_module/onCartAddBefore', // Метод-обробник
1,
1
);
}
public function uninstall() {
// Видаляємо подію під час деінсталяції
$this->load->model('setting/event');
$this->model_setting_event->deleteEventByCode('test_module_cart_add_before');
}
}
2. Мовний файл адмінки#
Файл: admin/language/uk-ua/extension/module/test_module.php (за потреби продублюйте англійською в admin/language/en-gb/extension/module/test_module.php)
<?php
$_['heading_title'] = 'Test module';
$_['text_extension'] = 'Доповнення';
$_['text_success'] = 'Налаштування модуля змінено!';
$_['text_edit'] = 'Редагування модуля';
$_['entry_status'] = 'Статус';
$_['error_permission'] = 'У вас недостатньо прав для зміни модуля Test module!';
3. Шаблон адмінки#
Файл: admin/view/template/extension/module/test_module.twig
Адмінка ocStore 3 використовує Bootstrap 3 і Font Awesome 4.
{{ header }}{{ column_left }}
<div id="content">
<div class="page-header">
<div class="container-fluid">
<div class="pull-right">
<button type="submit" form="form-module" data-toggle="tooltip" title="{{ button_save }}" class="btn btn-primary"><i class="fa fa-save"></i></button>
<a href="{{ cancel }}" data-toggle="tooltip" title="{{ button_cancel }}" class="btn btn-default"><i class="fa fa-reply"></i></a></div>
<h1>{{ heading_title }}</h1>
<ul class="breadcrumb">
{% for breadcrumb in breadcrumbs %}
<li><a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a></li>
{% endfor %}
</ul>
</div>
</div>
<div class="container-fluid">
{% if error_warning %}
<div class="alert alert-danger alert-dismissible"><i class="fa fa-exclamation-circle"></i> {{ error_warning }}
<button type="button" class="close" data-dismiss="alert">×</button>
</div>
{% endif %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-pencil"></i> {{ text_edit }}</h3>
</div>
<div class="panel-body">
<form action="{{ action }}" method="post" enctype="multipart/form-data" id="form-module" class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="input-status">{{ entry_status }}</label>
<div class="col-sm-10">
<select name="module_test_module_status" id="input-status" class="form-control">
{% if module_test_module_status %}
<option value="1" selected="selected">{{ text_enabled }}</option>
<option value="0">{{ text_disabled }}</option>
{% else %}
<option value="1">{{ text_enabled }}</option>
<option value="0" selected="selected">{{ text_disabled }}</option>
{% endif %}
</select>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{{ footer }}
4. Контролер подій на вітрині#
Файл: catalog/controller/extension/module/test_module.php
Він обробляє подію й записує рядок у журнал, коли вона спрацьовує.
Обробник події before отримує $route і $args за посиланням, тож може змінити аргументи виклику. Обробник події after додатково отримує $output — його можна змінити, щоб вплинути на кінцевий результат.
<?php
class ControllerExtensionModuleTestModule extends Controller {
public function onCartAddBefore(&$route, &$args) {
// Тут виконуйте свої дії
$this->log->write('onCartAddBefore() has been successfully triggered!');
}
}
5. Необов'язково: моделі#
Для власних операцій із базою даних створіть admin/model/extension/module/test_module.php або catalog/model/extension/module/test_module.php з класом ModelExtensionModuleTestModule extends Model і методами на кшталт addData() із SQL-запитами.
6. OCMOD для змін у ядрі (якщо подій недостатньо)#
Для змін, які не можна зробити через події, використовуйте OCMOD — XML-файл install.xml у корені архіву (поруч із текою upload/). Приклад додавання пункту меню в адмінку:
<?xml version="1.0" encoding="utf-8"?>
<modification>
<name>Example OCMOD</name>
<code>example_ocmod</code>
<version>1.0</version>
<author>Your Name</author>
<link>https://yourwebsite.com</link>
<file path="admin/controller/common/column_left.php">
<operation>
<search><![CDATA[if ($marketplace) {]]></search>
<add position="before"><![CDATA[
$data['menus'][] = array(
'id' => 'test-module',
'icon' => 'fa-cog',
'name' => 'Test Module',
'href' => $this->url->link('extension/module/test_module', 'user_token=' . $this->session->data['user_token'], true),
'children' => array()
);
]]></add>
</operation>
</file>
</modification>
Пакування та встановлення#
- Запакуйте вміст теки доповнення в ZIP з назвою на кшталт
test_module.ocmod.zip. Пакувати потрібно не саму текуtest_module/, а її вміст: відкривши архів, ви маєте одразу побачитиupload/(іinstall.xml, якщо він є). - Перейдіть у Доповнення → Установка доповнень і завантажте ZIP-файл. Установка запуститься автоматично, хід процесу відображається на сторінці, а пакет з'явиться в «Історії установок».
- Перейдіть у Доповнення → Доповнення, виберіть тип Модулі і натисніть «Активація» (зелена кнопка «+») навпроти вашого модуля. Під час цього виконується метод
install(). - Якщо пакет містить OCMOD, оновіть кеш модифікацій у Доповнення → Модифікатори → кнопка «Оновити» (синя).
- За потреби очистіть кеш: Панель стану → кнопка з шестернею («Налаштування розробника»).
- Налаштуйте й увімкніть модуль у Доповнення → Доповнення → Модулі (кнопка «Редагувати»).
Якщо виникають помилки, перегляньте журнали в system/storage/logs/ (або Система → Обслуговування → Журнал помилок) і переконайтеся у відсутності конфліктів файлів.
Рекомендації#
- Найменування класів: назва класу має відповідати шляху (
admin/controller/extension/module/test_module.php→ControllerExtensionModuleTestModule). - Інтернаціоналізація: увесь текст виносьте в мовні файли (щонайменше
uk-uaтаen-gb). - Безпека: перевіряйте вхідні дані та права доступу (
$this->user->hasPermission()). - Сумісність: тестуйте на різних темах і версіях PHP (ocStore 3.0.4.1 підтримує PHP 8).
- Прибирання: реалізуйте
uninstall(), щоб видаляти записи в БД і події. - Документація: додайте інструкції в README у пакеті.
- Мінімум змін у ядрі: коли можливо, віддавайте перевагу подіям, а не OCMOD.
- Тестування: працюйте на тестовому магазині, частіше оновлюйте кеш і модифікатори.
- Публікація: якщо поширюєте доповнення, дотримуйтеся вимог маркетплейсу, де його розміщуєте.
Більше прикладів#
Наведений приклад базовий і допомагає зрозуміти логіку створення доповнень. Щоб побачити, як улаштовані доповнення всіх типів (модулі, платіжні шлюзи, способи доставки тощо), найкраще вивчити стандартні доповнення, що входять до складу ocStore: їхні файли лежать у admin/controller/extension/<тип>/, catalog/controller/extension/<тип>/ і відповідних каталогах мов, моделей та шаблонів (наприклад, модулі bestseller, latest, carousel, способи оплати bank_transfer, cod). Скопіюйте структуру й адаптуйте її під свої потреби.