Joomla разработчикам и в частности разработчикам, работающим с JoomShopping часто не хватает актуальной документации для работы. Эта справочная статья призвана восполнить этот пробел и дать представление о всём потоке данных в процессе оформления заказа в компоненте интернет-магазина JoomShopping. Описывается порядок исполнения кода, все триггеры плагинов в хронологическом порядке, а так же какие данные они получают на вход и типы этих данных, описывается как прокидывать свои данные из плагина в шаблон JoomShopping в позиции вида _tmp_var....

Оглавление

Как читать этот документ

Этот документ построен строго по времени выполнения кода. Для каждого этапа показано:

  1. Где мы находимся (Controller -> Model -> View preparation -> View template).
  2. Какие события плагинов срабатывают и в каком порядке.
  3. Какие аргументы получает каждое событие (с типами аргументов).
  4. Что именно в этот момент можно прокинуть в шаблон: существующие _tmp_* позиции и собственные поля.

Собрано по файлам JoomShopping 5.9.0.

Принятый порядок слоев

В процессе оформления заказа (checkout) у JoomShopping фактический порядок чаще всего такой:

  1. Controller стартует этап.
  2. Controller вызывает model-методы, где формируются данные/фрагменты и срабатывают события плагинов в Model / Table.
  3. Controller собирает View и вызывает onBeforeDisplay...View.
  4. Только после этого выполняется template (display() или loadTemplate()).

Важно: в site/View/Checkout/HtmlView.php нет собственных triggerEvent(...).


Этап 0. Корзина (кнопка «Оформить заказ»)

Где мы

  • Controller: CartController::view()site/Controller/CartController.php.
  • Model: CartModelsite/Model/CartModel.php, CartpreviewModelsite/Model/CartpreviewModel.php, CheckoutModel (навигация) — site/Model/CheckoutModel.php.
  • View: site/templates/default/cart/cart.php.

Поток данных этапа

  1. Загружается cart и пересчитываются суммы/налоги.
  2. Генерируется href_checkout через CartpreviewModel::getUrlCheckout().
  3. В template выводится кнопка JSHOP_CHECKOUT с ссылкой на checkout&task=step2 (иногда check_login=1).

Хронология trigger-ов

#ГдеTriggerАргументы (тип)Что можно прокинуть в шаблон
1 CartController::init() onConstructJshoppingControllerCart (&$obj) (CartController) Можно изменить поведение контроллера до view()
2 CartModel::__construct() onConstructJshopCart (&$obj) (CartModel) Глобальная инициализация cart model
3 CartModel::load() onBeforeCartLoad (&$obj) (CartModel) Подготовка cart данных до загрузки
4 CartModel::load() onAfterCartLoad (&$obj) Можно дописать поля продуктов cart
5 CartModel::load() onAfterLoadPriceAndCountProducts (&$obj) После расчета цен/количества
6 CartpreviewModel::prepareView() onBeforeDisplayCart (&$cart, &$obj) (CartModel, CartpreviewModel) Удобная точка для подготовки cart-вставок до view
7 CheckoutModel::showCheckoutNavigation() onBeforeDisplayCheckoutNavigator (&$output, &$array_navigation_steps, &$step) (array, array, string|int) Можно менять HTML шагов в навигаторе
8 CheckoutModel::showCheckoutNavigation() onAfterDisplayCheckoutNavigator (&$view) (checkout view) Можно добавить поля в view меню
9 CartController::view() onBeforeDisplayCartView (&$view) (cart view) Прямое назначение _tmp_* полей cart template

Template-позиции cart, доступные на этом этапе

В CartController::view() инициализируются: _tmp_ext_html_cart_start, _tmp_html_after_subtotal, _tmp_html_after_total, _tmp_ext_subtotal, _tmp_html_before_buttons, _tmp_html_after_buttons, _tmp_ext_html_before_discount, _tmp_ext_html_after_discount, _tmp_ext_total, _tmp_ext_discount_text, _tmp_ext_discount, массив _tmp_ext_tax.

Пример (этап корзины)

public function onBeforeDisplayCartView(&$view): void
{
    $view->_tmp_ext_html_cart_start = '<div class="alert alert-info">Проверка корзины перед checkout</div>';
    $view->_tmp_ext_total = '<span class="text-muted"> (с учетом ваших условий)</span>';
}

Этап 1. Заполнение данных пользователя (checkout step2)

Где мы

  • Controller: CheckoutController::step2() и step2save()site/Controller/CheckoutController.php.
  • Model: CheckoutModel (showCheckoutNavigation, loadSmallCart, setEmptyCheckoutPrices, setMaxStep) — site/Model/CheckoutModel.php; CartModelsite/Model/CartModel.php; CartpreviewModelsite/Model/CartpreviewModel.php.
  • View: site/templates/default/checkout/adress.php + site/templates/default/cart/checkout.php (малая корзина).

Поток данных этапа

  1. Открытие шага step2: загрузка профиля пользователя, полей формы, навигатора и малой корзины.
  2. Сохранение step2save: валидация/сохранение пользователя, сброс shipping/payment в корзине.
  3. Переход на следующий шаг через CheckoutStepModel::getNextStep(2).

