How did I not know about ClassicPress before now?

ClassicPressI’ve been using WordPress for 15 years, and have made it my go-to platform for all new websites I’ve built since 2014. So how is it that it took me three years to discover that ClassicPress exists, especially since its whole raison d’être is to keep the pre-Gutenberg dream of WordPress alive?

On one hand, being a solo developer — even before the pandemic — has always kept me a bit out-of-the-loop, especially since I don’t attend conferences. But I suspect the fact that I knew nothing of this also speaks negatively to the project’s future.

Is it gaining enough traction to continue to exist? Is it really a viable option to use on new professional projects in 2021?

Has the Gutenberg ship sailed? Well, yes, it has. But my issues with the current and future state of WordPress go beyond Gutenberg, to the nature of Automattic’s role in steering the ship, the greater vision of what WordPress is and should become, and… well… Matt Mullenweg’s personality. I feel like the future of WordPress is increasingly diverging from what I hoped to get out of it as a platform, and it’s clear that I’m not alone. That’s why ClassicPress exists.

There are a lot of things to like about ClassicPress, right out of the gate, besides the most obvious element, which is the absence of anything Gutenberg. It does away with a lot of the cutesy crap that’s rolled into WordPress by default, not least of which being the annoying proliferation of the word “howdy” and the beyond-pointless-to-actively-detrimental* plugin Hello Dolly.

As I look to my own future with WordPress and/or ClassicPress, I am primarily thinking about two things: 1) how/if I will continue to use it as the platform of choice for client projects, and 2) what the future will be for the plugins I have contributed to the WordPress community, and more specifically, my commercial plugin, ICS Calendar Pro.

I’ve been struggling with these matters for almost four years now, ever since Gutenberg emerged on the scene and went through its early phases of absolutely sucking, to its too-soon release as the default WordPress editor, to its current state as a mostly good but highly quirky and weirdly limited page building tool.

The timing was not great for me, as I had just recently gone “all-in” on 34 Blocks, my own block-based starter theme that I have been using to create all of my client sites since 2017. It started from a series of one-off client themes beginning around 2015 and is built around Advanced Custom Fields and its “Flexible Content” fields. It’s all much more in line with what “WordPress” has always meant to me. But as WordPress becomes Gutenberg, my vision of what this tool is and the reality of what it has become are increasingly at odds.

In those four years I’ve been bouncing around between several different ideas:

  • Suck it up and finally embrace Gutenberg development, learning a bunch of new stuff like React, in which I am not only wholly disinterested but with which I philosophically disagree?
  • Cling for dear life to Classic Editor and pray the gods of Automattic keep it on life support?
  • Switch to an entirely new platform, whether that might be another open source or commercial CMS, or a complete SaaS approach like Squarespace?
  • Get out of the web development business entirely?

So far, I’ve mostly stuck with “cling for dear life to Classic Editor” although I have been tempted a great many times to “get out entirely.” My enthusiasm for this field hasn’t been helped by things like the caustic toxicity of social media, the rise of absolutely godawful and not-at-all-intuitive-regardless-of-their-claims-to-such interface concepts (see: Google’s Material Design), and technical snafus like Digital Ocean’s entire subnet getting spam blacklisted and them doing absolutely zero to rectify the situation.

I’ve been taking baby steps towards making sure I’m not caught out when/if they pull the plug on Classic Editor. My 34 Blocks theme is to the point where it works adequately in the Gutenberg environment, and I’m even moving it towards a potential future where I would scrap my ACF Flexible Content blocks altogether, in favor of Gutenberg blocks.

But I’ve also made sure ICS Calendar is backward-compatible with WordPress 4.9, so it works with ClassicPress. And I’m still looking at other tools, now and again, in case I need to switch directions entirely.

It’s happened before. After the first half of my career consisted largely of building “bespoke” CMSes for corporate overlords, I went out on my own. From 2008 to 2014 I sunk thousands of hours into the development of a feature-rich, completely custom-built CMS based on the CakePHP framework, which I used to create about 10 client sites per year throughout that period.

But the writing was on the wall for that project when I found it impractical to upgrade the CakePHP core past version 1.3, which was incompatible with PHP 7. (CakePHP is currently up to version 4.1 and now requires a minimum of PHP 7.2, for an indication of just how doomed my old CMS project was.) By 2014 I gave up on it and switched to WordPress. Has the time come to move on again? If so, I feel like in some ways, switching to ClassicPress would be a step backwards, or at best a lateral move, and would not set me up well for the future.

