MODX сниппеты (snippet)

MODX сниппеты (snippet) MODX Revo

В предыдущей статье мы разбили шаблон на чанки (мы к ним еще вернемся по мере разработки). Теперь разберемся, что такое сниппеты и создадим первый сниппет «year», который будет автоматически выводить текущий год. Год нам пригодится, например, в подвале, где указан Copyright. Чтобы каждый год его не менять вручную, MODX будет подставлять год автоматически.

Что такое

MODX сниппет — это элемент (как чанк), но содержащий в себе не HTML, динамический код PHP, который можно запускать на любой странице вашего сайта. Сниппеты позволяют вам создавать различные функциональные возможности, такие как меню, списки, поиск, формы и т.д.

Как создать

Что бы создать сниппет в MODX в дереве документов на вкладке «Элементы» нажмите на кнопку «Новый сниппет». Затем на открывшейся странице укажите имя (например: year), описание, категорию и вставьте код.

Код сниппета «year» следующий (см. синтаксис языка PHP):

<?php 
echo date('Y');

Создание сниппета year

?> прописывать не нужно. Если пропишите, то парсер MODX всё равно её проигнорирует. В принципе, и объявление PHP скрипта в виде <?php можно не прописывать, код будет исполняться корректно и без этого. Но для наглядности я привык прописывать это указание на то, что перед нами скрипт на языке PHP.

Если вы используете парсер fenom и у вас включена настройка pdotools_fenom_php, то вы можете вывести текущий год так.

{'' | date : 'Y'}

Получается так мы избавились от сниппета, как и до этого от чанков)

Вызов сниппета

Чтобы использовать сниппет, вы должны поместить его тег в шаблон, чанк, ресурс или другой сниппет, где вы хотите, чтобы он отображался. Вывод сниппетов аналогичен чанкам, для вызова не кэшируемого сниппета используем [[name_snippet]]:

&copy; Copyright 2022 - [[year]] [[++site_name]]. Все права защищены.

В код выведется: Copyright 2022 — 2024 Название сайта. Все права защищены.

Где название сайта берется из системных настроек: site_name (скоро до них дойдем).

Если нужен не кэшируемый вывод, то вызывается всегда по аналогии — с восклицательным знаком вначале [[!name_snippet]].

Вышеприведенный код на fenom.

&copy; Copyright 2022 - {'year' | snippet} {$_modx->config.site_name}. Все права защищены.
или 
&copy; Copyright 2022 - {'' | date : 'Y'} {$_modx->config.site_name}. Все права защищены.

В общем открываете чанк в котором хранятся сквозные блоки, или шаблон base и в подвале в блоке copyright прописываем одну из конструкций указанных выше.

Выводим копирайтинг

Параметры

Сниппеты могут иметь параметры — php-переменные, которые влияют на их вывод, и могут вызывать другие элементы, такие как чанки, переменные шаблона или другие сниппеты.

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

  • В коде вашего сниппета вы можете получить доступ к параметрам через массив $scriptProperties или прямо через переменные с теми же именами. Например, если вы хотите получить параметр 'start', вы можете использовать $scriptProperties['start'] или $start.
  • В вызове вашего сниппета вы можете задать параметры, используя синтаксис тегов. Например, если вы хотите передать параметр 'start' со значением '2022', вы можете использовать [[year? &start=`2022`]]. Обратите внимание, что вы должны использовать обратные кавычки, а не одинарные или двойные кавычки, для обрамления значений параметров.

Например усложним код нашего сниппета, до:

<?php
$year = date("Y");
if($year == $start) {
	return $year;
} else {
return ''.$start.' – '.$year.'';
}

Здесь мы добавили параметр start, следовательно, можем указать:

Copyright [[year? &start=`2022`]] [[++site_name]]. Все права защищены.

В код выведется то же самое, что и в предыдущем случае.

Указываются параметры в вызове сниппета после знака вопроса (?).

В случае с феном вызов будет следующим.

{'year' | snippet : [
    'start' => '2022'
]}

Пример написания собственного сниппета

Для наглядности давайте разберем еще один пример. У меня на одном из сайтов есть вот такой блок с цифрами для посадки на MODX.

Блок с цифрами

Я хочу чтобы каждая из этих цифр через определенное время менялась сама. Например, чтобы цифра 232 раз в неделю увеличивалась на 1, 521 раз в 3 дня увеличивалась на 1 и т.д.

