Debugging WordPress and PHP 8.1: a chicken-and-egg conundrum

If you’re a WordPress developer, trying to debug code on a server that’s running PHP 8.1, you may have noticed an absurd number of deprecation notices overwhelming your efforts to get anything done.

After trying in vain to resolve the issue by updating the value for error_reporting in my server’s php.ini file, I discovered why that doesn’t work, courtesy of a StackExchange answer.

WordPress sets its own value for error_reporting when you turn on WP_DEBUG, ignoring the php.ini value. It kind of has to do this. (Well, not “kind of.”) That’s the only way for WordPress to display more — or less — error output than what’s configured at the server level.

The problem is, when you turn on WP_DEBUG, WordPress shows you everything. Normally that would be desirable, but PHP 8.1 has introduced an unusually large number of deprecation notices in anticipation of PHP 9 imposing strict rules on things that have been generously allowed in earlier PHP versions.

OK, so we know what’s going on. But since a lot of the deprecated code is in WordPress core, or in third-party plugins, there’s not really anything a developer like me can do about fixing these issues. (Sure, I could fix it and submit a pull request, but I’m not currently a WordPress core developer and I am not sure I want to take that on, even in an extremely peripheral way.)

So… uh… how do I just make it stop? That is definitely easier said than done, and the reason is the sequential nature of how code is loaded and executed. “Everything everywhere all at once” is not how it works. WordPress loads one file, that loads another file, that loads several other files, each containing a mix of procedural and object-oriented code, and functions. The way WordPress lets you hook into that flow and insert modifications is… well.. hooks.

Hooks are great, but a) the hook you want has to exist, and b) your code that uses the hook needs to be loaded before WordPress processes the hook. Oh, and of course, c) hooks themselves are functions, so you can’t use them until those functions have been defined.

Hence our problem. The code that tells WordPress to show you all the stuff — errors, warnings, deprecation notices — happens pretty early in the sequence. Specifically (as of WordPress 6.1.1) it is in line 460 of wp-includes/load.php in a function called wp_debug_mode(). By that point, yes, the add_action() and add_filter() functions have been defined. But, WordPress hasn’t actually loaded any plugins yet (even “must-use” plugins in the mu-plugins folder). So if you write a plugin to modify the error_reporting value, it might work, but only on deprecation notices that are generated after your plugin has been loaded, and the ones we’re concerned with are all in WordPress core and get triggered before plugin loading starts.

Realizing this, I thought I might solve the problem by putting my filter into the wp-config.php file, a.k.a. the only “early” file you’re allowed to edit. But nope, can’t do that: the add_filter() function doesn’t exist until wp-includes/plugin.php gets loaded at line 49 of wp-settings.php, which itself gets loaded at the very end of wp-config.php.

Since wp_debug_mode() runs at line 80 of wp-settings.php, that means the only way to do what we’re trying to accomplish is to get it to fire off somewhere within those 31 lines of code inside wp-settings.php. Those lines consist of calls to a handful of low-level functions. I checked the source code of each of them for any hooks — not that it would be correct to use the hooks in any of those functions for this purpose, if they existed — but merely to see if it would even be possible.

There is only one hook in the entire lot, and it’s inside wp_debug_mode() itself. It’s called enable_wp_debug_mode_checks. I wrote my own filter function that leverages that hook to modify error_reporting, and it would work, except for the fact that there’s nowhere to put it. I can’t write any custom code in a plugin or theme to call that filter, because it wouldn’t be loaded yet by the time the filter is applied in wp_debug_mode(). And I can’t put it in wp-config.php because, as noted above, the add_filter() function isn’t even defined yet at that point.

So… there are only two place you can put this code to get it to work: either in wp-settings.php just before line 80, or by just editing the wp_debug_mode() function itself in wp-includes/load.php. And you very much are not supposed to do either of these things, because your changes will get overwritten the next time a WordPress core update runs.

But… what else are you going to do? Well… after going through all of the emotions on my wide spectrum from frustration to rage, I read the comments at the top of wp_debug_mode() that start with a pretty unambiguous statement:

This filter runs before it can be used by plugins. It is designed for non-web runtimes.

OK then.

Also inside the comment is a code example, mirrored in the next reply on the same StackExchange post I linked above. I initially ignored it because I instinctively ignore any PHP code example that includes $GLOBALS… but in this case, it’s apparently the official answer on the matter. Boo.

The code I ended up putting into wp-config.php looks a bit different though:

if (WP_DEBUG) {
  $GLOBALS[‘wp_filter’] = [
    ‘enable_wp_debug_mode_checks’ => [
      10 => [[
        ‘accepted_args’ => 0,
        ‘function’ => function() {
          error_reporting(E_ALL & ~E_DEPRECATED);
          ini_set(‘display_errors’, ‘on’);
          return false;
        },
      ]],
    ],
  ];
}

I’m not sure why the StackExchange poster put the error_reporting() call outside the conditional. I also found I needed to specifically set ini_set('display_errors', 'on'); because returning false from this function causes the rest of wp_debug_mode() not to execute — which we want, but we need to make sure to replicate any of the rest of its functionality that we do need. I probably should add the bit that doesn’t output errors on REST/AJAX calls, but I’ll worry about that when it becomes an issue. I don’t use either of those very often. (Of course the WP admin itself uses AJAX all the time.)

A few reasons why you should keep your old domain name indefinitely, even if you’ve changed your business name and never plan to go back

What follows is a slight reworking of an email I just sent to a client. I think it’s broadly useful enough that it deserves to be shared publicly.

Here’s the scenario: The client’s family business operated for many years under her father’s name, but when he retired and she took over, she changed the name. In the several years since, she has built a strong reputation for the new identity, and she was wondering if it was finally time to let the old domain name lapse.