Хронология trigger-ов (step2)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::init() onConstructJshoppingControllerCheckout (&$obj) (CheckoutController) Глобальная инициализация checkout controller
2 CheckoutController::step2() onLoadCheckoutStep2 () Старт шага, до подготовки view
3 CheckoutModel::showCheckoutNavigation() onBeforeDisplayCheckoutNavigator (&$output, &$array_navigation_steps, &$step) Модификация навигатора
4 CheckoutModel::showCheckoutNavigation() onAfterDisplayCheckoutNavigator (&$view) Доп. данные menu template
5 CartModel::__construct()showSmallCart) onConstructJshopCart (&$obj) Инициализация cart model для small cart
6 CartModel::load() onBeforeCartLoad (&$obj) Перед загрузкой cart
7 CartModel::load() onAfterCartLoad (&$obj) После загрузки cart
8 CartModel::load() onAfterLoadPriceAndCountProducts (&$obj) После пересчетов
9 CartpreviewModel::prepareView() (step=2) onBeforeDisplaySmallCart (&$cart, &$obj) Подготовка данных малой корзины
10 CartModel::getTaxExt() onAfterCartGetTaxExt (&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment) Можно корректировать tax-list
11 CartModel::getSum() onAfterCartGetSum (&$obj, &$incShiping, &$incRabatt, &$incPayment) Можно влиять на итог fullsum
12 CheckoutModel::showSmallCart() onBeforeDisplayCheckoutCartView (&$view) Прямые _tmp_* вставки в cart/checkout.php
13 CheckoutController::step2() onBeforeDisplayCheckoutStep2View (&$view) (checkout view) Прямые вставки в checkout/adress.php

Хронология trigger-ов (step2save)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step2save() onLoadCheckoutStep2save (&$post) (array<string,mixed>) Нормализация входных данных формы
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Правки cart перед сохранением.
3 CheckoutController::step2save() onBeforeSaveCheckoutStep2 (&$adv_user, &$user, &$cart, &$model) Записать свои поля в user/cart до save
4 CheckoutController::step2save() onAfterSaveCheckoutStep2 (&$adv_user, &$user, &$cart) Пост-обработка после save
5 CheckoutModel::setMaxStep() onAfterSetMaxStepJshopCheckout (&$step) Контроль перехода на следующий шаг

Template-позиции этапа

В step2 доступны: _tmp_ext_html_address_start, _tmp_ext_html_address_end, _tmpl_address_html_2..._tmpl_address_html_9.

Пример (этап step2)

public function onBeforeDisplayCheckoutStep2View(&$view): void
{
    $view->_tmp_ext_html_address_start = '<div class="checkout-tip">Заполните обязательные поля</div>';
    $view->_tmpl_address_html_7 .= '<div class="custom-block">Доп. блок перед submit</div>';
    $view->myAddressMeta = ['source' => 'plugin', 'ts' => time()];
}

Этап 2. Выбор оплаты (checkout step3)

Где мы

  • Controller: CheckoutController::step3() и step3save()site/Controller/CheckoutController.php.
  • Model: CheckoutPaymentModelsite/Model/CheckoutpaymentModel.php, CheckoutModel (навигация/малая корзина) — site/Model/CheckoutModel.php, CartModelsite/Model/CartModel.php, CartpreviewModelsite/Model/CartpreviewModel.php.
  • View: site/templates/default/checkout/payments.php.

Поток данных этапа

  1. Загружается список способов оплаты.
  2. Для каждого метода может быть построена HTML-форма платежного плагина.
  3. На step3save проверяется и сохраняется выбранный метод оплаты и её params.

Хронология trigger-ов (step3)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step3() onLoadCheckoutStep3 () Старт шага оплаты
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Коррекция cart перед рендером оплаты
3 CheckoutModel::showCheckoutNavigation() onBeforeDisplayCheckoutNavigator (&$output, &$array_navigation_steps, &$step) Меню checkout
4 CheckoutModel::showCheckoutNavigation() onAfterDisplayCheckoutNavigator (&$view) Данные в menu view
5 CartpreviewModel::prepareView() (step=3) onBeforeDisplaySmallCart (&$cart, &$obj) Данные small cart для шага оплаты
6 CartModel::getTaxExt() onAfterCartGetTaxExt (&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment) Влияние на налоги
7 CartModel::getSum() onAfterCartGetSum (&$obj, &$incShiping, &$incRabatt, &$incPayment) Влияние на итог
8 CheckoutModel::showSmallCart() onBeforeDisplayCheckoutCartView (&$view) _tmp_* для малой корзины
9 CheckoutController::step3() onBeforeDisplayCheckoutStep3View (&$view) _tmp_ext_html_payment_start/end, свои поля view

Хронология trigger-ов (step3save)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step3save() onBeforeSaveCheckoutStep3save (&$post) Валидировать/переписать post-параметры
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Подготовка cart к savePaymentData
3 CheckoutController::step3save() onAfterSaveCheckoutStep3save (&$adv_user, &$paym_method, &$cart) До перехода на следующий step
4 CheckoutModel::setMaxStep() onAfterSetMaxStepJshopCheckout (&$step) Контроль маршрута

Template-позиции этапа

В step3 доступны _tmp_ext_html_payment_start и _tmp_ext_html_payment_end.

Пример (этап step3)

public function onBeforeDisplayCheckoutStep3View(&$view): void
{
    $view->_tmp_ext_html_payment_start = '<div class="pay-note">Оплата защищена</div>';
    $view->myPaymentFlags = ['supportsInstallments' => true];
}

Этап 3. Выбор доставки (checkout step4)

Где мы

  • Controller: CheckoutController::step4() и step4save()site/Controller/CheckoutController.php.
  • Model: CheckoutShippingModelsite/Model/CheckoutshippingModel.php, CheckoutModelsite/Model/CheckoutModel.php, CartModelsite/Model/CartModel.php, CartpreviewModelsite/Model/CartpreviewModel.php.
  • View: site/templates/default/checkout/shippings.php.

Поток данных этапа

  1. Вычисляются доступные способы доставки по стране/оплате.
  2. Для каждого метода может отрисовываться форма способа доставки (shipping form).
  3. На step4save сохраняются параметры, пересчитываются суммы, при необходимости обновляется стоимость заказа (payment price).

