Tom McFarlin

Software Engineering in WordPress, PHP, and Backend Development

Remove Empty Shortcodes 0.6.0

In 2019, I wrote a WordPress plugin that’s primary feature was to prevent unused shortcodes from rendering in the content whenever a page was loaded.

It worked well enough for a little while. Then time passed.

During that time (and for one reason or another):

  • I removed all of my plugins from the WordPress plugin repository,
  • I focused on a number of different things both professionally and personally,
  • And though I let this plugin remain on GitHub (as opposed to archiving it), I stopped maintaining it.

Just recently, I came across the problem of rendering orphaned shortcodes again and I noticed someone had left an issue in GitHub. So I decided to rewrite the plugin, tag a release on GitHub, and release it into the WordPress plugin repository.


Remove Empty Shortcodes, Again

The original repository page for Remove Empty Shortcodes.

When I first wrote this plugin, I had stopped using Restrict Content Pro but the shortcodes were still littered throughout various posts in my archive. And this exposed a larger problem with shortcodes as a whole:

If a user installs a plugin that uses shortcodes and then deactivates the plugin, the shortcode will still render in the content of the post.

Obviously, this muddies the content for readers by leaving artifacts of code that’s no longer running. So rather than query the database for shortcodes that were orphaned in my content or just remove a single plugin’s shortcodes, it seemed easier to do something else: Automatically remove empty or inactive shortcodes from my WordPress content while preserving the original database entries.

And that’s what this plugin does. Specifically, it intercepts the content before it’s rendered, removes the shortcodes, then passes the rest of the data back to the main process to render the content.

The updated repository page for Remove Empty Shortcodes.

This ensures that if you ever reactivate the plugin, the shortcode still exists and will work as intended.

As of this post – and this version – the plugin only works on post and page post types.

You can read all about the details for the plugin (including the FAQ) on both GitHub or the Plugin Repository but here’s the gist of information relevant to this post:

How It Works

The plugin checks your content for shortcodes when pages are displayed. If it finds shortcodes that:

  • Don’t produce any output
  • Aren’t registered with WordPress
  • Are empty or inactive

Then it removes the shortcodes from the content before rendering it in the browser.

Use Cases

  • Clean up content after removing plugins that used shortcodes
  • Remove inactive shortcodes without editing posts manually
  • Maintain clean content for readers and search engines
  • Preserve original content in case you reinstall removed plugins

Conclusion

It’s been a long time since I’ve released a plugin in the WordPress Plugin Repository (regardless of how large or small) let alone bothered writing about one on this site.

But since this is one of those things that I’m using on a site with over a decade and a half of content, it may be useful for someone else, as well.

And yes, there additional things that thing plugin could do and maybe it will but that will largely depend on adoption or my own needs or both.

Code Standard Selector for Visual Studio Code

A lot of the PHP that I currently write uses one of two standards: PSR12 or WordPress (though there are some times where I’ll pull up another project with a different standard).

For years, my standard approach to changing code standards in the IDE has been to do the following:

  1. Install the standard that’s required (if I don’t already have it),
  2. Modify settings.json in Visual Studio Code so that it uses the same standard used in the rest of the project.

It’s a little cumbersome but it worked well enough. Overtime, I end up with a lot of settings commented out that I enable based on the project.

But this was getting tedious.

Instead, I preferred to quickly select and change coding standards within the IDE via the command palette or, really, a shortcut. So I wrote a Visual Studio Code Extension to do exactly that.


Code Standard Selector

PHP Code Standard Selector is a Visual Studio Code extension that makes it easy to switch your PHP coding standard without having to edit any settings in your IDE.

Using this extension, you can view and select the coding standards in three ways:

  • The command palette, type > Select Code Standard
  • A shortcut, CMD+ALT+S or whatever the equivalent may be on Windows and Linux,
  • The status bar, which shows the currently selected standard and gives you the ability to click on said standard to change the standard

All three of these options render the same menu: A list of all of the standards installed on your system. Once selected, the extension will then automatically set that standard as the active standard and apply it to your project.

Prerequisites

Note, however, there are a few prerequisites to use this extension. Code Standard Selector assumes – and requires – you have the following set up on your system:

PHP CodeSniffer is usually installed via Composer and PHP Sniffer & Beautifier (abbreviated as PHPSAB in Visual Studio Code) is installed via the Extensions Marketplace.

And if PHP CodeSniffer is installed at the project level, it’s easy enough to update the paths to phpcs and phpcbf in your User Settings or Workspace Settings.

Installing The Extension

You can find it in the Visual Studio Code Marketplace in your browser or searching for “Select Code Standard” in the Extensions Marketplace in the IDE itself.

Or, if you prefer, you can download the lastest vsix release from the GitHub repository (where you can also grab the code, open issues, feature requests, and all of the usual options provided by a repository).