Обычным PHP, это можно решить примерно так:

<?php
// Устанавливаем начальное значение цифры
$number = 232;
// Получаем текущую дату в формате ГГГГ-ММ-ДД
$date = date("Y-m-d");
// Определяем дату, с которой начинается отсчет недель
$start_date = "2024-01-29";
// Вычисляем разницу между текущей датой и датой начала в днях
$diff = (strtotime($date) - strtotime($start_date)) / (60 * 60 * 24);
// Делим разницу на 7, чтобы получить количество прошедших недель
$weeks = floor($diff / 7);
// Прибавляем к начальному значению цифры количество прошедших недель
$number += $weeks;
// Выводим результат на экран
echo $number;
?>

Чтобы не создавать 4 php сниппета, мы при помощи параметров можем сделать 1 универсальный сниппет, пусть будет counts:

<?php
// Получаем значение параметра start, который задает начальное значение цифры
$number = $modx->getOption('start', $scriptProperties);
// Получаем значение параметра startdata, который задает дату начала
$start_date = $modx->getOption('startdata', $scriptProperties);
// Получаем значение параметра deys_shag, который задает шаг в днях
$step = $modx->getOption('deys_shag', $scriptProperties);
// Получаем текущую дату в формате ГГГГ-ММ-ДД
$date = date("Y-m-d");
// Вычисляем разницу между текущей датой и датой начала в днях
$diff = (strtotime($date) - strtotime($start_date)) / (60 * 60 * 24);
// Делим разницу на шаг, чтобы получить количество прошедших периодов
$periods = floor($diff / $step);
// Прибавляем к начальному значению цифры количество прошедших периодов
$number += $periods;
// Возвращаем результат
return $number;

Теперь можно вызывать его в нескольких местах задавая параметры:

[[!counts? &start=`232` &startdata=`2024-01-29` &deys_shag=`7`]]
...
[[!counts? &start=`521` &startdata=`2024-01-29` &deys_shag=`3`]]
.. и т.д.

Если вы не особо знаете PHP (или вообще не знаете) — не переживайте, его знание для создания среднестатистического сайта не требуется. Тем более есть куча готовых решений, часть из них ниже. На худой конец если вообще не шарите в php и не нашли готового сниппета, то код снипетов (по крайней мере простеньких), может сгенерить chat gpt.

Как вызывать другие элементы MODX из своего собственного сниппета?

Да, можно вызывать другие элементы MODX из своего собственного сниппета. Для этого вам нужно использовать специальные методы API объекта $modx. Например, вы можете вызывать:

  • Чанки, используя метод getChunk. Это позволит вам получить содержимое чанка по его имени или идентификатору. Например, если вы хотите получить чанк с именем Header, вы можете использовать $modx->getChunk('Header').
  • Сниппеты, используя метод runSnippet. Это позволит вам запустить другой сниппет из вашего сниппета и получить его вывод. Вы также можете передать параметры в вызываемый сниппет. Например, если вы хотите запустить сниппет с именем HelloWorld и передать ему параметр name со значением Сергей, вы можете использовать $modx->runSnippet('HelloWorld', array('name' => 'Сергей')).
  • Переменные шаблона, используя метод getTemplateVar. Это позволит вам получить значение переменной шаблона по ее имени или идентификатору для определенного ресурса. Например, если вы хотите получить значение переменной шаблона с именем title для ресурса с идентификатором 1, вы можете использовать $modx->getTemplateVar('title', 1).

Подборка полезных мини сниппетов для разработчиков

Красивый вывод цифр (цен) с пробелами, используя php number_format

Вариант 1. (numformat)

<?php
if(strlen($input)==0) return '';
$input = floatval(str_replace(array(' ',','), array('','.'), $input));
return number_format($input,(floor($input) == $input ? 0 : 2),'.',' ');

Использование:

[[*price:numformat]]

Было: 33354567
Стало: 33 354 567
Давайте для примера разберем еще
Вариант 2. (nPrice)

<?php 
if ($price == "")
$price_output =  $modx->resource->getTVValue('Price');
else
$price_output = $price; 
return number_format($price_output, 0, '', ' ' );

Использование:

В месте, где у Вас выводится цифровое поле (цена), вставляем (пусть будет TV с именем price):

[[nPrice?price=`[[*price]]`]]

Ну или если у вас магазин на minishop2 то, вместо вывода [[+prise]] пишем:

[[nPrice?price=`[[+price]]`]]

