Da tempo volevo realizzare sul sito una cosa del genere: un calendario annuale (sia dell’anno corrente sia di ciascuno degli anni passati) in cui, per ogni data, ci sia un link che rimandi a una raccolta dei post del blog pubblicati proprio in quel giorno (se effettivamente è stato pubblicato qualcosa). In LiveJournal (e altre piattaforme di blogging) un calendario del genere esisteva ed era molto comodo come strumento per cercare vecchi articoli e/o per analizzare l’attività del blog (proprio o altrui). In WordPress, invece, un calendario così non c’è e, se ricordo bene, non c’è mai stato (o magari esisteva talmente tanto tempo fa che me ne sono completamente dimenticato): c’è solo un calendario analogo basato sui singoli mesi, che però risulta decisamente scomodo per la maggior parte delle ricerche e delle analisi.
Per realizzare una cosa del genere con le forze proprie mi serviva un po’ di tempo libero: finalmente sono riuscito a trovarlo! Ancora più importante (e interessante) è il fatto che questo tempo non è stato sprecato: sono riuscito a creare il calendario-archivio. Un esempio funzionante è disponibile sotto il link, mentre in questo articolo descriverò a parole tutte le caratteristiche del mio calendario e fornirò i codici base in PHP e CSS.
Le caratteristiche del mio calendario annuale del blog per WordPress:
– calendario completo dell’anno (sono visibili tutti i 12 mesi, indipendentemente dalla data corrente al momento della consultazione);
– possibilità di visualizzare gli anni passati (ma non precedenti all’anno del primo post pubblico del blog);
– i giorni con post pubblici vengono automaticamente trasformati in link che rimandano alle rispettive date nell’archivio degli articoli;
– al passaggio del cursore su un giorno con link compare un suggerimento con il numero di post pubblicati in quella data;
– nei calendari degli anni passati, la data corrente («oggi») è evidenziata con una cornice ben visibile;
– le celle corrispondenti ai giorni in cui è stato pubblicato almeno un post cambiano il colore di sfondo;
– il calendario ha un design responsive: su schermi grandi e medi viene mostrata una griglia di 3×4 mesi, mentre su schermi piccoli i mesi dell’anno sono disposti in colonna;
– le query al database sono ottimizzate in modo tale che il calendario non sia lento a caricarsi nemmeno nei blog con decine di migliaia di articoli.
Ed ecco che ora passiamo ai codici del calendario (spero che tu abbia letto tutto il testo qui sopra: può aiutarti a orientarti meglio).
Il codice PHP, che può essere testato direttamente così com’è: basta copiarlo e incollarlo nel layout della tua pagina:
<?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>';
?>
Per sicurezza preciso una cosa ovvia: con il codice PHP appena mostrato bisogna creare un template (una pagina *.php, per esempio calendarioblog.php), caricarlo nel tema del proprio sito WordPress e poi utilizzarlo per creare la pagina del calendario dalla admin.
Il codice CSS per la visualizzazione del calendario: si può copiarlo nel file style.css del tema oppure includerlo separatamente:
/* ===== 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; }
}
In questa forma, con queste funzionalità, è esattamente il calendario del blog di cui avevo bisogno. Cosa si potrebbe o si dovrebbe aggiungere? In realtà, non lo so nemmeno io. Se mi verrà in mente qualcosa (o se qualcuno mi darà un suggerimento), pubblicherò una seconda versione e ne darò notizia.



RSS del sito