Хронология trigger-ов (step4)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step4() onLoadCheckoutStep4 () Старт шага доставки
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Коррекция cart
3 CheckoutModel::showCheckoutNavigation() onBeforeDisplayCheckoutNavigator (&$output, &$array_navigation_steps, &$step) Навигатор
4 CheckoutModel::showCheckoutNavigation() onAfterDisplayCheckoutNavigator (&$view) Навигатор view
5 CartpreviewModel::prepareView() (step=4) onBeforeDisplaySmallCart (&$cart, &$obj) Small cart
6 CartModel::getTaxExt() onAfterCartGetTaxExt (&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment) Налоги
7 CartModel::getSum() onAfterCartGetSum (&$obj, &$incShiping, &$incRabatt, &$incPayment) Итог
8 CheckoutModel::showSmallCart() onBeforeDisplayCheckoutCartView (&$view) _tmp_* малого cart
9 CheckoutController::step4() onBeforeDisplayCheckoutStep4View (&$view) _tmp_ext_html_shipping_start/end, custom поля

Хронология trigger-ов (step4save)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step4save() onBeforeSaveCheckoutStep4save () Превалидация перед saveShippingData
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Коррекция cart
3 CheckoutController::step4save() onAfterSaveCheckoutStep4 (&$adv_user, &$sh_method, &$shipping_method_price, &$cart) Фиксация выбора доставки
4 CheckoutModel::setMaxStep() onAfterSetMaxStepJshopCheckout (&$step) Переход

Template-позиции этапа

В step4 доступны _tmp_ext_html_shipping_start и _tmp_ext_html_shipping_end.


Этап 4. Подтверждение заказа (checkout step5)

Где мы

  • Controller: CheckoutController::step5() и step5save()site/Controller/CheckoutController.php.
  • Model: CheckoutModelsite/Model/CheckoutModel.php, CheckoutOrderModelsite/Model/CheckoutorderModel.php, CartModelsite/Model/CartModel.php, OrderTablesite/Table/OrderTable.php, CartpreviewModelsite/Model/CartpreviewModel.php.
  • View: site/templates/default/checkout/previewfinish.php + малая корзина site/templates/default/cart/checkout.php.

Поток данных этапа

  1. Отображается финальный предпросмотр заказа: адрес, доставка, оплата, суммы.
  2. При отправке формы (step5save) выполняются проверки AGB (согласия на обработку перс.данных и право возврата) / stock (списание, наличие) / coupon (работа с купонами).
  3. Создается order и order items.
  4. Если оплата не нужна или сумма ноль — сразу finish, иначе step6/step6iframe.

Хронология trigger-ов (step5)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step5() onLoadCheckoutStep5 () Старт preview
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Подготовка cart
3 CheckoutModel::showCheckoutNavigation() onBeforeDisplayCheckoutNavigator (&$output, &$array_navigation_steps, &$step) Навигатор
4 CheckoutModel::showCheckoutNavigation() onAfterDisplayCheckoutNavigator (&$view) Навигатор view
5 CartpreviewModel::prepareView() (step=5) onBeforeDisplaySmallCart (&$cart, &$obj) Small cart
6 CartModel::getTaxExt() onAfterCartGetTaxExt (&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment) Налоги
7 CartModel::getSum() onAfterCartGetSum (&$obj, &$incShiping, &$incRabatt, &$incPayment) Итог
8 CheckoutModel::showSmallCart() onBeforeDisplayCheckoutCartView (&$view) _tmp_* малого cart
9 CheckoutController::step5() onBeforeDisplayCheckoutStep5 (&$sh_method, &$pm_method, &$delivery_info, &$cart, &$view) Можно дописать данные в delivery_info и view
10 CheckoutController::step5() onBeforeDisplayCheckoutStep5View (&$view) _tmp_ext_html_previewfinish_*, custom поля

Хронология trigger-ов (step5save)

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step5save() onLoadStep5save (&$checkagb) (string|null) Переопределить AGB check
2 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Подготовка cart
3 CartModel::checkListProductsQtyInStore() onBeforeCheckListProductsQtyInStore (&$obj) Влиять на pre-check stock
4 CartModel::checkListProductsQtyInStore() onCheckListProductsQtyInStoreForeach (&$obj, &$key, &$product, &$attr, &$qtyInStock, &$checkqty, &$check) Проверка каждого товара
5 CartModel::checkListProductsQtyInStore() onAfterCheckListProductsQtyInStore (&$obj) Финал stock-check
6 CartModel::checkCoupon() onBeforeCheckCouponStep5save (&$obj, &$coupon) Проверка купона перед orderDataSave
7 OrderTable::getListFieldCopyUserToOrder() onBeforeGetListFieldCopyUserToOrder (&$list) Добавить/убрать поля копирования user->order
8 OrderTable::formatOrderNumber() onAfterFormatOrderNumber (&$number, &$num) Формат номера заказа
9 OrderTable::copyDeliveryData() (если надо) onAfterCopyDeliveryData (&$obj) Правка delivery полей в order
10 CheckoutOrderModel::createOrder() onBeforeCreateOrder (&$order, &$cart, &$obj) Ключевая точка перед order->store()
11 OrderTable::store() onBeforeStoreTableOrder (&$obj) Последний guard перед сохранением заказа
12 CheckoutOrderModel::orderDataSave() onAfterCreateOrder (&$order, &$cart) После создания order
13 CheckoutOrderModel::couponFinished() onBeforeCouponFinished (&$coupon, &$cart, &$user_id, &$order) Коррекция coupon finalize
14 OrderTable::saveOrderItem() onBeforeSaveOrderItem (&$order_item, &$value) Изменение order item перед store
15 CheckoutOrderModel::orderDataSave() onAfterCreateOrderFull (&$order, &$cart) После полного набора order данных
16 OrderTable::saveOrderHistory() onBeforeJshopOrderSaveOrderHistory (&$history, &$notify, &$comments, &$obj) Комментарий/флаги history
17 OrderTable::changeProductQTYinStock() onBeforechangeProductQTYinStock (&$items, &$obj, &$change) До списания/возврата склада
18 OrderTable::changeProductQTYinStock() onAfterchangeProductQTYinStock (&$item, &$change, &$obj) После каждой позиции
19 OrderTable::changeProductQTYinStock() onAfterchangeProductQTYinStockPSR (&$items, &$obj, &$change, &$product_stock_removed) После всего batch
20 CheckoutController::step5save() onEndCheckoutStep5 (&$order, &$cart) Финал шага и выбор следующего этапа
21 CheckoutModel::setMaxStep() onAfterSetMaxStepJshopCheckout (&$step) Переход к step6/finish