Where does that leave me? I don’t know. There are options. But embracing Gutenberg and the future of WordPress is not at the top of the list. If anything, it’s never been lower.

* Why is Hello Dolly detrimental? The justification for its inclusion in the default WordPress build is that it is a demo for new developers to learn how to build a WordPress plugin. The problem is, it’s a terrible, no good, entirely wrong example of a plugin. It’s ancient and doesn’t conform to any modern WordPress coding standards, and it’s so rudimentary that there’s no useful structure to build on for people who want to create an actually useful plugin. So why is it still included? I don’t buy the “demo” argument. It’s still there because Matt wants it to be, and that in a nutshell is my problem with Automattic running the show. (I mean look, he even “cleverly” misspelled the company name so his own fucking name is embedded in it. That annoys me every damn time I see it… almost as much as “howdy.”)

Get rid of that annoying “WebSocket connection to ‘…’ failed” error on WordPress sites running Jetpack

If you run a self-hosted WordPress site with Jetpack, installed, you may have noticed a frequent error message showing up in your browser console.

In Chrome it looks like this:

WebSocket connection to ‘wss://public-api.wordpress.com/pinghub/wpcom/me/newest-note-data’ failed: Error during WebSocket handshake: Unexpected response code: 403

In Safari it’s slightly less specific, but the issue is the same:

WebSocket connection to ‘wss://public-api.wordpress.com/pinghub/wpcom/me/newest-note-data’ failed: Unexpected response code: 403

This issue has been reported various places online but nowhere do I find a true fix.

As indicated in some of those support threads I linked to above, it’s due to an issue with the Notifications module in Jetpack. What? It’s something I was not even really aware of and that can be extremely easy to ignore, especially if your site is not blog-focused or does not have active commenting. Turns out Jetpack has this little “Notifications” icon up in the admin bar next to your Gravatar, where you can get the latest updates on what’s happening on your blog.

If you’re like me, you don’t need or want the Notifications tool. And if getting rid of it gets rid of that stupid error that’s constantly popping up in the console, all the better.

Side note: Did you know there’s a hidden page where you can access the settings for a ton of Jetpack modules? (Neither did I.) Just go to /wp-admin/admin.php?page=jetpack_modules in your WP admin and there it is! If you’re just dealing with this issue on one particular site, and don’t want to write any code, simply deactivate the Notifications module here and you’re done. If this is something you are dealing with on many sites though and you want an automatic, code-based solution to stick into your base theme, read on…

I tried using Jetpack’s instructions for disabling a module via code. (Fun fact, the name for this module in the code is not 'notifications' as you might expect; it’s 'notes'.) Frustratingly, neither the 'option_jetpack_active_modules' filter nor the 'jetpack_get_available_modules' filter worked. I even scoured the Jetpack source code for other filters I might need to use, and none of them made a difference.

Oh, I was able to get 'notes' not to appear in the array those filters returns, and I was even able to use that to get “Notifications” to always appear as “inactive” on that hidden settings page.

But the error kept showing up in the console, and the little Notifications icon was still in the admin bar. The module was not inactive.

Finally, through further source code poking, I discovered there’s a static public method called Jetpack::deactivate_module(). I tried running it in those aforementioned filters but it resulted in an HTTP 500 error. (Strangely, it was an out-of-memory error. Shrug.)

So I decided to try the method in different actions. After some trial and error, it seems the 'init' action works. But that’s a bit of overkill, running this code on every front end page load, especially since once the module is deactivated, it should stay deactivated, so my solution is to run it on the 'admin_init' action instead. Especially since this issue only happens for logged-in users anyway, it should be adequate.

Here’s a bit of code you can stick into your theme’s functions.php file or wherever you like to put things like this:

add_action('admin_init', 'rm34_jetpack_deactivate_modules');
function rm34_jetpack_deactivate_modules() {
    if (class_exists('Jetpack') && Jetpack::is_module_active('notes')) {
        Jetpack::deactivate_module('notes');
    }
}

How to execute a no-nonsense upgrade to PHP 7.4 on Ubuntu 16.04 LTS

Yeah, yeah. Ubuntu 16.04 LTS is getting pretty long in the tooth. Long-term support ends in less than a year.

