A yearly archive for 2026 год

Annual blog calendar

For quite some time, I had been meaning to create something like this on my website: an annual calendar (both for the current year and for each of the past years) in which, for every date, there is a link leading to a collection of blog posts published on that very day (if anything was actually published). On LiveJournal (and other blogging platforms), such a calendar existed and was very convenient as a tool for finding old articles and/or analysing blog activity (one’s own or that of others). In WordPress, however, such a calendar does not exist and, if I remember correctly, it never has (or perhaps it did exist so long ago that I have completely forgotten about it): there is only a similar calendar based on individual months, which is decidedly inconvenient for most searches and analyses.
To create something like this on my own, I needed a bit of free time: at last, I managed to find it! Even more importantly (and interestingly), that time was not wasted: I succeeded in creating the calendar archive. A working example is available via the link below, while in this article I will describe all the features of my calendar and provide the basic PHP and CSS code.
Features of my annual blog calendar for WordPress:
— full-year calendar (all 12 months are visible, regardless of the current date at the time of viewing);
— the ability to view past years (though not earlier than the year of the blog’s first public post);
— days with published posts are automatically turned into links leading to the corresponding dates in the article archive;
— when hovering over a linked day, a tooltip appears showing the number of posts published on that date;
— in calendars for past years, the current date («today») is highlighted with a clearly visible border;
— cells corresponding to days on which at least one post was published change their background colour;
— the calendar features a responsive design: on large and medium screens, a 3×4 grid of months is displayed, while on smaller screens the months are arranged in a column;
— database queries are optimised so that the calendar loads quickly even on blogs with tens of thousands of posts.
And now we move on to the calendar code (I hope you have read all the text above—it may help you find your way around).
The PHP code, which you can test directly as it is: simply copy and paste it into your page layout:

<?php
global $wpdb;


/* ======================================
   1. THE FIRST YEAR OF 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. POST DATES (OPTIMISED SQL QUERY + 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. BROWSE BY YEAR
====================================== */
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. ‘TODAY IN THE PAST YEARS’ COMPARISON
====================================== */
$today_month = date('m');
$today_day = date('d');
$today_key = $year.'-'.$today_month.'-'.$today_day;
$today_has_posts = isset($post_dates[$today_key]);


/* ======================================
   5. YEAR CONTAINER
====================================== */
echo '<div class="calendar-year">';


/* ======================================
   6. MONTHLY CYCLE
====================================== */
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;
		}
	}

/* month title */
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. CALENDAR TABLE
====================================== */
echo '<table class="calendar-month">';
echo '<thead><tr>';
$weekdays = ['M','T','W','T','F','S','S']; //to change manually to your language
foreach ($weekdays as $w){
	echo '<th>'.$w.'</th>';
	}
echo '</tr></thead>';
echo '<tbody><tr>';

/* first day of the month */
$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. CYCLE DAYS
====================================== */
for ($day=1;$day<=$days;$day++){
	$date = $year.'-'.sprintf('%02d',$month).'-'.sprintf('%02d',$day);
	$is_today_past = false;
	/* ‘today in the past years’ comparison */
	if ($year < $current_year && $month==$today_month && $day==$today_day){
		$is_today_past = true;
	}
	$classes = &#91;&#93;;
	if ($is_today_past) $classes&#91;&#93; = 'today-past';
	if (isset($post_dates&#91;$date&#93;)){
		$classes&#91;&#93; = 'has-posts';
	} else {
		$classes&#91;&#93; = 'no-posts';
	}
	echo '<td class="'.implode(' ', $classes).'">';
	if (isset($post_dates[$date])){
		$count = $post_dates[$date];
		$title = ($count==1) ? '1 post' : $count.' posts';
		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++;
	}
	}

/* final table cells */
while ($weekday<=7){
	echo '<td class="empty"></td>';
	$weekday++;
	}
echo '</tr></tbody></table>';
echo '</div>';
}

echo '</div>';
?>

Just to be clear, here’s something obvious: with the PHP code shown above, you need to create a template (a *.php file, for example calendarblog.php), upload it to your WordPress site’s theme, and then use it to create the calendar page via the admin panel.
The CSS code for displaying the calendar: it can be copied into the theme’s style.css file or included separately:

/* ===== navigation by year ===== */
.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;
}
/* ===== monthly layout ===== */
.calendar-year{ display:block; }
.calendar-month-block{ margin-bottom:40px; }
/* ===== month title ===== */
.month-title{
	text-align:center;
	margin-bottom:10px;
}
/* ===== table ===== */
.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;
}
/* ===== days ===== */
.day-number{
	display:block;
	padding:6px;
}
/* table cells with items */
.calendar-month td.has-posts{ background:#C5C5C5; }
/* the link fills the entire cell */
.day-link{
	display:block;
	width:100%;
	height:100%;
	padding:6px;
	text-decoration:none;
	font-weight:bold;
	background:transparent; /* VERY IMPORTANT */
}
/* table cells without items */
.calendar-month td.no-posts{ background:#FFFFFF; }
/* non-hyperlinked numbers */
.day-number{
	display:block;
	padding:6px;
	background:#FFFFFF; /* guarantees full white */
}
.today-past{ outline:2px dashed #FF9800; }
/* hover */
.day-link:hover{ background:#C5C5C5; }
/* empty table cells */
.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 this form, with these features, this is exactly the blog calendar I needed. What could or should be added? In fact, I am not entirely sure myself. If something comes to mind (or if someone gives me a suggestion), I will publish a second version and announce it.


My Shop

On many large, «serious» websites, as you may have noticed, there are proper in-house shops: there, authors and administrators sell physical merchandise as well as various digital products (I am not even sure whether it is entirely correct to call the latter «merchandise»).
My website, too, occasionally tries to present itself as a serious one, so at some point I began to wonder: why not create an online shop of my own? I did consider it, but then immediately remembered that I have never had any physical merchandise, and that the site itself is rather small: the level of traffic is such that I would be unlikely to earn anything even from digital products. For this reason, at least for the time being, I have decided to take a different approach.
Under the label «shop», one actually finds a special page on the website, where I have collected links to all those specialised platforms on which my digital products are available, to a greater or lesser extent. Each link leads directly to my own «stall»: there you will find only my products—various web scripts (mainly in PHP, JavaScript and CSS), photographs, as well as images and videos generated by me with the help of AI (I simply cannot draw, either on paper or on a computer).
So, you have been warned: beware of imitations 🙂 Now you know where to find me.

And, of course, I do not rule out two possible developments in the future: that my «stalls» may increase over time, and that, sooner or later, I may indeed create a proper shop of my own on this website.


A Special Chess Operation

The science-fiction writer (a good one) and programmer (apparently an equally good one, although I am not very familiar with his digital products) Leonid Kaganov published yesterday a modern chess game entitled «OSS — Special Chess Operation».
It had been quite a long time since I had last played even an ordinary game of chess (that is, one not involving special operations), but I nevertheless managed, on my very first attempt, to defeat the dark forces, superior both in numbers and cunning. The battle ended in a highly realistic fashion:

I wish everyone the same success.
P.S. At the moment, Leonid Kaganov is looking for remote programming work in a Russian-speaking team based somewhere in the West. I cannot act as an intermediary in this matter, but I can at least publicise the fact itself. Well, I have just done so.


A few days ago, while making some minor changes to the website, I remembered that I had long wanted to add two features to my little toy tool, the «Text register converter». In other words, that little page which changes the case of all or some of the letters in the text entered into the field. And since it came back to mind, I finally went ahead and did it.

Yes, it is now possible to alternate between upper and lower case in two different ways. The toy has become more complete: I am pleased to have created something that actually works, and I hope that the few users of this little tool will be satisfied as well.
Jolly good.


At last, I have found the time to update the page on my website dedicated to so-called «blank themes» for WordPress. For years, that page had contained six themes—or perhaps it would be more accurate to call them "layouts"?—which today can be regarded as genuine pieces of web antiquity: they were technically up to date only up to WordPress version 4.9.x.
Now, however, these layouts are available in a completely reworked version created by me: in terms of code, internal architecture, and the file structure itself.

In short, feel free to download them if you need them and find them useful.


Midway through the journey of my earthly life, I have created my first crowdfunding campaign on Indiegogo. I do not yet know what may come of it, but without trying, I would never have found out, would I?
But let us proceed in order…
If this post is not the first thing you are reading on my website, you most likely already know that this same site has long been hosting several free and unlimited tools for transliterating into the Latin alphabet — that is, for the romanization — of certain non-Latin scripts (Armenian, Belarusian, Bulgarian, Greek, Georgian, Kyrgyz, Macedonian, Russian, and Ukrainian). Some of these transliterators of mine are relatively popular among users, while others are not at all. Yet each of these tools has been created with the same attention to detail and with the same goal: to build a useful, accurate, and at the same time easy-to-use instrument capable of transliterating (romanization) its «own» alphabet according to any of the existing systems of rules. I believe I have succeeded in achieving this goal — although I continue to hope for constructive feedback from specialists.
I have now decided that the time has come to add another tool to my existing transliterators: a Hebrew alphabet transliterator. Naturally, the underlying idea remains the same technical principle: the transliteration of the Hebrew alphabet should be possible according to the rules of any existing system (whether still in use today or not). I already have a theoretical understanding of how to create such a tool, and I have even gathered all the necessary academic material to work on it. I am ready to begin the work, but…
To do this kind of work properly — work that is rather tedious, extensive, and requires attention to a large number of small details (you may, for instance, ask specialists how many ways there are to represent vowels…) — I need to free up a considerable amount of working time: time during which I will not be distracted by paid professional tasks. This is why I have launched a crowdfunding campaign on Indiegogo. By following the link, you will be able to read about the technical features of the product I have in mind and to take part — if you have the desire and the financial means — in raising funds for the creation of my Hebrew alphabet transliterator. I should immediately point out that all contributors will not only be guaranteed a free and high-quality tool, but will also be able (if they wish) to obtain advertising space on the tool’s page or on any other page of my website.
If my proposal has caught your interest, please take part in the Indiegogo campaign. And/or tell those who might be interested about it: it would give me great pleasure if everything were to work out.

P.S. All those who would like to provide financial support for other parts of my website (or indeed for the entire site as a whole) may do so at any convenient time using one of the methods listed on the dedicated page.