Template-позиции этапа

В preview (step5) доступны:
- _tmp_ext_html_previewfinish_start
- _tmp_ext_html_previewfinish_agb
- _tmp_ext_html_previewfinish_before_button
- _tmp_ext_html_previewfinish_end

В малой корзине (showSmallCart) доступны:
- _tmp_ext_subtotal, _tmp_ext_discount_text, _tmp_ext_discount, _tmp_ext_shipping, _tmp_ext_shipping_package, _tmp_ext_payment, _tmp_ext_tax[], _tmp_ext_total
- _tmp_html_after_subtotal, _tmp_html_after_total, _tmp_html_after_checkout_cart
- checkoutcartdescr

Пример (этап step5)

public function onBeforeDisplayCheckoutStep5View(&$view): void
{
    $view->_tmp_ext_html_previewfinish_before_button = '<div class="legal">Нажимая кнопку, вы принимаете условия.</div>';
}

public function onBeforeDisplayCheckoutCartView(&$view): void
{
    $view->checkoutcartdescr = '<p>Итоговые суммы могут зависеть от статуса оплаты.</p>';
}

Этап 5. Переход к платежной системе (step6 / step6iframe)

Где мы

  • Controller: CheckoutController::step6iframe() / step6()site/Controller/CheckoutController.php.
  • Model: CheckoutOrderModelsite/Model/CheckoutorderModel.php, CheckoutModelsite/Model/CheckoutModel.php, OrderChangeStatusModel (если отмена) — site/Model/OrderchangestatusModel.php.
  • View: site/templates/default/checkout/step6iframe.php (iframe-режим).

Поток данных этапа

  1. step6iframe строит URL в платежный этап и может менять размеры/URL через trigger.
  2. step6 вызывает showEndFormPaymentSystem($order_id).
  3. Если пользователь вернулся назад в ПС (getSendEndForm()==1), вызывается cancelPayOrder() с полноценным статусным lifecycle.

Хронология trigger-ов

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step6iframe() onBeforeStep6Iframe (&$width, &$height, &$url) Можно изменить URL iframe, размеры
2 CheckoutOrderModel::showEndFormPaymentSystem() onBeforeShowEndFormStep6 (&$order, &$cart, $pm_method) Дополнить order/cart перед showEndForm()
3 CheckoutModel::cancelPayOrder() (ветка отмены) onAfterCancelPayOrderJshopCheckout (&$order_id, $status, $sendmessage) Пост-обработка cancel

Если на step6 произошла отмена: status-lifecycle triggers

При вызове cancelPayOrder()->changeStatusOrder()->OrderChangeStatusModel::store():

  • onBeforeChangeOrderStatus(...) или onBeforeChangeOrderStatusAdmin(...)
  • onBeforeJshopOrderSaveOrderHistory(...)
  • onBeforeCreateMailOrderStatusView(&$view)
  • onBeforeSendClientMailOrderStatus(...) / ...Admin... / ...Vendor...
  • onBeforeSendMailChangeOrderStatusClient(...) / ...Admin... / ...Vendor...
  • onAfterChangeOrderStatus(...) или ...Admin...

Этап 6. Обработка уведомлений о статусе заказа Callback/Return/Notify (step7)

Где мы

  • Controller: CheckoutController::step7()site/Controller/CheckoutController.php.
  • Model: CheckoutBuyModelsite/Model/CheckoutbuyModel.php, CheckoutOrderModelsite/Model/CheckoutorderModel.php, OrderTablesite/Table/OrderTable.php, OrderChangeStatusModelsite/Model/OrderchangestatusModel.php.
  • View: отсутствует (в этом шаге нет обычного display checkout view).

Поток данных этапа

  1. Загружаются URL params платежного метода (loadUrlParams).
  2. buy() проверяет транзакцию, вычисляет статус, сохраняет trx-данные.
  3. Если нужно, впервые «создает» order в смысле order_created=1 и меняет статус.
  4. Для notify завершает через nofityFinish и die().
  5. Для return/прочих завершает finish(...) и редиректит на checkout finish.

Хронология trigger-ов

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::step7() onLoadStep7 () Старт callback этапа
2 OrderTable::orderCreateAndSetStatus() onOrderCreateAndSetStatus (&$order_id, &$status, &$prev_order_status_data) Реакция на атомарную смену order_status/order_created
3 CheckoutBuyModel::buy() (если order создан впервые на step7) onStep7OrderCreated (&$order, &$res, &$obj, &$pmconfigs) Пост-логика после «досоздания» заказа
4 OrderChangeStatusModel::store() (если смена статуса) onBeforeChangeOrderStatus... -> mail triggers -> onAfterChangeOrderStatus... См. этап 5 Управление бизнес-логикой смены статуса
5 CheckoutBuyModel::buy() onStep7BefereNotify (&$order, &$obj, &$pmconfigs) Последняя точка перед notify/finish ПС
6 CheckoutModel::setMaxStep() (успешный путь) onAfterSetMaxStepJshopCheckout (&$step) Переход на finish