Short answer: No!

Here’s the longer answer, which also addresses the natural follow-up question: Why?

First, “google” your old domain name. Just go to Google, type the old domain name in the search bar, and see what comes up. You may be surprised how many websites out there still have links to URLs with your old domain.

Assuming you kept the old domain configured as an alias when you built your new website, if you keep the domain, those old links will still work, and redirect to the current site. If you were to let the domain lapse, those links would stop working. (Whether or not anyone is actually clicking those links is another matter, of course. If you have Google Analytics or other site stats, check your referrers for some insight on that.)

The same goes for email. Some people may still have old business cards, or for other reasons might still try sending email to those old addresses. If you have them configured to forward (which, again, you should have done when you initially made the switch), then you’ll still get those messages.

Another thing to keep in mind: if you let the old domain lapse, someone else will be able to register it, and could put it to nefarious use — phishing, scams, or just generally sleazy content. I have seen it happen. Even the best case scenario — no one registering it — will result in it loading a “this domain is available” placeholder page with the domain registrar, which may give people the impression you’ve gone out of business.

Given the relatively low annual cost of a domain registration, my recommendation is that you should keep your old domains registered for as long as you’re in business.

Web standards: a Win-Win-Win situation

Today is the fourth annual “Blue Beanie Day,” a tradition established by the father of web standards, Jeffrey Zeldman.

What are web standards? Simply put, they’re awesome. But seriously… the goal of web standards is to establish a set of best practices for web designers and developers, and a set of open, shared languages and tools for building websites and displaying them in a consistent manner.

At the heart of the modern web standards movement are a set of three core languages: HTML5, for organizing and structuring content; CSS3, for designing the presentation of that content; and JavaScript, for providing rich interaction with that content.

HTML5, CSS3, and JavaScript are all open standards. The specifications are published for anyone to see; they’re open and evolving, for anyone to contribute to; and they’re freely available for anyone to build an application for rendering content delivered via these languages (in common parlance, a web browser, but we’re starting to see “web” content appearing in all sorts of applications for computers and mobile devices these days).

But why are these three web standards so great? Because they create a win-win-win situation:

A win for web designers/developers. By establishing a common set of tools that are open and free to anyone, web designers and developers can get started with no barriers to entry. Plus, by standardizing these tools, the same skills can be applied anywhere a website is being built. And as web browser makers adopt these standards, the last 15 years’ worth of browser-to-browser inconsistency will fade. Our job is made easier, we can get more done in less time, and, with powerful frameworks like jQuery built on top of these standards, this power to do more with less will grow exponentially.

A win for site owners. If you’re paying to build a website, you want to know you’re spending your money wisely. You want your investment to last, and you want to make sure everyone who wants to access your site, can. Web standards are the key to an accessible, reliable, “future-proof” website. Some Internet technologies may come and go; jumping on the latest trend may make your site seem “with it” today, but tomorrow it will be painfully dated… if it even works at all. But these three core web technologies will always be at the heart of the web. Plus, a site built with web standards will automatically be structured well for search engine listings, without the need for expensive and questionable SEO tactics.

A win for Internet users. Web content that is built and delivered with a diligent adherence to web standards will work reliably with any device, any software, that is used to access the Internet. Plus, no well-formed, standards-compliant HTML page ever crashed a web browser.

Web standards: Win-Win-Win.

This proves my theory!

Further knocking Apple down from its pedestal (not that I’m not still a rabid fanboy as mentioned in the previous post), we have this further proof of my theory that although Steve Jobs usually has impeccable instincts, once he gets something stuck in his craw, no matter how outlandish it is, Apple simply must go through with it.

I’ve been thinking this a lot in regards to the grand trilogy of Leopard GUI design decisions that have been widely criticized by the world of Mac users (including myself): the translucent menu bar, the 3-D Dock, and the Stacks icons. But now here’s some proof that this really does go on (if you accept it as proof, which I do in this case), from the hardware side. The left side, to be specific, of the current MacBook line. I happen to be sitting in front of one right now, and I can vouch for this. The left side is “squishy,” right where those two screws are. They’re clearly not attached to anything! Therefore, they must be purely cosmetic.

Which is pretty ridiculous, when you think about it.

Even I am not this much of an Apple fanboy

Wow. I mean, wow. This guy freakin’ loves Apple. He must have a giant poster of Steve Jobs in his bedroom. Either that or he owns a mountain of Apple stock.

Whatever the case, Tom Yager finds Mac OS X Leopard to be without flaw. Not only a “10” but a “Perfect 10.” There’s no way that even I can say that.

Granted, my gripes with it are petty and purely visual: the translucent menu bar; the glossy, glassy Dock; the stupid Stacks icons. I love its functionality and performance, and haven’t run into any actual problems using it (other than the fact that iPhoto is flaking out on me, but I’m running an old version and I have over 7000 photos in my library, neither of which is Leopard’s fault; and I had to upgrade Photoshop for compatibility, but with CS3 I’m glad I did that anyway).

But still… perfect? Come on. And it gets even more nauseating as the article goes on.

So yes, if you have a Mac, by all means buy Leopard; it’s $129 far better spent than on Vista. (Not that you can get a usable version of Vista for that price… but if you could, you could run it on your Mac too.) If you don’t have a Mac, now’s a great time to give one serious consideration. But if you’re still on the fence, don’t read this article first; with friends like Tom Yager (and of course the ever-insufferable Guy Kawasaki), Apple needs no enemies: this kind of sycophantic Apple-can-do-no-wrong drivel only proves the point for people who think Apple products are just for the fanboys.

For an antidote to this sickening lovefest, check out this anti-Leopard rant a former coworker just emailed to me.