Improvements in Media component accessibility in WordPress 5.3

Form controls are still unlabelled in WordPress media views. Some don’t have associated <label> element, <aria-label>attribute or some have an empty label.

Properly labeling form controls is essential for a basic level of accessibility, as labels give form controls their accessible name. The name is then used by assistive technologies to inform users what the form control is about. Not to mention visible <label> elements are clickable and help users with motor impairments to set focus on the associated form control.

Also, the WordPress accessibility coding standards recommend explicitly associated labels (with for/id) attributes instead of implicitly (wrapping) labels.

WordPress 5.3 will now include some accessibility improvements of all the media views from controls:

  • Changes the media views form controls to have explicitly associated labels with for/id attributes
  • Adds a few missing labels / aria-labels
  • Improves a few existing labels / aria-labels
  • Improves semantics in a few places, by adding visually hidden headings, fieldset + legend elements, aria-describedby attributes
  • Improves the image custom size input fields and their labeling
  • Adds role=”status” to the “saved” indicator so that status messages are announced to assistive technologies
  • Swaps the columns source order in the image details template, to make visual and DOM order match
  • Swaps the “Replace” and “Back” buttons source order in the Replace Image view, to make visual and DOM order match
  • Gallery settings: move checkbox label to the right: checkboxes are supposed to have labels on the right
  • Merge similar strings, unified to “Drop files to upload” (removed “Drop files here”, and “Drop files anywhere to upload”)
  • Makes the “upload-ui” consistent across the media views
  • Hides the IE 11 “X” ::-ms-clear button in the Insert from URL field, as it conflicts with the uploading spinner
  • Adds comments to all the media templates to clarify their usage
  • Slightly increases the vertical spacing between form fields in the media sidebar
  • Removes some CSS selectors introduced as backwards compatibility for WordPress pre-4.4
  • Removes some CSS still targeting Internet Explorer 7 and 8
  • Fixes buttons group layout for Internet Explorer 11

The most important change to clarify is that the labeling changed from this (implicit labeling):

<label>
    My input
    <input type="text" />
</label>

to this (explicit labeling):

<label for="my-input">My input</label>
<input type="text" id="my-input" />

Simplified code sample


More details on these improvements can be found in Trac ticket #47122.

This note was drafted by @justinahinon and proofread by @afercia.

#5-3, #accessibility, #dev-notes, #media

Updates to Image Processing in WordPress 5.3

WordPress 5.3 includes several enhancements to how images are used and post-processed after upload.

When an image is uploaded to WordPress, alternate smaller sizes are automatically created. Some of these “intermediate” sizes are defined by core, and others by themes or plugins. These are used both for art direction uses, like alternate crops, and automatically by core for responsive images if they are the same aspect ratio.

Resizing images is very resource intensive. As average image sizes have increased over time, this has only increased the chances that requests may time out or run out of memory. WordPress 5.3 includes several enhancements to help more uploads succeed, and to aid users in recovery when they do not. These changes also enable WordPress to generate two new, higher resolution default sizes, to help user images look their best.

Saving of image metadata while creating intermediate sizes

Before 5.3, WordPress would first generate all intermediate sizes before saving proof of their existence in the database in meta.

This meant that if an upload failed in the middle, there could be many sizes that had completed successfully stored, but this wouldn’t be reflected in the database. A user’s only recourse was to re-upload over and over again in the hope that their server was less busy and all of the sizes would be generated.

In 5.3, this problem is fixed through saving metadata for each size as it is created in the database. This means more database writes, but allows WordPress to use the sizes generated earlier, and to resume failed uploads.

To make this possible, a new method make_subsize() was introduced in the WP_Image_Editor_GD and WP_Image_Editor_Imagick classes. It returns the new sub-size image path and dimensions ready to be added to the image meta’s sizes array. See #40439.