Где хранить свои данные на этом этапе

Здесь нет checkout-view. Данные обычно прокидывают через:

  • поля заказа ($order->order_add_info, пользовательские поля заказа вида $order->my_custom_data),
  • transaction data,
  • комментарий истории заказа,
  • сессию/логическую метку в вашем сервисе.

Этап 7. Финальный экран (checkout finish)

Где мы

  • Controller: CheckoutController::finish()site/Controller/CheckoutController.php.
  • Model: CheckoutFinishModelsite/Model/CheckoutfinishModel.php, CartModelsite/Model/CartModel.php, CheckoutModelsite/Model/CheckoutModel.php.
  • View: site/templates/default/checkout/finish.php.

Поток данных этапа

  1. Загружается текст order_finish_descr.
  2. Триггер плагина перед отображением может изменить text, text_end, order_id.
  3. После рендера вызывается paymentComplete().
  4. Очищаются cart и checkout session.

Хронология trigger-ов

#ГдеTriggerАргументы (тип)Что можно прокинуть
1 CheckoutController::finish() onBeforeDisplayCheckoutFinish (&$text, &$order_id, &$text_end) Основная точка финального контента на finish template
2 CheckoutFinishModel::paymentComplete() onAfterDisplayCheckoutFinish (&$text, &$order, &$pm_method) Пост-обработка после payment_system->complete()
3 CheckoutFinishModel::clearAllDataCheckout() динамические Helper::Js_add_trigger(..., "before") (&$callerObject, &$varsArray) Хуки до очистки cart/session
4 CartModel::load() onBeforeCartLoad / onAfterCartLoad / onAfterLoadPriceAndCountProducts (&$obj) Подготовка cart перед clear
5 CartModel::getSum() onAfterCartGetSum (&$obj, &$incShiping, &$incRabatt, &$incPayment) Если нужно вмешательство в пересчет перед clear
6 CartModel::clear() onBeforeClearCart (&$obj) До полной очистки cart
7 CartModel::saveToSession() onAfterSaveToSessionCart (&$obj) После фиксации пустой cart в session
8 CheckoutModel::deleteSession() onAfterDeleteDataOrder (&$obj) После очистки checkout session
9 CheckoutFinishModel::clearAllDataCheckout() динамические Helper::Js_add_trigger(..., "after") (&$callerObject, &$varsArray) Хуки после очистки

Что можно прокинуть на finish

На этапе onBeforeDisplayCheckoutFinish задавайте:

  • $text (основной HTML/текст),
  • $text_end (дополнительный блок в конце),
  • свои данные через $text/$text_end или через собственные поля view (если доработан шаблон).

_tmp_var..., _tmp_ext..., _tmpl_...: практическая карта

Где реально доступны позиции в checkout потоке

  1. step2 (checkout/adress.php): _tmp_ext_html_address_start/end, _tmpl_address_html_2...9.
  2. step3 (checkout/payments.php): _tmp_ext_html_payment_start/end.
  3. step4 (checkout/shippings.php): _tmp_ext_html_shipping_start/end.
  4. step5 (checkout/previewfinish.php): _tmp_ext_html_previewfinish_start, _tmp_ext_html_previewfinish_agb, _tmp_ext_html_previewfinish_before_button, _tmp_ext_html_previewfinish_end.
  5. Малая корзина checkout (cart/checkout.php): _tmp_ext_subtotal, _tmp_ext_discount_text, _tmp_ext_discount, _tmp_ext_shipping, _tmp_ext_shipping_package, _tmp_ext_payment, _tmp_ext_tax[], _tmp_ext_total, _tmp_html_after_subtotal, _tmp_html_after_total, _tmp_html_after_checkout_cart, checkoutcartdescr.
  6. Product/List (вне checkout, но часто используют вместе): _tmp_var_start, _tmp_var_buttons, _tmp_var_end и др.

Универсальный паттерн для каждого trigger

Если trigger дает &$view:

  1. Назначайте существующие _tmp_* позиции напрямую.
  2. Добавляйте свои поля ($view->myCustomData) и читайте их в override template.

Если trigger дает &$order, &$cart, &$product:

  1. Пишите данные в поля объекта (order_add_info, custom props).
  2. Либо в следующем ...BeforeDisplay...View переносите эти данные в view и _tmp_* позиции.

Пример: «существующая позиция + свои данные»

public function onBeforeDisplayCheckoutStep4View(&$view): void
{
    // 1) В существующую позицию
    $view->_tmp_ext_html_shipping_start = '<div class="shipping-banner">Курьер приедет в выбранный слот</div>';

    // 2) Свой payload
    $view->myShippingMeta = [
        'feature' => 'slot-selector',
        'enabled' => true,
    ];
}

Шаблон (checkout/shippings.php override):

<?php if (!empty($this->myShippingMeta['enabled'])): ?>
    <div class="slot-info">Feature: <?php echo htmlspecialchars($this->myShippingMeta['feature'], ENT_QUOTES, 'UTF-8'); ?></div>
<?php endif; ?>

