Calendar generator on the website

During some scheduled maintenance work on the website, I noticed a few imperfections in one of my oldest online tools: the calendar generator for any year starting from AD 1. First of all, for all years between the 1st and the 18th centuries, an error message appeared in the code next to each monthly table (even though the code was in fact producing the requested result). Secondly, the tool generated the Gregorian calendar even for the period from AD 1 to 1581—that is, for a period during which only the Julian calendar was used throughout the world.
And at last I have corrected these imperfections! It was fairly straightforward, so it did not take me long, but I have produced something that should be of great practical use to users.
At the same time, I have finally added two other features that seemed important to me. The first is the ability to generate a calendar not only for a given year, but also for a specific country or territory: after all, even if one considers only the Julian/Gregorian pair of calendars, the transition from one to the other took place in different years in different states. The second is the ability to save the generated calendar as a PDF (and/or print it) without the website navigation elements.

However, there are still a few aspects on which I need to reflect. For example, how to take into account the different dates on which the Gregorian calendar was adopted in the numerous German duchies and principalities, as well as in Eastern and Northern Europe, without turning the calendar generator’s menu into an endless list of options. If anyone has any ideas on this subject, or suggestions for additional features for my calendar generator, please do write to me!


Windows with a view

One day I’ll have a window overlooking snow-capped mountain peaks. Those peaks will be at the same level as the window. And there’ll even be several windows.

Well, apart from the windows, I hope there’ll be all the other parts of the house too. And the view won’t just be a rectangle in a frame.

I’ll spend most of the year up there, laughing maliciously at the little people baking in the heat down on the plain. And I’ll only share the house’s coordinates with a select few who aren’t too lazy to make the effort.

There has to be some sort of beautiful, tangible and personal goal in life too…


Solar eclipse

Children, remember: it’s best not to watch a solar eclipse using just your smartphone.

Make sure you also take a good camera with a telephoto lens.

By a good camera with a telephoto lens, I mean that big thing that keeps making you ask me if I’m a journalist, hahaha
P.S.: You already know everything there is to know about the solar eclipse on 12 August.


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.


I’ve Modernised the Blank Themes

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.


The Kyrgyz Transliterator

I am finally ready to share the news of the publication on my website of the Kyrgyz alphabet transliterator: I honestly cannot explain why I forgot to create it last year, when I developed my series of other transliterators… But now this one is also available, and I am even more pleased with the substantial work accomplished!
As you know — or as you can easily imagine — it is a tool that converts Kyrgyz characters into Latin characters with a single click. In the specific case of this tool, the transliteration — or, if you prefer, the romanisation — of the Kyrgyz alphabet can be carried out according to any of the seven existing official systems (three for the Kyrgyz alphabet of the first half of the 20th century and four for the modern Kyrgyz alphabet).
Try it out and spread the word among those who may find it useful. And of course, do write to me about any flaws or errors you encounter. I hope the tool will prove useful to at least one person on this planet.

Further announcements will follow about transliterators for other alphabets.
Those most interested can write to me specifying which transliterator they need.