Пишем модуль для DLE

Опубликовано 14 февраля, 2011 в CMS

Новый пост для рубрики Очумелые ручки.

Где-то полгода стабильно пишу модули для DLE, спрос достаточно хороший, правда цены низкие (по сравнению с тем же WP). В этом посте опишу процесс создания двух типов модулей: внутренний и внешний (позже объясню, в чем различие). Перед прочтением учтите, что писалось все это 14 февраля 2011 года, когда финальная версия DLE обозначалась, как 9.2. Возможно, в вашем мае 2033 года уже все изменилось.

Чтобы добавить свой функционал для DLE, нужно знать:

  1. Язык программирования PHP на уровне новичка.
  2. Архитектуру базы DLE и основные встроенные в двиг функции и классы.

Введение в DLE

Весь код в DLE достаточно прост для понимания. Каждая строка — будто бы пример в книге PHP для начинающих. Соответственно, и модули крепятся к каркасу посредством напильника, без всяких изысков, как в WP или Joomla.

Ядро

Архитектура — типичная для большинства самописных CMS. Все начинается с контроллера engine/engine.php. Открываем этот файл, ищем блок:

switch ( $do ) {
    //...
    case "deletenews" :
    include ENGINE_DIR . '/modules/deletenews.php';
    break;
    //Еще куча вариантов переменной $do
}

Читатель, знакомый с PHP. уже понял, что это и есть ядро (контроллер) DLE. В конструкции switch-case перечисляют варианты GET переменной $do в адресной строке (?do=deletenews) и, в зависимости от значения этой переменной, подключается тот или иной обработчик. В данном случае — engine/modules/deletenews.php. Что нам мешает добавить свой обработчик для урл «?do=testmodule»? Ничего! Вот, мы уже вплотную приблизились к разгадке тайны написания модулей для DLE.

Контроллер админки

У админки свое ядро и свой контроллер. Открываем engine/inc/options.php, видим массив-контроллер (ключ массива (config) — категория в общем меню):

$options['config'] = array (
    array (
         'name' => $lang['opt_all'],
         'url' => "$PHP_SELF?mod=options&action=syscon",
         'descr' => $lang['opt_allc'],
         'image' => "tools.png",
         'access' => "admin"
     ),
    //Тут еще куча элементов массива
}

В этом массиве перечисляются элементы главного меню админки («список всех разделов»), предполагается, что у каждого модуля есть отдельный элемент в этом меню. Каждый элемент массива — еще один маленький массив со следующими элементами (строками):

  • name — название модуля
  • url — урл админки, по которому вызывается данный модуль. В GET переменной mod содержится название php файла из папки engine/inc, который будет подключен при запросе юзером данного уро.
  • desc — описание модуля
  • image — картинка модуля
  • access — права достапа (какие бывают возможные значения — смотрите в options.php)

Да, установка любого модуля реализована достаточно тупо — пользователя заставляют копировать файлы, открывать исходный код контроллеров и вручную добавлять обработчики. Главное правило, которое программист должен внушать пользователю — «работает — не трожь!!!» тут не действует, пользователь обязан тронуть код, чтобы добавить сторонний модуль.

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

Работа с базой

Структура базы DLE очень простая. Открываем базу в phpmyadmin, тратим 10 минут на изучение. Никаких выкрутасов, как в WP, нет. Все банально — таблица постов, таблица категорий, таблица юзеров… Никаких связывающих таблиц, пост привязывается к нескольким категориям посредством перечисления ID категорий а поле category таблица dle_post.

Для работы с базой есть встроенный класс $db. Работать с ним очень просто:

$result = $db->query("SELECT * FROM `".PREFIX."_post` WHERE `category` = 1");
while($row = $db->get_row($result)) {
    print_r($row);
}

PREFIX — префикс таблиц из конфига engine/data/dbconfig.php (см. и другие конфиги папки engine/data, это пригодится).
Или, если необходимо вернуть одну строку:

$row = $db->super_query("SELECT * FROM `".PREFIX."_post` WHERE `category` = 1")
print_r($row);

Очистка строки (mysql_real_escape_string):

$str = $db->savesql($str);