Быстрый checklist для проверки своего плагина

  1. В каждом этапе цепляйтесь за самый поздний ...BeforeDisplay...View, если ваша цель — шаблон.
  2. Если цель — бизнес-логика заказа, используйте onBeforeCreateOrder, onAfterCreateOrderFull, onStep7OrderCreated.
  3. Если цель — статусная интеграция (CRM/ERP), используйте onAfterChangeOrderStatus... и mail-события.
  4. Для изменения внешнего вида страницы "спасибо за заказ" — onBeforeDisplayCheckoutFinish и onAfterDisplayCheckoutFinish.
  5. Не ожидайте триггеров внутри Checkout HtmlView: их нет, они происходят до display().

Приложение A. Полные сигнатуры trigger-ов по этапам (с путями к файлам)

События плагинов даны в хронологическом порядке срабатывания. Формат строк: Trigger(аргументы)path/to/file.php::method().

Обратите внимание на то, что JoomShopping до сих пор (JoomShopping 5.9.0) использует старые способы вызова событий и для получения аргументов события в своём плагине лучше, чтобы он наследовал SubscriberInterface и соответственно получал аргументы через [$param1, $param2, $paramXXX] = $event->getArguments(). Возможно когда-нибудь в будущем JoomShopping перейдёт на собственные классы событий.

A1. Cart (CartController::view)

  1. onConstructJshoppingControllerCart(&$obj)site/Controller/CartController.php::init().
  2. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  3. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  4. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  5. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  6. onBeforeDisplayCart(&$cart, &$obj)site/Model/CartpreviewModel.php::prepareView().
  7. onBeforeDisplayCheckoutNavigator(&$output, &$array_navigation_steps, &$step)site/Model/CheckoutModel.php::showCheckoutNavigation().
  8. onAfterDisplayCheckoutNavigator(&$view)site/Model/CheckoutModel.php::showCheckoutNavigation().
  9. onBeforeDisplayCartView(&$view)site/Controller/CartController.php::view().

A2. Step2 (CheckoutController::step2, step2save)

  1. onConstructJshoppingControllerCheckout(&$obj)site/Controller/CheckoutController.php::init().
  2. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  3. onLoadCheckoutStep2()site/Controller/CheckoutController.php::step2().
  4. onBeforeDisplayCheckoutNavigator(&$output, &$array_navigation_steps, &$step)site/Model/CheckoutModel.php::showCheckoutNavigation().
  5. onAfterDisplayCheckoutNavigator(&$view)site/Model/CheckoutModel.php::showCheckoutNavigation().
  6. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  7. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  8. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  9. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  10. onBeforeDisplaySmallCart(&$cart, &$obj)site/Model/CartpreviewModel.php::prepareView().
  11. onAfterCartGetTaxExt(&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment)site/Model/CartModel.php::getTaxExt().
  12. onAfterCartGetSum(&$obj, &$incShiping, &$incRabatt, &$incPayment)site/Model/CartModel.php::getSum().
  13. onBeforeDisplayCheckoutCartView(&$view)site/Model/CheckoutModel.php::showSmallCart().
  14. onBeforeDisplayCheckoutStep2View(&$view)site/Controller/CheckoutController.php::step2().
  15. onLoadCheckoutStep2save(&$post)site/Controller/CheckoutController.php::step2save().
  16. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  17. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  18. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  19. onBeforeSaveCheckoutStep2(&$adv_user, &$user, &$cart, &$model)site/Controller/CheckoutController.php::step2save().
  20. onAfterSaveCheckoutStep2(&$adv_user, &$user, &$cart)site/Controller/CheckoutController.php::step2save().
  21. onAfterSetMaxStepJshopCheckout(&$step)site/Model/CheckoutModel.php::setMaxStep().

A3. Step3 (CheckoutController::step3, step3save)

  1. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  2. onLoadCheckoutStep3()site/Controller/CheckoutController.php::step3().
  3. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  4. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  5. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  6. onBeforeDisplayCheckoutNavigator(&$output, &$array_navigation_steps, &$step)site/Model/CheckoutModel.php::showCheckoutNavigation().
  7. onAfterDisplayCheckoutNavigator(&$view)site/Model/CheckoutModel.php::showCheckoutNavigation().
  8. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  9. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  10. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  11. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  12. onBeforeDisplaySmallCart(&$cart, &$obj)site/Model/CartpreviewModel.php::prepareView().
  13. onAfterCartGetTaxExt(&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment)site/Model/CartModel.php::getTaxExt().
  14. onAfterCartGetSum(&$obj, &$incShiping, &$incRabatt, &$incPayment)site/Model/CartModel.php::getSum().
  15. onBeforeDisplayCheckoutCartView(&$view)site/Model/CheckoutModel.php::showSmallCart().
  16. onBeforeDisplayCheckoutStep3View(&$view)site/Controller/CheckoutController.php::step3().
  17. onBeforeSaveCheckoutStep3save(&$post)site/Controller/CheckoutController.php::step3save().
  18. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  19. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  20. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  21. onAfterSaveCheckoutStep3save(&$adv_user, &$paym_method, &$cart)site/Controller/CheckoutController.php::step3save().
  22. onAfterSetMaxStepJshopCheckout(&$step)site/Model/CheckoutModel.php::setMaxStep().