But if you’re anything like me (I’m sorry), you’re managing multiple VPSes that are, at the moment, still running it. And now WordPress is giving all of your clients scary warnings about needing to upgrade their version of PHP. What to do?

I’ve distilled the process down to 11 lines that you can just copy-paste straight into the command line. It’s not entirely hands-off; there are a few steps where you’ll be asked to confirm whether you want to keep your existing configuration files (YES!) and such. And — very important — you’ll want to review the set of PHP-related packages I’ve got listed here to make sure they’re ones you need, and that they’re all the ones you need. If you’re not sure whether or not there are others you may want, I suggest running apt update and then apt-cache search php7.4 and reviewing the list of results before proceeding.

Now then… here we go. I’ll break it all down after the code sample.

CAVEAT EMPTOR: I’ve just run this series of commands on three servers and it seemed to work fine, but this code is provided AS IS and you’re on your own if anything gets screwed up.

This assumes you’re already in sudo mode. If not, start with a sudo -s and FEEL THE POWER.

apt update
apt -y install software-properties-common
add-apt-repository -y ppa:ondrej/php
add-apt-repository -y ppa:ondrej/apache2
apt update
apt -y dist-upgrade
apt -y autoremove
apt -y install php7.4 libapache2-mod-php7.4 php7.4-mysql php-imagick php7.4-cgi php7.4-cli php7.4-common php7.4-curl php7.4-gd php7.4-json php7.4-mbstring php7.4-opcache php7.4-soap php7.4-xml
a2dismod php7.0
a2enmod php7.4
service apache2 restart

OK, what are we doing here? Let’s break it down.

apt update

Updating our package cache. Gotta do this first, always.

apt -y install software-properties-common

You may already have this installed. I’m not entirely sure what it’s for but the other articles I read had me doing that before the next steps so who am I to argue?

add-apt-repository -y ppa:ondrej/php
add-apt-repository -y ppa:ondrej/apache2

We are adding external package repositories created by Ond?ej Surý that allow versions of Ubuntu Linux to install newer versions of PHP than what comes with the standard Canonical set.

apt update
apt -y dist-upgrade
apt -y autoremove

Gotta do this again, since we’ve added new repositories. We’re doing a full-blown update of any outdated packages in the OS, and using the -y switch means we’re not going to be asked to manually confirm before proceeding. Be careful!

apt -y install php7.4 libapache2-mod-php7.4 php7.4-mysql php-imagick php7.4-cgi php7.4-cli php7.4-common php7.4-curl php7.4-gd php7.4-json php7.4-mbstring php7.4-opcache php7.4-soap php7.4-xml

This is the big one. We’re installing PHP 7.4 as well as a bunch of related packages we probably need. If you don’t know what all of these do, I encourage you to research them. You may not need them all. You may need others not included here. But these seem to do the trick for a typical WordPress setup.

a2dismod php7.0
a2enmod php7.4

Here we’re telling Apache to stop using PHP 7.0 and to use PHP 7.4 instead. This assumes you’re currently running PHP 7.0, which would be the case if you’re still on the default Ubuntu 16.04 LTS packages.

service apache2 restart

Let’s restart Apache and get that PHP 7.4 goodness! Hopefully everything works! But I suppose we should also be forward-thinking. This command is deprecated and I believe removed completely in Ubuntu 20.04, so you could use the more modern (but to my eye, decidedly less friendly) systemctl restart apache2 instead.

Postscript

One more thing… along the way you might have updated some packages that recommend a restart. If that’s the case, throw in one last command for fun:

reboot

Obviously if your server gets a ton of traffic you may not want to reboot in the middle of the day. But then you shouldn’t have been doing any of this in the middle of the day. The Digital Ocean VPSes I use typically reboot in less than 10 seconds, so I am never too hesitant to reboot at any time. Some of the other commands above, however, may shut down Apache or MySQL for a longer period (probably not more than a minute or two).

Post-postscript

This should also work more or less the same for any other version of Ubuntu you’re trying to keep fresh past its sell-by date. The main thing you might need to look at is the a2dismod php7.0 line. You’re probably running a different version of PHP. You can use php -v to see which version you’re running, and you can run ls /etc/php to see which version(s) you have installed.

A quick fix for the impossibility of building new menus on a WordPress site with a large number of pages

I’m working on a theme migration for a WordPress site that as a lot of pages. A lot of pages. 451 pages.