Additional changes:

  • Introduces wp_get_missing_image_subsizes() and wp_update_image_subsizes() to generate image sub-sizes that are missing or were not created after the upload.
  • Adds a way to display errors that happened while creating sub-sizes.
  • Introduces wp_create_image_subsizes() intended for use after an image was uploaded. It saves/updates the image metadata immediately after each sub-size is created.

With that in place it became possible to attempt to finish post-processing of images after upload if the server runs out of resources while creating intermediate image sizes (the dreaded “HTTP Error” message). See #47872.

“BIG image” enhancements

Until now it was possible to use the originally uploaded images on the front-end even when they are were not “web ready”. In WordPress 5.3 when a large image is uploaded it is stored in the uploads directory but is not used on the web site. A new scaled down image is created and used as the largest available size. This scaled down image is usually much more suitable for web use, the file size is up to ten times smaller than the original. See #47873.

Additional changes:

  • Introduces wp_get_original_image_path() that retrieves the path to the originally uploaded image in all cases.
  • Introduces big_image_size_threshold filter to set the pixel value above which images will be scaled. The same value is used as max-width and max-height when scaling the original.

These enhancements also made it possible to automatically rotate uploaded photos according to the EXIF data, and to add two additional default image sizes to better support high-density displays. See #14459 and #43524.

Thanks @mikeschroder for helping to write this post.

#5-3, #dev-notes, #media, #upload

WordPress and PHP 7.4

PHP 7.4 is in the final stages of its release cycle. As of the publish date of this post, version 7.4 RC3 has been released, and the final release of PHP 7.4.0 is scheduled for November 28, 2019.

As the expected changes in PHP 7.4 were made public earlier this year, contributors to WordPress Core worked to identify compatibility issues within the code base. Overall, the changes needed to declare full PHP 7.4 support were minor, and have all been made.

WordPress aims to fully support PHP 7.4 in the 5.3 release (currently scheduled for November 12, 2019).

Here is a breakdown of the changes in PHP 7.4 that plugin and theme developers need to be aware of and should accommodate in their code.

Changes to Curly Brace Syntax

In the past, PHP has allowed the use of curly braces ({}) to access array elements and string offsets.

<?php
$array = [1, 2];
echo $array[1]; // prints 2
echo $array{1}; // also prints 2
 
$string = "foo";
echo $string[0]; // prints "f"
echo $string{0}; // also prints "f"

Using the curly brace syntax will now trigger a deprecated notice in PHP 7.4 with the plan to remove the feature entirely in PHP 8.0 (or another future release).

For more information about this change, see the accepted proposal on the official PHP RFC Wiki, or check out what changed in WordPress Core to fix these issues in #47751.

Specific Parameter Order Requirements For implode()

The implode() function accepts two parameters, $glue and $pieces. For historical reasons, implode() has accepted these parameters in any order, though it has been a recommendation that the documented order of implode( $glue, $pieces ) be used.

Starting in PHP 7.4, tolerance for passing the parameters in reverse order is deprecated and will be completely removed in PHP 8.0. Calling implode( $pieces, $glue ) in PHP 7.4 will trigger a deprecated notice.

Note: This also affects the join() function, which is an alias of implode() and accepts the same two parameters.

For more information about this change, see the accepted proposal on the official PHP RFC Wiki, or check out what changed in WordPress Core to fix these issues in #47746.

Accessing Array Offset on Non-Arrays/Objects

PHP has previously thrown a warning only when attempting to use an offset that is of an invalid type. However, starting with PHP 7.4, a warning will also be thrown when a container is of an invalid type.

While code which relies on the undocumented behavior of PHP returning null when attempting to array access a null/bool/int/float/resource will continue to work as expected, each and every instance of this will now throw a PHP E_WARNING.

This issue is most common when using array access on the outcome of functions with mixed return values, i.e. array|false. When the return values of these function are used, more type checking needs to be done before attempting to access the return value as if it were an array to prevent this warning.

