Replacing hard-coded style tags with wp_add_inline_style()

This dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase. highlights the changes made in WordPress 6.4 to style loading. The main focus of the changes was to replace manually created style tags printed at the wp_head action with calls to wp_add_inline_style(). This change was implemented to address issues related to redundant code and bypassing the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.’s style enqueuing system, which made it challenging for third-party developers to manage and control the output of style tags.

Deprecated Functions

To maintain backward compatibility, the following functions have been deprecated and replaced with the new approach:

  • print_embed_styles()
  • print_emoji_styles()
  • wp_admin_bar_header()
  • _admin_bar_bump_cb()
  • the_block_template_skip_link()

Backwards Compatibility Unhooking

Previously, when wanting to unhook certain functions like print_embed_styles() from happening at wp_print_styles(), a theme or pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party would do:

remove_action( 'wp_print_styles', 'print_emoji_styles' );

In 6.4 this print_emoji_styles() function is now deprecated. Nevertheless, the above method for preventing emoji styles from being printed is retained, even though they are now being printed by wp_enqueue_emoji_styles(). This applies to the other deprecated functions as well, so no developer action is required.

Developer Action Required

For developers who are currently using the wp_print_styles() function, whether it’s in unit tests or within their own code, some adjustments may be necessary to ensure a smooth transition. You should follow the example set by GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/. This is what you need to do:

/**
 * Remove the deprecated `print_emoji_styles` handler.
 * It avoids breaking style generation with a deprecation message.
 */
$has_emoji_styles = has_action( 'wp_print_styles', 'print_emoji_styles' );
if ( $has_emoji_styles ) {
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
}

ob_start();
wp_print_styles();
$styles = ob_get_clean();

if ( $has_emoji_styles ) {
    add_action( 'wp_print_styles', 'print_emoji_styles' );
}

This code snippet demonstrates how to handle the situation. It first checks if there’s an action hooked to wp_print_styles for print_emoji_styles(). If it does exist, it removes the action temporarily to avoid issues with style generation.

By following this approach, you can ensure that your code remains compatible with the changes introduced in this commit while avoiding any disruptions to style generation. It’s recommended to review and adjust your code accordingly if you’ve been using the wp_print_styles() function.

Exceptions

In the case of the functions for printing custom backgrounds and custom styles, converting them to use inline styles was deemed infeasible. Changing the style tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.) IDs in this context could potentially disrupt JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. functionality for several plugins in the repository. Therefore, these functions remain unaffected by this change.

Please refer to #58775 for additional details on these changes.

Props to @spacedmonkey for writing the dev note.
Props to @westonruter, @flixos90, @webcommsat, and @bph for review and proofreading.

#6-4, #dev-notes, #dev-notes-6-4, #performance

Improvements to Object Caching in WordPress 6.4

In WordPress 6.4, the Performance team has introduced several enhancements centered around object caching, leading to better handling of filters, reduced database queries, and improved overall system efficiency. 

Change the position of notoptions lookup in get_option()

In the get_option() function, a cache lookup for the notoptions key is performed; this stores an array of keys for options known to not exist. This optimization prevents repeated database queries when certain options are requested. However, the cache lookup for notoptions was conducted before checking if the requested option exists in the cache. Given that it’s more likely that the option does exist, a change has been made to reorder the checks to first verify the option’s existence in the cache before confirming its absence. This adjustment reduces redundant queries and also eliminates an unnecessary cache lookup, improving overall performance.

Please refer to #58277 for additional details on these changes.

Improvements to WP_Query caching

Forcing split queries when object caching is enabled 

WordPress introduced the ability to perform split queries starting from version 3.1. A split query occurs when the main query in WP_Query is executed to retrieve post IDs only, rather than retrieving the entire post objects. To populate the post objects, the function _prime_post_caches() is invoked, fetching the complete post information if it is not already loaded into local memory.

Before this change, split queries were restricted to posts numbering less than 500. However, this restriction has been eliminated when persistent/external object caching is enabled. This enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature. becomes even more significant with the introduction of wp_cache_get_multiple() in WordPress coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.. With this function, object caches can retrieve multiple objects in a single request, offering several benefits.

Benefits of Split Queries and Object Caching:

  • Performance Improvement: Object caches, which store frequently accessed data in memory, are substantially faster than traditional database queries. By using split queries, WordPress can fetch post IDs more efficiently, reducing the load time for your website.
  • Database Offloading: The implementation of split queries alleviates the strain on the database. With only the essential post IDs selected, less data needs to be retrieved from the database, and fewer database queries are executed.
  • Primery Key Loading: The primary key for loading the post object is the focus, ensuring that the necessary data is efficiently fetched from the object cache.

In summary, the ability to perform split queries, combined with object caching, enhances WordPress’s performance and reduces the load on your database. By opting for split queries, you can enjoy faster loading times and a smoother user experience for your WordPress website.

Please refer to #57296 for additional details on these changes.

Fix caching behavior if filters are used in WP_Query

The WP_Query class in WordPress allows developers to customize queries using various filters such as posts_fields_request, posts_request, and the_posts. These filters are instrumental in modifying both the queried fields and retrieved post objects. However, there have been cases where the use of these filters could result in incomplete or invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. post objects, lacking essential data. To address this issue and ensure data consistency and integrity, a change has been introduced.

In scenarios where the posts_fields_request, posts_request, or the_posts filters are active during a query, the get_posts() method now avoids caching post objects with the usual update_post_caches() function call. Instead, it opts for a call to _prime_post_caches(). This change is designed to prevent the caching of invalid post objects, prioritizing data consistency and integrity in filtered query scenarios.

While this enhancement ensures that invalid post objects are not cached, it may occasionally trigger new database queries to prime the post data cache. Developers should be aware that this might result in slightly increased database load in specific cases.

Please refer to #58599 for additional details on these changes.

Improved performance for WP_Query for id=>parents

In WordPress 6.2, a change was made to the WP_Query class (as documented in commit [53941]) which brought forth an unforeseen issue when querying to return fields id=>parent. This issue specifically affected websites with object caching enabled, especially when dealing with a substantial number of pages. During the second execution of this query, the _prime_post_caches() function for an id=>parent query was inadvertently triggered. This led to the unnecessary priming of post, metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress., and term caches, even when the query only requested ID and parent information.

To address this problem and optimize query performance, a new function, _prime_post_parent_ids_caches(), has been introduced. This function is responsible for priming a dedicated cache for post parents during the initial query execution. Subsequently, the wp_cache_get_multiple() function is utilized to retrieve all post parent data in a single object cache request, ensuring a significant performance improvement. Post parent caches are invalidated when the clean_post_caches() function is called. If you are updating a post in the database, please ensure that this function is called after making this update. 

Please refer to #59188 for additional details on these changes.

Improvements to WP_Term_Query caching

New cache_results parameter in WP_Term_Query

