The post Type declarations with WordPress filters by Peter Wilson first appeared on his blog.
]]>Seeing it come up in my timeline again recently, I started thinking about the affects of type declarations on projects, especially those with a plugin architecture.
In WordPress, most of the plugin architecture is handled via hooks: actions and filters. In particular, I was thinking about the affects of type declarations in a plugin’s filters.
Consider a plugin to prevent a particular wp-cron hook from been scheduled:
<?php
declare(strict_types = 1);
namespace Plugin1;
use stdClass;
/**
* Prevent scheduling of 'plugin1.no_run' event.
*
* @param bool|null $pre The preflight value.
* @param stdClass $event The cron event being scheduled.
* @return bool|null False if 'plugin1.no_run' event, otherwise unmodified $pre.
*/
function no_run( ?bool $pre, stdClass $event ) : ?bool {
if ( $event->hook === 'plugin1.no_run' ) {
return false;
}
return $pre;
}
add_filter( 'pre_schedule_event', 'Plugin1\\no_run', 10, 2 );
For the purposes of this article, the strict type declarations of the first parameter and the return type are the most important. In both cases the allowed values are null
, true
or false
.
The problem with this code is that it introduces a high level of implicit trust: trust in both WordPress Core and trust in other plugins you have installed on your site.
In code you are saying “I trust WordPress and other plugins to always pass null
, true
or false
to my function”.
Now consider another plugin, a plugin that uses “clever” code and decides that returning a truthy or falsy value is close enough to returning true
or false
.
<?php
function plugin2_no_run( $pre, $event ) {
// Do not schedule plugin2_no_run.
if ( $event->hook === 'plugin2_no_run' ) {
return 0;
}
return 1;
}
add_filter( 'pre_schedule_event', 'plugin2_no_run', 5, 2 );
This plugin’s code runs at priority five, before the type declared first plugin’s code. In effect, WordPress calls the functions like this:
$value = null; //default value
$value = plugin2_no_run( $value, /* event object */ );
// $value equals either 1 or 0.
$value = \Plugin1\no_run( $value, /* event object */ );
Due to the strict type declared in the first plugin, the result will be a fatal error in the first plugin: Uncaught TypeError: Plugin1\no_run(): Argument #1 ($pre) must be of type ?bool, int given
.
The fatal error is reported against the type declared plugin, even though the incorrect value was the result of the other plugin’s clever code. Not only has a fatal error been triggered, debugging the actual cause has become a painful process.
One of the things WordPress is known for is its strong commitment to backward compatibility. However, this doesn’t necessarily extend to typing: a stdClass
in one release may become a WordPress defined class in another, for example WP_Post_Type
.
In WordPress 5.7, the cron functions will be changing to allow for a WP_Error
object to be returned if the calling function requests it.
An additional parameter has been added to wp_schedule_single_event()
and wp_schedule_event()
to allow plugin authors to request further details.
The WordPress code has been written in such a way as to allow plugin authors to return a WP_Error
object from their filters, and WordPress will convert it to a boolean if needs be.
Consider a plugin that has been updated to return a WP_Error
object.
namespace Plugin3;
use stdClass;
use WP_Error;
/**
* Prevent scheduling of 'plugin3.no_run' event.
*
* @param bool|null|WP_Error $pre The preflight value.
* @param stdClass $event The cron event being scheduled.
* @return bool|null|WP_Error WP_Error if blocking event, otherwise unmodified $pre.
*/
function no_run_57( $pre, stdClass $event ) {
if ( $event->hook === 'plugin3.no_run' ) {
return new WP_Error(
'plugin3_no_run_denied',
"The 'plugin3.no_run' event can not be scheduled."
);
}
return $pre;
}
add_filter( 'pre_schedule_event', 'Plugin3\\no_run_57', 5, 2 );
The plugin author is doing everything correct, everything is in accordance with the WordPress way. Neither the first parameter or return type is declared allowing other plugins to return unexpected values.
The plugin has been updated to support WordPress 5.7 and above, and returns a WP_Error
object in the knowledge that WordPress will convert it to false
if needs be.
Again, assuming the plugin3.no_run
hook is been scheduled, let’s consider the code WordPress effectively runs:
$value = null; //default value
$value = Plugin3\no_run_57( $value, /* event object */ );
// $value is a WP_Error object for the hook plugin3.no_run.
$value = \Plugin1\no_run( $value, /* event object */ );
Once again, the typing enforced on the first plugin’s first parameter and return type will cause a fatal due to an Uncaught TypeError
.
Without the type declaration, both plugins would have been able to interact together error free.
For the boolean/truthy example above, the fatal error is only triggered in the first plugin due to the strict_types=1
declaration.
In this second example, in which the type passed is an object rather than a boolean, the fatal error occurs both with and without strict_types
declared.
For code running on WordPress filters, for the first parameter and return type I’d argue almost never. If you’re writing and thoroughly reviewing all the plugins used on a site yourself, you can probably get away with it but it introduces risk. To do so also requires a review of each version of WordPress before you upgrade.
For second and subsequent parameters running on WordPress filters, and any parameter of code running on WordPress actions, there is less risk with declaring types and you’re more likely to get away with it without errors. Again, it still requires a review of each version of WordPress before you upgrade.
For functions you are calling directly from other functions within your plugin, it is almost certainly safe to use type declarations.
Strict typing does have its benefits and can help ensure code quality and compatibility. To help address the issues with WordPress hooks, Juliette has opened a ticket proposing type aware actions and filters.
To return to Juliette’s article about the pain of upgrading projects to PHP 8, I think the problem comes from increasingly strict type rules in a runtime compiled language. The only way to detect type issues is to run the code. In projects with less than 100% test coverage (ie, most of them) problems are easily missed and may only become apparent in production.
The JavaScript world provides a good example for introducing a typed language: TypeScript. As a separate and compiled language, TypeScript allows the discovery of type errors to occur prior to runtime. The project specifically states that adding runtime errors is not one its goals.
I think compilation vs runtime design of TypeScript is something PHP could learn from.
The post Type declarations with WordPress filters by Peter Wilson first appeared on his blog.
]]>The post WordPress 5.6 released by Peter Wilson first appeared on his blog.
]]>For the first time, the release squad was made up entirely of people identifying as women or non-binary. In some corners of the internet this proved to be controversial.
Enough guys for it to be disheartening made the usual comments about choosing release squads, namely claiming that it should be a meritocracy.
None of the comments I saw came from people who were regular contributors.
Of course, what these men’s comments assume is that only a release squad with men can be merit based. This is, of course, wrong, disheartening and the men making these claims are the problem with the tech industry.
Most WordPress releases run very smoothy. The WordPress 5.6 release has been the smoothest I have seen for several releases. The release squad brought an extra layer of polish.
Members of a WordPress release squad work incredibly hard and donate a lot of time to the project. It’s not viable but I, for one, think it would be a huge benefit to the project if the the 5.6 release squad were to run another release some time soon.
So, to everyone in the WordPress 5.6 release squad: thanks folks, you’ve done an amazing job. The best I’ve seen for a while.
The post WordPress 5.6 released by Peter Wilson first appeared on his blog.
]]>The post A new (WP) Beginning by Peter Wilson first appeared on his blog.
]]>This product can in no way can be considered a typical WordPress instance as it is a highly customised edit screen used for creating articles. This was my second go round on the project; the first time I was a senior engineer at Human Made, working on it as a greenfield project. This time, I was an employee of Nine Publishing working on it as a mature project.
Yesterday was my last day at Nine Publishing, and after a lovely farewell get together with the team I signed out of G-Suite, Slack and I deleted my local Git repositories. Working on such a project once is privilege enough, to have the chance to work on it twice was an immense pleasure.
I’m taking a three day weekend before starting at the new job on Monday.
So what’s next? A few weeks ago a post from WP Beginner was retweeted into my timeline… I don’t know, roughly 200 times… their parent company Awesome Motive was looking to employ a developer to work on WordPress Core almost full time.
BuiltWith reports WordPress powers 10% of all websites they monitor, and 34% of the top one-million. W3Techs report slightly different numbers based on the top ten-million. I find the percentage of all sites slightly more interesting, because that includes everything from small sites, like this one, right through to news outlets getting a ridiculous amount of traffic.
Regardless of the numbers you find interesting, the point is that WordPress powers a lot of websites and a lot of different types of websites. To me, that makes it one of the most interesting CMS projects in the world. So I quickly decided to apply for the role at Awesome Motive.
As a result, from next week, I’ll be working on WordPress Core four days a week, and on Awesome Motive’s FOSS plugins for the remaining time.
At this stage, I am hoping to split my WordPress time between working on public tickets and other projects in the background. I have tickets and components I find interesting, no doubt my new boss, Syed, has his interests and, of course, there is the WordPress roadmap too.
Exactly what the new role will look like, I am yet to find out. What I can tell you is that I am very excited that I will be able to spend more time working on WordPress than I have previously had available.
When working on WordPress I try to focus on what is best for the product, from small through to large sites. That is a goal I hold dear and the starting point of this new role. I’m looking forward to seeing how I can put this in to practice with more dedicated time on the project.
Thank you to Dee Teal and Toby Sullivan for reviewing a draft of this post.
The post A new (WP) Beginning by Peter Wilson first appeared on his blog.
]]>The post This week I’m sick of it by Peter Wilson first appeared on his blog.
]]>Mostly, I’m sick of avoiding my friends and family like the plague.
The post This week I’m sick of it by Peter Wilson first appeared on his blog.
]]>The post Nick Cave’s stream is not the problem by Peter Wilson first appeared on his blog.
]]>Trying to reload the video’s page on my iPad Pro last night, the browser had crashed. This suggests to me that it was the tracking and social overlays on the page embedding the video that was causing the problems.
Either too much JavaScript was running, even for recent devices, or the social overlay was making too many connections back the the Dice FM server or other users signed in to the system.
Once I switched to my laptop, a typical web developer’s high powered machine, the streaming was perfect. Of course, by then I’d missed the first third of the concert.
Within 30 minutes of watching the show on my laptop, the battery had dropped back to 40%. This again suggests that JavaScript and tracking is the cause of the problem, these scripts are black holes when it comes to power usage.
As long as the tracking and social overlays remain on the page, it’s likely the show will only be viewable on powerful computers. With fewer viewers on the page at any one time it’s possible a less powerful device might work but really, that’s a roll of the dice.
The real irony of all the social crap on the page is that it’s invisible the moment a user sends the video full screen.
The post Nick Cave’s stream is not the problem by Peter Wilson first appeared on his blog.
]]>The post Accessible photo tinting by Peter Wilson first appeared on his blog.
]]>The difficulty arrises for the web developer wishing to produce an accessible site because they can never be sure what the colour of the photo will be.
A common pattern to work around this is to put a tint on the photo using a pseudo element.
Something I see too often with this pattern, is the web developer picks a value that looks good with the sample image without taking in to account how their authors will use it in the CMS.
If, as is often the case, the text is white the author may use a predominately white photo with standard sized text. If the tint isn’t strong enough the text will be difficult to read for users with the best vision, let alone for users with poor vision.
To stress test the image, you need to test the readability of your text on a background of the same colour as your text.
For white text, you need to test your semi-transparent black tint against an entirely white background, you will discover the minimum opacity to pass WCAG AA is 42%.
For clarity, to pass the WCAG AA standard, the tint needs to be rgba( 0, 0, 0, 0.42 )
. A huge white blob in your browser won’t look as nice as white text on a holiday photo, but stress testing your designs isn’t about making them pretty, it’s about accessibility.
For black text on a white tint, the minimum opacity of the tint needs to be 35% to pass accessibility standards.
I calculated these ratios using Lea Verou‘s contrast-ratio.com, which allows for semi-transparent backgrounds to be specified and will provide WCAG AA and AAA results for all possible colour combinations.
If you look at the source code of this page, you will notice that some of the ratios I have used are higher than that specified by the calculations used by WCAG to specify the accessible value.
I’ve done this for a couple of reasons: nice round numbers are easier to specify in my CMS; and, as with any algorithm, the contrast ratio calculations defined by WCAG are imperfect.
The post Accessible photo tinting by Peter Wilson first appeared on his blog.
]]>The post Using real cron for WordPress with WP CLI by Peter Wilson first appeared on his blog.
]]>wp-cron.php
file on a regular basis.
In the days before the WordPress CLI (WP-CLI), using the wp-cron.php
file was the only technique available to site owners wishing to use real cron events.
As WordPress doesn’t use real cron with wp-cron.php
, using the file has some limitations. It runs each event as request to your web server which means long running tasks may time out before they are complete.
More problematically, if your site is behind a username and password, using wp-cron.php
may fail to run in certain server configurations.
To configure WordPress to use real cron jobs requires disabling the faux cron jobs WordPress uses natively. This is done by adding a directive to the wp-config.php
file:
define( 'DISABLE_WP_CRON', true );
Disabling WordPress’s native cron instructs the Site Health Check feature to relax some of the rules around when a cron job is considered late or failed. A cron job is considered late if it hasn’t run within 15 minutes of the scheduled time, and failed if it hasn’t run within one hour of the scheduled time.
I recommend you configure your server to run real cron tasks every ten minutes to ensure you don’t get incorrect reports of errors in the WordPress dashboard.
Setting up a cron job differs depending on your web hosting provider, there is no one size fits all instruction available. For popular web hosting dashboards view cPanel’s cron job documentation or Plesk’s cron job documentation.
For the uninitiated, WP-CLI allows site owners to manipulate WordPress via the command line: you can modify posts, for example, but importantly you can also run cron events.
Many hosting providers include WP-CLI as a standard feature, especially those providing specialist WordPress hosting. This is a requirement for the modern approach to running cron.
The simplest approach is to run the following command as the cron job.
cd /path/to/site;
wp cron event run --due-now
If you have long running cron events in WordPress, the safest approach to running these is to run each task in its own process. It also prevents a fatal error in one of your events from preventing other events from running.
On the downside, the command is a little more complicated. The script becomes:
cd /path/to/site;
for hook in $(wp cron event list --next_run_relative=now --fields=hook --format=ids);
do wp cron event run "$hook";
done;
The portion of the script wp cron event list --next_run_relative=now --fields=hook --format=ids
gets a list of events ready to be run and returns them in a space separated format. On a basic install of WordPress, it might return wp_version_check wp_update_plugins wp_update_themes
if those three tasks are ready to be run.
The remainder of the script is a loop calling the wp cron event run
command for each of those tasks individually.
The important final step is to make sure it’s all working as expected. I mentioned above the Site Health pages within WordPress. One of the tests run is to ensure that scheduled events are still running.
By default, WordPress includes a task that runs every hour. As mentioned above, if a task is more than an hour late the Site Health report will considered it as failed.
After setting up your site to use real cron jobs, fill in a couple of hours (bike ride, walk the dog, make yourself a fancy dinner, whatever) and log in to your site’s dashboard and visit the Site Health page accessible to administrators in the Tools menu.
If everything is running as expected, in the passed tests section of the report you will see scheduled events are running. If that’s in the list of passed tests, you can rest easy knowing your site is using real cron jobs and everything is just dandy.
The post Using real cron for WordPress with WP CLI by Peter Wilson first appeared on his blog.
]]>The post Accessibility is more than access for all by Peter Wilson first appeared on his blog.
]]>This doesn’t feel like an access ticket, it feels like a VIP ticket.
I emailed the theatre our request and soon after had confirmed tickets. This slight friction is a necessity to prevent abuse of the system. We were told an access concierge would meet us in-front of the theatre.
As promised, on the night we introduced ourselves to an access concierge and he immediately showed us to our seats. During the night, he checked in with my friend a few times to see if she had everything she required. In short, he relieved us of the anxiety we had going in.
The theatre did not simply provide access, instead they provided equal access for all. There’s no queue for people physically unable to queue; there’s a staff member on hand to offer assistance for people needing it; there’s systems in place to prevent abuse. None of this happens without the full support of the theatre, the producers and their collective staff members. Basically everyone in the room.
Web designers and developers reflect the world, in that we are prodemently able bodied and do not require screen readers, can use a variety of input devices, and we see content as it is visually represented on screen.
As a result, accessibility often becomes an afterthought. We build a feature in such a way that it makes sense to us, can be used by us on our touch screens and with our mouses. We move fast and break things.
If time and budget allows, we might go back and think about accessibility later. Add in a few ARIA attributes to improve accessibility for screen readers.
This presents a problem, accessibility becomes an afterthought. The reason Hamilton West End blew us all away was because they treated access as a first class citizen, to provide equal access for all on the web, we need to do the same.
To provide equal access for all on the web requires the support of everyone involved, client stakeholders, sales staff, content strategists, startup founders, designers and developers. Everyone.
Code, content and design are the backbone to accessibility, but to truly build a website providing equal access to all requires advocacy within your organisation.
The post Accessibility is more than access for all by Peter Wilson first appeared on his blog.
]]>The post Vote Yes! Pull Request by Peter Wilson first appeared on his blog.
]]>Add the following to the bitbucket domain using Stylish.
@import url(https://peterwilsoncc.github.io/vote-yes-pull-request/bb.css);
Why? Because I am not one to let an offhand comment go unimplemented.
Replaces ‘Approve’ button with ‘Vote Yes’ in bitbucket?
— Tarei King (@tareiking) October 6, 2017
The post Vote Yes! Pull Request by Peter Wilson first appeared on his blog.
]]>The post Allow developers to make mistakes by Peter Wilson first appeared on his blog.
]]>The HTML has at least lost its font tags and table based layouts but my overall reaction is to wish I could curl up and hide.
The code is full of the kind of mistakes you’d expect of a new developer. Magic numbers, CSS and JavaScript files are hardcoded in the header rather than enqueued. Escaping has since been added.
If I could rewrite the site from scratch, I would.
If I could rewrite the site from scratch, I would. I would not go back in time and avoid newbie developer mistakes. Discovering these mistakes is a big reason I am the developer I am today.
The benefit of making mistakes comes from discovering you have made them. The slight embarrassment you feel helps you remember the code required to avoid them later.
Every line of code I write at work gets reviewed before going in to production. Frequently there are mistakes in my code that get picked up in these reviews, I love it and still sometimes make newbie mistakes. A recent comment: isset
check unnecessary, unset
won’t throw a notice on undefined things.
Cool, I’ve learnt something. ??
The comment above, “isset
check unnecessary, unset
won’t throw a notice on undefined things”, is to the point, helpful and – most importantly – it’s not judgmental. It takes the opportunity to educate.
We can help improve another developer’s skills by avoiding judgement when we discover a mistake.
Creating an environment where someone feels comfortable making newbie mistakes is to create an environment where someone feels comfortable learning. Be it a commercial agency or an open-source project, allowing mistakes is the most important role of an experienced developer.
The post Allow developers to make mistakes by Peter Wilson first appeared on his blog.
]]>