How It Works

Select Code Standard will check to make sure that the PHP Sniffer & Beautifier is installed and, if not, prompt you to install it before allowing you to actually use the extension.

Obviously, installed that particular extension implies you have at least one set of coding standards installed on your system.

Once installed, Select Code Standard will then generate a list of all standards installed on your system (by using phpcs -i) and use that to render the list of available standards.

When you select a standard, it will then use the value of the standard to tell PHP Sniffer & Beautifier what to use and it will update the extension and status bar with the standard currently in use.

Example Configuration

If you’ve not used PHP Sniffer & Beautifier before and you’re looking to get up and running quickly, here’s an example of my configuration in settings.json:

"phpsab.executablePathCS": "/Users/tommcfarlin/.composer/vendor/bin/phpcs",
"phpsab.executablePathCBF": "/Users/tommcfarlin/.composer/vendor/bin/phpcbf",
"phpsab.fixerEnable": true,
"phpsab.snifferShowSources": true,
"phpsab.standard": "PSR12",
"php.validate.run": "onSave",
"": {
    "editor.formatOnSave": true
},

Notice the line that contains phpsab.standard. This is the one that Select Code Standard will modify when you select your own standard from the extension’s interface.

Issues, Requests, Future Versions, etc.

I built this extension for me because I wanted to have an easy way to quickly change standards (and because I’d never built an extension for Visual Studio Code before).

If you’re a developer using PHP and have a similar set up – or are looking for a way to update your set up to something that works well with the aforementioned configuration – maybe this extension will help.

Further, I’ve set up templates in the GitHub repository for opening issues, bug reports, feature requests, and so on. You can read more about the plugin in the README, as well.

Finally, although the plugin can be automatically updated from within the Extensions Marketplace, each version will be released on GitHub prior to deploying in the marketplace. So if you typically follow – or star – repositories to track development, that’s an option.

With that said, I’m already using the Select Code Standard and it’s serving its purpose exactly as I need. If it works for you, great. And if you have issues, requests, or anything else, please open an issue.

Move Fast but Understand Things

In Beware of the Makefile Effect, the author defines the phrase as such:

Tools of a certain complexity or routine unfamiliarity are not run de novo, but are instead copy-pasted and tweaked from previous known-good examples.

If you read the article, you’ll see that there are a number of examples given as to what is meant by the phrase.

Originally, makefiles were files used for C (or C++) build tools to help assemble a program. This is not unlike:

Just as developers have long been susceptible to the ‘Makefile Effect’ when it comes to configuration files, the rise of generative AI tools brings a new risk of compounding a lack of understanding. Like copy-pasting Makefiles, using AI-generated code without fully following how it works can lead to unintended consequences.

Though it absolutely helps us move faster in building The Thing™️, it’s worth noting: Many of these configuration files are the result of taking a working version and copying and pasting them into our project, tweaking a few things until it works, and then deploying it.

As it currently stands, we may not be copying and pasting pre-existing files, but generative AI may be close enough (if not a step further): It produces what we need and, if it doesn’t work, we can just tell it to keep tweaking the script based on whatever error is returned until we have something that works.

It’s obviously not limited to configuration files, either. Let’s include functions, classes, libraries, or full programs.

Again, the advantage this gives us now versus just a few years ago is great but failure to understand what’s being produced has compounding effects.

To that end, prompt the LLM to explain what each line or block or function is actually doing and then consider adding comments in your own words to explain it. This way, future you, or someone else, will have that much more context available (versus needing to feed the code back into an LLM for explanation) whenever the code is revisited.

Perhaps this will help to resist the makefile affect as well as a lack of understanding as to whatever code is being produced and ultimately maintained.

Strategies for Locally Developing Google Cloud Functions

For the last few months, I’ve been doing a lot of work with Google Cloud Functions (along with a set of their other tools such as Cloud Storage, PubSub, and Cloud Jobs, etc.).

The ability to build systems on top of Google’s Cloud Platform (or GCP) is great. Though the service has a small learning curve in terms of getting familiar with how to use it, the UI looks exactly like what you’d expect from a team of developers responsible for creating such a product.

An Aside on UIs

Remember how UIs used to look in the late 90s and early 00s? The joke was something like “How this application would look when designed by a programmer.”

UX Planet has a comic that captures this:

If developers were responsible for UIs.

I can’t help but think of this whenever I am working in the Google Cloud Platform: Extremely powerful utilities with a UI that was clearly designed by the same types of people who would use it.

All that aside, the documentation is pretty good – using Gemini to work with it is better – and they offer a CLI which makes dealing with the various systems much easier.

With all of that commentary aside, there are a few things I’ve found to be useful in each project in which I’m involved when they utilize features of GCP.

