плагин для joomla

Установка набора апаче+mysql+php стандартная.

XAMMP

Устанавливаем через среду выполнения на локалхост xammp. 

Не очень приятный момент

При установке базы данных возник такой нюанс, joomla не принимала пароль от базы данных длиной 6 символов (требование минимум 12 знаков), то есть база у на уже была и там wordpress, webasyst и т.д. Таким образом пришлось менять пароль root@localhost пользователю базы данных (через phpmyadmin), но вроде пронесло...

При установке некоторая инфа проскакивает:
Модуль интернационализации (далее Intl) 
GD — это библиотека, которая предназначена для обработки изображений средствами языка PHP

Похожие плагины на наш

Наш это будет самовывоз и оплата наличными или по карте. Операцию производит продавец, то есть админ обычно (в бекенде).

Что мне не понравилось сразу это поиск

Пытаюсь найти по ключевому слову, отбор происходит, но далее поиском по странице какая-то хрень, а именно вроде находит что-то, но где не понятно.

фотка 1

Этот интерфейсный "косяк" только для режима вывода плиткой. Если списком, то в принципе все нормально и понятно.

JoomShopping или Virtuemart или Hikashop

Это аналоги WooCommerce в вордпресс, но их блин не один, а несколько, то есть это будет ваш магазин на сайте. Пока отложим выбор этого вопроса.

Плагины

Сразу, кто не знает еще Joomla, смотрим где находятся плагины в интерфейсе:

фотка 2

Итак мы создали простой плагин заготовку за пару часов с нуля, упаковали в zip, потом установили из файла и он появился уже в системе.

JoomShopping (Copyright MAXXmarketing GmbH)

Пытаемся накатить JoomShopping локально. Во первых это расширение (оно же компонент). В папке components должен в итоге появится каталог com_jshopping.

Перед этим скачали с какого-то сайта JoomShopping-5.5.0.zip, кинули в папку components. Потом этот файл выбираем при установке расширения (то есть это не плагин). Установка идет долго пару минут, это нормально.

фотка 3

Еще в результате в базе данных появилось множество таблиц с префиксами _jshopping_. Так и должно быть. Если установка или деинсталляция не проходят корректно, их нужно все глобальной удалить например через phpmyadmin.

В результате после успешно установки видим такое. Установка с web ресурса у нас не прошла почему-то успешно.

фотка 4

JoomShopping а дальше что

Вроде установили JoomShopping, но пользователь еще ничего не видит на странице. Оказывается фишка jooml-ы в том, что надо "как в конструкторе" все создавать. Начинаем с категории, добавляем товар и теперь создаем пункт меню например магазин.

В общем заработал магазин, далее кнопка купить уже работает сама, переход на проверку заказа и  далее идет все автоматом. 

Итак, чтобы получить способ доставки самовывоз из офиса, надо создать свой кастомный способ доставки, указать ему страну(ы) обязательно.

Далее способ доставки цены указываем обязательно тоже.

В итоге пробуем оформить заказ с оплатой налом, самовывоз в офисе. В админке появился заказ:

фотка 5