The cache_results parameter has been introduced in WordPress to provide developers with more control over the caching behavior in WP_Term_Query queries. It allows you to determine whether or not to load results from the query cache, enabling you to obtain a complete uncached result when set to false.

The cache_results parameter is a boolean parameter, and it accepts the following values:

  • true (default): Load results from the query cache (cached results).
  • false: Retrieve a complete uncached result.

This parameter is primarily designed for developers who are working on highly custom solutions and need to bypass caching mechanisms for specific queries. In most cases, it is recommended to keep the cache_results parameter enabled (set to true) in production environments. Caching is an essential performance optimization in WordPress, and disabling it may lead to slower query execution times.

In the example above, the cache_results parameter is set to false, ensuring that the query results are retrieved without using the cache.

$args = array(
    'taxonomy' => 'category',
    'cache_results' => false, // This will fetch uncached results
);

$term_query = new WP_Term_Query($args);

The cache_results parameter in WP_Term_Query offers flexibility for developers working on specialized projects. While it can be useful in certain scenarios, exercise caution when disabling caching, as it may impact performance in a production environment. Always consider the specific requirements of your project before deciding to disable query caching.

Please refer to #52710 for additional details on these changes.

Fix caching behavior if term_clauses filters are used

When utilizing the terms_clauses or get_terms_fields filters within WP_Term_Query and the selected fields are modified, the entire term object is now cached. This change was necessary because filters can broaden the selected fields beyond just the term ID. Fields linked to the term object, such as the count or parent, may undergo modifications when queried. Caching the complete object ensures the accurate storage of these modified fields within the cache.

Please refer to #58116 for additional details on these changes.


Props to @spacedmonkey for writing, @westonruter for editing.
Props to @joemcgill, @tillkruss, @flixos90 @webcommsat for review and proofreading.

#6-4, #dev-notes, #dev-notes-6-4, #performance

Improvements to Template Loading in WordPress 6.4

Improve performance of _register_theme_block_patterns() function

The _register_theme_block_patterns() function previously introduced a substantial resource overhead issue, especially noticeable when themes, such as Twenty Twenty Four, registered a large number of blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. patterns. This overhead was mainly due to the extensive file operations required by the function, including file system checks and file reads.

To address these performance issues, we have introduced caching using object cache in a new method called WP_Theme::get_block_patterns(). When theme development mode is disabled and a theme exists, the block patterns are stored in object cache. For sites using a persistent object cache, subsequent requests will use this cached data, eliminating the need for file lookups and reading files into memory, resulting in significant performance improvements.

It’s important to note that caches are also tied to the theme’s version number. Therefore, if you want to manually invalidate the cache, you can do so by changing the theme’s version number. This provides an additional method for cache management, especially useful during theme updates or changes.

Developers can bypass the pattern cache by enabling development mode for a theme, allowing for pattern additions and removals without the cache interfering. This is beneficial for accurate testing and development.

Cache invalidation occurs when themes are switched, the WP_Theme::cache_delete() method is called, or when the theme’s version number is updated. These mechanisms ensure that block patterns are not stored in the cache incorrectly.

Remove unnecessary checks if a theme file exists in the theme functions

In [56523] and [56357], WordPress theme functions were improved by removing unnecessary file existence checks, thereby enhancing performance and efficiency.

Background:
Previously, several functions and methods in the Themes APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. were designed to check for the existence of files within a child themeChild theme A Child Theme is a customized theme based upon a Parent Theme. It’s considered best practice to create a child theme if you want to modify the CSS of your theme. https://developer.wordpress.org/themes/advanced-topics/child-themes/. before falling back to the parent theme. 

However, these checks didn’t take into account whether the current theme was a child theme or not, leading to redundant file existence checks for non-child themes. This could result in unnecessary file system access and potentially slow down WordPress websites, especially in cases where there were numerous checks.

To address this issue and improve the overall performance of the Themes API, we’ve introduced an optimization that checks whether the current theme’s stylesheet directory matches the template directory before proceeding with file existence checks. This optimization significantly reduces the number of unnecessary file system accesses, as file existence checks can be resource-intensive in PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher.

As part of this enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature., we’ve updated the following functions and methods in WordPress:

  • WP_Theme::get_file_path()
  • get_theme_file_path()
  • get_theme_file_uri()
  • locate_template()

With these optimizations in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress., you can expect a noticeable improvement in the performance of your WordPress theme, especially if you have a non-child theme. The reduction in unnecessary file system access can lead to faster page load times and a smoother user experience.

Tickets: #59279, #58576

Improve performance of get_block_theme_folders()

The get_block_theme_folders() function suffered from suboptimal performance due to repeated file lookups using the file_exists() function. This resulted in unnecessary I/O operations and slowed down the process of locating block template folders within themes.

To address these performance issues and improve the efficiency of the get_block_theme_folders() function, the following changes have been implemented:

  • A new method, WP_Theme::get_block_template_folders(), has been added which incorporates basic caching, storing the result in the theme’s cache, similar to how block themes are cached in the block_theme property (as outlined in [55236]). The introduction of caching significantly reduces redundant file system lookups and optimizes the overall performance of the function.
  • Improved Error Handling: This update enhances error handling by first verifying the existence of a theme before attempting to look up the file. This proactive error handling approach helps avoid unnecessary file checks and enhances the overall reliability of the function.

Impact: 

The performance enhancement in the WP_Theme::get_block_template_folders() method will lead to quicker and more efficient lookups of block template folders within themes. WordPress developers and users can anticipate improved performance, reduced I/O overhead, and a smoother experience when working with block themes.

Ticketticket Created for both bug reports and feature development on the bug tracker.: #58319

Bundled Theme: Implement the_header_image_tag() function for enhanced compatibility for older core themes.

The the_header_image_tag() function was introduced in WordPress 4.4 as part of [35594]. It is used in all themes created since WordPress 4.4 that supported headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes. images. The function get_header_image_tag() continues to get updated with new image features, like lazy loading, async decoding and fetch priority. To ensure our core themes maintain compatibility and benefit from these enhancements, a backward compatibility shim has been applied, integrating the the_header_image_tag() function into the following core themes:

  • Twenty Ten
  • Twenty Eleven
  • Twenty Twelve
  • Twenty Fourteen
  • Twenty Sixteen

This change ensures future compatibility and modern image features are applied for header images to these older themes.

Ticket: #58675

Props to @spacedmonkey for writing this dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase..
Props to @westonruter for editing, @mikeschroder and @webcommsat for reviewing.

Edit: The implementation for caching theme patterns during pattern registration was changed from transients to standard object caches after this dev note was first published (See [56978]). This post has been updated to reflect those changes.

#6-4, #dev-notes, #dev-notes-6-4, #performance

Script loading changes in WordPress 6.4