Specifically, if you’re working with Google’s Cloud Platform and are using PHP (I favor PHP 8.2 but to each their own, I guess), here are some things that I use in each project to make sure I can focus on solving the problem at hand without navigating too much overhead in setting up a project.


Locally Developing Google Cloud Functions

Prerequisites

  • The gcloud CLI. This is the command-line tool provided by Google for interacting with Google Cloud Platform. The difference in this and the rest of the packages is that this is a utility to connect your system to Google’s infrastructure. The rest of the packages I’m listing on PHP libraries.
  • vlucas/hpdotenv. I use this package to maintain a local copy of environmental variables in a .env file. This is used to work as a local substitute for anything I store in Google Secrets Manager.
  • google/cloud-functions-framework. This is the Google-maintained library for interacting with Cloud Functions. It’s what gives us the ability to work with Google Cloud-based function locally while also deploying code to our Google Cloud project.
  • google/cloud-storage. Not every project will serialize data to Google Cloud Storage, but this package is what allows us to read and write data to Google Cloud Storage buckets. It allows us to write to buckets from our local machines just as if it were a cloud function.
  • google/cloud-pubsub. This is the library I use to publish and subscribe to messages when writing to Google’s messaging system. It’s ideal for queuing up messages and then processing them asynchronously.

Organization

Though we’re free to organize code however we like, I’ve developed enough GCP-based solutions that I have a specific way that I like to organize my project directories so there’s parity between what my team and I will see whenever we login to GCP.

It’s simple: The top level directory is named the same as the Google Cloud Project. Each subdirectory represents a single Google Cloud Function.

So if I have a cloud project called acme-cloud-functions and then there are three functions contained in the project, then the structure make look something like this:

tm-cloud-functions/
├── process-user-info/
├── verify-certificate-expiration/
└── export-site-data/

This makes it easy to know what project in which I’m working and it makes it easy to work directly on a single Cloud Function by navigating to that subdirectory.

Further, those subdirectories are self-contained such that they maintain their own composer.json configuration, vendor directories, .env files for local environmental variables, and other function-specific dependencies, files, and code.

So the final structure of the directory looks something like this:

tm-cloud-functions/
├── process-user-info/
│   ├── src/
│   ├── vendor/
│   ├── index.php
│   ├── composer.json
│   ├── composer.lock
│   ├── .env
│   └── ...
├── verify-certificate-expiration/
│   ├── src/
│   ├── vendor/
│   ├── index.php
│   ├── composer.json
│   ├── composer.lock
│   ├── .env
│   └── ...
└── export-site-data/
    ├── src/
    ├── vendor/
    ├── index.php
    ├── composer.json
    ├── composer.lock
    ├── .env
    └── ...

Testing

Assuming the system has been authenticated with Google via the CLI application, testing the function is easy.

First, make sure you’re authenticated with the same Google account that has access to GCP:

$ gcloud auth login

The set the project ID equal to what’s in the GCP project:

$ gcloud config set project [PROJECT-ID]

Once done, verify the following is part the composer.json file:

"scripts": {
  "functions": "FUNCTION_TARGET=[main-function] php vendor/google/cloud-functions-framework/router.php",
  "deploy": [
    "..."
  ]
},

Specifically, for the scripts section of the composer.json file, add the functions command that will invoke the Google Cloud Functions library. This will then, in turn, allow you to run your local code as if you were writing it in the Google Cloud UI. And if there are errors, notices, warnings, etc., they’ll appear in the console.

To run your function locally, run the following command:

$ composer functions

Further, if you’ve got Xdebug installed, you can even step through your code. (And if you’re using Herd and Visual Studio Code, I’ve a guide for that.)

Deployment

Next, in composer.json, add the following line to your the deploy section as referenced above:

"deploy": [
  "gcloud functions deploy [function-name] --project=[project-id] --region=us-central1 --runtime=php82 --trigger-http --source=. --entry-point=[main-function]"
]

Make sure the following values are set:

  • function-name is the name of the Google Cloud Function set up in the GCP UI.
  • project-id is the same ID referenced earlier in the article.
  • main-function is whatever the entry point is for your Google Cloud Function. Oftentimes, Google’s boilerplate generates helloHttp or something similar. I prefer to use main.

Then, when you’ve tested your function and are ready to deploy it to GCP, you can run the following command:

$ composer deploy

This will take your code and all necessary assets, bundle it, and send it to GCP. This function can then be accessed based on however you’ve configured it (for example, using authenticated HTTP access).

Note: Much like .gitignore, if you’re looking to deploy code to Google Cloud Functions and want to prevent deploying certain files, you can use a
.gcloudignore
file.

Conclusion

Ultimately, there’s still provisioning that’s required on the web to set up certain aspects of a project. But once the general infrastructure is in place, it’s easy to start running everything locally from testing to deployment.

