Clone wiki

CMS / Создание плагина

Общие правила

Есть несколько пунктов, которые просто обязательны. Это как бы система, которая призвана внести некий порядок. Хотя сама архитектура плагина может быть несоизмеримо объемной и ограничена, в конечном счете, только вашей фантазией.

  1. Все плагины должны находиться в папке /plugins/. Иначе система их просто не увидит.
  2. Каждый плагин должен представлять из себя дирректорию, чье имя состоит из бук, цифр или знака подчеркивания "_". Буквенные символы могут быть в любом регистре.
  3. Плагин должен содержать конфиг в формате JSON config.json. О его содержании описано ниже.
  4. Плагин должен содержать файл index.php, в котором будет находится основной класс.
  • ⚠ Обновлено в AtomM CMS 2.3.4: для описания его конфигураций используется только config.json в соответствующем формате описания. При его отсутствии теперь не ищется файл config.dat.

  • ⚠ Обновлено в AtomM CMS 5: в целях безопасности, стало доступно хранить конфиг плагина в формате config.php. Система будет пытаться его найти, если не сможет найти config.json. Структура данных у него аналогична, пример оформления:

<?php
return array(
  "title" => "fufu",
  "desc" => "simple plugin",
  "points" => "before_view"
);

Практика

Плагин подписывается на (список хуков), перечисленные в points. Когда система "доходит" до одного из хуков, на которые подписан плагин, создается объект основного класса (того, который в index.php) и вызывается метод common этого объекта. В качестве параметров в метод передаются параметры хука (индивидуальны для каждого хука) и название хука.

Для примера, возьмем хук before_view. Этот хук позволяет манипулировать полностью сформированной страницей, прямо перед ее выводом.

Теперь придумываем название нашего будущего плагина. Я не смог придумать ничего оригинальнее fufuplugin (уж простите).

Создаем в /plugins/ каталог fufuplugin и в нем два файла. index.php и config.json. PHP файл - это файл с логикой плагина. Там будет наш php код. config.json - это конфигурационный файл.


Создание конфигов

config.json

Конфиг должен содержать, как минимум, следующие параметры:

  • className - это название класса, который будет находится в файле index.php. Начиная с версии AtomM CMS 2.3.4 этот параметр не нужен.
  • title - название (любое)
  • points - выбранный хук. Можно вешать выполнение плагина сразу на несколько хуков, но об этом ниже.

Не обязательно, но желательно также заполнить:

  • desc - описание (любое)
  • icon - название файла с иконкой плагина в папке с ним.
  • more - ссылка на тему, страницу плагина, полное описание.
  • action - специально структурированный массив для настройки включения плагина только на определенных страницах, а не на всех. Подробнее о его назначении написано чуть ниже. Доступен начиная с версии AtomM CMS 4.

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

Хочу, так же, добавить, что конфиг может содержать любые дополнительные настройки, в том числе, и те, которые потом мы сможем изменять через админку. Ну или как угодно.

Конфиг файл можно создать и вручную (формат json очень простой) или воспользоваться конвертированием массива в формат json.

JSON формат выглядит так:

{
  "title":"fufu",
  "desc":"simple plugin",
  "points":"before_view"
}

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

{
  "title":"fufu",
  "desc":"simple plugin",
  "points":["before_print_page","before_view"]
}

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

Ограничение области действия плагина(параметр Action)

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

Так же как и ключ points, title, desc есть ключ action

Структура его состоит из двух вложенных ключей: allow и disallow , первый разрешает загружаться плагину только на страницах, которые в нем(ключ allow) указаны, а второй(ключ disallow) наоборот, запрещает загрузку плагина на страницах, которые в нем указаны.

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

Например наш URL вот такой: /news/view_theme/61 тогда в данном url будет три элемента:

  • под индексом "0" будет название модуля: "news";

  • под индексом "1" будет название текущего экшена: "view_theme";

  • ну и под номером "2" будет "61", в данном случае это id темы. На id темы тоже можно проверять, хотя я думаю это никому не нужно)

Разобравшись с тем, что такое индексы элементов URL можно приступить к более обширным примерам:

"action":{
  "allow": {
    "0":["news","stat"],
    "1":["view","index","add_form"]
  },
  "disallow": {
    "0":["news"]
  }
}

Таким образом построенный "action", в ключе "allow" разрешит загружаться плагину только, если элемент URL с индексом "0" равен либо "news" либо "stat", а элемент с индексом "1" равен либо "view", либо "index", либо "add_form". При этом настроек для элемента с url "2" не указано, тоесть будет годится любое его содержимое. Но стоит заметить, что при заполнении allow, если вы приравняете индекс элемента url пустому массиву ( [] ) это будет означать, что ни одно из значений url этого индекса не будет годится и на страницах, где этот элемент существует ваш плагин не загрузится, в отличие от того, когда вы вообще не укажите настройку для этого элемента URL.

В ключе "disallow" все немного проще, тут не имеет значения указали ли вы значение в виде пустого массива, или не указали значения вообще. В данном примере мы запретили загрузку плагина на страницах, где элемент URL "0" равен "news", что, конечно, идет наперерез с тем разрешением для "news" которое мы указали ранее. Запомните, "disallow" всегда имеет более высокий приоритет чем "allow" и в нашем примере, плагин никогда не будет загружен на страницах модуля "news".

Еще, что следует сказать. У ссылок с несуществующим "как бы" элементом URL № "1" он на самом деле существует и имя ему "index". А на главной странице, где не понять как называется не то что первый, но и нулевой элемент, элемент URL № "0" равен "pages" и "1" равен "index". Самый надежный и простой способ узнать название элемента, это вывести на странице его название, для этого есть специальные метки {{ params[0] }} , {{ params[1] }} и т.д.