Вернуть ID последней вставленной строки:

$id= $db->insert_id();

Остальные функции класса смотрите в engine/classes/mysql.class.php

Функции

Все основные функции DLE перечислены в engine/inc/include/functions.inc.php. Раскладывать их по полочкам здесь нет смысла.

Написание модуля DLE

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

Шаг 1. Добавляем обработчики. Для этого в engine/engine.php в конструкцию switch добавляем новый вариант для $do:

case "galery" :
include ENGINE_DIR . '/modules/galery.php';
break;

Теперь добавим элемент меню для админки. В engine/inc/options.php ищем массив $options['config'] и добавляем туда новый элемент:

    array (
         'name' => "Галерея",
         'url' => "$PHP_SELF?mod=galery",
         'descr' => 'Галерея DLE',
         'image' => "rules.png",
         'access' => "admin"
     ),

Мы присвоили нашему модулю урл /admin.php?mod=galery. При каждом обращении к этому урл, будет подключаться файл engine/inc/galery.php (его содержание рассмотрим позже). Вообще, массив $options не является контроллером, это всего-лишь перечисление элементов меню. Можно просто создать файл engine/inc/galery.php и обращаться к нашему модулю через адресную строку браузера.

Кстати, не совсем понимаю, почему разработчики DLE заставляют прописывать обработчик в engine/engine.php. Ведь можно, как в админке, искать переданный в урл файл в определенной папке, поключать его автоматически, если он существует.

Шаг 2. Создаем engine/modules/galery.php (обработчик ?do). Важно: файл должен начинаться с проверки «на вшивость»:

if(!defined('DATALIFEENGINE')) die("Hacking attempt!");

Так мы обезопасим наш модуль от вызова напрямую, без обработки $_GET[do] ядром двига.
Далее, получаем все загруженные картинки одним запросом к базе (они хранятся в таблице dle_images), забиваем картинками переменную $content. Немного усложним задачу, пусть атрибут alt картинок содержит заголовок поста, к которому привязана данная картинка.

<?php
//Защита от хакеров
if(!defined('DATALIFEENGINE')) die("Hacking attempt!");
//В этой переменной и будет html код с картинками
$content = '';
//Получаем все картинки
$imagesres = $db->query("SELECT * FROM `".PREFIX."_images`");
//Проходимся в цикле по всем картинкам
while($image = $db->get_row($imagesres)) {
    //Получаем заголовок записи, к которой картинка привязана
    $post = $db->super_query("SELECT `title` FROM `".PREFIX."_post` WHERE `id` = '$image[news_id]'");
    //Картинок в одной записи может быть несколько, они разделены "|||"
    $image = explode('|||', $image['images']);
    //Каждую картинку добавляем в $content
    foreach($image as $i) {
        $content .= "<img src=\"/uploads/posts/$i\" alt=\"$post[title]\" /><br />";
    }
}
//Тут подключаем шаблон
?>

Красава! Теперь в $content содержится код вывода всех картинок на сайте. Осталось только подключить шаблон. А это вообще проще простого. Создаем в файл templates/tplname/galery.tpl, вписываем туда {content} и ничего больше. Шаблон готов, осталось только указать на него в нашем модуле. Как вы уже поняли, шаблонизатор DLE занимается преобразованием меток (типа {content}) в html код. Давайте скажем шаблонизатору, что надо подключить шаблон galery.tpl и заменить в нем {content} на содержимое $content. В engine/modules/galery.php добавляем код:

$tpl->load_template('galery.tpl');
$tpl->set('{content}', $content);
$tpl->compile('content');
$tpl->clear();

Все, при вызове /?do=galery, наш шаблон galery.tpl вставится внутрь основного шаблона (main.tpl) в нужном месте с уже замененной на html код меткой {content}. Проверяйте. Чтобы узнать подробнее о шаблонизаторе, можете поковырять класс $tpl, он, как и другие классы DLE, находится в engine/classes.

