Skip to content
  1. Компоненты
  2. BannerPro
  3. Интеграция на сайте

Интеграция и сценарии

Сниппет BannerPro выбирает активные баннеры, рендерит их через pdoTools и отдаёт HTML для позиции. Клики считает плагин BannerProClickout, показы — BannerProImpression.

Базовый вывод

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'limit' => 3
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &limit=`3`
]]

positionName принимает одно имя или список через запятую: sidebar,footer. Если вы передали position, сниппет игнорирует positionName.

Типовые места на сайте

МестоИмя позицииТипичный вызов
Шапка / heroheaderlimit=1, sortby=RAND() или ab
Боковая колонкаsidebarsortby=idx, tplWrapper
Подвалfooterlimit=3
Карточка товара MS3shop-product-sidebarproductId текущего ресурса
HTML / AdSensesidebar-htmlтип HTML, tplHtml

Пример layout с тремя слотами:

fenom
<header>
  {'!BannerPro' | snippet : [
    'positionName' => 'header',
    'tpl' => 'byAd',
    'limit' => 1
  ]}
</header>

<aside>
  {'!BannerPro' | snippet : [
    'positionName' => 'sidebar',
    'tpl' => 'byAd',
    'sortby' => 'idx',
    'sortdir' => 'ASC',
    'tplWrapper' => '@INLINE <div class="sidebar-banners">{$output}</div>'
  ]}
</aside>

<footer>
  {'!BannerPro' | snippet : [
    'positionName' => 'footer',
    'tpl' => 'byAd',
    'limit' => 3
  ]}
</footer>
modx
<header>
[[!BannerPro?
  &positionName=`header`
  &tpl=`byAd`
  &limit=`1`
]]
</header>

<aside>
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &sortby=`idx`
  &sortdir=`ASC`
  &tplWrapper=`@INLINE <div class="sidebar-banners">[[+output]]</div>`
]]
</aside>

<footer>
[[!BannerPro?
  &positionName=`footer`
  &tpl=`byAd`
  &limit=`3`
]]
</footer>

Экраны создания позиций и баннеров: Админка. Карточка товара: MiniShop3.

Выборка

Сниппет всегда добавляет базовые условия:

УсловиеЧто делает
start / endПоказывает баннер только в активный период
active = 1Скрывает выключенные баннеры, если не задан showInactive
byAdPositionБерёт только баннеры, привязанные к позиции
position / positions / positionNameФильтрует позиции
context_keyФильтрует позиции по контексту MODX (текущий или &context=)
max_clicks / max_impressionsСкрывает баннер при достижении лимита

Лимит кликов и показов не меняет поле active. Баннер просто перестаёт попадать в выборку.

Ротация и порядок

sortbyПоведение
RAND()Случайный порядок, значение по умолчанию
idxПорядок связи баннер + позиция
weightedВзвешенная ротация через RAND() * weight
abSticky A/B 50/50 при ровно двух баннерах в слоте
поле byAdСортировка по полю баннера

Фиксированный порядок:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'sortby' => 'idx',
  'sortdir' => 'ASC'
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &sortby=`idx`
  &sortdir=`ASC`
]]

Взвешенная ротация:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'sortby' => 'weighted',
  'limit' => 1
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &sortby=`weighted`
  &limit=`1`
]]

Вес задайте в админке на связи баннер + позиция.

A/B-деление

При sortby=ab компонент делит трафик 50/50 между ровно двумя баннерами в одной позиции (после фильтров расписания, лимитов и таргетинга). Повторные визиты закрепляют вариант в cookie bannerpro_ab_{positionId}:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'hero',
  'sortby' => 'ab',
  'limit' => 1
]}
modx
[[!BannerPro?
  &positionName=`hero`
  &sortby=`ab`
  &limit=`1`
]]
ПоведениеОписание
Первый визитСлучайный выбор одного из двух баннеров
Повторные визитыТот же баннер по cookie bannerpro_ab_{positionId}
Не 2 баннераA/B не применяется, выводятся все подходящие
Кэш сниппетаОтключён (как для RAND() и weighted)
TTL cookiebannerpro_ab_ttl (дней, по умолчанию 30)

Контекст MODX

Позиция может иметь поле context_key (web, mgr, …). Пустое значение означает все контексты.

Сниппет фильтрует позиции по текущему контексту. Другой контекст задают так:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'context' => 'web',
  'tpl' => 'byAd'
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &context=`web`
  &tpl=`byAd`
]]

Ключ кэша учитывает effective context. Два вызова с разным context на одной странице не делят один кэш.

Таргетинг

В админке на баннере задают ограничения показа. Сниппет применяет их автоматически:

МеханизмПоле / параметрЧто делает
Расписаниеshow_hoursДни недели и часы показа в рамках start / end
Страницаtarget_resource_idБаннер только на указанном ресурсе
Разделtarget_parent_idБаннер на дочерних страницах раздела
Метки&tags=, tagsModeФильтр по JSON-меткам баннера

Таргетинг по странице/разделу в админке: либо конкретный ресурс, либо дочерние страницы раздела, не оба сразу.

Фильтр по меткам в вызове:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tags' => 'sale,promo',
  'tpl' => 'byAd'
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tags=`sale,promo`
  &tpl=`byAd`
]]