Ох, почти забыл. Функция, которая читает данные конфиги довольно строгая к пунктуации, к примеру всегда нужно писать " (двойные кавычки) вместо одинарных ', так же после последних или единственных элементов массива нельзя ставить запятые, иначе весь массив не прочитается.


Файл логики

А теперь я покажу, как должен будет выглядеть самый простой класс для этого плагина. Файл index.php

<?php

class fufuplugin {
  public function common() {
    echo 'Hello, world!';
  }
}
?>

Метод common обязательный. Управление с хука передается именно ему, а дальше вы вольны делать, что угодно. Параметр $params - это данные с хука. В данном случае, это вся страница. Обратите внимание, я назвал класс именно так, как называется папка с плагинов - это важно. Иначе плагин не будет работать.

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

Начиная с версии AtomM 2.3.0 (21.07.13) появилась возможность выполнения определённых действий при первом включении плагина, то есть установка. Создайте в классе с плагином функцию install(). Для того, чтобы движок понял, что установка прошла успешно, функция должна возвращать массив с ключом status со значением 1. Если с ошибкой то пусть возвращает со значением 0. Также можно (но не обязательно) передавать ключ message с сообщением. Писать в нём "Установка выполнена" нет смысла, но можно какие-то важное замечание передать. Также пригодится, если установка не была выполнена успешно.

Пример плагина с использованием меток.

<?php

class fufuplugin {
  public function common($params) {
    $script = '<script src="{{ plugin_path }}/index.js"></script>';

    $marker = '#{{\s*script\s*}}#i';

    $params = str_replace($marker, $script, $params);

    return $params; 
  }
}
?>

Т.к. мы работаем в хуке before_view, то функция common являет собой всю страницу, уже ту, которую видит пользователь. Если добавить ей параметр $params, то переменная $params будет содержать всю эту страницу.

Теперь разберемся с тем, как же заменить метку(в примере {{ script }} , но можно, в принципе, заменить все что угодно) на то что мы хотим. Для этого нужно найти метку в переменной $params, заменить её на то, что мы хотим и вернуть результат функции, точнее вернуть измененную переменную $params .

Сделать это можно с помощью (str_replace())

str_replace($marker, $script, $params) заменяет в строке $params строку $marker на строку $script

далее результат замены мы возвращаем функции через return

Примечание: Метка {{ plugin_path }} - системная, и ведет в директорию с плагином. Указание метки в виде #{{\sscript\s}}#i не с проста, если так не сделать, то внешние { } не будут входить в строку.


Настройка из админки

Любой плагин можно довольно просто интегрировать в админ панель. Например для его настройки. Любой плагин можно включить и выключить через админку, для этого даже не надо ничего делать. Но вот, если мы хотим чего-то большего, прийдется кое-что добавить в наш плагин. Это кое-что - файл settings.php. Задача этого файла принимать некоторые параметры и возвращать контент страницы, которая будет отображена как одна из страниц админки.

В файле settings.php должна быть указана переменная $output. Содержимое этой переменной и будет использоваться как страница. Важно понимать, что данные из $output используются не как совершенно отдельная страница, а подставляются в выделенный блок админ панели. То есть такие элементы как верхнее меню, боковое меню и т.д. будут на странице в любом случае и об этом беспокоиться не стоит.

Например (settings.php):

<?php
$output = 'Plugin settings';
?>

Если ваш файл settings.php будет содержать такую строку, перейдя на страницу настройки своего плагина, вы увидите текст Plugin settings.

Теперь пример по-сложнее. Этот пример меняет значение параметра limit в конфиге:

<?php

$output    = '';
$conf_pach = dirname(__FILE__).'/config.json';
$config = json_decode(file_get_contents($conf_pach), true);

if (isset($_POST['send'])) {
    $config['limit'] = $_POST['limit'];
    file_put_contents($conf_pach, json_encode($config));

    $output .= '<div class="warning">Сохранено!<br><br></div>';
}

$output .= '<form action="" method="post">
  Введите значение для параметра limit: <input type="text" size="100" name="limit" value="' . $config['limit'] . '">
  <br>
  <input name="send" type="submit" value="Записать" class="save-button">
</form>';

?>

Но есть вещи по-интереснее. Например, мы желаем, чтобы у нас была не одна страница, а несколько и мы могли перемещаться между ними для детальной настройки нашего плагина AtomM CMS. На этот случай нам надо предусмотреть логику нашего кода в файле settings.php и знать, как формировать ссылки на наши страницы. Дело в том, что для перехода к настройкам плагина мы должны перейти по адресу host.com/admin/plugins.php?ac=edit&dir=каталог плагина. То есть в нашем случае, это будет host.com/admin/plugins.php?ac=edit&dir=fufuplugin. Теперь о логике самого файла settings.php.

Как видите, мы должны передать два обязательных параметра, но никто не запрещает добавлять свои. Например мы можем сделать, что-то типа:

<?php

if (!empty($_GET['page']) && $_GET['page'] == 2) {
  $output = '<a href="/admin/plugins.php?ac=edit&dir=fufuplugin&page=1">To page 1</a>';
        } else {
  $output = '<a href="/admin/plugins.php?ac=edit&dir=fufuplugin&page=2">To page 2</a>';?>
}

?>

Думаю тут все понятно. Мы просто передаем дополнительный параметр page и на основе этого параметра создаем логику.

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

Желаю вам легкого осознания всего вышеизложенного и жду ваши плагины в разделе форума "готовое". Плагины с хорошими отзывами будут переноситься в каталог плагинов AtomM.

Updated