В ходе плановых работ на сайте я заметил некоторые недостатки в одном из старейших моих онлайн-инструментов: в генераторе календарей за любой год с 1 года н.э.. Во-первых, для всех лет I–XVIII веков он к таблице каждого месяца приписывал сообщение об ошибке в коде (хотя на самом деле код выдавал требуемый результат). Во-вторых, он (инструмент) генерировал грегорианский календарь даже для периода 1–1581 годов: то есть для периода, когда во всём мире ещё использовался исключительно юлианский календарь.
И я наконец-то эти недостатки исправил! Это было довольно просто, так что времени я потратил мало, а пользователям пользы будет много.
Заодно я наконец-то добавил ещё две казавшихся мне важными штуки. Первая – возможность генерировать календарь не только для определённого года, но и для определённой страны или территории: ведь даже если ограничиться парой юлианский/грегорианский календарь, то переход с одного на другой в разных странах случился в разные годы! (Если вы считаете, что в советской России это произошло позже всего, то вы немного заблуждаетесь.) Вторая штука – возможность сохранять сгенерированный календарь в PDF (и/или распечатывать его) без надписей, относящихся к навигации по сайту.

Но мне ещё есть над чем подумать. Например, как учитывать разные годы перехода на грегорианский календарь в многочисленных германских, восточноевропейских и северных герцогствах и княжествах, не превратив при этом меню генератора календарей в длиннющую простыню из опций. Если у кого-то есть соображения на эту тему или предложения по созданию каких-то дополнительных функций моего генератора календарей – напишите мне об этом!
Архив метки «календарь»
Давно хотел сделать на сайте такую штуку – календарь года (текущего и каждого из прошлых), в котором с каждой даты ссылка ведёт на подборку соответствующих постов в блоге (если в тот день что-то было опубликовано) – то есть, «календарь года как в ЖЖ». В ЖЖ такой календарь существовал и был очень удобен в качестве одного из способов поиска старых записей и/или анализа активности блога (своего или чужого). А вот, например, в WordPress такого календаря нет и, если я правильно помню, не было никогда (ну или был настолько давно, что я уже полностью забыл о его существовании) – есть только аналогичный календарь по месяцам, что совсем неудобно для большинства видов поиска и анализа.
На реализацию такой штуки своими силами нужно было некоторое количество свободного времени – и я наконец-то его нашёл! Что ещё более важно и интересно, это время я потратил не зря: сделать календарь-архив у меня получилось. Работающий пример можно посмотреть по ссылке, а в данном посте я перечислю словами все характеристики и приведу базовые PHP и CSS коды.
Характеристики моего годового календаря блога для WordPress:
– полный календарь года (видны все 12 месяцев, какая бы дата ни была на дворе на момент просмотра);
– возможность просматривать прошлые годы (но не ранее, чем год самой первой публичной записи в блоге);
– дни с публичными записями автоматически превращаются в ссылки на соответствующие даты в архиве записей;
– при наведении курсора на день ссылку всплывает подсказка с числом записей за соответствующую дату;
– в календарях за прошлые годы дата просмотра («сегодняшняя») выделяется заметной рамкой;
– у ячеек с датами, в которые была опубликована хотя бы одна запись, меняется фоновый цвет;
– у календаря – адаптивный дизайн: на больших и средних экранах показывается сетка 3×4 месяца, а на маленьких экранах месяцы года выстроены в столбик;
– запросы к базе данных оптимизированы таким образом, чтобы календарь не «тормозил» даже в блогах с десятками тысяч записей.
Ну а теперь – сами коды календаря (надеюсь, вы прочитали весь текст выше – он может вам помочь сориентироваться).
PHP-код, который можно испытывать прямо в таком виде – его легко вставить в свой макет страницы обыкновенным копипастом:
<?php
global $wpdb;
/* ======================================
1. PRIMO ANNO DEL BLOG
====================================== */
$first_post_date = $wpdb->get_var("
SELECT post_date
FROM $wpdb->posts
WHERE post_status='publish'
AND post_type='post'
ORDER BY post_date ASC
LIMIT 1
");
$first_year = date('Y', strtotime($first_post_date));
$current_year = date('Y');
$year = isset($_GET['yr']) ? intval($_GET['yr']) : $current_year;
if ($year < $first_year) $year = $first_year;
if ($year > $current_year) $year = $current_year;
/* ======================================
2. DATE DEI POST (QUERY SQL OTTIMIZZATA + CACHE)
====================================== */
$cache_key = 'calendar_'.$year;
$post_dates = get_transient($cache_key);
if ($post_dates === false){
$post_dates = [];
$results = $wpdb->get_results($wpdb->prepare("
SELECT DATE(post_date) as post_day, COUNT(ID) as total
FROM $wpdb->posts
WHERE post_status='publish'
AND post_type='post'
AND YEAR(post_date)=%d
GROUP BY post_day
", $year));
foreach ($results as $row){
$post_dates[$row->post_day] = $row->total;
}
set_transient($cache_key,$post_dates,12*HOUR_IN_SECONDS);
}
/* ======================================
3. NAVIGAZIONE CON TUTTI GLI ANNI
====================================== */
echo '<div class="calendar-nav">';
for ($y=$first_year; $y<=$current_year; $y++){
if ($y==$year){
echo '<span class="current-year">'.$y.'</span>';
}else{
echo '<a href="?yr='.$y.'">'.$y.'</a> ';
}
}
echo '</div>';
/* ======================================
4. CONTROLLO "OGGI NEGLI ANNI PASSATI"
====================================== */
$today_month = date('m');
$today_day = date('d');
$today_key = $year.'-'.$today_month.'-'.$today_day;
$today_has_posts = isset($post_dates[$today_key]);
/* ======================================
5. CONTENITORE ANNO
====================================== */
echo '<div class="calendar-year">';
/* ======================================
6. CICLO MESI
====================================== */
for ($month=1; $month<=12; $month++) {
echo '<div class="calendar-month-block">';
$month_name = date_i18n('F', mktime(0,0,0,$month,1,$year));
$month_has_posts = false;
foreach ($post_dates as $date => $count){
if (strpos($date,$year.'-'.sprintf('%02d',$month))===0){
$month_has_posts = true;
break;
}
}
/* titolo mese */
if ($month_has_posts){
echo '<h3 class="month-title">
<a href="'.get_month_link($year,$month).'">'.$month_name.'</a>
</h3>';
}else{
echo '<h2 class="month-title">'.$month_name.'</h2>';
}
/* ======================================
7. TABELLA CALENDARIO
====================================== */
echo '<table class="calendar-month">';
echo '<thead><tr>';
$weekdays = ['L','M','M','G','V','S','D']; //da cambiare per le lingue diverse da quella italiana
foreach ($weekdays as $w){
echo '<th>'.$w.'</th>';
}
echo '</tr></thead>';
echo '<tbody><tr>';
/* primo giorno mese */
$first_day = date('N', strtotime("$year-$month-01"));
for ($i=1;$i<$first_day;$i++){
echo '<td class="empty"></td>';
}
$days = cal_days_in_month(CAL_GREGORIAN,$month,$year);
$weekday = $first_day;
/* ======================================
8. CICLO GIORNI
====================================== */
for ($day=1;$day<=$days;$day++){
$date = $year.'-'.sprintf('%02d',$month).'-'.sprintf('%02d',$day);
$is_today_past = false;
/* controllo "oggi negli anni passati" */
if ($year < $current_year && $month==$today_month && $day==$today_day){
$is_today_past = true;
}
$classes = [];
if ($is_today_past) $classes[] = 'today-past';
if (isset($post_dates[$date])){
$classes[] = 'has-posts';
} else {
$classes[] = 'no-posts';
}
echo '<td class="'.implode(' ', $classes).'">';
if (isset($post_dates[$date])){
$count = $post_dates[$date];
$title = ($count==1) ? '1 articolo' : $count.' articoli';
echo '<a class="day-link" href="'.get_day_link($year,$month,$day).'" title="'.$title.'">'.$day.'</a>';
}else{
echo '<span class="day-number">'.$day.'</span>';
}
echo '</td>';
if ($weekday==7){
echo '</tr><tr>';
$weekday=1;
}else{
$weekday++;
}
}
/* celle finali */
while ($weekday<=7){
echo '<td class="empty"></td>';
$weekday++;
}
echo '</tr></tbody></table>';
echo '</div>';
}
echo '</div>';
?>
CSS-код визуализации календаря – скопируйте его в файл style.css вашей темы или подключите отдельно:
/* ===== navigazione anni ===== */
.calendar-nav{
text-align:center;
margin:40px 0;
font-size:22px;
line-height:2;
}
.calendar-nav a{
margin:0 10px;
text-decoration:none;
}
.current-year{
font-weight:bold;
margin:0 15px;
}
/* ===== layout mesi ===== */
.calendar-year{ display:block; }
.calendar-month-block{ margin-bottom:40px; }
/* ===== titolo mese ===== */
.month-title{
text-align:center;
margin-bottom:10px;
}
/* ===== tabella ===== */
.calendar-month{
width:100%;
border-collapse:collapse;
}
.calendar-month th{
padding:5px;
text-align:center;
font-weight:bold;
}
.calendar-month td{
padding:0;
height:32px;
text-align:center;
}
/* ===== giorni ===== */
.day-number{
display:block;
padding:6px;
}
/* celle con articoli */
.calendar-month td.has-posts{ background:#C5C5C5; }
/* link riempie tutta la cella */
.day-link{
display:block;
width:100%;
height:100%;
padding:6px;
text-decoration:none;
font-weight:bold;
background:transparent; /* IMPORTANTISSIMO */
}
/* celle senza articoli */
.calendar-month td.no-posts{ background:#FFFFFF; }
/* numeri non linkati */
.day-number{
display:block;
padding:6px;
background:#FFFFFF; /* garantisce bianco pieno */
}
.today-past{ outline:2px dashed #FF9800; }
/* hover */
.day-link:hover{ background:#C5C5C5; }
/* celle vuote */
.empty{ background:#FFFFFF; }
/* ===== layout desktop ===== */
@media (min-width:1024px){
.calendar-year{
display:grid;
grid-template-columns:repeat(3,1fr);
gap:30px;
align-items:start;
}
.calendar-month-block{ margin-bottom:0; }
}
В таком виде, с таким функционалом – это именно тот календарь блога, который мне был нужен. Что к нему можно или нужно добавить – даже и не знаю. Если придумаю (или кто-то подскажет) – выпущу вторую версию и о ней сообщу.
Случается со мной – хотя и очень-очень редко – сильно раздражающая ситуация: знаю, какой предмет мне нужен, всё знаю о его желаемых характеристиках и внешнем виде, а вот официального названия – не знаю. А так как эксперта по интересующему предмету может поблизости не оказаться, приходится мне мучать поисковики своими длинными словесными описаниями – в надежде на то, что рано или поздно вылезет нужная картинка с подписью (бесплатная версия Чата ЖэПэТэ в таких вопросах пока часто ошибается или вообще сообщает о собственной некомпетентности).
К счастью, иногда – но совсем редко – желаемый предмет физически находится быстрее, чем я узнаю его название. Вот, например, «вечный календарь», показывающий день месяца, название месяца и день недели (последняя функция, оказывается, есть не у всех моделей).

Для смены дня недели на этой конкретной модели нужно крутить на себя чёрную ручку. Для смены дня месяца нужно крутить от себя по горизонтальной оси металлическую коробочку. Названия месяцев написаны Продолжить чтение этого поста »



RSS статей сайта