Шаг 3. Бредово я раскидал процесс по шагам, но, думаю, никто не будет сильно психовать по этому поводу. В общем, тут мы создадим страницу нашего модуля в админке. Я не знаю, что бы такого добавить туда, поэтому дам вам шанс пофантазировать. Настройки там какие-нибудь добавьте или еще чего. Я же покажу, как создать пустую страницу с заголовком «hello, world!».

Урл нашего модуля — /admin.php?mod=galery, значит создаем файл engine/inc/galery.php следующего содержания:

<?php
echoheader("galery", 'Управление галереей');
?>
<h1>Hello, world!</h1>
<p>Вот и все. Тут можно форму добавить, выше - обработчик формы. В форме чего-то посылать, в обработчике - чего-то сохранять.</p>
<?php
echofooter();
?>

Вроде готово. Раскрыто далеко не все, лишь основы. Но, поверьте, пока будете писать свой первый модуль, станете профессиональным модулеписателем, потому что DLE прост, как три копейки.

Внешний модуль DLE

Выше я писал, что подразумеваю под внешним модулем. Суть в том, чтобы подключить к файлу все API от DLE, далее работать также, как через ядро описанным выше способом. Делается это в 4 строки:

<?php
define('DATALIFEENGINE', true);
define('ROOT_DIR', dirname (__FILE__));
define('ENGINE_DIR', ROOT_DIR . '/engine');
require_once(ROOT_DIR.'/engine/init.php');
//Все, тут можно писать сам модуль.
?>

Это в 100 раз удобнее, чем внедряться через ядро engine.php. Скопировать файл (файлы) на сервер и запустить — все, что требуется от пользователя.

Бонус. Давайте еще добавим сквозную метку для всего сайта. Открываем index.php, ищем строку

$tpl->compile ( 'main' );

Это компиляция шаблона main.tpl. Перед этой строкой вставляем:

$tpl->set ( '{SUPERMETKA}', 'Привет, мир!' );

Готово. Теперь строка {SUPERMETKA} в main.tpl будет заименена на «Привет, мир».




Комментарии «Пишем модуль для DLE»:
Комментариев: 33. Обязательно оставьте свой!
vestnik 26.03.2011 в 12:13

Спасибо. Данный мануал помог мне разобраться с созданием собственного модуля.

Майкл 03.04.2011 в 16:37

Хороший ман !!!!!Даже вопросов не возникло.Хотелось бы увидеть вот такой пост- «Пишем модуль для Joomla»

Максим 15.04.2011 в 13:29

Сделал всё по инструкции, но dle мне показывает пустую страницу без галереи.Хотелось бы понять почему?

pistol 16.04.2011 в 8:28

Максим, скорее всего, где-то синтаксическую ошибку допустили при редактировании файлов.

pistol 16.04.2011 в 8:30

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

Сергей 19.04.2011 в 6:15

написал свой модуль get_it.php, подключил так:
1)файл engine.php
case «get_it» :
include ENGINE_DIR.’/modules/get_it.php’;
break;

2)файл .htaccess
RewriteRule ^get_it(/?)+$ /?do=get_it

сабж:
есть еще модуль gen.php, который генерирует ссылку, ссылка выглядит так: «http://mysite.ru/index.php?do=get_it&link_file=743b9420e29c8d4f7b2902156a10db20″
идея такая: при переъоде по этой ссылке, модулю get_it.php должен передаться параметр link_file со значением.
проблема: при переходе по данной ссылке браузер говорит, что такая ссылка «http://mysite.ru/index.php?do=get_it&link_file=743b9420e29c8d4f7b2902156a10db20″ не существует. прошу помочь разобраться в чем проблема.

DLE v9

pistol 19.04.2011 в 7:16

Сергей, а без правки htaccess?

Максим 20.04.2011 в 10:56

Да,действительно. Посмотрел в базе данных таблицу, используемую в запросе, а она пуста. Вот и результат.

Артем 19.06.2011 в 21:05

Такой вопрос. Я написал модуль, но мне его нужно вывести не на главной странице в а шаблоне addcomment.tpl как мне это сделать?
Т.е. вывести его в определенном месте где добавляется комментарий!

pistol 20.06.2011 в 6:18