Удаляем последний символ в строке

last

<?php
return mb_substr($input, 0, -1);

Примечание: Полезно при формировании каких-либо последовательностей (например, ID ресурсов через запятую), у которой последний символ вызывает ошибку.

Использование:

[[*resources:last]]

Было: 33,35,45,67,
Стало: 33,35,45,67

Формирование корректной ссылки с атрибутом tel при выводе телефона на сайте

phone

<?php
$p1 = array(" ", "-", "(", ")");
$p2 = array("", "", "", "");
return str_replace($p1, $p2, $input);

Примечание: Удаляются скобки, дефисы и т. д.

Использование:

<a href="tel:[[++phone:phone]]">[[++phone]]</a>

на fenom можно без создания сниппета вывести, так.

<a href="tel:{$_modx->config.phone  | preg_replace : '/[^0-9+]/' : ''}"> {$_modx->config.phone}</a>

Было: 8 (927) 778-45-45
Стало: 89277784545

Склоняем числовые определения

plural

<?php
if($n!=''){
$plural = $n%10==1&&$n%100!=11?$w1:($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)?$w2:$w3);
return $plural;
}

Примечание: Данное решение позволяет склонять числовые определения. То есть, не «1 штук», а «1 штука», «3 штуки» и т. д. 

Использование:

[[plural? &n=`число` &w1=`штука` &w2=`штуки` &w3=`штуки`]]

Убирает лишние символы в строке

title

<?php
$str = preg_replace ("#([^=])\"([^\"]+)\"#", "\\1«\\2»", $input);
return str_replace('&', '', $str);

Данный снииппет полезен тем, что зачастую заказчики в pagetitle вводят название ресурса типа О компании «Рога и копыта» и в код выводятся двойные кавычки, если такие кавычки вывести в meta или в img, например так:

<img src="[[*image]]" alt="[[*pagetitle]]"/>

выведется:

<img src="путь к изображению" alt="О компании "Рога и копыта""/>

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

Данный модификатор заменяет кавычки на «» и дополнительно убивает символ &.

Использование:

<img src="[[*image]]" alt="[[*pagetitle:title]]" />

Запись в сессию и вывода значения какой-либо переменной

getGet

<?php
$get = htmlentities(trim(strip_tags((string) $_GET[$var])), ENT_QUOTES, 'UTF-8', false);
session_start();
if ($get == '' ) {
return $_SESSION[$var];
} 
else {
$_SESSION[$var] = $get;
return $_SESSION[$var];
}

Для чего он: Например нужно передать на страницу формы заказа название товара, на котором нажата ссылка «Купить».

Примечание: Можно в первой строке вместо $GET[$var] прописать $_REQUEST[$var] — тогда будет работать и с GET и с POST.

Использование:
Ссылка:

<a href="[[~id? &item=`[[*pagetitle]]`]]">Заказать</a>

В форме:

<input type="hidden" name="item" value="[[!getGet? &var=`item`]]" />

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

Время чтения

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

readtime

<?php
$options = (int) $modx->getOption('options', $scriptProperties, 220, true); // 220 слов в минуту
$wordCount = (int) str_word_count(strip_tags($input)); // Чтобы отобразить количество слов, установите для параметров значение 0
if ($options === 0) return $wordCount;
return ceil($wordCount / abs($options));

Использование:

<p>Время чтения [[*content:readtime]] мин.</p>

Если ваш сайт с jQuery то можете воспользоваться продвинутым, настраиваемым миниатюрным скриптом выводящим время чтения.

Данный сниппет нужно вызвать в секции head.

<?php
$res = $modx->resource;
$site_url = $modx->getOption('site_url');
$site_start = $modx->getOption('site_start') ?: 1;
$ids = $modx->getParentIds($res->id, 10, array('context' => $modx->context->key));
$pids = ($res->id != $site_start) ? [$res->id] : [];
foreach($ids as $id) {
    if($res->id != $id) {
        $pids[] = $id;    
    }
}
$pids = array_reverse($pids);
$output = [];
$index = 0;
foreach($pids as $id) {
    if ($id == 0) {
        $id = $site_start;
    }
    if($res->id != $id) {
        $res = $modx->getObject('modResource', $id);
    }
    
    $uri = $site_url . $res->get('uri');
    if($res->get('id') == $site_start) {
        $uri = $site_url;
    }
    $output[] = '{
        "@type": "ListItem",
        "position": '.++$index.',
        "name": "'.$res->get('pagetitle').'",
        "item": "'.$uri.'"
    }';
}
$wrapper = implode(',', $output);
return '<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": ['.$wrapper.']
}
</script>';

