I just read this article on HTMX being a big deal for WordPress and I just don’t see it. To vastly simplify the article, give the code below and using the HTMX JavaScript library:

<a href="https://mysite.com/books" hx-target="#books">
	View Books

<div id="books"></div>

This tells HTMX to fetch the content at the /books location and populate it in the #books ID. Somehow this is better than making an AJAX call to do the exact same thing.

I just don’t see it. The author goes on to call WordPress a “monolithic PHP server” as if it’s a bad thing. To me it seems like people like hating on PHP and HTMX is simply a way to “make it modern” instead of using a traditional AJAX call.

I can’t say I see any benefit to HTMX at all. The good part is I don’t need to invest time into learning it then.

Bold or italics in text is often used by sighted users as described in style guides to represent book titles or other citations. How does this impact users with disabilities and users that access your site with a screen reader?

What not to use

Both <b> and <i> tags are considered WCAG compliance errors. Don’t use them.

Using a style element style="font-weight:bold" is not accessible. It only changes the appearance of the text and does nothing to convey meaning to any screen reader user. If this is a purely visual decoration this should be in your stylesheet not inline in your content.

Headings are often bold, but they should not be use simply to bold text. They are used by many users to navigate the content of a page and provide structure to your content.

Screen Readers and Bold Text

While a sighted user can see text marked with <em> or <strong> tags most non-sighted screen reader users won’t have the same notation available since screen readers don’t acknowledge <em> or <strong> unless they use a specific one and turn on the setting. Most users don’t change the defaults on anything though so this is unlikely to be a use case that could be viably considered.

What to do instead of bold?

Gov.uk has a great look at this with their Warning text. If you click through to the HTML version you’ll see a visually hidden piece of text that says Warning.

<div class="govuk-warning-text">
  <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
  <strong class="govuk-warning-text__text">
    <span class="govuk-visually-hidden">Warning</span>
    You can be fined up to £5,000 if you do not register.

Using this Warning text means that users of screen readers get the semantic meaning of the text while visual users do not see the extra warning and instead see the styled text with a graphical element denoting that the piece of text is something to take extra note of. This is the same type of notation that is recommended by Deque University

In general text your text-level semantics should be treated as a progressive enhancement instead of required to make what you’re writing understandable. If you need a bold element to make your content have the emphasis you feel it needs that’s likely a sign of bad writing. Your text should put the emphasis on the right point without the need for any extra bold markup

Is the <em> or <strong> tag the best element to describe what you’re trying to emphasize?

<cite> is intended for short citations such as book titles.

<var> is designated to represent variables or computer code and mathematical equations.

<code> is for longer blocks of code or for the code references you note here

<kbd> is designated to specify key presses to be typed be a user.

nix-shell is an excellent package manager for any macOS in large part because it doesn’t install things globally so you don’t end up with version conflicts. While you can always go to the web to search for nix packages, you can also do this from the command line if you enable the experimental features of nix.

To do this on macOS open /etc/nix/nix.conf in your editor. I use NeoVim so my command is sudo nvim /etc/nix/nix.conf. Then add the following line and save.

experimental-features = nix-commad flakes

Now you can use nix search nixpkgs nodejs to search for all the available nodejs packages in the nix repository.

Like an idiot while I was going to do a “quick” bit of work to get ahead for next week on Friday. First I decided it was time to update Homebrew before I really got into diagnosing a problem for a client. Of course mayhem ensued with the wpcli commands no longer working with LocalWP after I ran brew update && brew upgrade.

There were two main errors to search. First the icu4u library wasn’t loaded. This library is used for unicode characters and is a requirement of PHP, MySQL and a number of other things that Homebrew was managing. The specific error is below.

Library not loaded: /opt/homebrew/opt/icu4c/lib/libicuio.73.dylib

Further down in the same error block there was a note about PHP 8.0 not being installed.

Error: php@8.0 has been disabled because it is a versioned formula!

After searching and finding these general directions to remove and reinstall LocalWP, I was still out of luck. Worse, I no longer had any development sites installed locally as I removed them all during the uninstall process.

Fixing with Homebrew

Ultimately after a bunch of fruitless searching I came across this article saying that PHP 8.0 was no longer supported in Homebrew. To continue to have it installed I needed to get it from a different repository with the following commands.

  • Add the new repository to Homebrew – brew tap shivammathur/php
  • install php 8.0 – brew install shivammathur/php/php8.0

Now my wpcli commands work as expected and I no longer see the errors from icu4c. The big problem with this, and anything installed with Homebrew, is that we’re messing with my main PHP version in my shell. I’m always running PHP 8.0 now, even on projects that may need earlier or later versions of PHP.

Fixing it with nix-shell

Of course you’ll need to install nix-shell first with these instructions.