Артем, в engine/modules/show.full.php найти строку $tpl->compile( ‘addcomments’ ); и перед ней (и после $tpl->load_template( ‘addcomments.tpl’ ); ) вписать свои $tpl->set

Артем 20.06.2011 в 12:22

Да это действительно сработало но в другой версии. Мне нужно вставить модуль в DLE 8.0 Незнаете случаем как в ней сделать?
Потому что в 8 версии строчки $tpl->compile( ‘addcomments’ ); нету
Но вставив свой $tpl->set(‘{antispam}’,$antisp); после
$tpl->load_template( ‘addcomments.tpl’ ); в шаблоне addcomment.tpl пропало слово {antispam} которое и должно было заменяться. Видимо оно сработало, но почемуто нечего не выводится.

Артем 20.06.2011 в 12:27

Да великолепно!!!! Спасибо огромное за совет, просто надо было перед моим
$tpl->set(‘{antispam}’,$antisp);
вставить
require_once ENGINE_DIR.’/modules/antispam.php’;
И все заработало!!!! Спасибо, единственный сайт где дельные вещи говорят! РЕспект!!!

Артем 24.06.2011 в 12:48

Появился новый вопрос. Модуль почти дописл но появилась новая проблема. Я добавил в форму добавления комментария, два дополнительных поля (input). В то место где вписывается Имя, мыло, коммент и капча. Так вот при отправке данных мои переменные не отправляются, т.е. все значения полей отправляются кроме моих двух. В чем может быть проблема?
Проверял отправку данных через FireBug. Html правильный, инпуты имеют и id и name

pistol 24.06.2011 в 16:16

Артем, какая-нибудь глупая противная ошибка допущена. Типа, одна буква в теге пропущена или еще чего. Советую просто перепечатать код. Ну и проверить отправку через print_r($_POST);

SparkY 27.06.2011 в 8:41

Крепил модуль банов к дле.

<?php

if(!defined('DATALIFEENGINE'))
   {
	 die("Hacking Attempt!");
   }
include ENGINE_DIR.'/data/worldofwarcraft/wowdb.php';
 $tabletext='
  Список Баннов
  IP:Причина:Дата банаДата снятия бана
';

function connectwowbandb($dbnum){
global  $wowdb;
if($dbnum=='realmd'){
	mysql_connect($wowdb['realmdhost'],$wowdb['realmdusername'],$wowdb['realmdpassword']);
	mysql_select_db($wowdb['realmddbname']);
	mysql_query ("set character_set_client='cp1251'");
	mysql_query ("set character_set_results='cp1251'");
	mysql_query ("set collation_connection='cp1251_general_ci'"); 

}
}
connectwowdb("realmd");
$query = "SELECT ip, banreason, bandate, unbandate  FROM ip_banned";
$result = mysql_query($query);   

while ($vystup = mysql_fetch_array($result))
 {
  $tableip='
'.$vystup["ip"].'
'.$vystup["banreason"].'
'.date("d.m.Y H:m",$vystup["bandate"]).'
'.date("d.m.Y H:m",$vystup["unbandate"]).'
 ';  

 $tpl->load_template('worldofwarcraft/worldofwarcraft_banned.tpl');
 $tpl->set('{tableip}', $tableip);
$tpl->set('{tabletext}', $tabletext);

 $tpl->compile('content');

}

 $tpl->clear();
mysql_close($dbnum);   

?>

Где {tabletext} — вывод таблици с названием
{tableip} — читает из таблицы кто как почему забанен
Проблема при вынесении в шаблон, он повторяет текст в worldofwarcraft_banned.tpl столько раз сколько выводит строк из мускула {tableip}
Как эту проблему решить не подскажете?

SparkY 27.06.2011 в 9:26

да и если $tpl->compile(‘content’); ставить после }
}
$tpl->compile(‘content’);

то таблица не посторяется но выводит последний запрос который произвёл {tableip} те что выше не отображаются…..

pistol 27.06.2011 в 9:46

SparkY, а вы вначале переменную сформируйте, потом компилируйте шаблон.