And, as demonstrated, it’s not limited to functions but also to working with Google Cloud Storage, PubSub, Secrets Manager, and other features.


Finally, props to Christoff and Ivelina for also providing some guidance along setting up some of this.

Review and Highlights of 2024

I usually don’t write a full “year in review” type of post, but I do sometimes highlight various milestones, goals, and/or notable things that have happened in the last year. And this year, I’ve both the desire and time to write about exactly that.

When drafting the last post, I re-read some of the posts I’d published in the past. While it’s fun to see how things evolve over the years, it also provides a guide for how to write these kinds of posts even when I feel out of the habit.

So here’s a summary of the highlights from this year.


Highlights of 2024

Most Popular Posts

Books

For the past couple of years, I’ve been trying to read two books simultaneously – one fiction and one non-fiction. I don’t participate in book clubs, I don’t try to accomplish a certain number of books per month (or year or whatever other unit of time), and I don’t always try to grab whatever the most recent best seller is.

Instead, I try to read the things that I want and that seem relevant, interesting, and/or helpful. I read a total of 20 books this year (10 fiction, 10 non-fiction).

Here are the things I enjoyed the most:

Omission from this list doesn’t mean that I didn’t like it or that it wasn’t something educational. I tried to limit this list to one book from each category but I couldn’t do it so I arbitrarily decided to include two from each instead.

Fitness

Over the years, I’ve tried to make exercise a consistent part of my day-to-day. On the whole, I’ve been good about it even though the type of fitness I do each year tends to change.

Some years, I’ve done nothing but run. Other years, I’ve incorporated some type of guided program. And there are other times where I’ve mixed it up between the two.

This year was kind of like the latter: I was running at least two-to-three 5Ks a week and lifting weights every other day. Unfortunately, I pinched a nerve in my back in September and that brought everything to a grinding halt.

I started walking every day once again in November but that’s about the extent of what I’m doing. My goal is to get back to both cardio and basic weight lifting in January, but we’ll see.

Lastly, if you workout and have an Apple Watch or an iPhone, I recommend Gentler Streak. It’s far an away my favorite fitness app primarily because it aims to keep you moving and in a healthy state without having you just blindly try to close your rings.

Music, TV, and Podcasts

My favorite music from 2024 include the following albums:

  • Moment of Truth by the Red Clay Strays (and their Live At The Ryman album is absolutely worth it, too). If there was a way to capture 50s rock and roll with 70s southern rock and timeless blues lyrics, this is the band.
  • Deeper Well by Kacey Musgraves. I’ve been a fan of hers for a longtime. Golden Hour is still my favorite by her and I haven’t really been a fan of anything sense, but Deeper Well is a bit of a return to form.
  • Rebel Diamonds by The Killers. This is more of a greatest hits collection but if you’ve never listened to the band or are looking to hear how their sound has changed over the year, it’s a good listen.
  • I started listening to Wild Rivers this year and am a fan of what I’ve heard so far. I can’t recommend any single album since most of their songs came up in a recommended playlist.

Most of the shows I watch during the year are whenever I’m on the treadmill or it’s the period between when the kids are done for the day and Meghan and I are still up.

  • Only Murders in the Building. I thoroughly enjoy Steve Martin and Martin Short’s comedy in this show (and Selena Gomez holds her own with them while also balancing them out). We’ve not watched the most recent season yet, but very much enjoy this show so far.
  • From. It’s hard to succinctly describe this show. If you’re into sci-fi horror, then read up on the premise on Wikipedia. It’s shame how much time passes between seasons, but that seems to be the norm in the age of streaming. I wish this show was available on a platform with a wider reach
  • Shrinking. I didn’t start watching this until October but am glad I did so much so that I watched it once through on my own then and immediately watched it through again with Meghan. If you’re a fan of Scrubs, you’ll likely love this show.

I was going to do a Music, Movies, and TV section but I can count the number of movies I watched this year on one hand so I’m mixing it up and adding the podcasts I enjoyed the most this year.

This is not an exhaustive list nor is my sharing this saying I’ve listened to every single episode (unless I mention it, obviously). But they are the ones that kept me coming back a few times a month.

To 2025

Since the majority of what I write here on a daily, weekly, monthly basis primarily has to do with my day-to-day, I try to cover anything outside of that in posts like this.

And these are the highlights for 2024. Like most, I have things that I’m planning to do in 2025 though I’ll wait until this time next year to share how everything went.

If anything the last couple of years has shown me, it’s that this stage of life – while great – has all kinds of ways for making it difficult to make concrete plans. So beyond the high-level goals of reading, working out, listening to music, and writing, there’s not much more to add.

Whatever it is you’ve planned for 2025, here’s to it all going well. And if not, here’s to having the fortitude to push through.

« Older posts

© 2025 Tom McFarlin

Theme by Anders NorenUp ↑