A far more portable and repeatable way to fix my issue is to use nix-shell. Instead of messing with the main versions of software running on my machine, I’m only messing with the current instance of the terminal that I’m working in.

The easy way to test this is to run the following command which temporarily installs php8.1 and wpcli in my terminal.

nix-shell -p php81 wp-cli

You’ll still get an error connecting to the database because the shell doesn’t understand how to make the connection to LocalWP but that can be fixed by going to the Database tab in LocalWP and copying the socket value into the DB_HOST value. It should look something like this:

define( 'DB_HOST', 'localhost:/Users/curtismchale/Library/Application Support/Local/run/CiNKEaTuy/mysql/mysqld.sock' );

Now when I run a wp-cli command I have a connection which means the next step is to create a shell.nix file I can place in the root directory of my project which has the values I need setup already so I don’t have to manually run them each time. This is what my shell.nix file looks like.

  nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-23.11";
  pkgs = import nixpkgs { config = {}; overlays = []; };

pkgs.mkShellNoCC {
  packages = with pkgs; [

Then when I open up my terminal I run nix-shell and the current shell is setup with php81 and wp-cli every time. I can move the same shell.nix file to a new site, or a new computer and run nix-shell and I’ll get the same environment in my shell every time.

I use MailPoet on my personal site to run my email lists and that means I sometimes have it active when I’m developing locally. When I have any site set up to develop locally I use the WP_ENVIRONMENT_TYPE constant to tell WordPress that I’m on a local site, but unfortunately MailPoet doesn’t respect this.

I found out that MailPoet is monitoring my emails (fine) and found that I had some URL’s that were unreachable at curtismchale.test because they’re on my local computer and can’t be reached by anyone but me. Thus my account was blocked from sending and marked as spam. I got a fairly pleasant but strongly worded email about sending spam and my account is now under review until I confirm that I’ve removed the curtismchale.test domain.

So instead of using built in features of WordPress to make my life easy MailPoet wants me to always make sure I disable the plugin locally so I don’t send emails. That sounds good, but I’ve found bugs in MailPoet during local development that I would not have found in a live environment. Bugs I was able to fix or work around because I was developing locally.

What MailPoet should do is what WooCommerce Subscriptions does, notice I’m on a local environment and then put up a nag about being disabled because I’m probably local and if I want it to process payments or emails anyway I have to click a button.

I never have to manually worry about WooCommerce Subscriptions trying to charge my users twice because they built a plugin that anticipates developer needs.

I’ll forget to turn MailPoet off some other time when I’m doing development and I’ll get another email about it. Maybe next time they’ll shut my account down…but that could be fixed if they added the local check.

Yes I did mention that to the support agent, but I likely won’t wait for them to add the feature. I’ll likely build a plugin that lets you choose plugins to turn off locally that will automatically turn them off if it detects WP_ENVIRONMENT_TYPE set to local.

His overall answer is no, WordPress is JavaScript focused. While I think there are a few interesting sessions that Reuben highlighted I feel disappointed to still see WP going down the React route as it is so slow.

As I wrote a few days ago, we should send HTML to users then use some JavaScript to make the interactions a bit nicer. Your whole site should work without JavaScript involved in any fashion.

All this JS crap continues to feel to me like we’re slowly heading back to the Flash days where you had to wait for loading screens.

Out of the box Varying Vagrant Vagrants lets you define a PHP version to use for each site you’re adding to the configuration file. What this doesn’t do is change the PHP version that WP CLI uses when you use vagrant ssh to log into the sites you’ve just created. Unless you take an extra step WP CLI will continue to use the default PHP version for VVV.

Installing Other PHP Versions

In your ~/vvv-local/config/config.php file you’ll see a section that looks like this.

# Extensions https://varyingvagrantvagrants.org/docs/en-US/utilities/
# are system level items that aren't websites, that install tools or packages
# the core extensions install tools such as phpmyadmin or new PHP versions
# these used to be called utilities but people kept requesting
# extensions not realising so it was renamed
  core: # The core VVV extensions
    - tls-ca # HTTPS SSL/TLS certificates
    - phpmyadmin # Web based database client
    #- memcached-admin # Object cache management
    #- opcache-status # opcache management
    #- webgrind # PHP Debugging
    #- mongodb # needed for Tideways/XHGui
    #- tideways # PHP profiling tool, also installs xhgui check https://varyingvagrantvagrants.org/docs/en-US/references/tideways-xhgui/
    #- nvm # Node Version Manager
    #- php56
    #- php70
    #- php71
    #- php72
    #- php73
    #- php74
    - php80
    - php81
    - php82

Note at the bottom of the section of code I’ve removed the comments on PHP 8.0, 8.1, and 8.2. By doing this I’ve asked VVV to install those versions of PHP when it provisions.

Setting PHP Version for WP CLI

Now we need to log into VVV with vagrant ssh. To see which versions of PHP you have available navigate to /usr/bin. Then I usually type php and hit the tab key twice to try and autocomplete the command. Since there are many things starting with php terminal shows me a bunch of options.

Now I need to set the version of PHP I want to use with sudo update-alternatives --set php /usr/bin/php8.0 if I want to use 8.0. This sets the default php call to the version of PHP you want to use for a site.

Now in the documentation for changing PHP versions in VVV there is a troubleshooting section at the bottom that talks about changing the value in vvv.nginx.conf file, but as with much documenation…it doesn’t tell you where that file is and I can’t find it. Ideally I’d change the default PHP version to 8.2 as it’s the most current version, but after looking through the docs a few times…there aren’t clear instructions on it.

If I do figure this out, I’ll update the documentation so that everyone can benefit from clear obvious documentation.

While doing a site inspection I noticed that we had over 20,000 spam subscribers on the site with addresses that lead to telegram. The WordPress admin is a terrible way to try and delete users when you have this many to do, so we turned to wp cli.

First I noted that the site couldn’t delete all the users at once because the command would time out so I used wp list user --role=subscriber --number=10 --field=ID to list 10 users and then increased the number of returned results till I was able to retrieve 5,000 users at once. Then it was a matter of combining this with wp delete user to delete the listed users. Then I ran the command a few times to clean up the site.

Our final command looked like this.

wp user delete $(wp user list --role=subscriber --field=ID --number=5000) --reassign=1

My current WordPress project has multiple custom plugins and themes with different repositories. Since I manage 80+ sites, I also end up working on bugs and features on a few different sites throughout the day which means I need to get any updates I’ve made to those custom plugins. Today I’ll show you the command I use to do that from the terminal.

find . -type d -depth 2 -exec git --git-dir={}/.git --work-tree=$PWD/{} pull origin master \;

Let’s walk through the command above so you can understand how to change it to suit your needs.

First find . searches through the current directory and we set a few options for it. -type d tells the find command to only search directories. -depth 2 tells the command to search 2 levels of directories down. I use 2 as the depth because I execute this command from the wp-content folder which lets me pull any changes to themes or plugins with a single command. -exec runs a custom command in each directory.

Next, we define the custom command to be run in each directory. git --git-dir={}/.git --work-tree=$PWD/{} pull origin master matches directories with the .git folder and then runs pull origin master on those directories.

A number of our directories have been switched over to the new default main branch as well so I run the same command a second time replacing master with main to make sure I get those repositories.

I still make sure that I have manually run git pull when I start working on a custom plugin or theme, but this command helps make sure that if I forget I’m not stuck in merge conflict hell.

For a long time, I manually changed the $version parameter when I was using wp_enqueue_script or wp_enqueue_style. At some point, I’d forget to make the change though and then some caching plugin would have issues because it wouldn’t realize that the script/style had been updated and I’d waste time wondering why I was seeing a cached version of scripts.

To combat this I started adding the version number of the plugin or theme as the $version argument in wp_enqueue_script so let’s look at how I do that.


My first stab at solving this problem was while writing a plugin and dealing with admin scripts and styles only. If this is your sole use case then get_plugin_data( __FILE__ ) will get you the information you need.

add_action( 'admin_enqueue_scripts', 'admin_enqueue' );

function admin_enqueue(){

	$plugin_data = get_plugin_data( __FILE__ );
	$version = $plugin_data['Version'];

	wp_enqueue_script( 'my_script_name', plugins_url( '/plugin-folder/path-to/script.js' ), array( 'jquery'), esc_attr( $version ), true );


Unfortunately, if you want a method that works when you’re adding scripts to the frontend and to the admin area of WordPress you’re going to be let down by get_plugin_data as this function is only defined in the WordPress admin area.

To get reliable access to this data anytime you want to add $version to your enqueued scripts you need to use get_file_data . This is available on both the frontend and the admin area in WordPress.

add_action( 'wp_enqueue_scripts', 'frontend_enqueue' );

function frontend_enqueue(){

	$plugin_data = get_file_data( __FILE__, [
		'Version' => 'Version',
	], 'plugin' );
	$version = $plugin_data['Version'];

	wp_enqueue_script( 'my_script_name', plugins_url( '/plugin-folder/path-to/script.js' ), array( 'jquery'), esc_attr( $version ), true );


get_file_data reads the first 8kb of a file for metadata embedded in the file. Then you can define the metadata values you want to be passed through in an array. The final declaration of plugin above will translate into a filter that will be named extra_plugin_headers that you could modify if needed.


The biggest caveat to using get_file_contents is that you need to be doing your enqueue work in the main plugin file that has the standard WordPress plugin headers as that is what the plugin is reading.

That works for me, and using get_file_contents I can use a standard snippet to enqueue scripts and make sure I have the version number appended all the time.