$tableip = "";
while ($vystup = mysql_fetch_array($result)){
 $tableip .= '
     '.$vystup["ip"].'
     '.$vystup["banreason"].'
     '.date('d.m.Y H:m',$vystup["bandate"]).'
     '.date('d.m.Y H:m',$vystup["unbandate"]);
}
//Тут шаблон
SparkY 27.06.2011 в 10:02

Большое человеческое спасибо! Помогло!

sima 27.06.2011 в 21:56

Последняя версия движка 9.2 , а вы пишете модули в стиле, эдак 8.2 .
Почитайте документацию к DLE, станет легче писать модули.
Как минимум, подключение через шаблон,
«Главное правило, которое программист должен внушать пользователю – «работает – не трожь!!!» тут не действует, пользователь обязан тронуть код, чтобы добавить сторонний модуль.»
Можно ничего не трогать, точнее не трогать никаких php-файлов.
В админке, dle_admin_sections, по поводу options.php .
[aviable] в самом движке. В общем, читайте документацию и сорцы, и тогда станет легче писать. и понимать будете много ;)

wovo4ka 28.06.2011 в 23:31

Хочу сделать отправку дополнительного параметра в строке запроса (типа так http://incod.in/form.html?ref=65 ), но никак не пойму, что и где дописать (переписать), чтобы переменная $_GET['ref'] передавалась скрипту… подскажите, пжлст

Миша 24.07.2011 в 3:04

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

$tpl->load_template(‘worldofwarcraft/worldofwarcraft_banned.tpl’);
$tpl->set(‘{tableip}’, $tableip);
$tpl->set(‘{tabletext}’, $tabletext);

$tpl->compile(‘content’);

Вот такая конструкция не работает. :( После первого $tpl->compile(‘шаблон-1′); , второй $tpl->compile(‘шаблон-2′); не обрабатывается! Прикиньте, а?! :)

Миша 24.07.2011 в 12:44

pistol, помоги. Я чего уже только не пробовал. Но нужно сделать.. Иначе буду перепахивать ведь модуль. А это ой как не приятно.

pistol 24.07.2011 в 15:47

Миша, не совсем понятно, что ты хочешь. Чтобы выводилось сразу 2 страницы с шапкой и футером одна за другой?

Миша 24.07.2011 в 18:00

Да, наверно так.

Проблему решил следующим образом:
echo $tpl->result['шаблон'];

и теперь подключаю сие творение через {include file=»"}

turgor 04.08.2011 в 9:03

Спасибо большое!! Очень интересная статья! Давное хотел приступить к изучению DLE, после ковыряний в Joomla.

Александр 06.10.2011 в 21:00

доброе время нужен модуль для проверки доменов для движка DLE модуль ХАМЕРА не катит .. надо что бы на одной странице водишь проверка на другой выдает результат… помогите…

Павел 20.10.2011 в 22:11

Статья супер.
Такой вопрос возник. Как сделать чтобы например в статической странице был универсальный тег {gal cat=»номер категории»} и в зависимости от номера категории выводил бы картинки из нужного каталога. Я так понимаю нужно колдовать с файлом static.php

Сергей 22.11.2011 в 17:01

Даааа конечно ни чего не получилось что и следовало ожидать похоже что я из 2033 года хотя на дворе конец 2011.Написано очень красиво но ничего не получается по этой инструкции,хотя вроде и скрипты писал и cms для себя.

Роман 16.12.2011 в 12:16

Как узнать id новости на которой странице находимся?

pistol 16.12.2011 в 12:27

Роман, \engine\modules\show.full.php

$row['id']

Роман 16.12.2011 в 12:42

спасибо

Роман 16.12.2011 в 13:01

Я смысла понять не могу, какие можно переменные использовать в новом модуле.
И как их подключить.
Мне надо чтобы для посетителей была обычная ссылка на файл а для гостей другая (кодированая). В short.tpl инклуд модуль. И он должен определить зареганый пользователь или нет и выдать соответствующие ссылки. Так вот в этом модуле какие переменные можно использовать. Как подключить значение переменной вот отсюда например:
«Роман, \engine\modules\show.full.php

$row['id']»
Извиняюсь за столь длинный и непонятный комент))

vbvb 27.01.2012 в 3:26

vbvbvb



Ваш комментарий: