Статья, в которой рассмотрим процесс создания плагина по учёту количества просмотров страниц (тикетов) в CMS MODX Revolution. Плагин будет напоминать собой компонент HitsPage. Но в отличие от него он будет считать уникальные просмотры ресурсов (посредством технологии COOKIE), а также предоставлять плейсхолдеры для вывода количества просмотров на страницах. Кроме этого создадим ещё сниппет для вывода 5 самых популярных статей сайта.

Создание плагина по учёту количества просмотров

Процесс создания плагина, с помощью которого будем считать просмотры страниц, выполним посредством 2 действий:

  1. Создадим TV поле для ресурсов. В данное поле будем записывать просмотры страницы.
  2. Напишем плагин, который будет записывать в данное TV поле просмотры.

Создание TV поля для хранения счётчика просмотров

Создадим дополнительное поле (TV-параметр) со следующими характеристиками:

  • имя: views;
  • подпись: Количество просмотров;
  • тип ввода: Число;
  • значение по умолчанию: 0;
  • тип вывода: По умолчанию;
  • доступно для шаблонов: отметить галочками необходимые шаблоны (которые используются для вывода тикетов и разделов).
MODX Revolution - Создание дополнительного поля views
MODX Revo - Создание дополнительного поля views

В разделе TV-поле views используется для хранения числа просмотров всех его ресурсов. Данное поле позволит вывести количество просмотров всех его дочерних ресурсов без суммирования (т.е. без использования в запросе агрегатной функции SUM).

Создание плагина для обновления TV-поля views

Разработаем в CMS MODX Revolution плагин (например, с именем viewsCount) по учёту количества просмотров статей (тикетов).

Тикет – это расширение стандартного типа ресурса modDocument. Данные типы ресурсов (тикет и раздел для тикетов) можно создавать только после установки дополнения CMS MODX Revolution Tickets.

Код плагина будет выполняться при наступлении системного события OnLoadWebDocument. Данное событие наступает после загрузки документа, но до обработки MODX тегов. Для получения текущего ресурса в плагине будем использовать конструкцию $modx-resource.

Код плагина viewsCount:

<?php
if ($modx->event->name == 'OnLoadWebDocument') {
  // id дополнительного поля views
  $id_tv = 2;  
  // получим ресурс
  $resource = $modx->resource;
  // получим тип ресурса
  $class_key = $resource->get('class_key');

  // если тип ресурса == Ticket
  if ($class_key == 'Ticket') {
    // получим id ресурса
    $id = $resource->get('id');
    // получим tv поле
    $tv_ticket = $modx->getObject('modTemplateVarResource',array(
      'tmplvarid' => $id_tv,
      'contentid' => $id
    ));

    // если не существует COOKIE viewticket
    if (!isset($_COOKIE['viewticket'])) {

      // если tv поле является объектом
      if (is_object($tv_ticket)) {
        // получаем его значение
        $views_ticket = $tv_ticket->get('value');
        // увеличиваем количество просмотров на 1
        $views_ticket++;
        // сохраняем количество просмотров в таблицу
        $tv_ticket->set('value',$views_ticket);
        // сохраняем
        $tv_ticket->save();        
      } else {
        // устанавливаем количество просмотров равным 1
        $views_ticket = 1;
        // создаём новый объект modTemplateVarResource
        $tv_ticket = $modx->newObject('modTemplateVarResource');
        // установливаем значение поля tmplvarid
        $tv_ticket->set('tmplvarid',$id_tv);
        // установливаем значение поля contentid       
        $tv_ticket->set('contentid',$id);
        // устанавливаем значение поля value
        $tv_ticket->set('value',$views_ticket);
        // сохраняем
        $tv_ticket->save();
      }      

      // получаем родительский ресурс      
      if ($section = $resource->getOne('Parent')) {
        $id_section = $section->get('id');
        $tv_section = $modx->getObject('modTemplateVarResource',array(
         'tmplvarid' => $id_tv,
         'contentid' => $id_section
        ));
        if (is_object($tv_section)) {
          // получаем его значение
          $views_section = $tv_section->get('value');
          // увеличиваем количество просмотров на 1
          $views_section++;
          // сохраняем количество просмотров в таблицу
          $tv_section->set('value',$views_section);
          // сохраняем
          $tv_section->save();
        } else {
          // устанавливаем количество просмотров секции равным 1
          $views_section = 1;
          // создаём новый объект modTemplateVarResource
          $tv_section = $modx->newObject('modTemplateVarResource');
          // установливаем значение поля tmplvarid
          $tv_section->set('tmplvarid',$id_tv);
          // установливаем значение поля contentid       
          $tv_section->set('contentid',$id_section);
          // устанавливаем значение поля value
          $tv_section->set('value',$views_section);
          // сохраняем
          $tv_section->save();          
        }
      }        
      // отправка COOKIE viewticket
      setcookie('viewticket', '1',time() + (86400 * 365),'/'.$resource->get('uri')); 
    } else {
      $views_ticket = $tv_ticket->get('value');
    }
    // устанавливаем плейсхолдер viewsTicket
    $modx->setPlaceholder('viewsTicket', $views_ticket);
  } 

  if ($class_key == 'TicketsSection') {
    // получим id ресурса
    $id = $resource->get('id');
    // получим tv поле
    $tv_section = $modx->getObject('modTemplateVarResource',array(
      'tmplvarid' => $id_tv,
      'contentid' => $id
    ));
    // если tv поле является объектом
    if (is_object($tv_section)) {
      // получаем его значение
      $views_section = $tv_section->get('value');
      // устанавливаем плейсхолдер viewsTicket
      $modx->setPlaceholder('viewsSection', $views_section);
    }
  }
}

