ST:TNG Treadmill Review: A new blog series

Introducing a new blog series here on UoP: ST:TNG Treadmill Reviews!

What’s all this then? It’s a long story.

Let’s start with ST:TNG. If you don’t know what that stands for, I’m not going to bother to explain, because you won’t be interested anyway. I have seen almost every episode of the series at least twice: First, when it was originally airing in first-run syndication in the late ’80s and early ’90s, I was in high school, and my dad and I would watch it every Saturday night with our Tendermaid hamburgers. (I liked mine with cheese, onions and mustard.) Then I rewatched almost the entire series with friends in the dorm my freshman year of college, when it was on in weeknight rerun syndication, at 10:30 PM. (Snack of choice: microwave popcorn and Pepsi.) But I haven’t really watched it much at all since then.

Now, on to treadmill. I’ve been running since 2011. I run outside most of the year, but I have a hip issue that makes running on ice and snow dangerous, so in the winters I’d run on the indoor track at the local YWCA. For reasons I won’t get into here, we canceled our Y membership last year, and finally broke down and bought a treadmill.

I previously hated treadmills, but I learned to tolerate it by watching TV episodes on Netflix or Hulu. In particular, I got into watching Star Trek: Enterprise, which I had not really given a fair shake when it first aired. (I haaaaaaate the theme song, and that was enough to turn me off entirely, back when I couldn’t fast-forward through it.) Well, I finished all of Enterprise, so this winter I’m going to have to watch something else. I’ve been trying to watch the final season of The Good Place, but I’ve finally come to terms with the fact that I just don’t like it, and not liking something makes it hard for me to keep running on the treadmill while I’m watching it.

That last point inspired Sara to inspire me to start this blog series. I can, to some extent, rate the quality of a TV episode by how long I’m willing to run on the treadmill while watching it. So I’m going to write reviews of all of the ST:TNG episodes I watch this winter on the treadmill, giving them a rating based on how far I run before I lose enthusiasm and switch to walking.

I’m not watching the series systematically. I watched a smattering of the first season late last winter, after I finished Enterprise, but I skipped some because they were… not good. The first season of TNG is notoriously inconsistent, and even includes unquestionably the worst episode in all of Star Trek. So I’m starting with season two. But a lot of these episodes are pretty bad, too. In particular, I have little patience for episodes that take place entirely on the Holodeck, as well as ones that are too dependent on Deanna Troi’s empathic powers. So I’m reading the one-sentence synopses on Netflix, and using those to determine whether or not to watch a particular episode.

I’ve done two episodes so far, yesterday and today, so I’ll be posting those first two entries shortly after this one. Then, I’ll post new ones as I watch the episodes.

Just like the worst Star Trek episodes, there will be a formula to these posts:

Title / season and episode number / original airdate
Netflix synopsis
My brief review
Memorable moment
Crew rando
Distance rating

Engage!

Get Gmail to scale inline images to fit the browser window (in Chrome and Safari)

If you use Gmail on the web as your main email platform, and your work often involves people sending you emails with large high-resolution images (which ideally would be attachments, but are often embedded inline in the message), you know this problem. The images are frigging huge in the browser window, and the viewing panel ends up with a horizontal scrollbar, with paragraph text trailing off the screen. Having to scroll horizontally to read emails is really awkward and irritating! Why doesn’t Gmail at least offer an option to auto-scale inline images to fit the width of the window?

I discovered there’s a Chrome extension to fix this. If you’re a Chrome user, just download it and you’re done.

But I don’t use Chrome, I use Safari. And there doesn’t appear to be an equivalent Safari extension. I did, however, continue down the trail to the CSS file in the GitHub project for that Chrome extension. The CSS is quite simple:

[data-message-id] > div:nth-child(2) img:not([role=button]):not([role=menu]):not([width]) {
max-width: 100%;
width: auto !important;
height: auto !important;
}

That’s all it takes to get Gmail to shrink inline images in an email to fit the window. But how do you get Safari to apply that CSS? This is not so hard, either.

First, save the above CSS code into a file, maybe called gmail.css so you’ll remember what it’s for, and save it somewhere that makes sense to you, such as your Documents folder.

Next, open the Safari preferences, and click on the Advanced tab.

Click on the Style sheet dropdown and navigate to the gmail.css file you saved. That’s it! If you have a Gmail message containing a huge image open in Safari while you’re doing this, you should immediately notice the image pop down to a reasonable size. Huzzah!

CSS text-transform can’t do “sentence case” but there’s a really simple alternative

Need to capitalize just the first letter of a text string? CSS text-transform has capitalize but that capitalizes every word.

Fortunately, you can use the ::first-letter pseudo element! In my case, I wanted all of the links in my navigation to definitely start with a capital letter, so I went with this:

#primary_navigation a::first-letter {
  text-transform: uppercase;
}

Slick!

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.