Разработчикам
Архитектура в двух словах
Чекаут собирается из блоков двух типов:
core-блоки - это обычные контроллеры ядра OpenCart (
checkout/register,checkout/shipping_method,checkout/payment_method,checkout/confirmи т.д.), конструктор просто вызывает их и расставляет на странице в нужном порядке. Те же самые экраны, что были в OpenCart изначально.custom-блоки - рендерятся универсально, по списку полей из базы данных, одним общим шаблоном.
Весь функционал лежит в расширении extension/ru_checkout. Если вы делаете свою тему или своё расширение и хотите с этим взаимодействовать - вам понадобится один из двух сценариев ниже.
Сценарий 1: переопределить вёрстку блока чекаута в своей теме
Если вы делаете тему и хотите изменить HTML конкретного блока чекаута (например, по-своему оформить блок регистрации), вам не нужно писать PHP или регистрировать события ядра. Конструктор сам ищет файл переопределения по условленному пути - достаточно положить .twig-файл в папку вашей темы.
Как это работает:
По умолчанию рендерится:
extension/ru_checkout/catalog/view/template/checkout/{route}.twig
Если в вашей теме есть файл:
extension/{ваша_тема}/catalog/view/template/ru_checkout/checkout/{route}.twig
...будет использован именно он.Где {route} - один из: checkout, register, shipping_address, shipping_method, payment_method, confirm, block_custom.
Пример. Допустим, код вашей темы - mytheme, и вы хотите переопределить блок «Способ оплаты». Просто создайте файл:
extension/mytheme/catalog/view/template/ru_checkout/checkout/payment_method.twigСодержимое может быть любым - скопируйте оригинальный файл из extension/ru_checkout/catalog/view/template/checkout/payment_method.twig как отправную точку и правьте вёрстку как вам нужно. Переменные ({{ heading_title }}, список полей и т.д.) останутся теми же - меняется только то, как они отображаются.
Никакой регистрации в install(), никаких PHP-классов. Тема просто появляется - и конструктор сам её подхватывает, пока модуль ru_checkout установлен.
Сценарий 2: прочитать значения кастомных полей чекаута в своём расширении
Если вы пишете расширение, которому нужно знать, что покупатель заполнил в кастомных полях чекаута (например, модуль доставки, которому нужно поле «Пункт выдачи»), значения уже сохранены в заказе, в отдельной таблице.
Таблица oc_checkout_order_field:
order_id — id заказа
block_code — код блока (например, "company")
field_code — код поля внутри блока (например, "inn")
value — сохранённое значениеКак прочитать значения в своём коде:
// Подключаем модель чекаута
$this->load->model('extension/ru_checkout/checkout/checkout');
// Получаем все кастомные поля конкретного заказа
$fields = $this->model_extension_ru_checkout_checkout_checkout->getOrderFields($order_id);
// $fields — массив строк вида ['block_code' => ..., 'field_code' => ..., 'value' => ...]
foreach ($fields as $field) {
if ($field['block_code'] === 'company' && $field['field_code'] === 'inn') {
$inn = $field['value'];
}
}Доступные события (events)
Если вашему расширению нужно среагировать на действия в чекауте, не трогая код ru_checkout напрямую, используйте штатный механизм событий OpenCart ($this->event->trigger / oc_event). Уже зарегистрированные точки, на которые можно повесить своё событие:
// Срабатывает сразу после создания заказа — удобно, если вам нужно
// что-то сделать с заказом сразу после оформления
'catalog/model/checkout/order.addOrder/after'
// Срабатывают перед рендером каждого блока чекаута — то, через что
// работает механизм переопределения тем из Сценария 1
'catalog/view/checkout/register/before'
'catalog/view/checkout/shipping_address/before'
'catalog/view/checkout/shipping_method/before'
'catalog/view/checkout/payment_method/before'
'catalog/view/checkout/confirm/before'Пример регистрации своего события (в install() вашего расширения):
// Сперва удаляем старую запись (на случай повторной установки), затем регистрируем заново
$this->db->query("DELETE FROM `" . DB_PREFIX . "event` WHERE `code` = 'myext_after_order'");
$this->db->query("
INSERT INTO `" . DB_PREFIX . "event` SET
`code` = 'myext_after_order',
`description` = 'Делаем что-то своё сразу после оформления заказа',
`trigger` = 'catalog/model/checkout/order.addOrder/after',
`action` = 'extension/myext/event/order.addOrderAfter',
`status` = '1',
`sort_order` = '0'
");И сам обработчик (extension/myext/catalog/controller/event/order.php в вашем расширении):
<?php
namespace Opencart\Catalog\Controller\Extension\Myext\Event;
class Order extends \Opencart\System\Engine\Controller {
// $route и $args — то, с чем вызывался исходный метод (нам здесь не нужно).
// $output — то, что он вернул. addOrder() возвращает id нового заказа,
// поэтому именно отсюда берём order_id, а не из $args.
public function addOrderAfter(string &$route, array &$args, &$output): void {
$order_id = (int)$output;
// ваша логика здесь
}
}Если нужно больше
Для более глубокой интеграции (свой тип блока, своя логика сохранения) стоит смотреть исходники extension/ru_checkout напрямую - архитектура простая: admin/model/other/checkout_constructor.php отвечает за блоки/поля, catalog/controller/checkout/checkout.php - за рендер на витрине. Больше 90% задач решается через Сценарий 1 или 2 выше.