alternate hreflang

Для мультиязычных сайтов (выводить в секции head), подробнее зачем и почему можно почитать здесь: https://netpeak.net/ru/blog/tegi-alternate-hreflang-media-type-zachem-i-kak-ikh-ispol-zovat/

<?php
$ctxDefault = $modx->getOption('x-default', $scriptProperties, 'web', true);
$tplDefault = '<link rel="alternate" href="{$page}" hreflang="x-default"/>';
$tpl = '<link rel="alternate" href="{$page}" hreflang="{$lang}"/>';
$output = '';
$contexts = $modx->getCollection('modContext', array('key:!=' => 'mgr'));
if(!count($contexts)) return;
foreach($contexts as $context) {
    $ctx = $modx->getContext($context->key);
    $site_url = $ctx->getOption('site_url');
    $site_start = $ctx->getOption('site_start');
    if($modx->resource->uri != 'index') {
        $site_url .= $modx->resource->uri; 
    }
    $cultureKey = $ctx->getOption('cultureKey');
    if($context->key == $ctxDefault) {
        $parseTpl = str_replace('{$page}', $site_url, $tplDefault);
        $output .= $parseTpl;
    }
    $parseTpl = str_replace('{$page}', $site_url, $tpl);
    $parseTpl = str_replace('{$lang}', $cultureKey, $parseTpl);
    $output .= $parseTpl;
}
return $output;

FileSize — вывод размера файла и расширения файла

Использование:

  • [[!FileSize? &input=`assets/files/myfile.pdf`]] — Будет автоматически выбрана единица измерения.
  • [[*file_catalog:FileSize]] — Вывод размера файла из TV-параметра.
  • [[!FileSize? &input=`assets/files/myfile.pdf` &unit=`b`]] — Явно указываем единицу измерения.
  • [[!FileSize? &input=`assets/files/myfile.pdf` &get_ext=`1`]] — Получить расширение файла, а не размер.
  • [[*file_catalog:FileSize?&get_ext=`1`]] — расширение файла из TV-параметра.
  • {'!FileSize' | snippet : ['input' => 'assets/files/myfile.pdf']} — Fenom.
<?php
if(!empty($get_ext)){
  //Получить расширение файла в нижнем регистре
  $ext = mb_strtolower(pathinfo($input, PATHINFO_EXTENSION));
  return $ext;
}else{
  //Получить размер файла
  $units = array(
    'gb' => array('size' => 1073741824, 'label' => 'ГБ'),
    'mb' => array('size' => 1048576,    'label' => 'МБ'),
    'kb' => array('size' => 1024,       'label' => 'КБ'),
    'b'  => array('size' => 0,          'label' => 'байт')
  );
  $input = MODX_BASE_PATH . $input;
  $size = is_file($input) ? filesize($input) : 0;
  $unit = (isset($unit) && isset($units[$unit])) ? $unit : false;
  
  if ($size > 0) {
    if ($unit === false) {
      foreach ($units as $key => $properties) {
        if ($size >= $properties['size']) {
          $unit = $key;
          break;
        }
      }
    }
    if ($unit != 'b'){
      $size = $size / $units[$unit]['size'];
    }
  }
  else {
    if ($unit === false) $unit = 'b';
  }
  return round($size, 2) . ' ' . $units[$unit]['label'];
}

FaviconGenerator — aвтоматическая генерация favicon

Размеры генерит дополнение phpthumbof, если оно не установлено, то нужно установить с основного репозитория, также можно использовать pthumb или phpthumbon.

Допустим, название FaviconGenerator, код:

<?php
if (version_compare(PHP_VERSION, '5.4.0') < 0) {
    return '<!-- Your version of PHP is very ancient -->';
}
$output = '';
// Цвет фона. Если не указан, то не применяется.
$backgroundColor = (string)$modx->getOption('backgroundColor', $scriptProperties, '');
// Путь до изображения
$image = (string)$modx->getOption('image', $scriptProperties, '');
// Нужно ли генерировать favicon.ico
$ico = (int)$modx->getOption('ico', $scriptProperties, 0);
// Сниппет, создающий миниатюры (phpthumbof, pthumb, phpthumbon)
$snippet = (string)$modx->getOption('snippet', $scriptProperties, 'phpthumbof');
// Цвет вкладки для мобильных браузеров
$tabColor = (string)$modx->getOption('tabColor', $scriptProperties, '');

