Архив метки «жж»

Давно хотел сделать на сайте такую штуку – календарь года (текущего и каждого из прошлых), в котором с каждой даты ссылка ведёт на подборку соответствующих постов в блоге (если в тот день что-то было опубликовано) – то есть, «календарь года как в ЖЖ». В ЖЖ такой календарь существовал и был очень удобен в качестве одного из способов поиска старых записей и/или анализа активности блога (своего или чужого). А вот, например, в 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; }
}

В таком виде, с таким функционалом – это именно тот календарь блога, который мне был нужен. Что к нему можно или нужно добавить – даже и не знаю. Если придумаю (или кто-то подскажет) – выпущу вторую версию и о ней сообщу.


Слава Сэ умер

Только что узнал, что умер Слава Сэ.
Я как-то незаметно перестал читать его несколько лет назад, когда начали заметно увеличиваться объёмы работы и немного меняться жизненные интересы, но всё равно Слава Сэ до сих пор остаётся одним из лучших моих воспоминаний о ЖЖ.
В общем, очень жаль.


Прочитал я вчера вечером, что Сбербанк покупает у Александра Мамута оставшуюся долю Rambler Group и становится её стопроцентным владельцем.
Возможно, тут было бы правильным написать большой аналитический текст о том, что пока один действующий интернет-гигант не смог купить банк, другой банк купил бывшего интернет-гиганта. Но я до такого уровня аналитики пока не дорос. А потому просто в очередной раз задумаюсь о судьбах рунета. Просто, мне почти дословно вспомнился пот этот пассаж из одного из последних постов Антона Носика, опубликованного 5 июля 2017 года:

Не в этом месяце, так в следующем, Саша Мамут устанет палить бабло на поддержку существования морально устаревшей, убыточной для него платформы ЖЖ, и мы с вами расстанемся. Конечно, не навсегда, и даже не надолго, но скоро это случится. К Александру Леонидовичу тут никаких претензий быть не может, наоборот – спасибо ему, что он не дёрнул рубильник до сих пор, хотя давно понял, куда всё катится, и чем закончится. Он мог бы потушить свет полгода назад, но он этого не сделал, спасибо ему. Но нет причин рассчитывать, что его терпение продлится вечно, или что его карманы окажутся бездонны. ЖЖ – убыточный проект для владельца, он будет закрыт […]

В общем, к сожалению, Сбер мне не кажется тем собственником, который способен всерьёз заняться реанимацией технологически устаревающих проектов. Если у вас ещё осталось в ЖЖ что-то ценное – не поленитесь скачать на диск копию текстов и занести в закладки новые адреса интересных авторов.


Однако, юбилей

Совершенно случайно узнал, что ЖЖ сегодня исполняется 20 лет.
Помните ещё, что это такое?
Я вот поздравлю старика кросспостингом этого поста и честным заявлением, что до сих пор регулярно читаю там целых трёх человек. Иногда ещё про какого-нибудь интересного автора из прошлого вспоминаю, но проверка в большинстве случаев показывает, что журналы их мертвы. И, судя по отсутствию записок «я переехал туда-то», сами авторы тоже уже не с нами. Потому и френдленту не читаю уже не помню сколько лет.


Где искать автора

Многие из вас уже много лет назад наверняка заметили, что в русскоязычных статьях Википедии о известных людях часто стоят ссылки на их жж. Ссылка может стоять внизу статьи (в разделе «ссылки» или «в социальных сетях»), а может – в боковом прямоугольнике с краткой информацией.
Вот несколько примеров:

А теперь – загадка века. Почему с началом оттока людей из ЖЖ в статьях Википедии не начали массово появляться ссылки и на другие их активно используемые соцсети? Учитывая, что статьи может редактировать и пополнять абсолютно любой человек, не является ли вышеуказанная проблема изящным способом положить что-то там на собственных читателей?
Думаю, учёные ещё долго будут ломать голову над этим вопросом.
P.S.: да, похоже, что я навсегда утратил некоторых любимых авторов из числа незнаменитых людей – поставить ссылки на свои новые адреса в профиле или в прощальном жж-посте они поленились.
P.P.S.: я как бы намекаю – не будьте ленивыми, потратьте несколько минут на публикацию ваших ссылок. Нечего читателями разбрасываться.


Умер Антон Носик

Как рядовой читатель, внезапно ощутил пустоту. Тяжёлую такую пустоту.

Антон Носик, спасибо за всё.

R.I.P.


О пользовательских соглашениях ЖЖ. Буду краток.

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

Данное предупреждение, как и все мои немногочисленные посты последнего времени, можно прочитать на моём стендэлоне eugigufo.net/blog.

Всем хороших текстов!


Прекрасная подборка цитат из школьных сочинений: http://grimnir74.livejournal.com/5216606.html.

Специально пощу (или постю?) в субботу, так как на работе с умным/сосредоточенным видом вы это читать не сможете. И начальство обеспечит вас большим количеством свободного времени.


Зачёт маркетологу

Сегодня в ЖЖ-шечке у Лебедева выскочил гениалный рекламный баннер (т.н. нанофантик). Настолько гениальный, что даже я по нему щёлкнул.

С одного раза угадайте, который.

Автор – молодец.


А тем временем, в офис ЖЖ зашёл хирург и выпрямил кому-то руки. В связи с этим кросспост кириллистических меток из вордпресс в жж опять заработал.

Не знаю точно, когда произошло сие чудо – только сейчас заметил.

В любом случае – ура.