Для того чтобы плагин отслеживал данное событие, его необходимо отметить флажком на вкладке "Системные события".

Выбор событий, которые должен отслеживать плагин viewsCount
Установка событий, которые должен отслеживать плагин viewsCount

Для того чтобы счётчик посещений не увеличивался при просмотре некоторого ресурса одним и тем же пользователем будем использовать COOKIE. Отправку куки будем осуществлять посредством функции setcookie, а её проверку - с помощью ассоциативного php массива $_COOKIE.

Кроме этого с помощью этого плагина будем ещё устанавливать плейсхолдер, с помощью которого можно будет сразу вывести просмотры текущего ресурса или раздела на экран:

  • [[!+viewsTicket]] (для тикета).
  • [[!+viewsSection]] (для раздела с тикетами).

Плейсхолер необходимо вызывать не кэшированным.

Сниппет для пересчёта значений полей views разделов

Если по каким-то причинам вам необходимо пересчитать количество просмотров секций (разделов с тикетами), то можете воспользоваться следующим сниппетом:

<?php
$tv_id = 2;
$sections = $modx->getIterator('modResource', array('class_key' => 'TicketsSection'));
foreach ($sections as $section) {
  $tv = $modx->getObject('modTemplateVarResource', array(
    'tmplvarid' => $section->get('id'),
    'contentid' => $tv_id
  ));
  if ($tv) {
    $tickets = $modx->getIterator('modResource', array('class_key' => 'Ticket','parent' => $section->get('id')));
    $views = 0;
    foreach ($tickets as $ticket) {
      $tv_ticket = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => $ticket->get('id'),
        'contentid' => $tv_id
      ));
      if ($tv_ticket) {
        $views += $tv_ticket->get('value');
      }
    }
    $tv->set('value',$views);
    $tv->save();
  }
}

Для выполнения этого сниппета (например, countViewsSection) необходимо поместить его вызов в любой ресурс:

[[!countViewsSection]]

После открытия ресурса в браузере значение TV полей разделов views пересчитаются.

Сниппет для вывода самых популярных статей

Создадим сниппет для вывода самых просматриваемых статей (тикетов) на сайте. Работа сниппета осуществляется на значениях TV-поля views (в примере id поля равно 2). Для снижения нагрузки, результат работы сниппета будем сохранять в кэш на 3 часа. Оформление результатов будем выполнять с помощью чанка.

Код сниппета topTicketsView:

<?php
// попробуем получить содержимое кэша по ключу topticketview
$output = $modx->cacheManager->get('topticketview');
// если кэш не найден, то...
if (empty($output)) {
  // создадим новый запрос, используя объект modTemplateVarResource
  $query = $modx->newQuery('modTemplateVarResource');
  // присоединяем к нему объект modResource
  $query->innerJoin('modResource','Resource');
  // добавляем к запросу условие
  $query->where(array(
    'modTemplateVarResource.tmplvarid'=>'2',
    'Resource.class_key' => 'Ticket'
  ));
  // выполним сортировку по TV (для преобразования строки в беззнаковое число используем mysql функцию CAST)
  $query->sortby('CAST(modTemplateVarResource.value as unsigned)',DESC);
  // укажем поля для выборки
  $query->select(array(
    'Resource.pagetitle as pagetitle',
    'Resource.uri as uri',
    'modTemplateVarResource.value as countviews'
  ));
  // ограничим выборку 5 полями
  $query->limit(5);
  // подготовим и выполним запрос (используем PDO)
  $query->prepare();
  $query->stmt->execute();
  $rows = $query->stmt->fetchAll(PDO::FETCH_ASSOC);
  // переменная для хранения результата
  $output = '';
  // номер записи (для использования в чанке)
  $idx = 0;
  // переберём все записи
  foreach ($rows as $row) {
    $idx++;
    $row['idx'] = $idx;
    // оформлять результат будем с помощью чанка tplTopViewTickets
    $output .= $modx->getChunk('tplTopViewTickets',$row);
  }
  // сохраним результат на 3 часа в кэше (для сокращения нагрузки)
  $modx->cacheManager->set('topticketview',$output,10800);
}
// возвратим результат
return $output;

Чанк tplTopViewTickets:

<li>
  <a href="[[+uri]]">[[+pagetitle]]</a> (Просмотры: [[+countviews]])
</li>

Вызов сниппета topTicketsView в шаблоне:

<section>
  Популярные статьи:
  <ol>
    [[!topTicketsView]]    
  </ol>
</section>

После оформления (с помощью стилей CSS) блок самых популярных статей может визуально на сайте выглядеть так:

Пример дизайна секции самых просматриваемых ресурсов на сайте
Пример дизайна секции самых просматриваемых ресурсов на сайте