[HolidaysContent] Вывод контента в определённую дату и/или период времени
Всем привет, поступила банальная на первый взгляд задача, выводить в праздничные дни оформление тематическое… Всё бы ничего, просто написать сниппет который проверяет текущую дату и выводит чанк при совпадении… Но как быть с новым годом? Заказчик просит с 20.12 текущего года, по 10.01 соответственно следующего года показывать снег на сайте, тут уже нужно учитывать период, год начала и конца события.
Не стал искать решения на просторах интернета, решил написать самостоятельно, за одно подтянуть в очередной раз свои знания в PHP… Как сделал, всё же посмотрел на modstore.pro, есть ли какие ни будь подобные компоненты, оказывается есть My_holidays, почитал описание, показалось, что он не совсем мне удобен возможно.
В общем и целом, надеюсь кому нибудь пригодится мой сниппет)
Сниппет HolidaysContent
Использование:
В определённую дату, например 8 марта
Новый год, с 20.12 текущего года, по 10.01 следующего года
Обратите внимание, что параметр date — приоритетнее параметров периода (start/end).
Несколько вызовов не будут мешать друг другу, т.е. вы можете выводить как контент по периоду, так и контент в определённую дату, даже если эта дата попадает в этот период.
Не стал искать решения на просторах интернета, решил написать самостоятельно, за одно подтянуть в очередной раз свои знания в PHP… Как сделал, всё же посмотрел на modstore.pro, есть ли какие ни будь подобные компоненты, оказывается есть My_holidays, почитал описание, показалось, что он не совсем мне удобен возможно.
В общем и целом, надеюсь кому нибудь пригодится мой сниппет)
Сниппет HolidaysContent
<?php
$date = $modx->getOption('date', $scriptProperties, '');
$start = $modx->getOption('start', $scriptProperties, '');
$end = $modx->getOption('end', $scriptProperties, '');
$chunk = $modx->getOption('tpl', $scriptProperties, '');
$currentTimestamp = time();
$currentYear = date('Y');
// Проверяем, совпадает ли текущая дата с указанной датой
if (!empty($date)) {
$dateWithYear = $date . '.' . $currentYear;
$dateTimestamp = strtotime($dateWithYear);
if ($dateTimestamp !== false && date('d.m', $currentTimestamp) == date('d.m', $dateTimestamp)) {
return $modx->getChunk($chunk);
}
}
// Проверяем, попадает ли текущая дата в указанный период
if (!empty($start) && !empty($end)) {
// Определяем год для начала и конца периода
list($startDay, $startMonth, $startYear) = explode('.', $start);
list($endDay, $endMonth, $endYear) = explode('.', $end);
// Определяем год для начала периода
if ($startYear == 'this') {
$startYear = $currentYear;
} elseif ($startYear == 'next') {
$startYear = $currentYear + 1;
} else {
$startYear = $currentYear;
}
// Определяем год для конца периода
if ($endYear == 'this') {
$endYear = $currentYear;
} elseif ($endYear == 'next') {
$endYear = $currentYear + 1;
} else {
$endYear = $currentYear;
}
$startWithYear = $startDay . '.' . $startMonth . '.' . $startYear;
$endWithYear = $endDay . '.' . $endMonth . '.' . $endYear;
$startTimestamp = strtotime($startWithYear);
$endTimestamp = strtotime($endWithYear);
// Если период пересекает новый год, нужно учесть это
if ($startTimestamp > $endTimestamp) {
// Проверяем, если текущая дата попадает в период пересекающий год
if ($currentTimestamp >= $startTimestamp || $currentTimestamp < $endTimestamp) {
return $modx->getChunk($chunk);
}
} else {
if ($currentTimestamp >= $startTimestamp && $currentTimestamp <= $endTimestamp) {
return $modx->getChunk($chunk);
}
}
}
Использование:
В определённую дату, например 8 марта
[[!HolidaysContent? date=`08.03` &tpl=`8march`]]
Новый год, с 20.12 текущего года, по 10.01 следующего года
[[!HolidaysContent? start=`20.12.this` &end=`10.01.next` &tpl=`newyear`]]
Обратите внимание, что параметр date — приоритетнее параметров периода (start/end).
Несколько вызовов не будут мешать друг другу, т.е. вы можете выводить как контент по периоду, так и контент в определённую дату, даже если эта дата попадает в этот период.
Комментарии: 7
Ух ты! Осенний код подъехал, спасибо! Всегда жара с заявками в праздники, может и пригодится!
Тоже решаю такие квесты регулярно, поэтому позволю себе задать вопрос)
Просто интересно, а ты не пробовал стандартные для Revo планируемые даты публикации прикрутить для этих целей как-то?
Имею в виду перед тем, как решение выработал. Сниппет конечно круче, т.к. он универсальный, один раз поставил, и будет срабатывать каждый год))
Тоже горожу сниппеты, но сейчас подумал, что по-простому кажется можно было типа такого
Как думаешь, @Денис Усманов, рабочая это схема для одноразовых событий?
Тоже решаю такие квесты регулярно, поэтому позволю себе задать вопрос)
Просто интересно, а ты не пробовал стандартные для Revo планируемые даты публикации прикрутить для этих целей как-то?
Имею в виду перед тем, как решение выработал. Сниппет конечно круче, т.к. он универсальный, один раз поставил, и будет срабатывать каждый год))
Тоже горожу сниппеты, но сейчас подумал, что по-простому кажется можно было типа такого
[[#8.published:is=`1`:then=`[[#8.content]]`]]
выводить в шаблоне страницы, а в стандартных полях ресурса (с id=8 из моего примера) ставить планируемую дату публикации, и снятия с публикации, вот эти:Как думаешь, @Денис Усманов, рабочая это схема для одноразовых событий?
Привет! Да, можно вполне было пойти, через ресурсы, но мне нужно было решение в виде сниппета, который выводил бы по датам чанки с CSS/HTML/JS в разных местах… Поэтому, сниппет оказался на мой взгляд, самым верным решением.
Вообще чем-то похоже на работу пакета BannerY получилось кстати. Только опять же, со срабатыванием каждый год. На самом деле для ежегодных праздников твой вариант подходит конечно идеально!
И добавлю, что предлагаемый тобою вариант, полуавтоматический, т.е. после срабатывания придётся менять дату на следующий год. Мне нужно было сделать решение, которое как говорится «на века» и «без лишней возни») т.к. у заказчика сайтом управляет в основном HR отдел по вакансиям, и там точно разбираться с такими вещами не будут.
Немного сократил и добавил поддержку файловых чанков.
<?php
$start = $modx->getOption('start', $scriptProperties, '');
$end = $modx->getOption('end', $scriptProperties, '');
$chunk = $modx->getOption('tpl', $scriptProperties, '');
// определяем в каких случаях мы ничего не будем делать, нам важно не перетрудиться.
if((!$start && !$end) || !$chunk){
return '';
}
// завозим поддержку файловых чанков
if(!$parser = $modx->getService('pdoTools')){
$parser = $modx;
}
$now = strtotime('d.m.Y');
$currentYear = date('Y');
// предполагается что дада передаётся строкой вида "d.m"
$startTime = strtotime($start . '.' . $currentYear);
// если задана только дата начала, считае, что оформление будет активно только в эту дату
if(!$end){
if($now === $startTime){
return $parser->getChunk($chunk);
}
}
$startParts = explode('.', $start);
$endParts = explode('.', $end);
// проверяем больше месяц даты начала месяца даты окончания
if((int)$startParts[1] > (int)$endParts[1]){
$endTime = strtotime($end . '.' . ($currentYear + 1));
}else{
$endTime = strtotime($end . '.' . $currentYear);
}
if ($now < $startTime || $now > $endTime) {
return '';
}
return $parser->getChunk($chunk);
Как по мне, чересчур громоздко. Логика с date и start/end не очевидна. Да и в коде слишком много лишней логики. Я бы предложил вариант с датой и длительностью (просто в целях разминки полушарий)
$date = $modx->getOption('date', $scriptProperties, '');
$duration = $modx->getOption('duration', $scriptProperties, '1');
$chunk = $modx->getOption('tpl', $scriptProperties, '');
if (empty($date) || empty($chunk)) {
return '';
}
[$day, $month, $year] = sscanf($date, "%d.%d.%d");
$year ??= date('Y');
$date = "$day.$month.$year";
$currentTimestamp = time();
$startTimestamp = strtotime($date);
$endTimestamp = strtotime($date . " + $duration days");
if ($currentTimestamp >= $startTimestamp && $currentTimestamp < $endTimestamp) {
$pdoTools = $modx->getService('pdoTools');
return $pdoTools->getChunk($chunk);
}
Указал год — сработает только для него. Не указал, ежегодно. Если длительность не указана, то она равна 1 дню.
Раз уж в статье написано про «подтянуть в очередной раз свои знания в PHP», напишу тут свои мысли.
1. Работать с датами можно через объект DateTime. Насколько помню там даже можно просто сравнивать даты обычным оператором $myDate > $yourDate
2. Может быть имеет смысл не привязываться к году, а просто выводить за столько то дней до и после определённой даты. Новый год всегда 1 января не важно какого года, другие праздники тоже.
3. На мой взгляд удобнее и нагляднее вместо:
1. Работать с датами можно через объект DateTime. Насколько помню там даже можно просто сравнивать даты обычным оператором $myDate > $yourDate
2. Может быть имеет смысл не привязываться к году, а просто выводить за столько то дней до и после определённой даты. Новый год всегда 1 января не важно какого года, другие праздники тоже.
3. На мой взгляд удобнее и нагляднее вместо:
$start = $modx->getOption('start', $scriptProperties, '');
$end = $modx->getOption('end', $scriptProperties, '');
$chunk = $modx->getOption('tpl', $scriptProperties, '');
писать в таком стиле:$options = array_merge([
'start' => '',
'end' => '',
'tpl' => "@INLINE {$var}"
], $scriptProperties);
4. Я всегда стараюсь делать один return в сниппетах или функциях. Для меня лично тоже так удобнее и нагляднее (единая точка выхода).
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.