My “Typographer” – Finally Published

Let us begin with a basic question: is there anyone who does not know what a «web typographer» is?
Even if you do not, you can probably guess quite easily: it is a program that makes a text intended for publication on the web correct and visually appealing from the point of view of screen typography. Screen typography differs only slightly from traditional «paper» typography: mainly in the proper handling of hyperlinks and in replacing special characters with their HTML codes (if and when there is a risk that they may not be displayed correctly in a browser window). In practice, proper screen typography can be achieved in two ways:
1. By processing the text manually (which means inserting dozens, if not hundreds, of non-breaking spaces, proper quotation marks, dashes, and hyphenation points, identifying problematic signs and symbols in the original text, and so on and so forth);
2. By using a «Web Typographer» (copy the text into a field, choose the required settings, click the button to process it, and receive a result ready for publication).
Which method do you prefer?
In this respect, it does not really matter what your main occupation is—whether you build websites, write or edit texts, or simply publish material created by someone else. Most normal people are reluctant to waste time and energy on monotonous work. Receiving a properly formatted and attractive text, on the other hand, should not feel like a burden at all: ordinary users will simply find typographically processed texts easier to read, while perfectionists will be less inclined to deal with you in the most brutal manner imaginable.
The first «Web Typographer» known to me appeared in the public domain back in 2002. Over the following years, several more typographers appeared on the internet: I can think of about a dozen off the top of my head, although I have never attempted to determine the exact total number. I also know that some CMSs include built-in typographers or similar plugins, although these are often solutions developed for a particular media outlet or organisation. And I know for a fact that many website developers and web authors/editors have their own pocket typographers—tools unavailable to the public and used solely for their professional needs.
I myself had my own pocket Web Typographer from the first half of the 2010s onwards. The most attentive visitors may have noticed that I used it to process every text published on my website.
Why am I referring to that typographer in the past tense?
Because last week it ceased to be a pocket tool—I finally made it publicly available! Hooray!

Someone might reasonably ask why I decided to share my creation with the world only now. Well, there are several reasons.
First, I finally worked out how to add a couple of features that I had wanted for a long time and, in doing so, make it unique among its competitors (none of the other typographers known to me can do this yet).
Second, some of the publicly available typographers I knew have ceased to be publicly available.
Third, the owner of one of the most famous typographers has embraced extremist political symbolism and rhetoric to such an extent that I can fully understand why some people no longer wish to use his products.
Fourth, if my Typographer gains users, they will inevitably send me plenty of suggestions and feature requests over time.
So, if you publish texts on the web and care about how they look, here is another useful tool for your collection.
And if you have any comments, suggestions, or observations, please send them to me—either by email or in the comments section.


Silver

It’s hard to believe, but it’s true: in my coin collection, which I’ve been building up consciously and thoughtfully for almost twenty years, the very first silver coin — a 20-kopeck coin from 1923 — only joined the collection this summer. In fact, it’s the first coin in my collection made entirely of a precious metal.

But it’s not the composition that appeals to me (it would be rather odd to get overly excited, in public, about 3.6 grams of 500-fine silver), nor even the fact that it has become one of the oldest Russian coins in my collection…

I’m simply amused by the very fact that I’ve almost accidentally moved into a new, more serious category of collecting. I didn’t do this by buying up coins that interested me, but purely by ‘hunting’ for them. As practice shows, this method requires more time and, consequently, patience, but at the same time, it calls for greater imagination in finding sources of collectables. That is precisely why this method is more interesting.
What’s more, it’s entirely feasible from a practical point of view. It is to confirm this great truth that I’ve taken it upon myself to write this boastful post.


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.