A4. Step4 (CheckoutController::step4, step4save)

  1. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  2. onLoadCheckoutStep4()site/Controller/CheckoutController.php::step4().
  3. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  4. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  5. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  6. onBeforeDisplayCheckoutNavigator(&$output, &$array_navigation_steps, &$step)site/Model/CheckoutModel.php::showCheckoutNavigation().
  7. onAfterDisplayCheckoutNavigator(&$view)site/Model/CheckoutModel.php::showCheckoutNavigation().
  8. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  9. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  10. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  11. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  12. onBeforeDisplaySmallCart(&$cart, &$obj)site/Model/CartpreviewModel.php::prepareView().
  13. onAfterCartGetTaxExt(&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment)site/Model/CartModel.php::getTaxExt().
  14. onAfterCartGetSum(&$obj, &$incShiping, &$incRabatt, &$incPayment)site/Model/CartModel.php::getSum().
  15. onBeforeDisplayCheckoutCartView(&$view)site/Model/CheckoutModel.php::showSmallCart().
  16. onBeforeDisplayCheckoutStep4View(&$view)site/Controller/CheckoutController.php::step4().
  17. onBeforeSaveCheckoutStep4save()site/Controller/CheckoutController.php::step4save().
  18. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  19. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  20. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  21. onAfterSaveCheckoutStep4(&$adv_user, &$sh_method, &$shipping_method_price, &$cart)site/Controller/CheckoutController.php::step4save().
  22. onAfterSetMaxStepJshopCheckout(&$step)site/Model/CheckoutModel.php::setMaxStep().

A5. Step5 (CheckoutController::step5, step5save)

  1. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  2. onLoadCheckoutStep5()site/Controller/CheckoutController.php::step5().
  3. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  4. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  5. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  6. onBeforeDisplayCheckoutNavigator(&$output, &$array_navigation_steps, &$step)site/Model/CheckoutModel.php::showCheckoutNavigation().
  7. onAfterDisplayCheckoutNavigator(&$view)site/Model/CheckoutModel.php::showCheckoutNavigation().
  8. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  9. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  10. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  11. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  12. onBeforeDisplaySmallCart(&$cart, &$obj)site/Model/CartpreviewModel.php::prepareView().
  13. onAfterCartGetTaxExt(&$obj, &$tax_summ, &$incShiping, &$incRabatt, $incPayment)site/Model/CartModel.php::getTaxExt().
  14. onAfterCartGetSum(&$obj, &$incShiping, &$incRabatt, &$incPayment)site/Model/CartModel.php::getSum().
  15. onBeforeDisplayCheckoutCartView(&$view)site/Model/CheckoutModel.php::showSmallCart().
  16. onBeforeDisplayCheckoutStep5(&$sh_method, &$pm_method, &$delivery_info, &$cart, &$view)site/Controller/CheckoutController.php::step5().
  17. onBeforeDisplayCheckoutStep5View(&$view)site/Controller/CheckoutController.php::step5().
  18. onLoadStep5save(&$checkagb)site/Controller/CheckoutController.php::step5save().
  19. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  20. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  21. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  22. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  23. onBeforeCheckListProductsQtyInStore(&$obj)site/Model/CartModel.php::checkListProductsQtyInStore().
  24. onCheckListProductsQtyInStoreForeach(&$obj, &$key, &$product, &$attr, &$qtyInStock, &$checkqty, &$check)site/Model/CartModel.php::checkListProductsQtyInStore().
  25. onAfterCheckListProductsQtyInStore(&$obj)site/Model/CartModel.php::checkListProductsQtyInStore().
  26. onBeforeCheckCouponStep5save(&$obj, &$coupon)site/Model/CartModel.php::checkCoupon().
  27. onBeforeGetListFieldCopyUserToOrder(&$list)site/Table/OrderTable.php::getListFieldCopyUserToOrder().
  28. onAfterFormatOrderNumber(&$number, &$num)site/Table/OrderTable.php::formatOrderNumber().
  29. onAfterCopyDeliveryData(&$obj)site/Table/OrderTable.php::copyDeliveryData().
  30. onBeforeCreateOrder(&$order, &$cart, &$obj)site/Model/CheckoutorderModel.php::createOrder().
  31. onBeforeStoreTableOrder(&$obj)site/Table/OrderTable.php::store().
  32. onAfterCreateOrder(&$order, &$cart)site/Model/CheckoutorderModel.php::orderDataSave().
  33. onBeforeCouponFinished(&$coupon, &$cart, &$user_id, &$order)site/Model/CheckoutorderModel.php::couponFinished().
  34. onBeforeSaveOrderItem(&$order_item, &$value)site/Table/OrderTable.php::saveOrderItem().
  35. onAfterCreateOrderFull(&$order, &$cart)site/Model/CheckoutorderModel.php::orderDataSave().
  36. onBeforeJshopOrderSaveOrderHistory(&$history, &$notify, &$comments, &$obj)site/Table/OrderTable.php::saveOrderHistory().
  37. onBeforechangeProductQTYinStock(&$items, &$obj, &$change)site/Table/OrderTable.php::changeProductQTYinStock().
  38. onAfterchangeProductQTYinStock(&$item, &$change, &$obj)site/Table/OrderTable.php::changeProductQTYinStock().
  39. onAfterchangeProductQTYinStockPSR(&$items, &$obj, &$change, &$product_stock_removed)site/Table/OrderTable.php::changeProductQTYinStock().
  40. onEndCheckoutStep5(&$order, &$cart)site/Controller/CheckoutController.php::step5save().
  41. onAfterSetMaxStepJshopCheckout(&$step)site/Model/CheckoutModel.php::setMaxStep().

A6. Step6 / Step6iframe

  1. onBeforeStep6Iframe(&$width, &$height, &$url)site/Controller/CheckoutController.php::step6iframe().
  2. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  3. onBeforeShowEndFormStep6(&$order, &$cart, $pm_method)site/Model/CheckoutorderModel.php::showEndFormPaymentSystem().
  4. При cancel-ветке дополнительно запускается lifecycle site/Model/OrderchangestatusModel.php::store() (см. A7).
  5. onAfterCancelPayOrderJshopCheckout(&$order_id, $status, $sendmessage)site/Model/CheckoutModel.php::cancelPayOrder().