For more information about this change, see the accepted proposal on the official PHP RFC Wiki, or check out what changed in WordPress Core to fix these issues in #47704.

Note: because this issue cannot be easily/reliably detected using static analysis tools, it is possible that there are more occurrences of this issue in Core. Please open a new ticket on Trac and tag it with the php74 keyword if additional issues of this type are discovered.

Concatenation & Plus/Minus Operator Precedence

In past versions of PHP, the operator precedence of the ., +, and - operators has been exactly the same. Because of this, operations are evaluated from left to right. However, because concatenated strings generally are not numbers, this often produces undesired behavior. It’s rare that the intended behavior is to add or subtract concatenated strings.

// Example:
echo "sum: " . $a + $b;
 
// Current behavior: evaluated left-to-right
echo ("sum: " . $a) + $b;
 
// Desired behavior: addition and subtraction have a higher precedence
echo "sum :" . ($a + $b);

In PHP 8.0, the . operator will have a lower precedence than + and -. This will ensure that additions and subtractions are always performed before concatenation occurs.

As an example, the expression '3' . '5' + 7 will now be equal to “312” instead of previously “42”.

Starting in PHP 7.4, a deprecation notice will be triggered for any unparenthesized expressions containing a . before a + or -. While this is a subtle change, every occurrence of this pattern will result in a change of behavior in PHP 8.

For more information about this change, see the accepted proposal on the official PHP RFC Wiki, or check out what changed in WordPress Core to fix this issue in #47441.

Deprecated: Magic Quotes Related Functions

The magic_quotes configuration was removed from PHP in version 5.4. The function implementations that check whether or not these settings have been enabled have returned false since then. Later, PHP 7.0 removed magic_quotes entirely.

As of PHP 7.4, get_magic_quotes_gpc() and get_magic_quotes_runtime() are now marked as deprecated and they are slated for removal in PHP 8.

For more information about this change, see the accepted proposal on the official PHP RFC Wiki, or check out what changed in WordPress Core to fix this issue in #47783.

Left-Associative Ternary Operators

In most other languages, the ternary operator is right-associative. However, in PHP, it is left-associative. This behavior is generally not useful and can be confusing for programmers who switch between different languages.

In PHP 7.4, nested ternaries without explicit parentheses will throw a deprecation warning In PHP 8.0, it will become a compile-time error instead.

<?php
1 ? 2 : 3 ? 4 : 5;   // deprecated
(1 ? 2 : 3) ? 4 : 5; // ok
1 ? 2 : (3 ? 4 : 5); // ok

There were no occurrences of this pattern in WordPress Core, but it’s important to check your plugins, themes, and custom code to ensure PHP 7.4 compatibility. For more information about this change, see the accepted proposal on the official PHP RFC Wiki.

Compatibility Tooling

To help detect potential compatibility issues with supported versions of PHP, the PHPCompatibility checker has been added to WordPress Core with a custom tailored ruleset that extends the PHPCompatibilityWP ruleset.

If you build or maintain plugins or themes, it is highly recommended that you add the PHPCompatibility checker to your toolkit to make detecting PHP version compatibility issues easier and consistent. Aside from the array offset issue, all other issues mentioned in this article can be automatically detected through the use of PHPCompatibility.

When working on WordPress Core, composer compat can be run to scan the Core code base for potential compatibility issues. Furthermore, every TravisCI build will now contain a “PHP Compatibility Check” job that will scan for potential compatibility issues. This job is currently allowed to fail while the results are analyzed and the ruleset is refined to eliminate false positives.

For more information, see #46152 on Trac.

External Libraries & Dependencies

WordPress Core contributors have collaborated with the maintainers of several external libraries and dependencies to ensure compatibility with PHP 7.4.

getID3

The getID3 library was updated from v1.9.14 to v1.9.18. This update removes some occurrences of the now deprecated curly brace syntax and some code related to magic quotes. For more details, check out these pull requests, #47783, or [46112].

