У всех, кто впервые сталкивается с MODx Evolution, очень часто возникают подобные вопросы: как вывести дату создания документа, как вывести автора документа, как вывести заголовок родителя и т.д. и т.п. Согласитесь, не для всех это может оказаться элементарным на первых шагах изучения MODx. А сколько было потрачено нервов и времени в бесплодных попытках найти нужный ответ! И не всегда даже найденный ответ бывает очевиден и понятен. Хватит! Настало время дать сразу все ответы на все вопросы. Ну в меру собственных сил и знаний, конечно. В этой статье я буду собирать все подобные вопросы и стараться дать максимально подробный ответ, конечно же все это будет сопровождаться готовыми рабочими примерами, которые каждый сможет применить на практике.

Автор не считает себя великим гуру, поэтому, в подготовке этой статьи рассчитывает на помощь читателей. Присылайте свои вопросы и найденные решения, комментируйте и предлагайте альтернативные подходы, критикуйте и становитесь соавторами этой подборки.

Спрашивали? Отвечаем!

1. Как вызвать сниппет в шаблоне другого сниппета?

Сниппеты можно вызывать двумя способами:

[[НазваниеСниппета]] - кэшируемый вызов сниппета
[!НазваниеСниппета!] - некэшируемый вызов сниппета

Если вызов основного сниппета некэшируемый, то в шаблоне сниппет обязательно должен быть кэшируемым. Более того, чтобы избежать проблем с выводом сниппетов (например с постраничным разбиением), основной сниппет желательно всегда делать некэшируемым.

К примеру, имеем некэшируемый вызов Ditto:

[!Ditto? &startID=`10` &tpl=`ditto_tpl`!]

у которого в шаблоне ditto_tpl надо вызвать сниппет Wayfinder:

<div class="wrapper">
    [[Wayfinder? &startId=`[+id+]`]]
</div>

2. Как вывести дату создания документа?

Расширим задачу, сформулировав вопрос так: Как вообще выводить даты? Т.е. это может быть любая дата, как в шаблоне для Ditto так и на странице самого документа.

а) Задача: вывести дату создания документа в ленте новостей

Для вывода даты нам потребуется вставить в шаблон news_tpl в месте вывода этой даты специальный плэйсхолдер Ditto - [+date+] – он выводит дату в установленном формате (которую мы зададим позже, при вызове Ditto). По умолчанию используется значение createdon (дата создания документа). Может принимать значения: editedon (дата последнего редактирования) и pub_date (дата публикации документа).

Создаем чанк news_tpl:

<div class="news">
    [+date+] | [+longtitle+]
    <p>[+introtext+]</p>
</div>

Для того, чтобы задать параметр из которого Ditto будет брать значение даты используем &dateSource=`editedon`. Для того чтобы задать формат даты, используем &dateFormat=`%d.%m.%Y`, где значением выступает любой валидный формат времени, который соответствует правилам функции PHP - strftime:

