Простая система баннеров для Cotonti
Популярные запросы: Open Graph, плагин Reading Time, тема Quebec, плагин Telegram, набор иконок Analogue
- 804 просмотра +2
- 25 июня, 2024
- Обновлено: 18 марта, 2025
- admin
- Время чтения: 7 минут
- 2 (Подробно)
Недавно для одного из проектов возникла идея реализации баннерной системы. Требования оказались довольно простыми – хотя бы потому, что системы ротации баннеров в классическом понимании достаточно давно устарели. Мне же понадобилось реализовать следующие возможности:
Вывод баннера в конкретной локации
Поскольку размер рекламного баннера прямо зависит от того, где он размещается, необходимо дифференцировать их по локациям. Например,
- баннеры в header или “шапке” (глобальные),
- баннеры на главной странице,
- баннеры в сайдбаре внутренней страницы (шаблоны страниц или разделов).
Понятно, что дело этим не ограничится, и для каждого из вариантов баннер должен быть различным. В самом простом понимании – горизонтальной и квадратной компоновки.
Отсюда полагаем, что основным атрибутом баннера (или их группы) должна стать локация.
Дополнительные атрибуты баннера
Каждый баннер должен иметь следующие компоненты:
- URL перехода,
- имя файла с картинкой,
- текстовое значение для HTML-атрибутов title и alt.
В качестве глобальных параметров мы будем использовать:
- местоположение папки с картинками,
- значение атрибута rel.
Нет смысла хранить единый путь в поле с именем файла. Мы будем использовать единый путь для всех картинок и добавим его в настройки плагина.
Кроме этого, не стоит забывать о правильном оформлении баннерных ссылок с помощью атрибута rel. Более подробно об этом мы рассказывали раньше. В нашей реализации мы не будем указывать значение для каждого баннера, и вместо этого используем общий глобальный параметр. Как и местоположение папки с картинками, его мы внесем в настройки будущего плагина.
Удобный формат хранения массива данных
Как понятно из названия, я не стал использовать отдельную таблицу базы данных для хранения наших баннеров. Возможно, это более правильный подход, но для него необходимо создать инструментальную часть, с помощью которой можно будет управлять списком (добавлять и удалять баннеры).
Более простым мне показалось использование ассоциативного массива для хранения записей. Его структура оформилась таким образом:
$sbs_banners = [
'page' => [
'1' => [
'image' => [
'astronaut.jpg',
'pilot.jpg',
],
'link' => [
'https://sed.by/blog',
'https://sed.by/archive',
],
'text_1' => [
'Астронавт',
'Космонавт',
],
'text_2' => [
'Изображение астронавта',
'Картинка космонавта',
],
],
'2' => [
'image' => [
'desktop.jpg',
],
'link' => [
'https://sed.by/cot',
],
'text_1' => [
'Десктоп',
],
'text_2' => [
'Изображение десктопа',
],
],
],
];
Кстати, если закомментировать какой-либо элемент массива, можно легко поставить баннер "на паузу". Ну а для того, чтобы все это работало быстрее, можно использовать возможности кэширования. В готовом виде получим следующий код:
<?php
/**
* SBS Plugin Settings
*
* @package sbs
* @version 1.00
* @author SED.BY
* @copyright (c) sed.by 2024
*/
defined('COT_CODE') or die('Wrong URL');
define('SBS_REALM', '[SEDBY] SBS Simple Banner System');
if ($cache && $cache->db->exists('banners', SBS_REALM)) {
$sbs_banners = $cache->db->get('banners', SBS_REALM);
} else {
$sbs_banners = [
'page' => [
'1' => [
'image' => [
'astronaut.jpg',
'pilot.jpg',
],
'link' => [
'https://sed.by/blog',
'https://sed.by/archive',
],
'text_1' => [
'Астронавт',
'Космонавт',
],
'text_2' => [
'Изображение астронавта',
'Картинка космонавта',
],
],
'2' => [
'image' => [
'desktop.jpg',
],
'link' => [
'https://sed.by/cot',
],
'text_1' => [
'Десктоп',
],
'text_2' => [
'Изображение десктопа',
],
],
],
];
$cache && $cache->db->store('banners', $sbs_banners, SBS_REALM, Cot::$cfg['plugin']['sbs']['cache']);
}
Соответственно, у нас добавился еще один параметр – срок жизни кэша. Его мы добавим в настройки нашего плагина.
Как видно из примера, в качестве ключей массива я использовал значение поля page_id в таблице cot_pages. Это удобно для того, чтобы привязывать баннер к конкретной странице.
Условие и формат вывода баннера
В отдельных случаях нам необходимо проверять наличие в массиве баннера, привязанного к конкретной локации и id ее элемента. Например, если мы выводим баннер для конкретной страницы. Отсюда необходимость в функции проверки. Назовем ее sedby_banner_exists(). Параметров – исходя из структуры массива – будет два: локация и id. Сама же функция будет выглядеть так:
...
require_once cot_incfile('sbs', 'plug', 'settings');
function sedby_banner_exists($area, $id) {
global $sbs_banners;
return array_key_exists($id, $sbs_banners[$area]);
}
...
Таким образом, в шаблоне page.tpl мы можем указать:
<!-- IF {PHP.id|sedby_banner_exists('page', $this)} === true -->
{PHP.id|sedby_banner('sbs', 'page', $this)}
<!-- ENDIF -->
Если sedby_banner_exists() вернет true, будет сгенерен и выведен соответствующий баннер.
Второй момент – это формирование баннера. Здесь, как говорится, могут быть варианты, поэтому надо использовать подгружаемый TPL-шаблон. Функция sedby_banner() получит четыре параметра: имя шаблона, локацию, id элемента и режим вывода (первый элемент или случайный). В моей реализации она выглядит так:
function sedby_banner($tpl = 'sbs', $area = 'global', $id = 'random', $elems = 'first') {
if (Cot::$cfg['plugin']['sbs']['enable']) {
global $sbs_banners;
($id == 'random') && $id = array_rand($sbs_banners[$area]);
if ($elems == 'random') {
$banner_link = array_rand($sbs_banners[$area][$id]['link']);
$banner_image = array_rand($sbs_banners[$area][$id]['image']);
$banner_text_1 = array_rand($sbs_banners[$area][$id]['text_1']);
$banner_text_2 = array_rand($sbs_banners[$area][$id]['text_2']);
} else {
$banner_link = $banner_image = $banner_text_1 = $banner_text_2 = 0;
}
(!isset($tpl) || empty($tpl)) && $tpl = 'sbs';
$t = new XTemplate(cot_tplfile($tpl, 'plug'));
$t->assign([
"BANNER_LINK" => $sbs_banners[$area][$id]['link'][$banner_link],
"BANNER_IMAGE" => Cot::$cfg['mainurl'] . Cot::$cfg['plugin']['sbs']['folder'] . $sbs_banners[$area][$id]['image'][$banner_image],
"BANNER_TEXT_1" => $sbs_banners[$area][$id]['text_1'][$banner_text_1],
"BANNER_TEXT_2" => $sbs_banners[$area][$id]['text_2'][$banner_text_2],
"BANNER_REL" => 'rel="' . Cot::$cfg['plugin']['sbs']['rel'] . '"',
]);
$t->parse();
$output = $t->text();
} else {
$output = '';
}
return $output;
}
Я немного разнообразил возможности и добавил к ним вывод случайно выбранного баннера из указанной локации. Это будет реализовано при указании значения random для параметра $id. В остальных случаях производится поиск баннера по его id.
Дефолтный шаблон sbs.tpl будет иметь следующий вид:
<!-- BEGIN: MAIN -->
<a href="{BANNER_LINK}" title="{BANNER_TEXT_1}" class="mb-3 d-block" {BANNER_REL}>
<img src="{BANNER_IMAGE}" alt="{BANNER_TEXT_2}" class="img-fluid">
</a>
<!-- END: MAIN -->
Естественно, в качестве параметра $tpl можно указать и свой собственный шаблон.
Если же вам необходимо выводить случайный баннер, необходимо немного изменить параметры функции:
{PHP|sedby_banner('sbs', 'page', 'random')}
<!-- Можно и так: -->
{PHP|sedby_banner('sbs', 'page')}
<!-- Или так: -->
{PHP|sedby_banner('sbs', 'page', 'random', 'random')}
Проверять что-либо перед вызовом нашей функции с параметром random уже не надо. Необходимо лишь убедиться в том, что в массиве $sbs_banners() существует локация page, и в ней в нужном количестве (не менее одного) присутствуют элементы, из которых будут сформированы наши баннеры.
Хранение изображений
Для наглядности по умолчанию я разместил изображения в папке /plugins/sbs/img/ Если вам хочется иначе, измените этот путь в настройках плагина.
При размещении баннеров, например, в папке /datas/banners/ учтите, что по умолчанию корневая папка /datas/ закрыта от индексирования. Об этом мы также уже упоминали. Соответственно, и изображения ваших баннеров также не будут проиндексированы. Поэтому если вам необходимо обратное, откройте доступ для поисковых ботов соответствующей директивой в файле robots.txt
Allow: /datas/sbs
Или разместите картинки вне папки datas.
Подключение функций
Поскольку мне понадобилось выводить баннеры только на страницах модуля Page, я подключил функции плагина через хук page.tags файлом sbs.page.tags.php
<?php
/* ====================
[BEGIN_COT_EXT]
Hooks=page.tags
[END_COT_EXT]
==================== */
defined('COT_CODE') or die('Wrong URL.');
require_once cot_incfile('sbs', 'plug');
Если вам необходимо использование баннеров в разделах, на главной странице, в шапке сайта и проч., создайте дополнительный файл с соответствующим хуком (page.list.tags, index.tags, header.tags). Либо используйте хук global для доступности функций в любой локации сайта.
Заключение
У нас получился простой и нересурсоемкий плагин для вывода баннеров. Данные получаем из массива в файле настроек и кэшируем для ускорения доступа к его элементам. Срок кэширования по умолчанию – 7 дней. Создавать сложную инструментальную часть и размещать данные в таблице базы данных я не стал, поскольку настройка баннеров – это не рутинная и далеко не ежедневная задача.
Выводить с помощью нашего плагина баннеры можно в режиме привязки “баннер – страница сайта” или в режиме “случайный баннер”. Практически никаких проверок я не делал – опять же по причине отсутствия необходимости в оных. Если они все же где-то необходимы, пишите в комментариях. Готовый плагин выкладываю в Github-репозитории.
Ранее мы разбирались с тонкостями верстки блока загрузки файла в шаблоне page.tpl
| 29.06.2024 | Все элементы 3 уровня теперь являются массивами, функция sedby_banner() принимает 4 параметра: $tpl, $area, $id и $elems |
| 26.06.2024 | Вместо одного теперь используются два текстовых элемента |
Необходимо использовать $_SESSION для фиксирования уже показанных баннеров.
Интересный плагин. И движок тоже хорошо что развивается. Мой вопрос такой: а можно сделать так, чтобы посетителю выводился не случайный баннер, который может повториться, а все по очереди из указанной группы?
Новый комментарий
Ошибка
Выполнено