It adds a layer of humanity and personality to the Web. It introduces me to cool new people, and re-introduces me to cool people whom I’d crossed paths with at a distance: Joe’s one of
the latter, but I’ve now taken the time to ensure he’s in my RSS reader… and, by proxy, in my blogroll.
I don’t have a return address for anybody who posted anything to me, yet (obviously I’d have masked it out from the postcard if I had!), but I feel like I ought to buy some postcards
now too. It’s only a matter of time.
And hey, maybe there’s mileage in starting an Personal Web Postcards Club or something…
In January 2024 I participated in Bloganuary, a “write a blog post every day for a month” challenge organised by Automattic. I wasn’t
100% impressed by the prompts made available and was – as an employee of Automattic – shuffling towards trying to help make them better in a future year. To be part of the solution!
There’s definitely something in this ‘winter sun’ thing that seems to help me stay sane in the cold dark months. This morning, I’m blogging from a
hotel balcony in Peurtro de la Cruz, Tenerife.
Of course, two significant things changed since then:
As part of a sweeping range of redundancies, I was let go from my position at Automattic2,
and
Automattic ceased running Bloganuary: I’m guessing that the folks responsible for making it happen were among the many that Automattic decided to axe, or else their shifting
priorities – reflected by their waves of layoffs – are no longer compatible with providing that service to bloggers.
Ah well, I figured. I’d just do my own thing. I can write something for every day in January 2026, can’t I?
Generating a chart...
If this message doesn't go away, the JavaScript that makes this magic work probably isn't doing its job right: please tell Dan so he can fix it.
In general, I suppose I’ve been blogging more-frequently lately. Why is that? I guess it’s been a realisation that a blog post doesn’t always have to be polished to perfection.
I still write long-form posts which require research and planning, like setting up a network of Windows 3.x VMs just to get screenshots of what
programming then looked like or making that podcast episode with the music in it… but I’m also feeling more-free to just
express myself in the moment. To share things I see that look interesting or funny or
pretty, or just whatever I’m thinking. I’ve been using “kinds” to categorise my posts so it’s easy for people to avoid my more-inane stuff if
they like, but that’s a secondary consideration because ultimately… I blog for me.
Anyway… all of which is to say that I’ve been writing more and I’ve been loving it. The best way to read more of what I’m writing, if you’d like to, remains: by subscribing via RSS.
1 I’d anticipated having a lack of Internet access, but in fact 4G was widespread
throughout both islands and overall I managed to post something on every day except three in January 2025.
2 Based on friends I’ve spoken to, there seem to have been a lot more folks let go since;
the company seems to be shrinking quite a lot, which might go some way to explaining my second observation too.
Well, quite a lot, actually. It tells me that there’s loads of you fine people reading the content on this site, which is very heart-warming. It also tells me that RSS is
by far the main way people consume my content. Which is also fantastic, as I think RSS is very
important and should always be a first class citizen when it comes to delivering content to people.
…
I didn’t get a chance to participate in Kev’s survey because, well, I don’t target
“RSS Zero” and I don’t always catch up on new articles – even by authors I follow closely – until up to a few weeks after they’re published1.
But needless to say, I’d have been in the majority: I follow Kev via my feed reader2.
But I was really interested by this approach to understanding your readership: like Kev, I don’t run any kind of analytics on my personal sites. But he’s onto something! If you
want to learn about people, why not just ask them?
Okay, there’s going to be a bias: maybe readers who subscribe by RSS are simply more-likely to respond to a survey? Or are more-likely to visit new articles quickly, which
was definitely a factor in this short-lived survey? It’s hard to be certain whether these or other factors might have thrown-off Kev’s results.
But then… what isn’t biased? Were Kev running, say, Google Analytics (or Fathom, or Strike, or Hector, or whatever)… then I wouldn’t show up in his results
because I block those trackers3
– another, different, kind of bias.
We can’t dodge such bias: not using popular analytics platforms, and not by surveying users. But one of these two options is, at least, respectful of your users’ privacy and bandwidth.
I’m tempted to run a similar survey myself. I might wait until after my long-overdue redesign – teased here – launches,
though. Although perhaps that’s just a procrastination stemming from my insecurity that I’ll hear, like, an embarrassingly-low number of responses like three or four and internalise it
as failing some kind of popularity contest4! Needs more thought.
Footnotes
1 I’m happy with this approach: I enjoy being able to treat my RSS reader as sort-of a
“magazine”, using my categorisations of feeds – which are partially expressed on my Blogroll page – as a theme. Like: “I’m going to spend 20 minutes
reading… tech blogs… or personal blogs by people I know personally… or indieweb-centric content… or news (without the sports, of course)…”
This approach makes consuming content online feel especially deliberate and intentional: very much like being in control of what I read and when.
3 In fact, I block all third-party JavaScript (and some first-party
JavaScript!) except where explicitly permitted, but even for sites that I do allow to load all such JavaScript I still have to manually enable analytics
trackers if I want them, which I don’t. Also… I sandbox almost all cookies, and I treat virtually all persistent cookies as session cookies and I
delete virtually all session cookies 15 seconds after I navigate away from a its sandbox domain or close its tab… so I’m moderately well-anonymised even where I do somehow
receive a tracking cookie.
4 Perhaps something to consider after things have gotten easier and I’ve caught up with my backlog a bit.
I’m not saying the plain-text is the best web experience. But it is an experience. Perfect if you like your browsing fast, simple, and readable. There are no
cookie banners, pop-ups, permission prompts, autoplaying videos, or garish colour schemes.
I’m certainly not the first person to do this, so I thought it might be fun to gather a list of websites which you browse in text-only mode.
…
Terence Eden’s maintaining a list of websites that are presented as, or are wholly or partially available via, plain text. Obviously my own text/plain
blog is among them, and is as far as I’m aware the only one to be entirely presented as text/plain.
Anyway, this inspired me to write a post of my own (on text/plain blog, of course!), in which I ask the question: what do we
consider plain text? Based on the sites in the list, Markdown is permissible as plain text, (for the purposes of Terence’s list), but this implies that “plain text” is a
spectrum of human-readability.
If Markdown’s fine, then presumably Gemtext would be too? How about BBCode? HTML and RTF are explicitly excluded by Terence’s rules,
but I’d argue that HTML 1.0 could be more human-readable than some of the more-sophisticated dialects of BBCode (or any Markdown that contains tables, unless those tables are laid-out
in a way that specifically facilitates human-readability)?
As I say in my post:
<-- More human-readable Less human-readable -->
|-----------|-----------|-----------|------------|-----------|-----------|-----------|-----------|
Plain text Gemtext Markdown BBCode HTML 1.0 Modern HTML RTF
This provocation is only intended to get you to think about “what does it mean for a markup language to be ‘human readable’?” Where do you draw the line?
But I’m pretty sure there are some people who’d rather receive updates to my blog via WhatsApp. And
now, they can. Here’s how I set up an RSS-to-WhatsApp gateway, in case you want to run one of your own2.
A Whapi account connected to your WhatsApp account3
– when you set up an account you’ll get a free trial; when it ends you need to find the link to say that you want to carry on with the free tier (or upgrade to the paid tier if you
expect to send more messages than the free tier’s limit)
A WhatsApp channel to which you want to push your RSS feed: I’d recommend that you make a newsletter (from the Updates tab in WhatsApp, press the kekab menu then
Create Channel) rather than a traditional group: groups are designed for multiple people to talk and discuss and everybody can see one another’s identity, but a newsletter
keeps everybody’s identity private and only allows the administrator(s) permission to post updates.
You probably want to use the kind of channel that’s for one-to-many ‘push’ communication, not a discussion group.
In Settings > Secrets and Variables > Actions, add two new Repository Secrets:
WHATSAPP_API_TOKEN: set to the token on your Whapi dashboard
WHATSAPP_CHANNEL: set to your newsletter ID (will look like 123456789012345678@newsletter) or group ID (will look
like 123456789012345678@g.us): you can get this from the Newsletters or Groups section of Whapi by executing a test GET /newsletters or GET /groups request4.
Do a test run: from the Actions tab select the “Process feeds” action and click “Run workflow”. If it finishes successfully (and you get the WhatsApp message), you’re done! If it
fails, click on the failed action and drill-in to the failed task to see the error message and correct accordingly.
By default, the processor will run on-demand and every 30 minutes, but you can modify that in.github/workflows/process-feeds.yml. It’s configured to send the single oldest
un-sent item in any of the RSS feeds it’s subscribed to, on each run (it tracks which ones it’s sent already by their guids, in a "seen": [...] array in
feeds.json): sending a single link per run ensures that WhatsApp’s link previews work as expected. At that rate, you could theoretically run it once every 10 minutes and
never hit the 150-messages-per-day limit of Whapi’s free tier5), but you’ll want to work out your own optimal rate based on the
anticipated update frequency of your feeds and the number of RSS-to-WhatsApp channels you’re running.
You can, of course, run it on your own infrastructure in a similar way. Just check out the repository to your local system with Ruby 3.2+ running, run bundle to install the
dependencies, then set up a cron job or some other automation to run ./process_feeds.rb. Doing this could be used to hook it up to your RSS feed updating pipeline, for
example, to check for new feed items right after a new post is published.
Footnotes
1 Their own incomprehensible, illogical, weird reasons.
2 I hope that the title gives it away, but you can do this completely for free.
So long as you keep your fork of the GitHub repository open-source then you can run GitHub Actions for free, and so long as you’re pushing out no more than 150 updates per day to no
more than 5 different channels in a month then you can do it within Whapi’s free tier: that’s probably fine for a personal blogger, and there’s a reasonable pricing structure (plus
some value-added extras) for companies that want to use this same workflow as part of a grander WhatsApp offering.
3 Setting this up requires giving Whapi access to your WhatsApp account. If you don’t like
the security implications of that, you could get a cheap eSIM, set that up with WhatsApp, and use that account: if you do this, just remember to “warm up” your new WhatsApp
account with some conversations with yourself so it doesn’t look so much like a spammer! Also note that the way Whapi works “uses up” one of the ~4 devices on which you can
simultaneously use WhatsApp Web/WhatsApp Desktop etc.
4 Prefer the command-line? So long as you’ve got curl and jq
then you can get a list of your newsletters (or groups) and their IDs with curl -H 'Authorization: Bearer YOUR_API_TOKEN' -H 'accept: application/json'
https://gate.whapi.cloud/newsletters?count=100 | jq '.newsletters[] | { id: .id, name: .name }' or curl -H 'Authorization: Bearer YOUR_API_TOKEN' -H 'accept:
application/json' https://gate.whapi.cloud/groups?count=100 | jq '.groups[] | { id: .id, name: .name }', respectively.
5 Going beyond the free tier would require sending one message, on average, every 9
minutes and 36 seconds.
A couple of weeks ago I blogged about setting up a PO Box and adding postal mail to the ways you can
contact me. I went for a “pay as you go” PO Box because I didn’t know if anybody would actually use it, but I’ve already received two delightful postcards and I couldn’t be more
thrilled.
The PO Box worked very well: I’m using UK Postbox principally because of their “pay as you go” rate (with a free tier in case you don’t receive
any mail at all, which I figured was a risk) but I was later pleased to discover they’re a nice company in other ways,
too. They scan the outside/one side of my mail as it arrives and I can optionally pay to scan the whole thing and/or to bundle and forward it on to me3.
I’ve started a new page to collect all the cards, including a (hopefully pretty-accessible) CSS-powered interactive “flipper” so you can turn them over, and
I’m hopeful that I might attract a few more as time goes on. Getting physical mail from “Internet friends” helps make the digital world feel a little bit smaller, and I
love it.
1 Florence’s RSS feed was missing a <![CDATA[ ... ]]> block around some
embedded HTML, which was causing the HTML to be evaluated “as if” it were XML, which – not being XHTML – it failed to do.
2 My suggestion was a variation of Derek Dingle’s Too Many Cards that I’ve been performing all over the place: it’s an immensely satisfying trick to perform, requiring a challenging but achievable set of sleights and
suitable to do without preparation and using a borrowed deck, which is pretty much the gold standard in card magic.
3 I’ve opted to have it forwarded: I’m wondering if I can combine all the postcards I get
into a single poster frame or something: maybe a double-sided one so the whole thing can be flipped to show the text, not just the fronts?
Last month I was on em’s personal site, where I discovered their contact page
lists not only the usual methods (email addresses, socials, contact forms etc.) but also a postal address1: how cool is that‽ I could have written in
their guestbook… but obviously I took the option to send a postcard instead!
Now I’ve set up a PO Box of my own, and I’ve love it if you feel up to saying “hi” via a postcard2.
As a bonus, it’s more-likely to get through than anything that has to face-off against my spam filter!
So, if you want to send me a letter or postcard (no parcels, nothing that needs a signature), my address is:
Dan Q
Unit 159610
PO Box 7169
Poole
BH15 9EL
United Kingdom
It makes me sad to see the gradual disappearance of the contact form from personal websites. They generally feel more convenient than email addresses, although this is
perhaps part of the reason that they come under attack from spammers in the first place! But also, they provide the potential for a new and different medium: the comments
area (and its outdated-but-beautiful cousin the guestbook).
Comments are, of course, an even more-obvious target for spammers because they can result in immediate feedback and additional readers for your message. Plus – if they’re allowed to
contain hyperlinks – a way of leeching some of the reputability off a legitimate site and redirecting it to the spammers’, in the eyes of search engines. Boo!
Well this was painful to write.
But I’ve got to admit: there have been many times that I’ve read an interesting article and not interacted with it simply because the bar to interaction (what… I have
to open my email client!?) was too high. I’d prefer to write a response on my blog and hope that webmention/pingback/trackback do their thing, but will they? I don’t know in
advance, unless the other party says so openly or I take a dive into their source code to check.
Your Experience May Vary
I’ve had both contact/comment forms and exposed email addresses on my website for many years… and I feel like I get aproximately the same amount
of spam on both, after filtering. The vast majority of it gets “caught”. Here’s what works for me:
My contact/comments forms use one of a variety of unobtrustive “honeypot”-style traps. These “reverse CAPTCHAs” attempt to trick bots into interacting with them in some
particular way while not inconveniencing humans.
Antispam Bee provides the first line of defence, but I’ve got a few tweaks of my own to help counteract the efforts of
determined spammers.
Once you’ve fallen into a honeypot it becomes much easier to block subsequent contacts with the same/similar content, address, (short-term) IP, or the poisoned cookie you’re given.
Keyword filtering provides a further line of defence. E.g. for contact forms that post directly back to the Web (i.e. comment forms, and perhaps a future guestbook form), content
with links goes into a moderation queue unless it shares a sender email with a previously-approved sender. For contact forms that result in an email, I’ve just got a few “scorer” rules
relating to geo IP, keywords, number and density of links, etc. that catch the most-insidious of spam to somehow slip through.
I also publish email addresses all over the place, but they’re content-specific. Like Kev, I anticipated spam and so use unique email addresses on
different pieces of content: if you want to reply-by-email to this post, for example, you’re encouraged to use the address
b27404@danq.me. But this approach has actually provided secondary benefits that are more-valuable:
The “scrapers” that spam me by email would routinely send email to multiple different @danq.me addresses at the same time. Humans don’t send the same identical message
to me to different addresses published on my site and from different senders, so my spam filter picks up on this rightaway.
As a fringe benefit, this helps me determine the topic on an email where it’s unclear. E.g. I’ve had humans email me to say “I tried to follow the guide on your page but it didn’t
work for me” and I wouldn’t have had a clue which page had they not reached out via a page-specific email alias.
I enjoy the potential offered by rotating the email address generation mechanism and later treating all previously-exposed addresses as email honeypots.
They’ve all got different “sender” addresses, but that fact that this series of emails were identical except for the different recipient aliases meant that catching them was very easy
for my spam filters.
Works For Me!
This strategy works for me: I get virtually no comment/contact form spam (though I do occasionally get a false positive and a human gets blocked as-if they were a robot), and very
little email spam (after my regular email filters have done their job, although again I sometimes get false positives, often where humans choose their subject lines poorly).
It might sound like my approach is complicated, but it’s really not. Adding a contact form honeypot is not significantly more-difficult than exposing automatically-rotating email
aliases, and for me it’s worth it: I love the convenience and ease-of-use of a good contact/comments form, and want to make that available to my visitors too!
(I also allow one-click reactions with emoji: did you see? Scroll down and send me a bumblebee! Nobody seems to have found a way to spam me with these, yet: it’s not a very expressive
medium, I guess!)
Today, for the first time ever, I simultaneously published a piece of content across five different media: a Weblog post, a video essay, a podcast episode, a Gemlog post, and a
Spartanlog post.
Must be about something important, right?
Nope, it’s a meandering journey to coming up with a design for a £5 coin that will never exist. Delightfully pointless. Being the Internet I want to see in the world.
Last month my pest of a dog destroyed my slippers, and it was more-disruptive to my life than I would have anticipated.
Look what you did, you troublemaker.
Sure, they were just a pair of slippers1, but they’d
become part of my routine, and their absence had an impact.
Routines are important, and that’s especially true when you work from home. After I first moved to Oxford and started doing entirely remote work for the first time, I found the transition challenging2.
To feel more “normal”, I introduced an artificial “commute” into my day: going out of my front door and walking around the block in the morning, and then doing the same thing in reverse
in the evening.
My original remote working office, circa 2010.
It turns out that in the 2020s my slippers had come to serve a similar purpose – “bookending” my day – as my artificial commute had over a decade earlier. I’d slip them on when I was at
my desk and working, and slide them off when my workday was done. With my “work” desk being literally the same space as my “not work” desk, the slippers were a psychological reminder of
which “mode” I was in. People talk about putting on “hats” as a metaphor for different roles and personas they hold, but for me… the distinction was literal footwear.
And so after a furry little monster (who for various reasons hadn’t had her customary walk yet that day and was probably feeling a little frustrated) destroyed my slippers… it actually
tripped me up3. I’d be doing
something work-related and my feet would go wandering, of their own accord, to try to find their comfortable slip-ons, and when they failed, my brain would be briefly tricked
into glancing down to look for them, momentarily breaking my flow. Or I’d be distracted by something non-work-related and fail to get back into the zone without the warm, toe-hugging
reminder of what I should be doing.
It wasn’t a huge impact. But it wasn’t nothing either.
The bleppy little beast hasn’t expressed an interest in my replacement slippers, yet. Probably because they’re still acquiring the smell of my feet, which I’m guessing is
what interested her in the first place.
So I got myself a new pair of slippers. They’re a different design, and I’m not so keen on the lack of an enclosed heel, but they solved the productivity and focus problem I was facing.
It’s strange how such a little thing can have such a big impact.
Oh! And d’ya know what? This is my hundredth blog post of the year so far! Coming on only the 73rd day of the year, this is my fastest run at
#100DaysToOffload yet (my previous best was last year, when I managed the same on 22 April). 73 is exactly a fifth of 365, so… I guess I’m on
track for a mammoth 500 posts this year? Which would be my second-busiest blogging year ever, after 2018. Let’s see how I get on…4
Footnotes
1 They were actually quite a nice pair of slippers. JTA got them for me as a gift a few years back, and they lived either on my feet or under my desk ever since.
2 I was working remotely for a company where everybody else was working
in-person. That kind of hybrid setup is a lot harder to do “right”, as many companies in this post-Covid-lockdowns age have discovered, and it’s understandable that I found it
somewhat isolating. I’m glad to say that the experience of working for my current employer – who are entirely distributed –
is much more-supportive.
3 Figuratively, not literally. Although I would probably have literally tripped
over had I tried to wear the tattered remains of my shredded slippers!
I’ve been trying to comment more on other people’s blogs. It’s tough, because comment forms continue to wane in popularity, and it’s not always clear who’ll accept Webmentions, but
there’s often the option of a good old-fashioned email or a fediverse ping.
It occurred to me that I follow a significant number of personal blogs, and my privacy systems mean I’m a bit of a ghost to most analytics systems they might use, so the only way they’d
ever know I was there would be if I said so.
Plus, the Internet is better when it’s social. There are some great people out there, and I’m enjoying meeting them!
(You’re welcome to throw comments, Webmentions, or emails my way, of course, too!)
When you’re writing online, being unique doesn’t matter nearly as much as being found.
I’m not sure I could disagree more. But I’ve jumped in half way through his post. Let’s backtrack a bit.
Andy begins:
A blogger showed me his website the other day.
…
But no one was reading it.
Firstly: let’s just observe that you were shown a website… and now you’re talking about it… but you haven’t linked to it? You’re complaining about its lack of discoverability,
while simultaneously being part of the problem.
Hyperlinks remain, as they have been since the mid-to-late 1990s, a primary mechanism in helping search engines’ spiders to discover new sites, and nowadays they’re doubly-important
because they help establish legitimacy.
When you search for, say, “history of web search” and this Wikipedia article is at the top, a significant
reason for that is that people link to that page when talking about the history of web search! A secondary reason is that lots of people link to Wikipedia in
general.
Your mileage may vary depending on your preferred search engine and other factors.
Berating somebody for an unindexed site… but not linking to that site… feels awfully-close to victim-blaming!
(Especially recently, as still-dominant search engine Google continues to make it harder and harder for “new” sites to get onto the ladder.)
When I asked him why he didn’t just use WordPress or Bear Blog, he looked offended.
“Those are so basic. Everyone uses those. I wanted something unique.”
I’m not sure I understand the logic of the person whose argument against e.g. WordPress is that it’s not “unique”. There are lots of great reasons that you might use WordPress. There
are lots of great reasons that you might not. The right choice of CMS should be based on a variety of factors.
It’s possible that the person being referred to meant “customisable”. They’d still be wrong (in the case of WordPress, at least: Bear Blog offers significantly less customisation
options, which is fine if the other features are what you’re looking for), but anyway: the short of it is that I briefly agreed, here, until:
WordPress powers about 43% of all websites. That means search engines know exactly how to read WordPress sites.
They know where to look for the content, the metadata, the tags.
Let’s correct the points here:
Search engines know exactly how to read HTML. WordPress outputs HTML. (If you’re outputting HTML, your site can be indexed. Hell, even that isn’t a firm
requirement: my plaintext-only blog shows up in search engines!)
Web standards dictate how content, metadata, and tags should be laid out. A search engine’s spider doesn’t look at your site and go “hey, it’s WordPress, so I need to
look for this“. Instead, it’ll generally look for content and metadata based on established standards. Titles, headings, <meta> tags, semantic elements:
these are the things a search engine looks for.
Sure, WordPress gets those things right. But they’re not hard to get right. You shouldn’t use WordPress (or Bear, or anything else) based just on the fact
that it exposes metadata correctly. Any site can do this. And because what’s eventually exposed to the search engine – and to the user – is HTML code… which is independent of the CMS
that generated it… it doesn’t have to matter what the underlying CMS is.
Then there’s some more confusion:
Here’s what matters: WordPress and other major platforms have spent years optimising for search engines and social sharing.
They’ve spent millions making sure posts load fast.
This sounds like it’s conflating WordPress (the open-source CMS) with one or more of several WordPress hosting providers (probably WordPress.com). That’s a common mistake, but it is a mistake.
WordPress can do terrible SEO. WordPress can be really slow. Trust me: in a previous life I’ve made a part of my living out of fixing and improving people’s WordPress-powered websites!
A large part of this comes from WordPress’s flexibility: the theme you choose, for example, can completely change the functionality of your site. Inspired by my plain text blog,
Terence Eden made a WordPress theme that does the same thing! That WordPress theme completely
upends the way that most people would use WordPress, but it’s still fundamentally WordPress, even though it exposes to search engines no HTML code, no metadata,
and no tags.
WordPress can also do great SEO, and it can be really fast. A properly-configured WordPress site can be a well-oiled machine. But if you conflate WordPress itself with its output,
you’re arguing against a straw man.
Don’t get me wrong: I love WordPress! But I dislike people making the false claim that if you’re not using it (or another popular blogging tool), you’re destined to fail at SEO. There’s
nothing “magical” about WordPress. It just takes content and renders HTML, in the end!
But all of this is moot, perhaps, when we get back to that first point:
When you’re writing online, being unique doesn’t matter nearly as much as being found.
This entire statement presupposes the purpose of “writing online”.
It’s 100% okay to write for yourself, first and foremost. It’s also okay to write for a small target audience, like for your friends or family. It’s okay to write content that
isn’t exposed to search engines (consider all of the wonderful content that my fellow RSS Club members put out, sometimes!). It’s
okay to write just for the joy of making things.
A website doesn’t have to be “professional”, as Andy’s post goes on to imply. A website doesn’t have to be anything in particular. A website can just… be. And that’s
enough.
As I mentioned in my recent Blog Questions Challenge, I recently switched my blog from WordPress, which it had been running on for over 20 years of its 26 year history, to ClassicPress.1
I’m aware that I’m not the only person for whom ClassicPress might be a better fit than WordPress2,
so I figured I should share the process by which I undertook the change.
Switching from WordPress to ClassicPress
Switching from WordPress to ClassicPress should be a non-destructive, 100% reversible process, but (even though I’ve got solid backups) I wasn’t ready to
trust that, so I decided to operate on a copy of my site. I’m glad I did, because there were a couple of teething issues I needed to tackle before I could launch.
1. Duplicating the site
I took a simple approach to duplicating the site: (1) I copied the site directory, and (2) I copied the database, and (3) I set up a new subdomain to use for testing. Here’s how I did
each step:
1.1. Copying the site directory
This should’ve been simple, but a du -sh revealed that my /wp-content/uploads directory is massive (I should look into that) and I didn’t want to
clone it. And I didn’t want r need to clone my /wp-content/cache directory either. So I ran:
rsync -av --exclude=wp-content ./old-site-directory/ ./new-site-directory/ to copy everything exceptwp-content, and then
rsync -av --exclude=uploads --exclude=cache ./old-site-directory/wp-content/ ./new-site-directory/wp-content/ to copy wp-contentexcept the
uploads and cache subdirectories, and then finally
ln -s ./old-site-directory/wp-content/uploads ./new-site-directory/wp-content/uploads to symlink the uploads directory, sharing it between the two sites
1.2. Copying the database
I just piped mysqldump into mysql to clone from one database to the other:
mysqldump -uUSERNAME -p --lock-tables=false old-site-database | mysql -uUSERNAME -p new-site-database
I edited DB_NAME in wp-config.php in the new site’s directory to point it at the new database.
If you’re going to clone your WordPress site before converting to ClassicPress, you’ll want to be comfortable editing your wp-config.php.
1.3. Setting up a new subdomain
My DNS is already configured with a wildcard to point (almost) all *.danq.me subdomains to this server already. I decided to use the name classicpress-testing.danq.me as my
temporary/test domain name. To keep any “changes” to my cloned site to a minimum, I overrode the domain name in my wp-config.php rather than in my database, by adding the
following lines:
Because I use Caddy/FrankenPHP as my webserver3,
configuration was really easy: I just copied the relevant part of my Caddyfile (actually an include), changed the domain name and the root, and it just worked,
even provisioning me out a LetsEncrypt SSL certificate. Magical4.
2. Switching the duplicate to ClassicPress
Now that I had a duplicate copy of my blog running at https://classicpress-testing.danq.me/, it was time to switch it to ClassicPress. I started by switching my wp-admin
colour scheme to a different one in my cloned site, so it’d be immediately visually-obvious to me if I’d accidentally switched and was editing the “wrong” site (I also made sure I was
logged-out of my primary, live site, so I was confident I wouldn’t break anything while I was experimenting!).
ClassicPress provides a migration plugin which checks for common problems and then switches your site
from WordPress to ClassicPress, so I installed it and ran it. It said that everything was okay except for my (custom) theme and a my self-built plugins, which it understandably couldn’t
check compatibility of. It recommended that I install Twenty Seventeen – the last WordPress default theme to not
require the block editor – but I didn’t do so: I was confident that my theme would work anyway… and if it didn’t, I’d want to fix it rather than switch theme!
I failed to take a screenshot of the actual process, but it looked broadly like this.
And then… it all broke.
3. Fixing what broke
After swiftly doing a safety-check that my live site was still intact, I started trying to work out why my site wasn’t broken. Debugging a ClassicPress PHP issue is functionally
identical to debugging a similar WordPress issue, for obvious reasons: check the logs, work out what’s broken, realise it’s a plugin, disable that plugin while you investigate further,
etc.
EWWW Image Optimizer: I use this plugin to pregenerate WebP variants of my images, which I then serve using webserver rules. It’s not a
complex job, and I should probably integrate the feature into my theme at some point, but for now I use this plugin. Version 8.0.0 of the plugin doesn’t work on ClassicPress 2.3.1, so
I used WP-CLI to downgrade to the last version that does (7.7.0), and then it worked fine.
Dan’s Geocaching Log Reposter: a self-made plugin that copies my logs from geocaching websites stopped working properly, which I think is because
ClassicPress is doing a more-aggressive job than WordPress at nonce validation on admin REST endpoints? I put a quick hack into my plugin to work around it, but I’ll need to look into
this properly at some point.
Some other bits of my stack, e.g. CapsulePress (my Gemini/Spartan/Nex server), have their own copies of my
database credentials, because I’ve been too lazy to centralise them into environment variables, and needed updating (but not until live switchover time).
I ran the two sites in-parallel for a couple of weeks, with the ClassicPress one as a “read only” version (so I didn’t pollute my uploads directory!), but it was pretty unnecessary
because it all worked pretty seamlessly, despite my complex stack of custom code. When I wanted to switch for-real, all I needed to do was swap the domain names over in my Caddyfile and
edit the wp-config.php of my ClassicPress installation: step 1.3, but in reverse!
If you hadn’t been told5, you probably wouldn’t have even known I’d made a change: I suppress basically all infrastructure-identifying
headers from my server output as a matter of course, and ClassicPress and WordPress are functionally-interchangeable from a front-end perspective6.
So what’s difference?
From my experience, here are the differences I’ve discovered since switching from WordPress to ClassicPress:
The good stuff
😅 ClassicPress has no Gutenberg/block editor. This would absolutely be a showstopper for many people, and that’s fine: I have nothing against the block editor (I
use it basically every day elsewhere!), but I’ve never really used it on danq.me and don’t feel the need to change that! My theme, my workflow, and my custom plugins are all
geared around the perfectly-good “classic” editor, and so getting a more-lightweight CMS by removing a feature I wasn’t using anyway falls somewhere between neutral and a blessing.
⚡The backend is fast again! One of the changes the ClassicPress team have been working on applying to WordPress is to strip out jQuery and other redundancies from
the backend, and I love how much faster and lighter my editor interface is as a result. (With caveat; see below!)
🔌Virtually everything “just works”. With the few exceptions described above, everything works exactly as it does under WordPress. Which is what you’d hope for a fork
that’s mostly “WordPress, but without the block editor”, right, but it’s still reassuring (and, for me, an essential feature). There are a few “new” features to do with paging through
posts and the media library and they’re fine, I suppose, but not by themselves worth switching for (though it might be nice to backport them into WordPress!).
The bad stuff
🏷️ Adding tags to posts takes a step backwards. A side-effect of dropping jQuery is the partial loss of the autocomplete feature when selecting tags to add to a post.
You still get a partial autocomplete, but not after typing a comma: you need to press enter to submit the tag you were writing and then start typing them next, which
frankly sucks. This is because they’re relying on a <datalist>, which isn’t as full-featured as the Javascript solution WordPress employs. This bugs
me almost enough to be a showstopper, but I gather it’s getting fixed in a near-future version.
🗺️ You’re in uncharted territory when things go wrong. One great benefit of WordPress is the side-effects of its ubiquity. If you have a query or a problem
you can throw a stone at your favourite search engine and get a million answers… and some of them will even be right! If you have a problem in ClassicPress and it’s not shared with (or
you’re not sure if it’s shared with) WordPress… you’re mostly on your own. The forums are good and friendly,
but if you want a quick answer to something, you’re likely to have to roll your sleeves up and open some source code. I don’t mind this at all – when I first started using WordPress,
this was the case, too! – but it might be a showstopper for some folks.
In summary: I’m enjoying using ClassicPress, even where there are rough edges. For me, 99% of my experience with it is identical to how I used WordPress anyway, it’s relatively
lightweight and fast, and it’s easy enough to switch back if I change my mind.
Footnotes
1 It saddens me that I have to keep clarifying this, but I feel like I do: my switch from
WordPress to ClassicPress is absolutely nothing to do with any drama in the WordPress space that’s going on right now: in fact, I’d been planning to try it out since before
any of the drama appeared. I appreciate that some people making a similar switch, including folks who use this blog post as a guide, might have different motivations to me, and that’s
fine too. Personally, I think that ditching an installation of open-source WordPress based on your interpretation of what’s going on in the ecosystem is… short-sighted? But
hey: the joy of open source is you can – and should! – do what you want. Anyway: the short of it is – the desire to change from WordPress to ClassicPress was, for me, 100% a
technical decision and 0% a political one. And I’ll thank you for leaving any of your drama at the door if you slide into my comments, ta!
2Matt recently described ClassicPress as “the last decent fork
attempt for WordPress”, and I absolutely agree. There’s been a spate of forks and reimplementations recently. I’ve looked into many of them and been… very much underwhelmed. Want my
hot take? Sure, here you go: AspirePress is all lofty ideas and no deliverables. FreeWP seems to be the same, but somehow without the lofty ideas. ForkPress is a ghost. Speaking of
ghosts, Ghost isn’t a WordPress fork; they have got some cool ideas though. b2evolution is even less a WordPress fork but it’s pretty cool in its own right. I’m not sure what
clamPress is trying to achieve but I’ve not given it a serious look. So yeah: ClassicPress is, in my mind, the only WordPress fork even worth consideration at this point, and as I
describe in this blog post: it’s not for everybody.
3 I switched from Nginx over the winter and it’s been just magical: I really love
Caddy’s minimal approach to production configuration. The only thing I’ve been able to fault it on is that it’s not capable of setting up client-side SSL certificate authentication on
a path, only on an entire domain, which meant I needed to reimplement the authentication mechanism I use on a small part of my (non-blog) internal
infrastructure.
4 To be fair, it wouldn’t have been hard if I’d still be using Nginx, because I’d
set up Certbot to use DNS-based vertification to issue me wildcard SSL certificates. But doing this in Caddy still felt magical.
6 Indeed, I wouldn’t have considered a switch to ClassicPress in the first place if it
wasn’t a closely-aligned-enough fork that I retained the ability to flip-flop between the two to my heart’s content! I’ve loved WordPress for over two decades; that’s not going to
change any time soon… and if e.g. ClassicPress ceased tracking WordPress releases and the fork diverged too far for my comfort, I’d probably switch back to regular old WordPress!