A7. Step7 (CheckoutController::step7, CheckoutBuyModel::buy)

  1. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  2. onLoadStep7()site/Controller/CheckoutController.php::step7().
  3. onOrderCreateAndSetStatus(&$order_id, &$status, &$prev_order_status_data)site/Table/OrderTable.php::orderCreateAndSetStatus().
  4. onStep7OrderCreated(&$order, &$res, &$obj, &$pmconfigs)site/Model/CheckoutbuyModel.php::buy().
  5. Если меняется статус, вызывается lifecycle site/Model/OrderchangestatusModel.php::store():
  6. onBeforeChangeOrderStatus(&$order_id, &$status, &$sendmessage, &$comments, &$prev_status, &$return)site/Model/OrderchangestatusModel.php::store().
  7. onBeforeChangeOrderStatusAdmin(&$order_id, &$status, &$status_id, &$notify, &$comments, &$include_comment, &$view_order, &$prev_status, &$return)site/Model/OrderchangestatusModel.php::store().
  8. onBeforeJshopOrderSaveOrderHistory(&$history, &$notify, &$comments, &$obj)site/Table/OrderTable.php::saveOrderHistory().
  9. onBeforeCreateMailOrderStatusView(&$view)site/Model/OrderchangestatusModel.php::getMessage().
  10. onBeforeSendClientMailOrderStatus(&$message, &$order, &$comments, &$tbl_order_status, &$vendorinfo, &$order_details_url, &$ishtml, &$mailfrom, &$fromname, &$subject, &$datavendor)site/Model/OrderchangestatusModel.php::sendMail().
  11. onBeforeSendAdminMailOrderStatus(&$message, &$order, &$comments, &$tbl_order_status, &$vendorinfo, &$order_details_url, &$ishtml, &$mailfrom, &$fromname, &$subject, &$datavendor)site/Model/OrderchangestatusModel.php::sendMail().
  12. onBeforeSendVendorMailOrderStatus(&$message, &$order, &$comments, &$tbl_order_status, &$vendorinfo, &$order_details_url, &$ishtml, &$mailfrom, &$fromname, &$subject, &$datavendor)site/Model/OrderchangestatusModel.php::sendMail().
  13. onBeforeSendMailChangeOrderStatusClient(&$mailer, &$order_id, &$status, &$sendmessage, &$order)site/Model/OrderchangestatusModel.php::sendMail().
  14. onBeforeSendMailChangeOrderStatusAdmin(&$mailer, &$order_id, &$status, &$sendmessage, &$order)site/Model/OrderchangestatusModel.php::sendMail().
  15. onBeforeSendMailChangeOrderStatusVendor(&$mailer, &$order_id, &$status, &$sendmessage, &$order)site/Model/OrderchangestatusModel.php::sendMail().
  16. onAfterChangeOrderStatus(&$order_id, &$status, &$sendmessage, &$prev_status)site/Model/OrderchangestatusModel.php::store().
  17. onAfterChangeOrderStatusAdmin(&$order_id, &$status, &$status_id, &$notify, &$comments, &$include_comment, &$view_order, &$prev_status)site/Model/OrderchangestatusModel.php::store().
  18. onStep7BefereNotify(&$order, &$obj, &$pmconfigs)site/Model/CheckoutbuyModel.php::buy().
  19. onAfterSetMaxStepJshopCheckout(&$step)site/Model/CheckoutModel.php::setMaxStep().

A8. Finish (CheckoutController::finish, CheckoutFinishModel)

  1. onConstructJshopCheckout(&$obj)site/Model/CheckoutModel.php::__construct().
  2. onBeforeDisplayCheckoutFinish(&$text, &$order_id, &$text_end)site/Controller/CheckoutController.php::finish().
  3. onAfterDisplayCheckoutFinish(&$text, &$order, &$pm_method)site/Model/CheckoutfinishModel.php::paymentComplete().
  4. Динамический trigger (Js_add_trigger before) с параметрами (&$callerObject, &$varsArray)site/Model/CheckoutfinishModel.php::clearAllDataCheckout().
  5. onConstructJshopCart(&$obj)site/Model/CartModel.php::__construct().
  6. onBeforeCartLoad(&$obj)site/Model/CartModel.php::load().
  7. onAfterCartLoad(&$obj)site/Model/CartModel.php::load().
  8. onAfterLoadPriceAndCountProducts(&$obj)site/Model/CartModel.php::load().
  9. onAfterCartGetSum(&$obj, &$incShiping, &$incRabatt, &$incPayment)site/Model/CartModel.php::getSum().
  10. onBeforeClearCart(&$obj)site/Model/CartModel.php::clear().
  11. onAfterSaveToSessionCart(&$obj)site/Model/CartModel.php::saveToSession().
  12. onAfterDeleteDataOrder(&$obj)site/Model/CheckoutModel.php::deleteSession().
  13. Динамический trigger (Js_add_trigger after) с параметрами (&$callerObject, &$varsArray)site/Model/CheckoutfinishModel.php::clearAllDataCheckout().

Об авторе

Толкачев Сергей Юрьевич

Толкачев Сергей Юрьевич

Joomla-разработчик. Контрибьютер ядра Joomla. Один из ведущих Telegram-канала русскоязычного Joomla-сообщества JoomlaFeed, один из модераторов чата русскоязычного Joomla-сообщества. Мои расширения в официальном маркетплейсе расширений Joomla - Joomla Extensions Directory. Имею публикации в официальном журнале международного Joomla-сообщества - Joomla Community Magazine и на официальном сайте русскоязычного Joomla-сообщества.

Муж. Отец 3 детей.

Россия, Саратов.

Расширения Joomla WebTolk

103 Всего расширений
12 Категорий
522 Выпущено версий
664382 Всего скачиваний