// Apple
$sizes = ['57x57', '72x72', '144x144', '60x60', '120x120', '76x76', '152x152'];
foreach ($sizes as $size) {
	$as = explode('x', $size);
	$options = 'w='.$as[0].'&h='.$as[1].'&zc=1&f=png&bg='.$backgroundColor;
	$output .= '<link rel="apple-touch-icon-precomposed" sizes="'.$size.'" href="'.$modx->runSnippet($snippet, ['input' => $image, 'options' => $options]).'" />'.PHP_EOL;
}

// Classic
$sizes = ['32x32', '16x16', '96x96', '128x128', '196x196'];
foreach ($sizes as $size) {
	$as = explode('x', $size);
	$options = 'w='.$as[0].'&h='.$as[1].'&zc=1&f=png';
	if (!empty($backgroundColor)) {
		$options .= '&bg='.$backgroundColor;
	}
	$output .= '<link rel="icon" type="image/png" sizes="'.$size.'" href="'.$modx->runSnippet($snippet, ['input' => $image, 'options' => $options]).'" />'.PHP_EOL;
}

// Microsoft
$output .= '<meta name="msapplication-TileColor" content="#FFFFFF" />'.PHP_EOL;
$output .= '<meta name="msapplication-TileImage" content="'.$modx->runSnippet($snippet, ['input' => $image, 'options'=>'w=144&h=144&zc=1&f=png&bg='.$backgroundColor]).'" />'.PHP_EOL;
$sizes = ['70x70', '150x150', '310x310'];
foreach ($sizes as $size) {
	$as = explode('x',$size);
	$options = 'w='.$as[0].'&h='.$as[1].'&zc=1&f=png';
	if (!empty($backgroundColor)) {
		$options .= '&bg='.$backgroundColor;
	}
	$output.='<meta name="msapplication-square'.$size.'logo" content="'.$modx->runSnippet($snippet, ['input' => $image, 'options' => $options]).'" />'.PHP_EOL;
}

// favicon.ico
if ($ico == 1) {
	$options = 'w=16&h=16&zc=1&f=ico';
	if (!empty($backgroundColor)) {
		$options .= '&bg='.$backgroundColor;
	}
	$output .= '<link rel="shortcut icon" href="'.$modx->runSnippet($snippet, ['input' => $image, 'options' => $options]).'" type="image/x-icon" />'.PHP_EOL;
	$output .= '<link rel="icon" href="'.$modx->runSnippet($snippet, ['input' => $image, 'options'=>$options]).'" type="image/x-icon" />'.PHP_EOL;
}

if (!empty($tabColor)) {
	$output .= '<meta name="theme-color" content="#'.$tabColor.'" />'.PHP_EOL;
	$output .= '<meta name="msapplication-navbutton-color" content="#'.$tabColor.'" />'.PHP_EOL;
	$output .= '<meta name="apple-mobile-web-app-status-bar-style" content="#'.$tabColor.'" />'.PHP_EOL;
}

return $output;

Пример использования

[[FaviconGenerator? 
    &image=`favicon.png`
    &backgroundColor=`f00`
    &tabColor=`f00`
    &ico=`1`
    &snippet=`phpthumbof`
 ]]

Параметры

Параметр Значение по умолчанию Пример значения
image assets/images/favicon.png
backgroundColor bada55
tabColor bada55
ico 0 1
snippet phpthumbof pthumb

Большинство сниппетов взято на просторах интернета.

В следующем уроке разберем поля ресурсов MODX и как их выводить.

Поделиться с друзьями
Алексей

Веб-дизайнер и SEO оптимизатор. Занимаюсь созданием сайтов с 2010 года и их продвижение с 2012 года!

Оцените автора
( 5 оценок, среднее 4.2 из 5 )
Web-Revenue.ru
Добавить комментарий

  1. Seva

    Продолжение будет?

    Ответить
    1. Алексей автор

      Будет как время появится, сейчас немного не до ведения блога

      Ответить
  2. Сергей

    А есть в modx возможность вставки карты от яндекс например как в wordpress, плагином?

    Ответить
    1. Алексей автор

      А зачем вам плагин, создайте чанк поместите в него код карты и вызовите в любом месте сайта

      Ответить