The old version of the site was using page menus, not custom menus, but it was relying on a constellation of abandoned plugins, and that approach just won’t work for the new theme. We need to build custom menus.

The problem is, building a new menu on a WordPress site that has 451 pages is a daunting task. Granted, only 39 of these pages need to go into the main navigation. (A lot of them really should probably be deleted, but that’s the client’s call, not mine.) So, I’m glad I don’t have to wrangle over 400 pages into a menu, but even 39 can be difficult given the shoddy interface WordPress provides for finding pages to add to your menu.

There are three tabs: Most Recent, View All, and Search. Most Recent is useless unless you’re just adding recently created pages to an existing menu. View All is useless because it’s paginated, inside this tiny box, and it lists the pages in an entirely inscrutable order. (OK, it’s not inscrutable. I can scrute it. But just because I understand the logic of how they’re ordered doesn’t mean that order is easy to work with.) And lastly we have Search which seems like the saving grace. But it’s actually the most maddening of the three because of two things:

  1. WordPress search sucks. It doesn’t give extra weight to page titles; it searches the full content. So even if I type in the exact title of the page I want, it’s usually not first in the list. And that’s a problem because…

  2. It only returns 10 results. That’s it. Ten. No lazy loading of more, no pagination, nothing. If your page doesn’t come back in the top 10 results, it may as well not exist.

I’d really love to rebuild the internal WordPress search engine to be smarter about weighting titles. Well, OK, no I wouldn’t. That would be a project I would not enjoy. But I would like for it to be done by someone.

Since that’s not likely to happen, at least there’s a way we can modify the search results to change the number of pages returned. I found the solution, as I often do, on StackExchange. But I dislike a few of the answer’s coding conventions, and I wanted to make one specific change for myself, so here’s my version. (You may not like using closures, especially in a scenario like this because it prevents you, or anyone else, from being able to remove this logic elsewhere. If I were writing a public plugin for this, I’d definitely make it a named function, but this should be fine for a custom theme.)

add_action('pre_get_posts', function($query) {
  if (is_admin()) {
    if (isset($_POST['action']) && $_POST['action'] == 'menu-quick-search' && isset($_POST['menu-settings-column-nonce'])) {
      if (is_a($query->query_vars['walker'], 'Walker_Nav_Menu_Checklist')) {
        $query->query_vars['posts_per_page'] = -1;
      }
    }
  }
  return $query;
}, 10, 2);

The important difference between the StackExchange sample and my code is that I changed the results from 30 to -1 which, in the WordPress universe, equals . Fun!

The standard warning is that setting posts_per_page to -1 is inherently risky because it could cause performance problems. But in my testing of this change, it does not appear to be an issue on this site with 451 pages, so I’m guessing it won’t be for you, either.

Now, instead of getting back a paltry ten results, you’ll get all the results that match your search. And the exact page title you typed in should be in there, somewhere.

Add arbitrary product data to order items in WooCommerce

This seems to be way more convoluted than it needs to be, but I’m not sure how much of that is that it’s actually convoluted, how much is that Woo’s documentation sucks, and how much is that everyone else’s tutorial on it is tl;dr.

Anyway… I just wanted to do something fairly simple. I want to have each product’s short description get sent into the order data. This is a specific use case with a client who’s syncing data over the REST API with an external system, and we’re shoehorning data into the short description that maybe could go somewhere else. The point is, use your imagination as to how this might be useful to you.

I’m stripping out a lot of the other details. All I want is a way to a) add the data to the item in the cart, and b) carry that data over into the order item meta data in the database. You may need or want more, but this will get you started.

// Add custom order item meta data to cart
add_filter('woocommerce_add_cart_item_data', function($cart_item, $product_id) {
  if (!isset($cart_item['short_description'])) {
    if ($product = wc_get_product($product_id)) {
      $cart_item['short_description'] = $product->get_short_description();
    }
  }
  return $cart_item;
}, 10, 2);

// Add custom order item data from the cart into the order
add_action('woocommerce_checkout_create_order_line_item', function($item, $cart_item_key, $values, $order) {
  if  (isset($values['short_description'])) {
    $item->add_meta_data('Short Description', $values['short_description'], true);
  }
}, 10, 4);

This is a major distillation of stuff I found in these two tutorials: How to Add a Customizable Field to a WooCommerce Product and Add Custom Cart Item Data in WooCommerce.