Символы для обозначения формата времени функции strftime
%a сокращенное название дня недели в текущей локали Пт
%A полное название дня недели в текущей локали 22.11.2024
%b сокращенное название месяца недели в текущей локали 22.11.2024
%B полное название месяца недели в текущей локали Ноябрь
%c предпочтительный формат даты и времени в текущей локали 22.11.2024
%C столетие (год, деленный на 100 и огругленный до целого, от 00 до 99) 22.11.2024
%d день месяца в виде десятичного числа (от 01 до 31) 22.11.2024
%D аналогично %m/%d/%y 22.11.2024
%e день месяца в виде десятичного числа, если это одна цифра, то перед ней добавляется пробел (от ' 1' до '31') 22.11.2024
%g подобно %G, но без столетия. 22.11.2024
%G Год, 4-значное число, соответствующее номеру недели по ISO (см. %V). Аналогично %Y, за исключением того, что если номер недели по ISO соответствует предыдущему или следующему году, используется соответствующий год. 2024
%h аналогично %b ноя
%H номер часа от 00 до 23 22.11.2024
%I номер часа от 01 до 12 22.11.2024
%j номер дня в году (от 001 до 366) 327
%m номер месяца (от 01 до 12) 22.11.2024
%M минуты 22.11.2024
%n символ "\n" 22.11.2024
%p `am' или `pm', или соответствующие строки в текущей локали 22.11.2024
%r время в формате a.m. или p.m. 22.11.2024
%R время в 24-часовом формате 22.11.2024
%S секунды 22.11.2024
%t символ табуляции ("\t") 22.11.2024
%T текущее время, аналогично %H:%M:%S 22.11.2024
%u номер дня недели от 1 до 7, где 1 соответствует понедельнику 22.11.2024
%U порядковый номер недели в текущем году. Первым днем первой недели в году считается первое воскресенье года. 22.11.2024
%V Порядковый номер недели в году по стандарту ISO 8601:1988 от 01 до 53, где 1 соответствует первой неделе в году, в которой как минимум 4 дня принадлежат этому году. Первым днем недели считается понедельник. (Используйте %G or %g для определения соответствующего года) 47
%W порядковый номер недели в текущем году. Первым днем первой недели в году считается первый понедельник года. 22.11.2024
%w номер дня недели, 0 соответствует воскресенью 22.11.2024
%x предпочтительный формат даты без времени в текущей локали 22.11.2024
%X предпочтительный формат времени без даты в текущей локали 22.11.2024
%y год без столетия (от 00 до 99) 22.11.2024
%Y год, включая столетие 22.11.2024
%Z временная зона в виде смещения, аббривеатуры или полного наименования 22.11.2024
%% символ `%' 22.11.2024

Примеры вызова Ditto с разными значениями даты:

[!Ditto? &startID=`10` &tpl=`news_tpl` &dateSource=`createdon` &dateFormat=`%d.%m.%Y` &display=`5`!] // дата создания документа
[!Ditto? &startID=`10` &tpl=`news_tpl` &dateSource=`editedon` &dateFormat=`%d.%m.%Y` &display=`5`!] // дата последного редактирования документа
[!Ditto? &startID=`10` &tpl=`news_tpl` &dateSource=`pub_date` &dateFormat=`%d.%m.%Y` &display=`5`!] // дата публикации документа

б) Задача: вывести дату на странице самой новости

Казалось бы, чего проще? Меняем в чанке news_tpl все + на * и нужный чанк готов. Но в MODx нет специального тега [*date*], поэтому, вместо него придется использовать [*createdon*], [*editedon*] или [*pub_date*]

Для начала пробуем [*createdon*] или [*editedon*] и получаем вместо даты что-то типа этого:

1318407717

Почему же так получилось? Потому что, любое время в БД записывается в виде Unix Timestamp — количество секунд от 1 января 1970 года до текущего момента. Зачем же такое придумали? Ну, например, для того, чтобы была возможность оперировать датой в независимости от ее формата. На самом деле, это будет легко перевести в нужный нам формат, но об этом чуть позже.

Берем следующий параметр [*pub_date*] и получаем:

0

Ну а тут то что не так, спросите вы? Оказывается, по-умолчанию параметр pub_date не устанавливается, поэтому его значение равно 0 и попытка его вывести выдаст 0 или 01.01.1970. Чтобы избежать этого, придется параметр pub_date делать обязательным к заполнению или установить ему значение по умолчанию. В этом нам поможет ManagerManager. Но даже если параметр будет заполнен, на выходе мы вновь увидим количество секунд, прошедших с 01.01.1970.

Решение 1.  На помощь придет PHx, только прежде чем его устанавливать, ознакомьтесь с возможными проблемами. При установленном PHx вывод даты можно сделать таким образом:

[*createdon:date=`%d.%m.%Y`*] // дата создания документа
[*editedon:date=`%d.%m.%Y`*] // дата последнего редактирования документа
[*pub_date:date=`%d.%m.%Y`*] // дата публикации документа

Кстати, PHx можно использовать и в шаблоне Ditto, вставив вместо плэйсхолдера [+date+] один из этих плэйсхолдеров:

[+createdon:date=`%d.%m.%Y`+] // дата создания документа
[+editedon:date=`%d.%m.%Y`+] // дата последнего редактирования документа
[+pub_date:date=`%d.%m.%Y`+] // дата публикации документа

В этом слачае, при вызове Ditto параметры &dateSource и &dateFormat не нужны.

Решение 2.  Для вывода даты в нужном формате можно воспользоваться сниппетом. Создаем новый сниппет, назовем его, к примеру, DateFormat, и помещаем в него следующий код:

<?php
setlocale(LC_ALL, 'ru_RU.UTF-8');

if ( $val == '' ) $val=time();
if ($format == '' ) $format = "%d.%m.%Y";
return strftime($format, $val);
?>

В том месте, где нам необходимо вывести дату, помещаем такой вызов этого сниппета:

[!DateFormat? &val=`[*createdon*]` &format=`%d.%m.%Y`!]

В параметре &val мы задаем значение для даты, а в параметре &format нужный формат. Сниппет может применяться как на странице новости, так и в шаблоне для Dito, не забудьте, если Ditto вызывается некэшируемым, то в его шаблоне сниппет должен вызываться как кэшируемый.

Если вызвать сниппет вообще без параметров:

[!DateFormat!]

то он выведет текущую дату в формате заданном по умолчанию: "%d.%m.%Y", этот формат можно поменять в коде сниппета.

3. Как отсортировать документы по TV-параметру с типом ввода Date?

Вот пример, где это может пригодиться: Необходимо отсортировать горящие туры по дате вылета. Дата вылета задается в TV-параметре data_toura с типом ввода Date. При этом, эта дата должна быть выведена в ленте горящих туров и на странице самого тура в формате %d-%m-%Y.

Для того, чтобы можно было отсортировать туры в ленте горящих туров, которая выводится с помощью снипета Ditto, мы будем использовать параметр &orderBy=`data_toura ASC`. Для того, чтобы сортировка у нас получилась правильная, необходимо задать параметру data_toura значение в формате количества секунд, прошедших с 1 января 1970 года. Для этого нам необходимо установить у этого параметра значение Визуальный компонент как Unixtime:

Для отображения этой даты в шаблоне Ditto и на странице тура будем использовать PHx или сниппет DateFormat из предыдущей статьи:

[!DateFormat? &val=`[*data_toura*]` &format=`%d-%m-%Y`!] // на странице тура
[[DateFormat? &val=`[+data_toura+]` &format=`%d-%m-%Y`]] // в шаблоне Ditto

4. Как вывести дату на русском языке?

Т.е. мы хотели бы увидеть дату в формате: 12 декабря 2012 года.

Создаём сниппет convertDate и вставляем в него такой код:

<?php
$MyDate= (isset($MyDate)) ? $MyDate: $modx -> documentObject['MyDate'];
$type= (isset($type)) ? $type: $modx -> documentObject['type'];
$monthes = array('','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря');
$day = date("j" ,$MyDate);
$month = $monthes[date("n",$MyDate)];
$year = date("Y",$MyDate);

echo $day.' '.$month.' '.$year.' года';
?>

Вызываем сниппет:

[!convertDate? &MyDate=`[*createdon*]`!] // в документе MODx
[[convertDate? &MyDate=`[+createdon+]`]] // в шаблоне Ditto

В качестве значения параметра &MyDate могут выступать createdon, editedon, pub_date, unpub_date и TV-параметр с типом ввода Date и визуальным компонентом Unixtime.

5. Как вывести автора документа?

Решение 1. Для этой цели можно воспользоваться возможностями PHx, если он у вас установлен.

Логин того, кто создал документ,  будет выводиться таким образом:

[*createdby:userinfo=`username`*] // в докуенте MODx
[+createdby:userinfo=`username`+] // в шаблоне Ditto

К примеру, если документ создал администратор, то выведется его логин admin.

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

[*createdby:userinfo=`fullname`*]

В этом случае выведется Default admin account - это значение полного имени администратора по умолчанию. Чтобы вывелось Администратор или как-то иначе, необходимо заменить его полное имя в Пользователи >> Управление менеджерами.

Для вывода E-mail пользователя:

[*createdby:userinfo=`email`*]

Решение 2. Плагин PHx можно заменить простым сниппетом. Создадим новый сниппет UserInfo с таким кодом:

<?php
/*
* UserInfo - сниппет для получения данных пользователя
*/
$output = "";
$userinfo = $modx->getUserInfo($id); //Используем Id пользователя для получения массива с данными пользователя
$out1 = $userinfo["fullname"]; // Получаем полное имя пользователя
$out2 = $userinfo["phone"]; // Получаем телефон пользователя
$out3 = $userinfo["email"]; // Получаем электронный адрес пользователя
$output = 'Автор: ' . $out1 . ' Телефон: ' . $out2 . ' E-mail: ' . $out3;
return $output;
?>

В шаблоне помещаем такой вызов сниппета:

[!UserInfo? &id=`[*createdby*]`!]

где

&id=`[*createdby*]` - передаем в наш сниппет ID пользователя, создавшего документ. С помощью параметра editedby можно передать ID пользователя, редактировавшего документ.

С помощью этого сниппета можно выводить любые данные пользователя из таблицы user_attributes. Описание getUserInfo.

6. Как вывести заголовок родительского документа?

Решение 1. Вновь расширим задачу: Как вообще выводить параметры родительского документа?

На помощь опять придет PHx.

Вывести ID родительского документа мы можем с помощью специального тега MODx:

[*parent*] // в документе MODx
[+parent+] // а шаблоне Ditto

Чтобы вывести заголовок родительского документа, применяем PHx:

[*id:parent=`pagetitle`*] // в документе MODx
[+id:parent=`pagetitle`+] // а шаблоне Ditto

Чтобы вывести ID родителя родителя, т.е. дедушки:

[*parent:parent=`id`*] // в документе MODx
[+parent:parent=`id`+] // а шаблоне Ditto

Чтобы вывести заголовок прадедушки:

[*parent:parent=`id`:parent=`pagetitle`*] // в документе MODx
[+parent:parent=`id`:parent=`pagetitle`+] // а шаблоне Ditto

и т.д.:

[*parent:parent=`id`:parent=`id`:parent=`pagetitle`*] // в документе MODx
[+parent:parent=`id`:parent=`id`:parent=`pagetitle`+] // а шаблоне Ditto

Таким образом можно получать не только id или заголовок, а и любой другой параметр, например расширенный заголовок родителя:

[*id:parent=`longtitle`*] // в документе MODx
[+id:parent=`longtitle`+] // а шаблоне Ditto

Решение 2. Если по каким-то причинам вы не можете использовать PHx, на помощь придет сниппет getField.

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

[!GetField? &parent=`0` &field=`pagetitle`!]

При parent=0 будет использоваться родительский документ. В качестве значения параметра field можно указывать любое поле документа или TV-параметр.

Чтобы получить заголовок или другое поле "дедушки", используются следующие параметры:

[!GetField? &parent=`1` &parentLevel=`2` &field=`pagetitle`!]

При parent=1 используется корневой каталог. Параметр parentLevel определяет глубину вложенности от текущего документа до корневого каталога: 0 - корневой документ, 1 - родитель, 2 - дедушка, 3 - прадедушка и т.д.

Этот сниппет позволяет выводить любой параметр любого документа. С помощью параметра docid можно задать ID интересующего документа, а с помощью параметра field необходимое поле или TV-параметр:

[!GetField? &docid=`25` &field=`pagetitle`!]

7. Как обрезать длину строки?

К примеру, выводим ленту новостей и необходимо, чтобы длина заголовка не превышала 200 символов, при этом, надо чтобы слова не обрезались и в конце строки появлялись три точки.

Для этих целей используем сниппет truncate. Код сниппета:

<?php  
$lenf = $len;

//Заменяет символы перевода строки на HTML тег
$order   = array("\r\n", "\n", "\r");
$replace = '<br />';
$what  = str_replace($order, $replace, $text);

if (strlen($what) > $lenf) {
  $what = preg_replace('/^(.{' . $lenf . ',}? ).*$/is', '$1', $what) . '...';
}
return $what;
?>

Вызов сниппета будет таким:

[!truncate? &text=[*pagetitle*] &len=200!] // в документе MODx
[[truncate? &text=[+pagetitle+] &len=200]] // а шаблоне Ditto

Сниппет обрежет текст до определенного количества символов не обрезая слова и добавит в конце три точки.

8. В RSS ленте вместо даты публикации выводится дата создания документа, как исправить?

Придется отредактировать файл assets/snippets/ditto/formats/rss.format.inc.php
На 80 строчке есть такая запись:

$GLOBALS["dateSource"] = isset($dateSource) ? $dateSource : "createdon";
    // date type to display (values can be createdon, pub_date, editedon)

// set tpl rss placeholders
$placeholders['rss_date'] = array($GLOBALS["dateSource"],"rss_date");

Т.е. по умолчанию используется createdon. Надо заменить на pub_date, т.е.:

$GLOBALS["dateSource"] = isset($dateSource) ? $dateSource : "pub_date";

9. Как убрать из TransAlias знаки препинания?

Если у вас псевдонимы генерируются автоматически с помощью плагина TransAlias, то такие знаки препинания, как "!", ":", "," и т.д. автоматически появятся и в вашем псевдониме, если они присутствуют в заголовке. Но если запятая или восклицательный знак не влияют на работоспособность псевдонима, тем не менее, их присутствие вряд ли его украсит. К счастью, это легко исправляется.

В настройках TransAlias достаточно выбрать в параметре Restrict alias to значение lowercase alphanumeric и псевдонимы будут генерироваться правильно, т.е. без лишних знаков препинания.

10. Как вывести количество документов в папке?

Для этого воспользуемся сниппетом ChildCounter (сниппет найден здесь):

<?php
$docid = isset($docid) ? intval($docid) : $modx->documentIdentifier;
$depth = isset($depth) ? intval($depth) : 0;
$isfolder = isset($isfolder) ? intval($isfolder): 0;
$tpl = isset($tpl) ? $tpl: -1;
$published = isset($published) ? intval($published): 1;
$davailable = $modx->getChildIds($docid, $depth);
 
if ($davailable){
    $where = ($tpl > 0) ? 'template='.$tpl : 'isfolder='.$isfolder;
    $dcount = $modx->getDocuments($davailable, $published, 0, 'id', $where);
    return count($dcount);
}
return 0;
?>

Параметры сниппета ChildCounter:

&dicId - ID сканируемой папки
&depth - глубина сканирования
&isfolder - Если 1 - вернёт количество папок, если 0 - количество документов НЕ папок. Значения 0 или 1. По умолчанию 0.
&published - Если 0 - вернёт количество неопубликованных документов, если 1 - количество опубликованных документов. Значения 0 или 1. По умолчанию 1.
&tpl - если указан, то возвращает количество документов с шаблоном id которого равен &tpl

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

[[ChildCounter? &docid=`406` &depth=`2` &tpl=`15` &published=`0` &isfolder=`0`]]

вернет количество неопубликованных документов с шаблоном 15 в контейнере с id равным 406 при глубине сканирования 2.

11. pagetitle или longtitle? Или конструкция if else.

Очень часто мы сталкиваемся с необходимостью вывести на странице какой-то параметр, например, расширенный заголовок longtitle. Но что делать, если этот параметр не заполнен, а выводим мы его в качестве заголовка? Конечно, можно с помощью плагина ManagerManager задать обязательное заполнение этого параметра и наша головная боль будет решена. Но что, если мы в силу некоторых обстоятельств не можем этого сделать?

Пример 1.

С помощью плагина PHx.

Вместо тега [*longtitle*] вставляем такую конструкцию:

<h1>[+phx:if=`[*longtitle*]`:is=``:then=`[*pagetitle*]`:else=`[*longtitle*]`+]</h1>

Читается это так: Если параметр longtitle пустой, то выводим pagetitle, иначе выводим longtitle.

С помощью сниппета alterTitle

Сниппет alterTitle выводит pagetitle если не заполнен longtitle.

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

<h1>[[alterTitle? &id=`[*id*]`]]</h1>

где

&id=`[*id*]` - передаем в сниппет ID ресурса, в котором вызываем сниппет. Фактически, этот сниппет можно использовать и для вывода заголовка родителя, передав [*parent*].

Пример 2.

С помощью плагина PHx.

Аналогичную конструкцию можем применять и для других параметров. Например, у нас есть параметр foto у шаблона Новости, в котором содержится картинка для новостей, но не у всех новостей будут картинки. И если у новости нет картинки, нам необходимо вывести картинку "заглушку". Я поступил следующим образом, создал еще один параметр nofoto тип ввода Image и назначил его шаблону Новости. В значении по умолчанию указал путь к картинке "заглушке". С помощью плагина ManagerManager спрятал этот параметр от всех пользователей:

mm_hideFields('nofoto');

А в том месте, где нужно вывести параметр foto поместил такую конструкцию:

[+phx:if=`[*foto*]`:is=``:then=`<img alt="Нет фотографии" src="[*nofoto*]">`:else=`<img alt="[*pagetitle*]" src="[*foto*]">`+]

С помощью сниппета if

Документация к сниппету.

С помощью виджета Custom Widget.

Используется только для TV-параметров. Детали тут.

12. Ссылка на предыдущий и следующий документ в папке

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

Пример вызова сниппета:

[[prevnextPage? &directOutput=`1` &letsCycle=`1`]]

где

&directOutput=`1` - выводим результат работы сниппета напрямую, без использования плэйсхолдеров
&letsCycle=`1` - зацикливаем ссылки

13. Автоматическая смена года в копирайте

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

Создайте новый сниппет (название не так важно, ну пусть будет copyright)  с таким кодом:

<?php
$copyfrom = (isset($copyfrom )) ? $copyfrom : '2012';
$copyholder  = (isset($copyholder)) ? $copyholder : ' [(site_name)]';
if (date('Y') != $copyfrom) { $copytill = ' - ' . date('Y'); }
$copyright = '&copy; ' . $copyfrom . $copytill . $copyholder;
return $copyright;
?>

Пример вызова:

[[copyright]]

или

[[copyright? &copyfrom=`2008` &copyholder=`Иван Иванович Иванов.`]]

где

copyfrom=`2008` - год начала авторских прав. По умолчанию 2012, можно изменить прямо в коде сниппета.
&copyholder=`Иван Иванович Иванов.` - обладатель авторских прав. По умолчанию - название сайта.

Поделитесь ссылкой

Статистика

Яндекс цитирования
© 2011 - 2023 Школа MODX
Напишите нам в Telegram