При &tags= баннер без меток не попадёт в выборку.

Кэш HTML

BannerPro кэширует готовый HTML, если включена настройка bannerpro_cache и вызов подходит для кэша.

Сниппет не использует кэш при таких условиях:

  • sortby=RAND()
  • sortby=weighted
  • sortby=ab
  • &cache=0
  • &toSeparatePlaceholders
  • &showLog=1 и активная сессия mgr

Принудительно отключить кэш для одного вызова:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'sortby' => 'idx',
  'cache' => false
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &sortby=`idx`
  &cache=`0`
]]

Ключ кэша учитывает контекст, культуру, сортировку, параметры вызова и часовой bucket. Кэш сбрасывается при смене периода показа (start / end).

Чанки

В пакете два базовых чанка:

ЧанкДля чего
byAdБаннер-изображение со ссылкой клика
byHtmlHTML-баннер

В чанке byAd и byHtml ссылку клика берите из click_url (URL учёта клика + UTM при включённых настройках):

fenom
<article class="banner" data-banner-id="{$id}" data-adposition="{$adposition}">
  <a class="banner__link"
     href="{$click_url|escape:'html'}"
     {if $description}title="{$description|escape}"{/if}>
    {if $image}
      <img class="banner__image" src="{$image}" alt="{$name|escape}" loading="lazy" />
    {else}
      <span class="banner__title">{$name|escape}</span>
    {/if}
  </a>
</article>
modx
<article class="banner" data-banner-id="[[+id]]" data-adposition="[[+adposition]]">
  <a class="banner__link" href="[[+click_url]]" title="[[+description]]">
    <img class="banner__image" src="[[+image]]" alt="[[+name]]" loading="lazy" />
  </a>
</article>

Вызов с файловым чанком:

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => '@FILE chunks/banner.fenom.tpl',
  'fastMode' => true
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`@FILE chunks/banner.fenom.tpl`
  &fastMode=`1`
]]

Клики

Поток клика:

  1. Посетитель открывает ссылку из click_url/{bannerpro_click}/{adposition}.
  2. MODX не находит ресурс и вызывает OnPageNotFound.
  3. BannerProClickout ищет связь byAdPosition по adposition.
  4. Компонент пишет клик в bannerpro_clicks.
  5. Компонент вызывает OnBannerProClick.
  6. MODX перенаправляет посетителя на URL баннера.

Повторный клик с того же IP за сутки на ту же пару баннер + позиция не создаёт новую запись. Редирект и событие выполняются. В JSON события будет duplicate: true.

URL баннера поддерживает плейсхолдеры из query string:

fenom
<a href="{$click_url|escape:'html'}?page_id={$_modx->resource.id}">
  <img src="{$image}" alt="{$name|escape}" />
</a>
modx
<a href="[[+click_url]]?page_id=[[*id]]">
  <img src="[[+image]]" alt="[[+name]]" />
</a>

UTM при перенаправлении

Настройки bannerpro_utm_* добавляют UTM к URL баннера после клика. См. Системные настройки. UTM из настроек не перезаписывают query-параметры, уже указанные в URL баннера.

Если в админке URL равен https://shop.example/sale?utm_campaign=[[+utm_source]], компонент подставит sidebar.

Показы

Для показов включите настройку bannerpro_track_impressions.

При bannerpro_impression_lazy = 1 (по умолчанию) impression.js подключается через IntersectionObserver, а не блокирующим <script> в head.

После включения сниппет:

  1. Оборачивает каждый баннер в data-bannerpro-impression.
  2. Подключает assets/components/bannerpro/js/impression.js.
  3. Отправляет pixel /{bannerpro_impression}/{adposition}, когда баннер попадает в область видимости.
  4. Вызывает OnBannerProImpression.
  5. Отправляет браузерное событие bannerpro:impression.

Дубликаты показов с того же IP за сутки не пишутся в БД. В событии будет duplicate: true.

Вывод в плейсхолдер

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'toPlaceholder' => 'sidebarBanners'
]}
{$_modx->getPlaceholder('sidebarBanners')}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &toPlaceholder=`sidebarBanners`
]]
[[+sidebarBanners]]

Обёртка

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'tplWrapper' => '@INLINE <div class="banners banners--sidebar">{$output}</div>',
  'wrapIfEmpty' => false
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &tplWrapper=`@INLINE <div class="banners banners--sidebar">[[+output]]</div>`
  &wrapIfEmpty=`0`
]]

Срок хранения статистики

Срок задают bannerpro_clicks_retention_days и bannerpro_impressions_retention_days.

Запуск:

bash
php core/components/bannerpro/cron/purge.php

На активном сайте запускайте cron раз в сутки.

Отладка

showLog работает только для авторизованных пользователей с контекстом mgr.

fenom
{'!BannerPro' | snippet : [
  'positionName' => 'sidebar',
  'tpl' => 'byAd',
  'showLog' => true
]}
modx
[[!BannerPro?
  &positionName=`sidebar`
  &tpl=`byAd`
  &showLog=`1`
]]

В конце вывода появится блок <pre class="pdoUsersLog"> с таймингами pdoFetch.