Именно здесь мы должны внедрить свой плагин оплаты наличными или по карте. Дальше смотрим какая страница и идем по ней дебаггером (http://localhost/jml4/administrator/index.php?option=com_jshopping&controller=orders&task=show&order_id=3).

Дебаггером с ходу не понять почти ничего. Ищем похожий плагин, точнее плагин, который хотя бы будет срабатывать при входе в заказ.

И тут нюанс выясняется, что мало установить плагин, надо его не забыть активировать. Наконец нашелся такой плагин:

<?php
defined( '_JEXEC' ) or die();
 
class plgJshoppingOrderMail_sender_client extends JPlugin{
   
    function onBeforeSendOrderEmailAdmin(&$mailer, &$order, &$manuallysend, &$pdfsend, &$vendor, &$vendors_send_message, &$vendor_send_order){
        $mailer->setSender($order->email);
    }
   
}

Его функция onBeforeSendOrderEmailAdmin  срабатывает на нажатие кнопки Send mail.

Как загружается страница и инициализируется Send Mail кнопка? Это происходит здесь в классе HtmlView extends BaseHtmlView{ , размещение здесь components\com_jshopping\View\Order:

    function displayShow($tpl=null){
        ToolbarHelper::title($this->order->order_number, 'generic.png');
        ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_jshopping&controller=orders');
        ToolbarHelper::custom('send', 'mail', 'mail', Text::_('JSHOP_SEND_MAIL'), false);
        ToolbarHelper::custom('edit', 'edit', 'edit', Text::_('JSHOP_EDIT'), false);
        parent::display($tpl);
    }

Шаблон загружаемой страницы здесь ..\administrator\components\com_jshopping\tmpl\orders\show.php. 

Все это конечно хорошо, но как подключать визуально свой плагин или как его там еще называть.

Модуль

А еще есть модули оказывается и это вроде как и плагин, но у модуля может быть набор своих js, css. 

Берем первый попавшийся демо модуль в интернете (например mod_vk_contactus), кидаем его файл (vk_contactus.zip) в папку modules, устанавливаем через install Extentions и видим, что все гут установилось (см. в Extensions: Manage). 

Теперь как-то надо указать - где выводить на экран наш модуль. Для этого наш модуль надо еще опубликовать (включить для отображения). Тут есть нюанс сразу - есть сайт, а есть админка. 

фотка 6

Есть модули сайта (/modules/) , а есть модули админки, у админки они находятся здесь /administrator/modules/. 

Оказывается есть еще каталог с компонентами и там есть components\com_jshopping, то есть при установке расширения, кроме моделей,плагинов, устанавливается и компонента.

Отладчиком пытаемся понять как грузится любая страница. Конкретно нас интересует: 
http://localhost/jml4/administrator/index.php?option=com_jshopping&controller=orders&task=show&order_id=4

Стек вызовов к счастью небольшой для изучения. Итак сначала определяется загружаемый компонент, это option=com_jshopping. Происходит это в AdministratorApplication.php:

    public function dispatch($component = null)
    {
        if ($component === null) {
            $component = $this->findOption(); // вот здесь узнаем, что надо грузить com_jshopping
        }


        // Load the document to the API
        $this->loadDocument();


        // Set up the params
        $document = Factory::getDocument();


        // Register the document object with Factory
        Factory::$document = $document;


        switch ($document->getType()) {
            case 'html':
                // Get the template
                $template = $this->getTemplate(true);
                $clientId = $this->getClientId();


                // Store the template and its params to the config
                $this->set('theme', $template->template);
                $this->set('themeParams', $template->params);


                // Add Asset registry files
                $wr = $document->getWebAssetManager()->getRegistry();


                if ($component) {
                    $wr->addExtensionRegistryFile($component);
                }


                if (!empty($template->parent)) {
                    $wr->addTemplateRegistryFile($template->parent, $clientId);
                }


                $wr->addTemplateRegistryFile($template->template, $clientId);


                break;


            default:
                break;
        }


        $document->setTitle($this->get('sitename') . ' - ' . Text::_('JADMINISTRATION'));
        $document->setDescription($this->get('MetaDesc'));
        $document->setGenerator('Joomla! - Open Source Content Management');

// отрисовка компонента

        $contents = ComponentHelper::renderComponent($component);

        $document->setBuffer($contents, 'component');


        // Trigger the onAfterDispatch event.
        PluginHelper::importPlugin('system');
        $this->triggerEvent('onAfterDispatch');
    }


Скажем так пока не понятно как внедрится в компонент com_jshopping и добавить в него функционал (без правки кода самого компонента).

Addon

Оказывается есть еще понятие Addon. Но похоже это те же модули, плагины и расширения, только в виде пакета.  

triggerEvent 

При помощи triggerEvent находим, что можно попробовать воспользоваться событием onBeforeShowOrder компонента JoomShopping.

getSubscribedEvents()

Долго как ни странно искали в интернете ответ где подписаться на события в приложении. Оказывается это реализуем метод getSubscribedEvents(). Странно мало кто пользуется что ли.

Небольшой успех

Удалось связать событие onBeforeShowOrder компонента com_jshopping и плагина ActionLogPlugin в компоненте com_actionlogs.    

use Joomla\Event\SubscriberInterface; // добавили


abstract class ActionLogPlugin extends CMSPlugin implements SubscriberInterface
{
     public static function getSubscribedEvents(): array
     {
         return [
             'onBeforeShowOrder' => 'onBeforeShowOrder'
         ];
     }
 
     public function onBeforeShowOrder( $arr )
     {
        $aa = $arr; // срабатывает
     }

Попутно выясняем,что implements SubscriberInterface присутствует только в варианте:

...  extends CMSPlugin implements SubscriberInterface 

то есть работает только с плагинами?!... Но допустим.

Как можно теперь внедриться в интерфейс заказа 

А никак (не изменяя кода самой страницы заказа). Но оказывается можно что-то добавить в Toolbar, например через статический метод ToolbarHelper::custom :

ToolbarHelper::custom('send', 'mail', 'mail', '3453454', false);

И вот это уже лучше, то есть можно интерфейс менять, добавлять свой функционал. Но хочется так сказать знать как и куда можно вставлять свой интерфейс.

Helper

В joomla классы заканчивающиеся Helper имеют не двусмысленное зарезервированное значение. Именно через ModuleHelper можно отрисовать свое содержание где-то там (пока еще не понятно).

deprecated

На joomla 4.4.2 уже столкнулись с deprecated сущностями, а именно нашли пример:

$mods = JModuleHelper::getModules('mod_vk_contactus');

а он вываливает ошибку такую:

 Class "Joomla\Component\Actionlogs\Administrator\Plugin\JModuleHelper" not found

 Оказалось, что надо использовать теперь ModuleHelper:

В итоге констатируем (на практике): 

Не важно из какого каталога вы устанавливаете что-то в виде zip файла и не важно как называется zip файл. Важно, что внутри zip фала , а именно внутри вложенного файла xml одноименным названием.

Если там  type="module", то установка чего-то идет в каталог modules, если type="plugin", то соответственно в каталог plugin.

Далее внутри может быть два и более файла xml

Но xml разложены по разным каталогам ()

У плагинов если указан параметр group="xxxxxx" в xml то приведет к созданию верхнего каталога xxxxxx и в него уже будет помещена папка с плагином. Если group не указан, будет создана одна папка с названием плагина. group для предназначена для объединения нескольких плагинов и т.д.

Модули

Для модуля в xml нужно указать client="site" или client="administrator".

Установка модуля

для модуля админки установка происходит как расширение (из файла zip) на вкладке Extentions Install. Потом на странице Modules (Administrator) публикуем плагин и там же входим в настройки.

Потом здесь же указываем размещение (у нас выбираем top).

Удаление модуля

Удаление модуля на странице Extentions:Manage: отключить и uninstall (и папка из administrator/modules) удаляется.

Наконец-то

На данном этапе имеем модуль, у которого есть шаблон для вывода на экран и у которого есть плагин, который может подписаться на событие из страницы редактирования заказа в joomshopping.

На картинке ниже уже видно, где внедрен наш интерфейс:

фотка 7

Что еще радует например, это то что событие onBeforeShowOrder компонента com_jshopping содержит как параметр объект view, в котором есть информация о составе заказа. С другой стороны номер заказа есть в GET параметре страницы option=com_jshopping&controller=orders&task=show&order_id=4.

Более универсальным будет вариант получить заказ по GET параметру и тогда нам уже не важно в каком магазине мы работаем JoomShopping или Virtuemart или Hikashop. 

PluginHelper::importPlugin подключает в код использование плагина, из какой директории указывается в первом параметре (он кстати может быть и пустой). Во втором парметре название самого плагина.

Где еще могут быть установлены плагины

Например в папке plugins/system , если в манифесте (xlm  файл) плагина мы укажем groupy="system".

Не именуйте первую папку плагинов префиксом plg_

Когда мы отладчиком ходили по коду встречалось отсекание префикса "plg_" прямо в ядре Joomla.

 Далее начинаем понимать процесс в динамике

Успешно подписывается на событие (onBeforeShowOrder) плагин, который устанавливается как системный (group="system"). 

Событие срабатывает при загрузке страницы заказа (в админке), плагин его получает.

Но уже после этого грузится модуль ( у нас в блок top).

загрузка js в админке

Странно, но addScript добавляет в начале /administrator/ к пути файла js. Хотя все media js и css при установке ложатся в  media. То есть не будет никогда при установке каталога и /administrator/media.

Решаем проблему пути так , обратите внимание на ../ :

$document->addScript('../media/mod_admin_payment_acceptance/js/bit_drv_kkt.js');Yt

Не знаю как хостинге, но на localhost это проблемка точно присутствует.

Свой css подключаем аналогично

$document->addStyleSheet('../media/mod_admin_payment_acceptance/css/bit_drv_kkt.css');

Свой jquery iu

Дело в том, что у нас то ли не установлен, то ли не подключен jquery-ui (для вывода модальных окон индикации процесса). В общем тащим с собой и подключаем так:

$document->addScript('../media/mod_admin_payment_acceptance/js/jquery-ui.js');

Итоги

Плагин и модуль (две сущности, устанавливаются отдельно , не зависимо). Но в целом все работает уже нормально. 

То есть нал принимаем, банковскую карту тоже принимаем:

фотка 8

Статус заказа пока автоматически не изменяем, делаем вручную после пробития чека.

Небольшое видео по результатам, чего удалось реализовать:

Joomla-4.4.8-плагин-и-модуль-для-оплаты-налом-и-по-карте-для-JoomShopping-через-АПИ-БИТ-драйвер-ККТ.mp4