PHPMailer

The PHPMailer library was updated from v5.2.22 to v5.2.27 in Core and patched to prevent deprecated notices related to magic quotes from being triggered. Magic quotes has been completely removed from PHPMailer 6.0 and higher. #41750 exists to upgrade PHPMailer to the latest and greatest early in the 5.4 release cycle. For more details, check out #40472 and #47783, or the relevant changesets ([46097] and [46378]).

Requests

The Requests library was updated to address occurrences of the now deprecated curly brace syntax and accessing array offsets on non-arrays. For more details on these updates, see PR-346 and PR-370 in the Requests repository, #47746, or the related changesets ([46258] and [46416]).

SimplePie

The SimplePie library was patched in Core to prevent deprecated notices related to passing parameters to implode() in the incorrect order from being triggered. This issue is fixed in the most recent release of version 1.5.3. Upgrading the entire library to the latest and greatest with increased test coverage is being explored and is expected early in the 5.4 release cycle (see #36669). For more details, check out #47746 or [46260].

Other Updates

A few other libraries that no longer have an externally maintained canonical source have also been updated.

Summary

As always, reading through the complete upgrade document is highly recommended.

Even as WordPress Core continues to expand its support for new versions of PHP, the current support for old versions will remain as is at PHP 5.6.20 and higher until usage numbers show that the impact on users will be minimal.

There is a separate initiative to decrease the usage numbers for older versions of PHP being guided by the Core PHP team through the servehappy initiative. If you wish to help with this effort, please join the #core-php room in the Making WordPress Core Slack instance.

WordPress continues to encourage all users to run the latest and greatest versions of PHP. This includes PHP 7.4 upon its official release.

A full list of tickets related to PHP 7.4 support can be found on Trac.

Props @jrf and @jorbin for peer reviewing.

#5-3, #dev-notes, #php-7-4

Filtering nested REST response _fields in WP 5.3

WordPress 4.9.8 introduced the ability to limit the fields included in the JSON objects returned from the REST API, for example specifying

/wp/v2/posts?_fields=id,title,author

to return a list of posts with only id, title & author fields in situations where we don’t need all of the data contained in other fields like content or media (see #38131). Since 4.9.8 we’ve made further improvements to skip computing fields we did not explicitly request when _fields is present, saving time on the server in addition to slimming down the JSON response object.

In WordPress 5.3 we are adding the ability to filter by nested fields. Previously we could only request top-level properties like content or meta, which would return the full content object (with raw and rendered properties when using an edit context) or the object containing all meta values. We can now specify a nested path such as content.raw and the REST API will skip computing the rendered content, a useful performance boost for applications like Gutenberg which only require that underlying raw post content.

Now that we can register complex array or object meta, we may similarly ask for only a few of many registered meta fields, or certain properties within a complex object, using a query such as this:

?_fields=meta.meta-key-1,meta.meta-key-2,meta.meta-key-3.nested-prop

(Note that this specific meta example depends on bugfix #48266, which will ship as part of RC1.)

Thank you @timothyblynjacobs, @dlh, @danielbachhuber, and @rmccue for assisting with the development of this useful feature!

#5-3, #dev-notes, #rest-api

WordPress 5.3 adds a “Show” button next to the password field on the login screen

Many web services today display a Show button next to the password fields. The purpose being to help the user ensure that the password entered is correct.

Note that a button already exists to show/hide the password in the New User, Edit User and Reset Password pages. This functionality is now available with WordPress 5.3 on the login screen.

Here’s a quick view of the behavior of the button.


For more information on this feature, check ticket #42888 on Trac and changesets [46256] and [46372].

#5-3, #dev-notes

WordPress 5.3: Backbone Upgrade Guide

In WordPress 5.3, the version of Backbone bundled with WordPress will be updated from v1.3.3 to v1.4.0. Developers who override on and off events on their models may run into a few issues if they have listenTo events being applied to them.

Consider the example below:

// Model
class Model extends Backbone.Model {
    initialize() {
        this.collection = new Backbone.Collection()
    }

    on() {
        this.collection.on.apply( this.collection, arguments )
    }

    off() {
        this.collection.off.apply( this.collection, arguments )
    }
}

// View
class View extends Backbone.View {
    initialize() {
        this.listenTo( this.model, 'event-name', null )
    }
}

// Create an instance of Model and View
const model = new Model()
new View( { model } )

// Remove callbacks from model
model.off();

A TypeError will now be thrown at model.off, as when the model’s callbacks are removed, Backbone attempts to remove the set of listeners applied to the model as well. These sets of listeners are no longer on the model, but instead are on the model’s collection.

The reason for this is because Backbone now uses the listened object’s public on method when applying the listenedTo event, and in the example above, the on event will be applied to model.collection. A simple fix to this error is to instead pass model.collection as the object to be listened to.

For a full list of changes in this release, see the Backbone Changelog. For reference on this update, see the Trac ticket #47478.

Props @adamsilverstein and @desrosj for peer review.

#5-3, #dev-notes, #external-libraries

Introducing handling of big images in WordPress 5.3

The way WordPress handles large images has always been a topic of discussion for users and developers.

There are generally two types of images that are uploaded:

  • Images that have been edited or created in an image editing application.
  • Photos that are uploaded either directly from the camera or haven’t been edited.

In the first case, the images are usually “web-ready”. They may have been scaled down to an appropriate size and optimized.

In the second case, the images are usually much bigger than needed and are not optimized for web use. A photo taken with an average modern smartphone is easily over 5MB in file size. Photos taken with a good quality camera can be much larger.

WordPress 5.3 introduces a new way to manage these images by detecting big images and generating a “web-optimized maximum size” of them.

How does it work?

When a new image is uploaded, WordPress will detect if it is a “big” image by checking if its height or its width is above a big_image threshold. The default threshold value is 2560px, filterable with the new big_image_size_threshold filter.

If an image height or width is above this threshold, it will be scaled down, with the threshold being used as max-height and max-width value. The scaled-down image will be used as the largest available size.

In this case, the original image file is stored in the uploads directory and its name is stored in another array key in the image meta array: original_image. To be able to always get the path to an originally uploaded image a new function wp_get_original_image_path() was introduced.

Disabling the scaling

The scaling is controlled by the big_image_size_threshold filter. Returning false from the filter callback will disable it.

add_filter( 'big_image_size_threshold', '__return_false' );

For reference on this change, see Trac ticket #47873 and changesets [46076] and [46353].

#5-3, #core-media, #dev-notes

WP 5.3: Introducing the spread operator

In WordPress 5.3, the PHP 5.6 spread operator has been introduced to WordPress in a number of places.

Using the spread operator allowed for simplifying the code and improves performance – both in speed as well as memory use -, especially as it has been introduced in a number of functions which are used a multitude of times during every single pageload, such as current_user_can() and add_query_arg().

For full details, see Trac ticket #47678.

Impact on plugins/themes

Most plugins and themes should see no impact of these patches, other than the improved performance.

However, if your plugin/theme is one of the limited number of plugins and themes which extends one of the below listed classes and overloads any of the listed methods, you will need to take action.

What to do if your plugin/theme is affected

In nearly all cases, WP 5.3 has added a new parameter to the function signature using the spread operator. This allows for an easy transition as you can adjust the function signature of the method overloading it to do the same.
You may also want to adjust the code within the overloaded method to get the same performance benefits as the parent method.

See the relevant patches linked below for the full details of the change to each method and for inspiration.

Adding the extra argument will allow your plugin/theme to be compatible with both WP 5.3 and older WP versions, though it does raise the minimum PHP requirement for your plugin/theme to PHP 5.6.
Make sure you annotate this in the readme.txt!

In only one case – wpdb::prepare() -, WP 5.3 has changed an existing parameter.
In the exceptional situation that you would be overloading that method, you will need to make a choice whether you want to continue supporting older WP versions or to set the minimum WP version to WP 5.3.
If you set the minimum WP version to WP 5.3, you need to change the function signature of the overloading method to match the new function signature in WP 5.3 and you may also want to simplify some code in your method too.
If you want to continue to support older WP versions, you will need two versions of the class overload and an if/else toggle to load the correct one depending on the WP version being used.
Note: this really only applies to overloaded wpdb::prepare() methods. There is no need to do this if you overload any of the other affected methods.

What will break if I don’t make the change to my plugin/theme

Nothing. The world will keep turning as it did before.

You may get some complaints from end-users that they are seeing PHP warnings about a mismatched function signature in their PHP error logs, but other than that, all should still work as before.

This is not to say that you shouldn’t update your plugins/themes… You should.
It is just that if you don’t have time to do it right away, you don’t need to worry that your plugin/theme will be bringing sites down.

List of affected classes:

List of affected test classes:

#fortheloveofcode, #modernizewp, #5-3, #dev-notes, #php

WP 5.3 Supports Object and Array Meta Types in the REST API

With WordPress 5.3, the register_meta functions (including register_post_meta) now support the 'object' and 'array' data types. Previously, the recommended solution to create complex meta-based Gutenberg blocks was to JSON encode the block’s complex attribute value, and pass that string to the API. The REST API now natively supports those complex metadata types. This allows leveraging the REST API to perform schema-based validation, and should additionally simplify client code which interacts with these complex values through the REST API.

Importantly, these data types follow the JSON specification, not the PHP definition. For comparison, that means a JSON object type is equivalent to an associative array in PHP. The JSON array type is a numerically indexed array.

When registering a complex meta field, it is almost always required to also specify a JSON schema describing the expected structure. This can be done by switching show_in_rest from a simple true value, to an array that specifies the desired schema under the schema array key.

Object Example

The following code sample registers a post meta field called “release” that accepts the given JSON data.

{
  "meta": {
    "release": {
      "version": "5.2",
      "artist": "Jaco"
    }
  }
}
register_post_meta(
     'post',
     'release',
     array(
         'single'       => true,
         'type'         => 'object',
         'show_in_rest' => array(
             'schema' => array(
                 'type'       => 'object',
                 'properties' => array(
                     'version' => array(
                         'type' => 'string',
                     ),
                     'artist'  => array(
                         'type' => 'string',
                     ),
                 ),
             ),
         ),
     )
 );

By default, only properties that are explicitly specified in the schema will be allowed. The additionalProperties keyword can be used to to change this behavior. additionalProperties should be another JSON schema that is used to validate any unknown object members. For instance, to enforce that any additional properties are numbers, the following code can be used.

{
   "meta": {
     "release": {
       "version": "5.2",
       "artist": "Jaco",
       "unknown_field": 5.3
     }
   }
 }
register_post_meta(
     'post',
     'version',
     array(
         'single'       => true,
         'type'         => 'object',
         'show_in_rest' => array(
             'schema' => array(
                 'type'       => 'object',
                 'properties' => array(
                     'version' => array(
                         'type' => 'string',
                     ),
                     'artist'  => array(
                         'type' => 'string',
                     ),
                 ),
                 'additionalProperties' => array(
                     'type' => 'number',
                 ),
             ),
         ),
     )
 );

Additionally, additionalProperties can be set to true to allow unknown properties of any format, but this is not recommended.

Array Example

The following code sample registers a post meta field called “projects” that contains a list of project names that accepts the given JSON data.

{
   "meta": {
     "projects": [
       "WordPress",
       "BuddyPress"
     ]
   }
 }
register_post_meta(
     'post',
     'projects',
     array(
         'single'       => true,
         'type'         => 'array',
         'show_in_rest' => array(
             'schema' => array(
                 'type'  => 'array',
                 'items' => array(
                     'type' => 'string',
                 ),
             ),
         ),
     )
 );

The “items” keyword is used to define the JSON schema to validate each array member against. It can be a simple type like “string” or a complex type like “object”.

For instance, to accept the given JSON data, the following meta registration would be used.

{
   "meta": {
     "projects": [
       {
         "name": "WordPress",
         "website": "https://wordpress.org"
       },
       {
         "name": "BuddyPress",
         "website": "https://buddypress.org"
       }
     ]
   }
 }
register_post_meta(
     'post',
     'projects',
     array(
         'single'       => true,
         'type'         => 'array',
         'show_in_rest' => array(
             'schema' => array(
                 'items' => array(
                     'type'       => 'object',
                     'properties' => array(
                         'name'    => array(
                             'type' => 'string',
                         ),
                         'website' => array(
                             'type'   => 'string',
                             'format' => 'uri',
                         ),
                     ),
                 ),
             ),
         ),
     )
 );

Non-Single Metadata

Non-single meta fields have an array of values per post, instead of one value per post. Each of those values is stored in a separate row in the postmeta table.

The array and object data types can be used with non-single meta fields as well. For example, if the “release” meta key from earlier had single set to false, the following JSON data could be accepted.

{
   "meta": {
     "release": [
       {
         "version": "5.2",
         "artist": "Jaco"
       },
       {
         "version": "5.1",
         "artist": "Betty"
       }
     ]
   }
 }

This would result in two postmeta database rows. The first containing { "version": "5.2", "artist": "Jaco" } and the second containing { "version": "5.1", "artist": "Betty" }.

Similarly, the following data would be accepted for the “projects” example if it had set single to false.

{
   "meta": {
     "projects": [
       [
         "WordPress",
         "BuddyPress"
       ],
       [
         "bbPress"
       ]
     ]
   }
 }

This would result in two postmeta database rows. The first containing [ "WordPress", "BuddyPress" ] and the second containing [ "bbPress" ].

Invalid Stored Values

If the existing value for a meta field does not validate against the registered type and schema, the value for that meta field will be returned as null. This is a change in 5.3, where previously only the meta type was validated.

#5-3, #dev-notes, #rest-api

WP 5.3 introduces new functions to add UGC attribute to links, and implements it to comments

Since version 1.5, WordPress has used the wp_rel_nofollow() function to add a “nofollow” attribute to links. Version 2.3 introduced wp_rel_nofollow_callback() as a callback function to handle that addition, so developers were able to programmatically add a “nofollow” rel attribute value to any link.

Google recently announced that the “ugc” link attribute value is now supported for user generated content, like comments.

UGC stands for User Generated Content, and the ugc attribute value is recommended for links within user generated content, such as comments and forum posts.

Source: Google Webmasters Blog, September 10, 2019

In WordPress 5.3, wp_rel_nofollow_callback() will be deprecated in favor of more generic callback function, wp_rel_callback(), which is now used to add other rel attribute values to a specified link.

wp_rel_callback() is used by the existing wp_rel_nofollow() function to add a single “nofollow” value, and with the new wp_rel_ugc() function, developers can add both “nofollow” and “ugc” values to the rel attribute.

Example: usage of wp_rel_ugc()

Add a “ugc” rel attribute value to a given link:

$link = '<a href="example.com">User generated link example</a>';
$ugc_link = wp_rel_ugc( $link );
echo $ugc_link;
// output: <a href="example.com" rel="nofollow ugc">User generated link example</a>

Implementation in comments

Starting in WordPress 5.3, links in comments and comment author URLs will use the rel="nofollow ugc" attribute by default.


For reference, see Trac ticket #48022 and the related changeset [46349] in the WordPress code base.

#5-3, #dev-notes