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');
    }
}

A WordPress URL rewrite rule to phase out year/month folders in the Media Library

This is one of those fixes where it is probably worth me explaining the very specific use case I needed it for first, to serve as an example of exactly why anyone would need this, because on the surface it may seem pointless.

Picture this: Restaurant client. Table cards with QR codes linking directly to menu PDFs, so customers can look at the menu on their phones instead of using a physical print menu that has been handled by dozens of other people.

Note to the future: I’m not sure what the restaurant experience looks like in your world. What I’m describing may be ubiquitous for you now, or may be a complete head-scratcher. Assuming it’s safe for you to touch your head. For context, I am writing this in the midst of the 2020 COVID-19 pandemic.

Here’s the problem: Menus change. URLs referenced by a QR code do not. By default, WordPress automatically creates year and month subfolders inside wp-content/uploads and puts files in the folder for the year and month the post they’re attached to was created, or if you’re uploading directly into the Media Library, not attached to a post, then the year and month the file was uploaded.

So that means that the URLs embedded in my client’s QR codes contain 2020/09. But now it’s October, so if they upload a replacement file today, its URL will contain 2020/10 and the QR code will not work. I should note at this point that I do not like the default WordPress behavior of putting files into these subfolders, but I sometimes forget to turn off this setting when I’m creating a new site, or — as is the case here — I’m working on a site someone else originally set up.

My solution: Turn off year/month folders, so that any newly uploaded PDFs with the same filename will have the same URL. (Assuming the client deletes the old one first!)

You may be thinking, well, that’s great, if you had done this before the QR codes were created. Yes, exactly. That’s where this rewrite rule comes in.

When you turn off the year/month folder setting, it doesn’t move any existing files or change any code that links to them. This purely affects new uploads going forward. So what I need is a rewrite rule that will allow existing file URLs with the year/month path to continue working, while automatically removing that bit from the URL and trying to find the same file in the main uploads folder, if there’s no file at the year/month URL.

OK, here’s the code:

# Redirect file URLs from year/month subfolders to base uploads folder if not found
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /wp-content/uploads/
RewriteRule ^index\.php$ – [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([0-9]{4})/([0-9]{2})/(.*) /wp-content/uploads/$3 [L,R=301]
</IfModule>

This should go not in your main .htaccess file, but in an .htaccess placed inside your wp-content/uploads folder.

Let’s assess what’s going on here, line by line.

# Redirect file URLs from year/month subfolders to base uploads folder if not found

Just a comment so we remember what this is all about. You may think you’ll remember. But you probably won’t. Comments are your future friend.

<IfModule mod_rewrite.c> and </IfModule>

Apache configuration conditionals wrapper for all of our actions, to make sure this code doesn’t run if mod_rewrite isn’t enabled. Honestly I often leave this out because… come on, the entire site is going to be broken if mod_rewrite isn’t enabled.

RewriteEngine On

If you don’t know what this is about, RTFM. (The “F” is directed at the manual, not you. I hate the Apache documentation.)

RewriteBase /wp-content/uploads/

This is the reference point for the ^ later on. Needs to be the relative path of the uploads folder below your WordPress site’s base URL.

RewriteRule ^index\.php$ - [L]

Honestly we probably don’t need this line, as there shouldn’t be any index.php files inside your uploads folder anyway, but it just feels weird not to include it. This just says “don’t do any rewrites to the index.php file.”

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

These lines are very common in this type of rewrite instruction set, and in fact come straight from the default WordPress rewrite rules. They are saying, only apply the following rules to URLs that don’t match existing real files or directories under this path. This is critical to keep all of your existing Media Library URLs working.

RewriteRule ^([0-9]{4})/([0-9]{2})/(.*) /wp-content/uploads/$3 [L,R=301]

This is what we’re here for. Note we are using the magic of regular expressions to make this work. There are three parenthetical groupings, though we technically could eliminate the first two sets of parentheses and change $3 to $1, but I just like having the parentheses to help me keep things straight.

([0-9]{4}) is matching a 4-digit number, representing the year folder.

([0-9]{2}) is matching a 2-digit number, representing the month folder.

And (.*) is matching… anything, representing the filename. That’s the bit we want to reference in the replacement string, /wp-content/uploads/$3 which tells Apache to serve up the filename from the year/month URL directly out of the uploads folder itself.

The final bit, if you’re not familiar with rewrite rules, [L,R=301], just says this is the last rule the previous set of conditions applies to, and that it should return an HTTP 301 (permanent redirect) status along with the redirect, which is good SEO karma.

How to get a Mac to stop trying to play audio through an HDMI monitor that doesn’t have speakers

How has it come to this? It’s 2020, and on top of everything else (a global pandemic, an incompetent and megalomaniacal U.S. president, police in my neighborhood murdering Black people, riots in my neighborhood over police murdering Black people, climate change-induced forest fires destroying California, murder hornets), my MacBook Pro has suddenly decided that it must try to send audio output to my HDMI monitor whenever it’s plugged in, even though the monitor doesn’t have speakers, and I have a set of speakers plugged into the headphone jack.

It’s a completely asinine scenario, and the solution is even more asinine, but it does seem to work. It also maybe just fixes one annoying issue I always had with my speaker setup: I would have to turn the Mac’s volume all the way up to get adequate output to the speakers, which have their own volume control.

What’s the solution? Create an aggregate device. What’s that? I’ll show you.

First go into Applications > Utilities and open Audio MIDI Setup. Hopefully you’ve never had to open this little utility before, because I doubt anyone who works in interface design at Apple ever has. (ZING!)

You’ll see something like this… but without the last item, which is the aggregate device I already created, much like a TV chef who already has a finished dish waiting in the oven.

That “VS248” is my HDMI monitor. “External Headphones” is my speakers, plugged into the MacBook Pro’s headphone jack. Then of course there are the internal microphone and speakers of the Mac itself.

Click the little plus sign at the bottom left, and choose Create Aggregate Device. Click the checkboxes under Use for “External Headphones” and your monitor. That will make them appear in Subdevices above. When I did this, it had VS248 on the left and External Headphones on the right, which was assigning the monitor to channels 1 and 2, and the headphones to channels 3 and 4. You can drag-and-drop the names of the devices to change the order. Move your External Headphones to the left so their color is assigned to channels 1 and 2. You can also give this aggregate device a distinct name by clicking its name in the left sidebar and typing in what you want. I cleverly called mine “Headphones and VS248.”

That’s it! Now close this window, open System Preferences, and click on Sound > Output. Select your new aggregate device for sound output, and you should be all set.

One thing I noticed about this that was initially annoying, but then I realized is actually a good thing! was that now the volume control and mute “buttons” on my MacBook Pro’s Touch Bar were grayed out. Damn it! Oh, wait. That’s actually fine, because this aggregate device is automatically setting the output on the headphone jack to maximum, allowing me to easily control the volume in the speakers with the speakers’ volume knob. I no longer have to manually turn the Mac up to maximum. And, hopefully, although I haven’t tried it yet, this also means that when I take my Mac away from my desk and plug my earbuds directly into the headphone jack, I won’t have to remember to adjust the volume before blowing out my eardrums! The Mac should remember the optimal volume I already have set for when the sound output is External Headphones-only.

A brief reflection on Facebook’s anti-UX

I am convinced that Facebook designs its user experience (UX) as anti-user experience. Their goal is not to make their site intuitive, friendly and convenient. It’s not to surprise and delight. (Well, surprise maybe.) It’s all about doing everything it can to dangle just enough of a carrot in front of you that you’ll click more times than you want to, exposing yourself to more ads, which translate to more revenue than they could reasonably justify if the advertisers knew just how brief and worthless those “impressions” really are.

Anyway… here’s an example of the latest annoyance, in the form of a Your Memories on Facebook block. This is what I saw in my browser window:

It’s an extremely brief teaser of and old post of mine that, yes, I actually am interested in seeing, since I am really missing the Minnesota State Fair this year. So I click on See more… but nothing happens.

I’m sure most users are just utterly confused by this, and may or may not understand that what they’re seeing is a preview of what their friends will see if they share this “memory” on their timeline. It doesn’t matter if they understand or not though, because Facebook has done enough user research to know that they’ll still keep clicking things to try to see more, leading them to the only links here that actually do anything, the Send and Share buttons.

Clicking Share pops up another window that shows a bit more of the post, but still not all of it, and another non-functional See more… “link”. But the only way to actually see the entire post is to share it on your timeline. Which is the only thing Facebook wants you to do here, because it “drives engagement”.

I’d insert an eye-roll emoji here but I’ve turned off that feature in WordPress, because I hate every part of everything right now.

Since I’m sure you’re dying to know how this all ends… here’s a screenshot of the shared post on Facebook.

See more…

Vegetarian Biscuits and Gravy

Do you want to read a long, drawn-out blog post intro to this recipe before I actually get down to the details? Of course you do!

But I don’t really care to write it. Suffice to say, the first time I ever had biscuits and gravy was at a restaurant somewhere on vacation with my parents when I was about 11 or 12. I loved biscuits and I loved gravy, so I assumed it would be awesome. But I’d never had (or even imagined the existence of) sausage gravy, and since I was at the age where — with food at least — surprise equals disgust, I hated it.

Over time I learned to like biscuits and gravy. But over time I also became a vegetarian. What to do? How about make my own vegetarian version? Of course!

The first thing you need to know is that I am not much of a baker, and my biscuit recipe is almost exactly the biscuit recipe from Mark Bittman’s How to Cook Everything, so I suggest before you do anything else, you head over to your favorite bookseller and buy it.

The next thing you need to know is that I am all about making sauces, gravies, béchamels, what-have-you. I have always found that recipes gloss over the trick of it, which is really not hard at all, but if you don’t know it, they turn into a lumpy disaster. So I’ll get to that in time.

First let’s make some biscuits.

Not Exactly Mark Bittman’s Buttermilk Biscuits

This makes somewhere between 10 and 15 biscuits, depending on how thin you roll it out and how careful you are about not wasting any dough.

Ingredients

2 c all-purpose flour
1 tsp salt
1 tbsp baking powder*
1 tsp baking soda
5 tbsp butter
1 c buttermilk

* Mark Bittman says 3 tsp, but since 3 tsp equals 1 tbsp, I don’t know why he does that, other than that baking is a science and maybe saying 3 tsp instead of 1 tbsp will make you be more precise in your measurements. Also make sure you pay attention to the difference between baking powder (which contains baking soda) and baking soda (which does not contain baking powder).

Preparation

  1. Preheat oven to 450ºF.
  2. In a large mixing bowl, combine the first 4 ingredients and stir together well.
  3. Cut the butter into small pieces — I actually hack away at it with kitchen scissors; you could also grate it with a box grater if it’s cold enough.
  4. Add the butter pieces into the dry ingredients, and then using your fingers, smoosh the butter together with the flour until there aren’t any big chunks of butter left. (Make the recipe a few times and you’ll probably figure out your own preferred way to do this.)
  5. Stir the buttermilk into the bowl 1/4 cup at a time, and continue stirring until the dough starts to come together. If your experience is like mine, it never totally does. Just avoid working it too much.
  6. Scoop the dough out onto a floured surface and knead a few times, just until it comes together. Again, don’t overwork it.
  7. Dust a rolling pin with flour, and roll the dough out to about 1/2 inch thick.
  8. If you have a biscuit cutter or a circular cookie cutter, awesome. Otherwise, an overturned juice glass supposedly works. You might want to rub some flour around the inside lip of the glass to keep the dough from sticking. Press the cutter/glass down straight through the dough quickly to make circles. Don’t twist.
  9. Hopefully your dough is dry enough not to stick to the cutter/glass and even more importantly to the counter. Assuming that’s the case, you can transfer the circles of dough to a nonstick baking sheet. Give about an inch between biscuits. They do expand while baking, but not a huge amount.
  10. If you have leftover dough, smoosh it back together, roll it out again, and cut out a few more biscuits! Then be sure to take the remaining scraps this time, mash them into a grotesque monster biscuit, and put that on the tray too!
  11. Bake for 7 to 9 minutes. (My oven takes 9.) Just look for the kind of golden brown color on top that you like to see.
  12. Remove the biscuits from the oven and cool slightly on a cooling rack before serving.

Here are the biscuits I made this morning (minus a couple Sara snagged before I could take a picture). Can you tell which ones I cut out first?

While the biscuits are in the oven, you can get started on the gravy.

Scott’s Vegetarian Sausage Gravy

Ingredients

3 tbsp butter
3 tbsp flour
1/4 c buttermilk
3/4 c vegetable broth
1 c milk
2 vegetarian breakfast sausage patties (e.g. Morningstar Farms)
fresh ground black pepper
salt to taste

Preparation

  1. Combine the liquid ingredients in a 2-cup measuring cup. (Should be 2 cups total.)
  2. Place butter in a medium saucepan over medium-high heat.
  3. While butter is melting, microwave the sausage patties 20-25 seconds, flip, then 20-25 seconds more.
  4. Add the sausage patties to the saucepan and break into small pieces with a wooden spoon.
  5. Add the flour and stir well for about 1 minute.
  6. Here’s the secret to good, smooth gravy/sauce/bechamel: Add the liquid a small amount at a time. By “small amount” I mean about 1/4 cup. Stir until all of the liquid is absorbed and the mixture is a consistent texture, then continue adding liquid 1/4 cup at a time until the overall mixture is more “liquid” than “paste,” then pour in all of the rest of the liquid and stir well.
  7. Turn the heat up to high and stir constantly until it comes to a boil. Reduce heat to medium.
  8. Continue stirring constantly, making sure to loosen up anything that’s starting to stick to the bottom of the saucepan.
  9. Stir in a generous amount of black pepper (fresh ground if you have it). Good sausage gravy has a lot of black pepper in it. I generally use at least 1/2 tbsp to 1 tbsp.
  10. Continue stirring and simmering until the gravy reaches your desired thickness. Taste and season with salt as needed.

That’s it! Put 2-3 biscuits in a bowl or on a plate, ladle the gravy over and enjoy!