Script loading strategies are now employed in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. and bundled themes to improve performance of loading scripts with defer and async attributes. Additionally, scripts on the frontend and login screen are now constructed using script helper functions, making it possible to utilize Content Security Policy to harden against any XSS vulnerabilities. This change also has back-compat implications for the obsolete use of the clean_url filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. to inject defer and async attributes; plugins should now use the script loading strategies APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. instead. The full details follow.

Utilizing script loading strategies

In WordPress 6.3, the script loading strategies were introduced (#12009), enabling scripts to finally have an API for marking them to be printed with async or defer without resorting to filtering script_loader_tag (or worse clean_url, per below). For more information, refer to the dev note on Registering scripts with async and defer attributes in WordPress 6.3.

In WordPress 6.4, script loading strategies are now being employed for frontend scripts in core and bundled themes. For the most part, the defer loading strategy is used since it is more consistent in its loading behavior, in that a defer script always executes once the DOM has loaded; a script with `async` may actually blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. rendering if it is already cached. 

Additionally, scripts now loading with defer have been moved from the footer to the head so that they are discovered earlier while the document is loading and can execute sooner once the document is loaded. The changes include:

  • The defer loading strategy is being used for all block view scripts, such as the Navigation, File, and Search blocks as well as any blocks added by plugins. (#59115)
  • The defer loading strategy is also now being used for the wp-embed script which is included when there is a WordPress post embed present on the page. (#58931)
  • Frontend scripts used in bundled themes also use the defer loading strategy. (#59316)
  • The async loading strategy is used for the comment-reply script, and it continues to load in the footer since it is low priority being that comments are not visible when first viewing a post. (#58870)

If there is any theme or pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party that enqueues a script that depends on any of the above scripts (which is unlikely), the script loading strategy API considers the dependents of a delayed script so that if any of them are blocking, the delayed script will also fall back to blocking. This ensures the execution order is preserved.

Eliminating manual construction of script tags

Throughout WordPress core there have been many places where script tags are manually constructed instead of relying on the helper functions wp_print_inline_script_tag(), wp_get_inline_script_tag(), wp_print_script_tag(), and wp_get_script_tag(). In WordPress 6.4 via #58664, these functions are now employed for all scripts printed to the frontend and for scripts printed on the login screen. This includes all scripts printed via wp_enqueue_script() as well as other functions that interact with WP_Scripts, namely wp_add_inline_script() and wp_localize_script(). More details on  #59446 which continues this work throughout wp-adminadmin (and super admin).

Using these helper functions makes core easier to read and maintain with less code duplication. It also opens the door to being able to leverage Content Security Policy (CSP) for hardening WordPress against script injection attacks (XSS vulnerabilities). This is due to these functions allowing additional attributes to be added to script tags via the wp_script_attributes and wp_inline_script_attributes filters, allowing the nonce attribute to be added. Refer to an example plugin that enables Strict CSP on the frontend and login screens.

On a related note to the script loading strategies above, there is one aspect of this change that breaks a prior method for adding async or defer to scripts using the clean_url filter:

<?php
// ⚠ WARNING: Do not do this.
function defer_parsing_of_js ( $url ) {
    if ( FALSE === strpos( $url, '.js' ) ) return $url;
    if ( strpos( $url, 'jquery.js' ) ) return $url;
    return "$url' defer ";
}
add_filter( 'clean_url', 'defer_parsing_of_js', 11, 1 );

This no longer works with WordPress 6.4 because the script URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org is now escaped when constructing the HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. attributes for the script tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.). So previously if it resulted in this script tag:

<script src='/wp-includes/js/underscore.js?ver=1.13.4' defer></script>

It now results in:

<script src="/wp-includes/js/underscore.js?ver=1.13.4%27%20defer"></script>

The clean_url filter (introduced in WP 2.3) never should have been used for this purpose once the script_loader_tag filter was introduced in WP 4.1. The clean_url filter runs on every single URL on the page, not just the script URLs. Also, the clean_url filter approach relied on scripts being printed with single-quoted HTML attribute values. 

Plugins continuing to use the clean_url filter in this way will find that the desired attribute is no longer injected, and that the attribute instead appears appended to the ver query parameter for the script. Plugins seeking to add defer or async attributes should instead now use the script loading strategies API. More on the dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase. Registering scripts with async and defer attributes in WordPress 6.3

Props to @webcommsat and @flixos90 for reviewing.

#6-4, #dev-notes, #dev-notes-6-4

Progressive Web @ WCUS Contributor’s Day

From whatwebcando.today you can get a sense of the large number of rich web APIs that are standard today. This is often referred to as the Progressive Web Platform. With these capabilities, alongside the use of modern development workflows and coding and performance best practices, web developers can create great user-first experiences on the web.  Similarly, the WordPress platform has also been evolving steadily since its inception, and most recently, sweeping changes are being introduced with the development of GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/.

An important part of the continued evolution of WordPress is the integration of modern Web Platform capabilities into coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. when possible, and into plugins and themes as well. We have been working on a project aimed at integrating the Service Workers API (#36995) and Web App Manifests (#43328) into WordPress core, as well as expanding core support for HTTPSHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information. (#28521). Right now this effort is been advanced under the umbrella of a PWA feature plugin.

Up until now this feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins. has primarily been collaboration between XWP and the Chrome team at Google. The pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party is a technology preview for a core foundation that themes and plugins can use to create new user experiences, like being able to access a site while offline. Service workers will also make it possible to do offline editing in Gutenberg. To be successful, the project needs the participation of the WordPress core community and wider ecosystem. We have been delaying the feature-as-plugin proposal until after Gutenberg launches, but now that WordPress 5.0 is around the corner, we want to start the formal feature-as-plugin process.

We will be at the WCUS Contributor Day in Nashville next week, and we want to discuss the current status of the PWA feature plugin and a roadmap for the work ahead. If you are interested in learning more about this proposal and possibly contribute to the project, we would love to chat.

#progressive, #pwa, #service-workers, #wcus

New Features and Enhancements with Customizer Changesets in 4.9

In WordPress 4.7 the concept of changesets was introduced in the CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings. (#30937). To understand the new Customizer improvements in 4.9, you must first go back and review what was proposed and implemented a year ago:

Customize Changesets Technical Design Decisions

Changesets are a way to persistently store changes made via the Customizer framework. Changesets contain the pending changes for any number of settings, and a setting can model any object in WordPress—whether options, theme mods, nav menu items, widgets, or even posts/pages and their postmeta. Changesets are identified by UUID (which is the post_name for the customize_changeset post type that stores the data as JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. in post_content). When a request is made to WordPress with the customize_changeset_uuid request param—whether to the frontend or to the REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/.—the Customizer framework will bootstrap and all of the values from the changeset will be read and applied to the response via WordPress filters added by the settings’ respective WP_Customize_Setting::preview() methods.

Only an authorized user can write changes into a changeset for a given setting (according to its respective capability). But once it has been written then anyone can preview the site with the changes in the changeset applied: all that is needed is the UUID. Since previewing a changeset is now a readonly operation (whereas before 4.7 it was always a POST request), a changeset can be previewed on a site by authenticated and unauthenticated users alike. With the changeset UUID supplied when opening the Customizer, a user can keep iterating on a set of changes over several days or longer and only publish them once stakeholders are satisfied. Now, freelancers and agencies will be better able to communicate and collaborate on site changes with clients.

Once a customize_changeset post transitions to the publish status then all of the values in the changeset will be passed into their respective WP_Customize_Setting::update() methods to publish (“go live”) on the site: in version controlversion control A version control system keeps track of the source code and revisions to the source code. WordPress uses Subversion (SVN) for version control, with Git mirrors for most repositories. terminology, the staged values from the changeset get committed and pushed. All of the changes go live together in a batch save operation (originally changesets were termed “transactions”).

As noted in the 4.7 merge proposal:

For the initial coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. merge, no UIUI User interface changes are being proposed. The feature will only be exposed as the new query parameter on the URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org. Adding a UI to this feature will happen in a future release.

The future [release] is now. Where the infrastructure of changesets was merged from the Customize Changesets feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins. in 4.7, the key UI features from the pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party are now being merged in 4.9 after a significant number of design iterations.

This dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase. contains sections on the following:

Continue reading

#4-9, #customize, #dev-notes

Improvements to the Customize JS API in 4.9

There are many user-facing CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings. improvements in 4.9, including: drafting/scheduling of changesets, autosave revisionsRevisions The WordPress revisions system stores a record of each saved draft or published update. The revision system allows you to see what changes were made in each revision by dragging a slider (or using the Next/Previous buttons). The display indicates what has changed in each revision., changeset post locking, frontend public previews, a new experience for browsing and installing themes, updated nav menu creation UXUX User experience, and the code editing improvements for the Custom HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. widgetWidget A WordPress Widget is a small block that performs a specific function. You can add these widgets in sidebars also known as widget-ready areas on your web page. WordPress widgets were originally created to provide a simple and easy-to-use way of giving design and structure control of the WordPress theme to the user. and Additional CSSCSS Cascading Style Sheets.But in addition to all of these, there are also many improvements for developers which will make extending the Customizer much more pleasant.

Something important to remember about the Customizer is that it is a single page application that is powered by JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/.. Many developers may only interact with the PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. for registering controls, settings, sections, panels, and partials. But controls, sections, and panels do not need to be registered in PHP at all. The PHP API for registration is essentially a wrapper for the underlying JSJS JavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors. API. When you load the Customizer all of the params for the PHP-registered constructs are exported to the client for the JavaScript API to instantiate and initially add to the UIUI User interface, but this JS API can dynamically instantiate additional constructs at any time thereafter in a Customizer session. This is how new widgets, nav menus, and nav menu items are added without requiring the entire Customizer to reload. You can also avoid statically registering settings and partials in PHP by instead adding filters to dynamically recognize settings and partials, allowing them to be registered on demand. All of this allows the Customizer application to scale out to be able to customize and preview an unlimited number of things on a site (e.g. any post or page with their postmeta in the Customize Posts feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins.). The point here is that in order for the Customizer to scale, the JavaScript API must be used directly. So this is why the Customizer JS API improvements in 4.9 are important as they fix many longstanding annoyances and shortcomings with the JS API.

This dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase. contains the following sections:

Continue reading

#4-9, #customize, #dev-notes

Widget Improvements in WordPress 4.9

On the heels of adding TinyMCE rich editing to the Text widget and the media widgets in 4.8, there are another round of improvements coming to the Text widgetWidget A WordPress Widget is a small block that performs a specific function. You can add these widgets in sidebars also known as widget-ready areas on your web page. WordPress widgets were originally created to provide a simple and easy-to-use way of giving design and structure control of the WordPress theme to the user. and Video widget in 4.9, among other improvements to widgets.

Shortcodes in Text Widget

One very longstanding request—for over 8 years—has been to support shortcodes in the Text widget (#10457). This is finally implemented in WordPress 4.9. It is no longer required to have plugins and themes do add_filter( 'widget_text', 'do_shortcode' ). CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. now will do_shortcode() at the widget_text_content filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. (added in 4.8) in the same way it is applied in the_content at priority 11, after wpautop() and shortcode_unautop(). If a pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party has added do_shortcode() to widget_text then this filter will be suspended while the widget runs to prevent shortcodes from being applied twice. If a Text widget is in legacy mode then it will manually do_shortcode() as well.

One reason for the long delay with adding shortcodeShortcode A shortcode is a placeholder used within a WordPress post, page, or widget to insert a form or function generated by a plugin in a specific location on your site. support in Text widgets was due to many shortcodes looking for a global $post when they run. Since the global $post varies depending on whatever the main query is, the shortcodes in a Text widget could render wildly different on different templates of a site. The solution worked out was to temporarily nullify the global $post before doing the shortcodes so that they will consistently have the same global state, with this global $post then restored after the shortcodes are done. So if you have shortcodes that depend on a global $post—or call get_post()—then you should make sure that they short-circuit when $post is null in order for them to behave properly if used in the Text widget.

As of [42185] this nullification of $post is only done for archive (non-singular) queries; for singular queries, the $post will instead be set to be the current main queried post via get_queried_object(). This ensures that the global $post is consistent and explicit. This setting of the $post global while applying filters (and shortcodes) is also now implemented for the Custom HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. widget. Additionally, to ensure that gallery shortcodes that lack ids do not end up listing out every attachment in the media library, a shortcode_atts_gallery filter has been added which makes sure the shortcode’s id attribute is set to -1 when the widget is rendered on archive templates. This allows you to embed the gallery for any currently queried post in the sidebarSidebar A sidebar in WordPress is referred to a widget-ready area used by WordPress themes to display information that is not a part of the main content. It is not always a vertical column on the side. It can be a horizontal rectangle below or above the content area, footer, header, or any where in the theme.. You should make sure such a Text widget is not displayed on an archive template by either adding it exclusively to a sidebar that appears on singular templates, or by using a feature like Jetpack’s Widget Visibility to hide the widget on non-singular templates.

Media in Text Widget

One reason why shortcode support in the Text widget was needed in this release is because 4.9 also allows media to be embedded in the Text widget (#40854). There is now the same “Add Media” button in the rich Text widget as on the post editor, allowing you to add images, galleries, videos, audio, and other media. To support these, core also needed to support shortcodes like captionaudiovideo, and gallery. Note there are also dedicated widgets (Image, Audio, Video, and Gallery) for these media types as well.

Having separate media-specific widgets helps with discovery and allows us to provide streamlined interfaces for each media type. For example, the Image widget now has a field specifically for supplying the link URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org (see #41274), and the Video widget now provides more guidance to users when supplying external URLs (#42039). The media-specific widgets are closely aligned with blocks in GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/; the existence of media inside the Text widget will align with eventual nested blocks in Gutenberg, and would be treated as Classic Text blocks in any future migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. from widgets to blocks.

Embeds in Text Widget and Video Widget

One shortcode not mentioned above is embed. This one was more difficult to support because oEmbeds have not been supported anywhere other than post content. This was because there were dependencies on having a post as context for the sake of caching, as the responses to oEmbed requests get stored in postmeta. However, as of #34115 if there is no post as context the oEmbeds will now get cached in an oembed_cache custom post typeCustom Post Type WordPress can hold and display many different types of content. A single item of such a content is generally called a post, although post is also a specific post type. Custom Post Types gives your site the ability to have templated posts, to simplify the concept. instead. Since a Text widget will explicitly nullify the global $post while shortcodes are processed, this means oEmbeds will get cached in this custom post type. Similarly to how do_shortcode() now applies in the widget_text_content filter like it applies on the_content, so too now WP_Embed::autoembed() and WP_Embed::run_shortcode() both also now run on widget_text_content.

In WordPress 4.8 the Video widget was introduced with support for displaying an uploaded video file, a YouTube video, or a video from Vimeo. Each of these were displayed using MediaElement.js. Just as oEmbeds are now able to be displayed in the Text widget, so too now the Video widget has been expanded to support any oEmbed provider for video. See #42039.

Theme Styling Changes

As with the previously-introduced media widgets (#32417) and the new Gallery widget (#41914), some themes will need to be updated to ensure the proper styling is applied to media and embeds that appear in the widget area context, since previously they would only appear in post content. Please follow #42203 and #41969 for style changes that are made to the core bundled themes, as you may need to make similar changes to your themes.

Improved Theme Switching

A longstanding difficulty with widgets has been where they end up when switching from one theme to another. With #39693 this experience is improved in 4.9 by having logic that is able to better map widgets between the themes’ widget areas. As noted by @obenland in [41555], there are three levels of mapping:

  1. If both themes have only one sidebar, they gets mapped.
  2. If both themes have sidebars with the same slug (e.g. sidebar-1), they get mapped.
  3. Sidebars that (even partially) match slugs from a similar kind of sidebar will get mapped. For example, if one theme as a widget area called “Primary” and another theme has “Main” then the widgets will be mapped between these widget areas. Similarly, widgets would get mapped from “Bottom” to “Footer”.

The names for the widget areas used for the mapping groups were obtained by gathering statistics from all the themes on WordPress.orgWordPress.org The community site where WordPress code is created and shared by the users. This is where you can download the source code for WordPress core, plugins and themes as well as the central location for community conversations and organization. https://wordpress.org/.

Widget Saved State on Adminadmin (and super admin) Screen

With #23120 there is now an indication for whether or not changes to a given widget has been saved on the widgets admin screen. (Widgets in the CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings. already had a saved state by virtue of being registered as regular settings.) When first opening a widget, the button will say “Saved” and appear disabled. Once a change is made to the widget (e.g. a change event triggered), then the button will become enabled and say “Save”. If you try leaving the admin screen at this point, an “Are you sure?” message will appear alerting that if you leave your changes will be lost. If you cancel, then the first widget with unsaved changes will be scrolled into view, expanded, and focused. Upon hitting “Save” the spinner will appear and then upon a successful save it will switch to “Saved” and become disabled. The “Close” link has been changed to “Done” and it only appears when the changes have been saved. Note that the HTML5 checkValidity method will now be called on the widget form prior to attempting to submit, and submitting will be blocked if it returns false. If you have JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/.-based fields in the widget, make sure that you trigger change events whenever changes are written into any hidden inputs; this was already a requirement for widgets in the Customizer.

Related Tickets

  • #10457: Parse shortcodes in text widgets by default
  • #23120: There should be indication that widget settings have been saved
  • #34115: oEmbed not working on author page without posts
  • #38017: Add widget instance to remaining widget argument filters
  • #39693: Fix missing assignment of widgets on theme switch
  • #40442: Widgets: Rename “Custom Menu” widget to “Menu”
  • #40854: Allow media to be embedded in Text widget
  • #41274: Improve discoverability of link URL in Image widget.
  • #41610: Widgets: Change “close” to “done?”
  • #41914: Widgets: Add gallery widget
  • #41969: Ensure Gallery widget is styled properly across widget areas in bundled themes
  • #42039: Widgets: Enable oEmbed support for Video widget
  • #42203: Ensure media & embeds in Text widget are styled properly across widget areas in bundled themes

See full list of tickets in the Widgets component with the 4.9 milestone.

#4-9, #dev-notes, #feature-oembed, #media, #media-widgets, #widgets

Code Editing Improvements in WordPress 4.9

The themes outlined for WordPress 4.9 are “editing code, managing plugins and themes, a user-centric way to customize a site, and polishing some recently added features over this last year.” Within the themes of editing code and polishing recent features, we’re improving the code editing functionality in the CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings.’s Additional CSS feature, the Custom HTML widget, and the PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party and Theme file editors. We included these improvements to code editing among the 4.9 goals and this release is packed with them.

CodeMirror: Syntax Highlighting, Linting, and Auto-completion

The most visible and drastic improvement to code editing in 4.9 is that there is now an actual code editing control rather than just a textarea input. If you’ve been using WordPress for a long time (over 8 years), this may sound like déjà vu. Syntax highlighting for the theme and plugin editors was originally introduced in WordPress 2.8 (#9173) but it was removed shortly after in 2.8.1 due to browser compatibility problems with the “CodePress” library (no relation to WordPress). So in the 8 years since the feature was re-proposed in #12423, after considering a slew of code editor libraries, we decided on incorporating CodeMirror:

CodeMirror is a versatile text editor implemented in JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. for the browser. It is specialized for editing code, and comes with a number of language modes and add-ons that implement more advanced editing functionality. ¶ A rich programming APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. and a CSSCSS Cascading Style Sheets. theming system are available for customizing CodeMirror to fit your application, and extending it with new functionality.

You have probably already used this CodeMirror library a lot online, since it powers the editors in many familiar products and services including Brackets.io, Bitbucket, Chrome’s DevTools, Codepen, Firefox Developer Tools, GitHubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/, and JSFiddle, among many others. In the WordPress world specifically CodeMirror is also very familiar. Jetpack switched from ACE to CodeMirror in 2013 for its Custom CSS module, and there are close to 100 search results for CodeMirror on the plugin directory. Many of them should be updated to re-use CodeMirror as bundled with coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. as well. See below for some details on how to do that.

The syntax highlighting abilities of CodeMirror can help authors catch many mistakes visually while writing code, as the color coding can quickly clue in that something isn’t right. In addition to color coding, WordPress also enables by default the add-ons which will auto-close brackets and tags, and then also highlight matching braces and tags which have already been written.

CodeMirror also supports linting to actually add explicit error checking beyond just stylistic helps. WordPress is initially bundling the following linters: CSSLint, JSHintHTMLHint, and JSONLint. See #41873 for adding a PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher linter as well, though as described below, the theme and plugin editors have a more robust means of checking for PHP errors by running the code on the server itself. The linters will report either errors or warnings with your code:

When a linter finds an error in your code (CSS, HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers., JSJS JavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors., or JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.) the code editor in WordPress will prompt you to fix the error before allowing you to proceed with saving. The nature of this error notice varies by whether the code editor is in Custom CSS control, Custom HTML widgetWidget A WordPress Widget is a small block that performs a specific function. You can add these widgets in sidebars also known as widget-ready areas on your web page. WordPress widgets were originally created to provide a simple and easy-to-use way of giving design and structure control of the WordPress theme to the user., or the file editor.

Another feature of CodeMirror which reduces mistakes is auto-completion (or hinting). As you start typing out a CSS property, JavaScript DOM object, or HTML tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.), an autocomplete dropdown will appear which you can use your keyboard to select an option:

 

There is still room for improvement with auto-completion (see #42213), but the feature does help suggest possibilities when you generally have an idea of what you’re wanting to enter.

Theme and Language Modes

For the CodeMirror library now bundled in core, we decided to not include any of the alternate themes, so the default theme is used with some styles added to bring it in line with core. Additionally we also did not include all of the language modes, as many would be very unlikely to be relevant in the WordPress context (e.g. Fortran). The WordPress-relevant modes we are including with the core bundle are: clikecss, diff, htmlmixed, http, javascript, jsx, markdown, gfm, nginx, php, sass, shellsql, xml, and yaml. If a plugin wants to use a mode that is not bundled with core, they may bundle and enqueue the mode script separately (e.g. fortran.js); a plugin may also bundle and enqueue a custom theme if desired.

AccessibilityAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) and User Preference

One of the biggest challenges when exploring the incorporation of a code editor library into WordPress was the concerns raised regarding accessibility. For users of screen readers, a plain textarea is just going to be easier to navigate and use. CodeMirror does have an inputStyle option which:

Selects the way CodeMirror handles input and focus. The core library defines the "textarea" and "contenteditable" input models. On mobile browsers, the default is "contenteditable". On desktop browsers, the default is "textarea". Support for IME and screen readers is better in the "contenteditable" model. The intention is to make it the default on modern desktop browsers in the future.

The code editor in WordPress goes ahead and explicitly defines contenteditable as being the default for both desktop and mobile due to better accessibility. Nevertheless, since there are still accessibility concerns we decided to not yet integrate CodeMirror in the post editor’s Text tab; as CodeMirror is enabled by default it could impede users of screen readers from performing the primary writing workflow upon upgrading to 4.9. Additionally, it doesn’t make sense to work on integrating CodeMirror in the post editor since it is being heavily revamped right now in Gutenberg; we should instead focus on integrating CodeMirror into GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ itself.

Lastly, if a user still does not want the CodeMirror library to be used when they edit code then there is now a user preference to turn it off. It is available on one’s user profile and it is called “Syntax Highlighting”. Again, it is enabled by default:

Additional CSS Integration

When the Additional CSS feature was introduced in 4.7, it used a plain textarea to edit the CSS code in the Customizer. For several years prior, Jetpack had already featured a Custom CSS module but it allowed CSS to be edited via a CodeMirror editor on an Edit CSS adminadmin (and super admin) screen. After 4.7 was released, Jetpack was updated to use Additional CSS in the Customizer instead, but enhanced it with the CodeMirror editor it had used on its Edit CSS admin screen. So now in WordPress 4.9, core is following suit and integrating CodeMirror into the Additional CSS feature as well (#38707), and there’s now an issue for Jetpack to newly re-use CodeMirror as bundled in core.

One key improvement from the initial implementation of Additional CSS is in regards to the detection of syntax errors. In 4.7 the error detection logic merely checked to make sure that the number of braces, brackets, and parentheses were balanced. This was not ideal because there were false positives when a balancing character was present in a comment (e.g. #39198). The goal was to eventually harden validation of CSS syntax validity by utilizing a tokenizer/parser (#39218). Instead of having to implement this logic in PHP, however, we now rely on client-side logic via CodeMirror and CSSLint to check for CSS errors and the unreliable server-side validation has been removed.

Code Editor Customizer Control

As when the Additional CSS feature was first introduced as being extensible, the updates feature new extensibility as well. When the feature was under development in 4.7 we debated whether or not to add a reusable code editor control for the Customizer. At that time we decided to opt for a regular textarea control with some enhancements since there wasn’t enough unique about the code editor to justify a separate control at that time. With the availability of CodeMirror, however, there is now justification for a reusable code editor Customizer control (#41897). This control is what is used to power the Additional CSS editor.

The code editor control may be registered in PHP via instantiating the WP_Customize_Code_Editor_Control class as can be seen in core. It allows you to pass a code_type param to indicate the file type being edited. Alternatively, an editor_settings array param may be passed which is the same format the new wp_enqueue_code_editor() function accepts (described below).

As with any Customizer control, the code editor control may also be added dynamically with just JavaScript. One example of this can be seen in the Customize Posts CSS plugin. Another example would be to add a second code editor control for Additional CSS to show up in the Colors section of the Customizer:

wp.customize.control.add( new wp.customize.CodeEditorControl( 'custom_colors', {
	section: 'colors',
	priority: 100,
	label: 'Custom CSS',
	editor_settings: {
		codemirror: {
			mode: 'css'
		}
	},
	setting: 'custom_css[' + wp.customize.settings.theme.stylesheet + ']'
} ) );

The code editor control registered for Additional CSS can itself also be extended. Either the registered custom_css control can be swapped out for a subclass of wp.customize.CodeEditorControl in JS (as seen in Jetpack PR), or the existing control can be modified at runtime. For example, in keeping with 4.7’s Custom SCSS Demo plugin, here is how you can dynamically change the Additional CSS control to use SCSS instead of plain CSS:

wp.customize.control( 'custom_css', function( control ) {

	/*
	 * CodeMirror gets initialized once the control's containing
	 * section is expanded. Note that if the Syntax Highlighting
	 * user preference is disabled, then the deferred will be
	 * rejected.
	 */
	control.deferred.codemirror.done( function() {
		var scssOptions = {
			mode: 'text/x-scss',
			lint: false, // CSSLint doesn't like SCSS.
			// The lint-marker gutter is automatically
			// toggled when lint option changes. 
		}
		_.each( scssOptions, function( value, option ) {
			control.editor.codemirror.setOption( option, value );
		} );
	} );
} );

And similarly, here is how you can change the default from CSS to SCSS via PHP:

add_action( 'customize_register', function( $wp_customize ) {
	$control = $wp_customize->get_control( 'custom_css' );
	if ( $control instanceof WP_Customize_Code_Editor_Control ) {
		$options = array();
		if ( isset( $control->editor_settings['codemirror'] ) ) {
			$options = isset( $control->editor_settings['codemirror'] );
		}
		$control->editor_settings['codemirror'] = array_merge(
			$options,
			array(
				'mode' => 'text/x-scss',
				'lint' => false,
				'gutters' => array(),
			)
		);
	}
}, 11 );

Custom HTML Widget Improvements

In WordPress 4.8.1 a dedicated Custom HTML widget was introduced in order to take over the role the Text widget had for adding arbitrary markup to sidebars, as the Text widget in 4.8 featured the TinyMCE visual editor. This new Custom HTML widget was introduced as essentially a clone of the old Text widget, aside from the absence of the “automatically add paragraphs” checkbox. Well now in WordPress 4.9 the Custom HTML widget comes into its own as it also now incorporates CodeMirror to provide users with syntax highlighting, auto-completion, and error checking. As with the Additional CSS feature, if you make a coding error in the Custom HTML widget, you will be blocked from saving until you fix the error. This guards against a misplaced div tag from breaking your site’s entire layout.

On multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site installs or any site on which an admin user lacks the unfiltered_html capability, there are restrictions for what HTML a user can provide in post content, Text widgets, and Custom HTML widgets alike. In 4.8.1 we resorted to listing out some common tags that would be illegal when a user cannot do unfiltered_html. With CodeMirror, however, this is greatly improved due to its integration with HTMLHint and because it is extensibleExtensible This is the ability to add additional functionality to the code. Plugins extend the WordPress core software. to allow custom rules to be added. There is now a custom kses rule for HTMLHint (htmlhint-kses.js) which checks HTML for any tags or attributes that are not returned by wp_kses_allowed_html( 'post' ). This means that we don’t need to tell users what they can’t do if they have no intention of doing it in the first place, and HTMLHint provides contextual inline error reporting when they do provide something invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid.. Plus, since saving is blocked when there are errors, a user’s illegal HTML will not be silently stripped from them when they attempt to save (as wp_kses_post() is still applied on the content when saving on the server).

The CodeMirror component in the Custom HTML widget is integrated in a similar way to TinyMCE being integrated into the Text widget, adopting the same approach for integrating dynamic JavaScript-initialized fields. See custom-html-widgets.js which exports a wp.customHtmlWidgets object to JS.

Just as CodeMirror has been integrated into the Custom HTML widget, once 4.9 is released a logical next step would then be to integrate CodeMirror into Gutenberg’s Custom HTML blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience., as per PR comment. Similarly, once CodeMirror is available in core it can then be explored for use in Gutenberg’s Text view (see issue).

Theme and Plugin File Editors

Now, about those theme and plugin editors. The file editor in WordPress has been the subject of much debate and skepticism over the years. This may be also why hasn’t received a lot of love in terms of improvements. For reasons why the file editor is still a valuable part of WordPress in its mission to democratize publishing, please see @melchoyce‘s post “From No Code to Pro Code”. She goes on to outline a few ways that the file editor can be improved and in WordPress 4.9 almost all of them have been implemented and beyond.

Nevertheless, when a user first visits the theme or plugin editor, they will be presented with the new warnings as follows:

Notice how the theme editor has a link directing a user to the Additional CSS feature in the Customizer. It is the hope that CodeMirror will be primarily used in Additional CSS and the Custom HTML widget, but for users who do need to make theme and plugin changes the editors have been vastly improved.

The file editors now also feature the same CodeMirror-powered syntax highlighting, auto-completion, and error checking. The allowed file extensions in the file editors can edit have been expanded to include formats which CodeMirror has modes for: conf, css, diff, patch, html, htm, http, js, json, jsx, less, md, php, phtml, php3, php4, php5, php7, phps, scss, sass, sh, bash, sql, svg, xml, yml, yaml, txt. In addition to increasing the number of editable file types, the file editors also now allow you to edit files deeper than two directories deep. And now given that the file list can be much longer than before, the files and their directories are now presented in an scrollable expandable tree like most editors provide:

When editing CSS, JS, HTML, and JSON files there is the same error checking powered by client side linters. As with Additional CSS and the Custom HTML widget, if a linter detects an error it will display an error and block you from saving the change. Here there is also a way for a user to override the error to proceed with saving anyway:

When editing PHP files, however, client-side linting is not enough (though it would be a nice enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature., see #41873). If attempting to call an undefined function this will not be a syntax error, but it will cause a fatal error and whitescreen your site. The plugin editor did previously have some basic safeguards for this by temporarily deactivating the plugin and then re-activating it in a sandbox to check for fatal errors, though it was not very reliable (see #39766). And even when it was able to check for errors, a fatal error would result in the plugin being deactivated, a plugin which could be critical to a site to function properly. For themes on the other hand, there was no such ability to temporarily deactivate the theme and do a sandboxed check for fatal errors since a theme cannot be deactivated like a plugin can.

Ultimately what was worked out in #21622 was a new sandboxed method for making PHP file changes in both plugins and themes. When attempting to save a PHP file edit for a plugin or theme, during the user’s save request WordPress will write the file to disk after first copying the old file’s contents into a variable. Then immediately after writing the change it will do a loopback request back to the file editor screen with the user’s same cookies to check to see if the PHP file edit would lock them out of the editor. If that loopback request generates a PHP fatal error, then the original PHP file is restored. Otherwise, if there is no fatal error then WordPress will open another loopback request to the homepage of the site to check if there is a fatal error generated there. If so, again, the PHP file edit is undone with the old version of the file restored. At that point, an error message is shown to the user informing them of what specifically the error was and prompting them to fix it. The user’s modifications to the PHP file remain in the editor for them to fix (also these save requests now happen over Ajax so the user never leaves the page). If they try leaving the page without fixing the error and successfully re-saving, they’ll get an “Are you sure?” dialog informing them they would lose their changes, in the same way as leaving the Customizer or the Add New Post screen. If the loopback requests aren’t able to complete, the file edits will also be reverted and the user will be prompted to use SFTPSFTP SFTP is an acronym for Secure File Transfer Protocol: A standard protocol to move computer files from one host to another over the Internet with enhanced security. to edit the file.

The JavaScript powering the new updated interface for the theme and plugin editors is located in theme-plugin-editor.js, which exports a wp.themePluginEditor object.

Code Editor APIs

The Customizer code editor control, Custom HTML widget, and file editor all make use of an underlying “code editor” API that provides an abstraction on top of CodeMirror. In PHP there is the wp_enqueue_code_editor() function which is named and functionally similar to wp_enqueue_editor() for TinyMCE. The wp_enqueue_code_editor() function takes an array of args, including the ability to specify the file type that you intend to edit, or else the file name itself. Alternatively, you can pass a codemirror array arg that has the same structure as what you would pass when initializing CodeMirror in JS. Then depending on the language mode that is either explicitly provided via codemirror arg or which is deduced from the file or type args, the function will specify various defaults depending on the selected mode. For example, if editing CSS then it will enable linting and if editing HTML it will enable the auto-closing of tags. Once the settings array is fully assembled it is then passed into a wp_code_editor_settings filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. to give plugins a chance to further modify the settings. If this filter returns false or if the user had previously disabled the syntax highlighting preference, then the function will return false and no scripts will be enqueued. Otherwise, the function will proceed to then enqueue the code-editor script and style along with the wp-codemirror script/style dependencies and then any supporting linter scripts.

The wp_enqueue_code_editor() function will exported its settings array to wp.codeEditor.defaultSettings in JS while also returning it to that a feature can directly pass it into the wp.codeEditor.initialize() API. This initialize method is modeled after CodeMirror.fromTextArea() in that it takes a textarea object or ID as its first argument and then the settings as its second. In addition to the settings exported from wp_qneueue_code_editor() the settings passed into the initialize method can also include several callbacks including onChangeLintingErrors, onUpdateErrorNotice, onTabPrevious, onTabNext. These callbacks are what the various integrations rely on to manage the displaying of linting errors as well as ensuring keyboard navigation.

Here is a simple example of turning the user’s bio into a CodeMirror HTML editor on their profile screen:

add_action( 'admin_enqueue_scripts', function() {
	if ( 'profile' !== get_current_screen()->id ) {
		return;
	}

	// Enqueue code editor and settings for manipulating HTML.
	$settings = wp_enqueue_code_editor( array( 'type' => 'text/html' ) );

	// Bail if user disabled CodeMirror.
	if ( false === $settings ) {
		return;
	}

	wp_add_inline_script(
		'code-editor',
		sprintf(
			'jQuery( function() { wp.codeEditor.initialize( "description", %s ); } );',
			wp_json_encode( $settings )
		)
	);
} );

As noted above, CodeMirror and its bundled modes and add-ons are registered in a wp-codemirror script handle. Also important to note here that this script does not define a global CodeMirror object but rather a wp.CodeMirror one. This ensures that other plugins that may be including other CodeMirror bundles won’t have conflicts. This also means that if you do want to include fortran.js from CodeMirror, that you’ll need to bundle it to call wp.CodeMirror.defineMode() instead of CodeMirror.defineMode(). A workaround for having to do this would be the following, but be aware of potential conflicts:

wp_add_inline_script( 
	'wp-codemirror', 
	'window.CodeMirror = wp.CodeMirror;'
);

Development History

The integration of CodeMirror into core was initially worked on in the Better Code Editing feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins. on GitHub. A full development history can be found there in the issues, pull requests, and commit log.

The principal contributors to code editing in this release were @afercia, @helen, @georgestephanis, @obenland, @melchoyce, @westonruter, and @WraithKenny.

The key tickets related to code editor improvements in 4.9 are:

  • #6531: Recursively search for files in theme and plugin editors
  • #12423: Include default code editor
  • #21622: Validate or sandbox theme file edits before saving them (as is done for plugins)
  • #24048: Code Editors: Increase the usability of Code Editor’s files list
  • #31779: Warn users before using a built-in file editor for the first time
  • #38707: Customizer: Additional CSS highlight, revisionsRevisions The WordPress revisions system stores a record of each saved draft or published update. The revision system allows you to see what changes were made in each revision by dragging a slider (or using the Next/Previous buttons). The display indicates what has changed in each revision., selection, per-page, pop-out (partially completed for this release)
  • #39218: Customize: Harden validation of CSS syntax validity by utilizing tokenizer
  • #39766: Plugin does not gracefully fail when editing active plugin causes fatal error
  • #39892: Default value in Additional CSS
  • #41073: Linting code changes: prevent saving, or add confirm message
  • #41872: Code Editor: Minor accessibility improvements to the CodeMirror editing areas
  • #41887: Code Editor: Error disables the Update File button.
  • #41897: Code Editor: Add reusable code editor Customizer control

#4-9, #codemirror, #dev-notes

Introducing the Gallery widget

In the last major releasemajor release A release, identified by the first two numbers (3.6), which is the focus of a full release cycle and feature development. WordPress uses decimaling count for major release versions, so 2.8, 2.9, 3.0, and 3.1 are sequential and comparable in scope. we introduced Media Widgets for Images, Video, and Audio. Per that dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.:

WordPress 4.8 includes media widgets (#32417) for not only images (#39993) but also video (#39994) and audio (#39995), on top of an extensibleExtensible This is the ability to add additional functionality to the code. Plugins extend the WordPress core software. base for introducing additional media widgets in the future, such as for galleries and playlists.

Now in the upcoming 4.9 release this Gallery widgetWidget A WordPress Widget is a small block that performs a specific function. You can add these widgets in sidebars also known as widget-ready areas on your web page. WordPress widgets were originally created to provide a simple and easy-to-use way of giving design and structure control of the WordPress theme to the user. (#41914) has just landed in trunktrunk A directory in Subversion containing the latest development code in preparation for the next major release cycle. If you are running "trunk", then you are on the latest revision. in [41590]. Just as users can add galleries to their post content they too can add galleries to their sidebars. The media widgets are being developed with GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ in mind, as widgets are essentially proto-blocks. Gutenberg has ported the Categories and Recent Posts widgets as dynamic blocks so that users can add to their posts what was formerly restricted to sidebars. In the same way, the media widgets are allowing for content that was formerly restricted to post content to also be available for addition to widget areas. As Gutenberg matures, widgets are planned to eventually transition over to use blocks, and the widgets for images, video, audio, and galleries will be able to be migrated over at that time. In the mean time, the user should not have to know there is any difference between post content and widget areas. Once the migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. from widgets to blocks is complete, users shouldn’t actually perceive any fundamental change in this regard.

Here are four screenshots that show how the Gallery widget is created and updated:

 

You’ll note that the widget re-uses the same media modals that a user is familiar with when adding and editing galleries in the post editor.

Code Reference

PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higherwp-includes/widgets/class-wp-widget-media-gallery.php
JSJS JavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors.: wp-admin/js/widgets/media-gallery-widget.js

Field Type Default Description
title string "" Title for the widget
ids array [] Attachment IDs
columns integer 3 Columns
size string "thumbnail" Size
link_type string "none" Link To
orderby_random boolean false Order by random

There is also a widget_media_gallery_instance_schema filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. which can be used to add additional properties, such as a type for Jetpack’s Tiled Galleries. See #42285.

Theme Styling Updates

As with the previously-introduced media widgets, some themes will need to be updated to ensure the proper styling is applied to galleries that appear in the widget area context, since previously galleries would only appear in post content. Please follow #41969 for style changes that are made to the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. bundled themes to then also make similar changes to your themes.

Conclusion

The gallery widget was first introduced and tested in the Core Media Widgets feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins.. The pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party is developed on GitHub and the issues and pull requests related to the gallery widget can be reviewed there for a full history of the feature.

Please report new issues on Trac in the Widgets component, after first checking for any existing Gallery widget tickets.

#4-9, #dev-notes