The WordPress coreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress. development team builds WordPress! Follow this site forย general updates, status reports, and the occasional code debate. Thereโs lots of ways to contribute:
Found a bugbugA bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority.?Create a ticket in the bug tracker.
This post is the latest in a series of updates focused on the performance improvements of major releases (see 6.8, 6.7, 6.6, 6.5, 6.4, 6.3, and 6.2).
WordPress 6.9 is the second and final major releasemajor releaseA 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. of 2025. It includes numerous improvements to the performance of loading pages on the frontend:
Scripts: improve script loading performance by adding support for fetchpriority, printing script modules in the footer, and optimizing the emoji detection script.
Styles: optimize loading of stylesheets by loading blockBlockBlock 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. styles on demand in classic themes, omitting styles for hidden blocks, increasing the inline style limit from 20K to 40K, and inlining minified stylesheets in block themes.
Introduce the template enhancementenhancementEnhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature. output buffer to implement optimizations previously impossible (such as the aforementioned on-demand style loading in classic themes).
More: spawn WP Cron at shutdown, eliminate layout shifts in the Video block, fix RSS feedRSS FeedRSS is an acronym for Real Simple Syndication which is a type of web feed which allows users to access updates to online content in a standardized, computer-readable format. This is the feed. caching, and so on.
The performance changes in this release include 38 Trac tickets (26 enhancements, 11 defects, 1 task) and 31 Gutenberg PRs, although this post does not describe improvements to the performance of the editor nor the database query and caching optimizations. This post highlights the key changes to the frontend for site visitors, as well as looking at their impact in terms of web vitals metrics, such as TTFB, FCP, and LCP.
WordPress 6.7 introduces a new @wordpress/a11y script module and a new APIAPIAn 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. to pass script module data from the server to the client.
Over the years of working on the GutenbergGutenbergThe 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/ project, we developed some common practices. These help us preserve the quality and the long-term viability of the project. They differ and often contradict what people are used to in other projects (especially outside WordPress CoreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress.).
These practices should be applied during implementation and PR reviews. Sharing and embracing them helps contributors make the right decisions and be more autonomous when working on the project.
This list is non-exhaustive and subject to change. These are guidelines to always keep in mind but shouldnโt be treated as hard rules. Context is always important to consider.
Start APIs as private
Gutenberg is organized in packages. Implementing features means introducing new APIs to one or multiple packages. Itโs important to understand that most of the packagesโย APIs are public WordPress APIs. Anything exported from a package and consumed by another package becomes a defacto WordPress APIAPIAn 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.. This API needs to be maintained forever to adhere with the WordPress backwards compatibility strategy. Thus, itโs recommended to start with private APIs.
Be intentional about providing public APIs
Extensibility is important to WordPress. We do want pluginPluginA 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 authors to extend what WordPress provides. We also want them to reuse tools that WordPress uses internally. This point can read as a contradiction with the previous one. But whatโs important here is that it needs to beย intentional. Before making an API public during the feature work, we should ask ourselves these questions:
Do we want to allow users to use this API?ย
And are we willing to support it for the next 10 years without breaking changes?ย
If the answer to both these questions is yes, then we can consider making this API public.
Avoid opening APIs for convenience, embrace copy/paste
Sometimes, for convenience and to abide to the DRY principle, we, developers create APIs and abstractions. This is seen as a good practice in most projects. But in the context of Gutenberg and WordPress, it is something to avoid. The cost of maintaining APIs is too high because of the backward compatibility strategy.
Say you have a low-level function or component already available to plugin authors or npm package users. To achieve their use-case, they maybe have to write some duplicate boilerplate code. Creating a higher-level abstraction to avoid the duplication should be avoided as much as possible. It is true that providing a great Developer Experience is important, though. There are cases where a higher-level abstraction is required. The main approach is that we should have very strong arguments for it and be intentional.
Prefer Semantic Extensibility
Plugin authors in WordPress want to be able to extend every piece of the UIUIUser interface. They also want to give way too much prominence to their own extensions and upsells. As WordPress history teaches us, this quickly leads to a degraded user experience. Who has never seen a WP Adminadmin(and super admin) with hundreds of notices? Who has never seen a WP Admin with menu items and call to actions competing for the userโs attention?
A non curated set of extensibility APIs can lead to stagnation as well. One example here is the metaMetaMeta 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. boxes API in the classic editor and how it created a lot of constraints for the development of the blockBlockBlock 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. editor. These kinds of APIs prevent iteration and evolution. It becomes very hard to improve the UI and UXUXUser experience of these screens. Any change, no matter how small, can lead to breaking changes for plugin authors.
To alleviate these issues, extensibility in Gutenberg is curated and semantic. APIs to register/unregister semantic pieces (blocks, patterns, actions, fields) are preferred. APIs that are too broad and whose purpose is unclear should be avoided. For example:ย
A slot in the editor headerHeaderThe 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. is not a very semantic API. Itโs unclear what it will be used for. This will prevent any redesign and iteration to the header area of the editor.
The ability to set aย priorityย orย orderย to extensions is often an API that we want to avoid. Itโs very prone to abuse. Often, plugins authors use these to give priority to their own extensions over what Core provides. It quickly leads to a degraded experience for users.
One package = one clear purpose
Developing features in Gutenberg often involves modifications to multiple packages at the same time. We need to ask ourselves: where should this piece of code live? To answer the question, itโs important to understand the purpose of each package. Here are some common examples:
Most of the editor UI is built within theย @wordpress/block-editorย package. So developers often change this package directly to accommodate their specific needs in the UI. The problem though is that itโs not the sole package responsible for adding UI to the editor. It is important to understand that this package is theย Tinymceย of Gutenberg. It can be used to build and integrate block editors within WordPress and outside WordPress. Itโs a framework to build block editors. If a part of the UI is specific to WordPress, itโs not the right place to make this change. A recent example I noticed here is the addition of a button to the block settings menu. That button was used to open the WordPress editor sidebarSidebarA 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., but editor sidebars are specific to WordPress block editors.
Making a REST APIREST APIThe 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/. request in a UI component is another common pitfall that happens often. For example, you may want to build a Language Switcher UI component. And you want it to be reusable in theย @wordpress/componentsย package. You canโt use a REST API call within the component to fetch the available languages. The components package is a generic WP agnostic UI components package. So instead, itโs better to have a prop to pass of the available languages instead.
Itโs also not recommended to add new packages just to share code between two existing packages. Usually, thereโs a better solution to the code sharing problem. ย @wordpress/utilsย package doesnโt exist for a reason. Utility packages are a place where we can just dump shared code without purpose. As mentioned earlier,ย copy/pasting is not always a bad idea when it comes to code sharing. It is preferable to avoid early abstractions as much as possible.
Measure then optimize
We, developers have a tendency to over optimize our code. Often these optimizations involve adding some complexity to the code, making it harder to maintain. It is better to avoid these early optimizations. Instead, measure the impact of the change you want to perform to validate that the optimization is worth the added complexity. Important metrics are tracked in the codevitals dashboard.
Other random common pitfalls
Besides the principles above that one needs to follow to make the right calls, here are some common pitfalls that weโve learned to avoid over time:
Avoid passing editor settings as inline JSJSJavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors. from the backend to the frontend. It is a pattern we used heavily early in the project. We should ideally move away from it and prefer a better separation between client and server (use REST API calls).
Adding settings to theย BlockEditorProviderย (and theย @wordpress/block-editorย package) is ok. But we should be intentional about it: what does the setting mean for third-party block editors? Always remember the block editor framework use case.
Be declarative as much as possible. Using state actions and selectors to share UI state is acceptable. But know that itโs risky. It can lead to bugs and race conditions quickly if multiple components compete to set the right state. This happened to us at least in two recent situations:
Insertion position:ย We moved away from declaratively computing the insertion position based on the selected block. We usedย setInsertionPointย action and state instead. The issue is that the inserting point is now incorrectly set at times. Or it persists as we navigate awayโฆ
Block editing mode:ย To support different UI modes for blocks (content-only, locking, template-locked mode, zoom-out mode) we introduced a state to manipulate what we call โblock editing modeโ usingย setBockEditingModeย action. We now have some hidden bugs because of that. These different modes compete to set the right block editing mode.ย
Avoid using stores in new packages. Be careful when introducing new data stores. Each time we register a new store, thereโs added complexity in the system. Stores are singletons by default, they can only be present once in the page. We do support multiple instances of the same store on the page but itโs not without complexity. We need to extend the global registry. We have also seen that using stores in bundled packages likeย @worpdress/interfaceย is not a good idea. When a plugin wants to use that package/store it leads to the store trying to be registered twice. The wrong store will be accessed from the components when it happens.ย
A new filterFilterFilters 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. runs for each Script Module that is enqueued or in the dependency graph. This filter allows arbitrary data to be associated with a given Script Module and added to the rendered page.
Script Module data is embedded in the page as JSONJSONJSON, 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 a <script type="application/json">tagtagA 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.).
Script Modules are responsible for reading the data and performing their own initialization.
This is a proposal. Everything in this post is open to feedback and discussion. Please, share your thoughts and ideas.
The feedback period will end 2024-05-24 (Friday, May 24). Please provide any feedback before then.
This post will use โscriptsโ to refer to WP Scripts and โmodulesโ to refer to WP Script Modules.
Scripts or modules?
Most JavaScriptJavaScriptJavaScript 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 WordPress is probably using scriptsunless it was specifically compiled as a module. Modern JavaScript is often authored using import apiFetch from '@wordpress/api-fetch', which is module syntax. Until very recently, WordPress build tooling has always removed the module syntax and compiled a script.
Only the most recent WordPress version 6.5 introduced support for modules. WordPress CoreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress. includes exactly two modules to expose functionality at this time: @wordpress/interactivity and @wordpress/interactivity-router. JavaScript that uses the Interactivity APIAPIAn 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. is probably a module.
This post will talk about a common script dependency, wp-api-fetch. The @wordpress/api-fetchmodule mentioned in this post is hypothetical; it does not exist at this time.
A note about modules
Itโs important to know a few things about scripts versus modules in the context of this post. A few key differences:
Scripts and their dependencies will be executed as the page is parsed even if a dependency is never directly used.
Script โexportsโ are attached to the window object, e.g. wp-api-fetch is available as window.wp.apiFetch.
Modules will execute after the page has finished parsing.
Module dependencies can be loaded on demand.
Modules have true encapsulation, using import and export to share values.
More about scripts and modulesโฆ
Scripts that are either enqueued or are dependencies of enqueued scripts will be added to the page as script tags, like <script src="path/to/script.js">. The browser will fetch and execute these scripts before it continues to parse the page. There are attributes like async and defer that can change how the browser executes scripts.
Modules that are enqueued will appear on the page as script tags of type module, like <script src="path/to/module.js" type="module">. Processing of modules is deferred, they will be executed after the whole document has been parsed. The async attribute will cause a module to execute in parallel as the document is parsed. WordPress Script Modules do not use async at this time.
Modules that are in the dependency graph of enqueued modules will appear in an importmap. This is a mapping of names to URLs so that a browser knows what module to fetch when it sees an import. Itโs what associates the module used in a statement like import "a-module"; with a URLURLA specific web address of a website or web page on the Internet, such as a websiteโs URL www.wordpress.org{ "imports": { "a-module": "path/to/a-module.js" } }.
The problem
Scripts often require some initialization or other data to work correctly in WordPress. The wp-api-fetch script is a good example, it requires a significant amount of configuration. For example, Core uses the following inline script to initialize wp-api-fetch so it can send requests to the appropriate place:
This snippet uses PHPPHPThe web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher to create a string of JavaScript code with some data from PHP embedded. This will be included in a script tag that appears immediately after the script tag for wp-api-fetch, something like this:
<script src="path/to/wp-api-fetch.js"></script>
<script>
// The JavaScript code is printed here:
wp.apiFetch.use( wp.apiFetch.createRootURLMiddleware( "โฆ/index.php?rest_route=/" ) );
// More code may follow from other calls to `wp_add_inline_script`โฆ
</script>
Notice that the JavaScript depends on wp-api-fetch, it imperatively calls wp.apiFetch.use(โฆ). That same approach with a hypothetical @wordpress/api-fetch module would look something like this:
In this approach, the initialization module would fetch and execute the @wordpress/api-fetch module just to initialize it! That eliminates one of the important advantages of modules, their ability to load on-demand. ๐ค It looks like this imperative initialization isnโt a good fit for modules. Letโs see if thereโs a better solutionโฆ
The proposal
Here are some requirements that arise from the naive implementation:
Modules should be fetched and initialized on demand.
Modules should be responsible for their own initialization when theyโre executed.
Variables should be scoped to modules and not pollute the global namespace.
The data should introduce minimal overhead.
Add server data via filters
Filters provide a nice method to collect the data needed by modules. The WP_Script_Modules class introduces a new filter that runs for each module that is enqueued or present in the dependency graph. Adding or modifying data for a module looks like this:
Multiple filters can be added to add or modify the data exposed to the script, and if no data is added, nothing will be serialized on the page for the client. Itโs also worth mentioning that no JavaScript code is written in PHP, a nice improvement over wp_add_inline_script which requires valid JavaScript to be added.
A drawback to this approach is that all the data passed must pass through JSON. Data without a valid JSON representation is not supported by default.
Use an inert script tag to expose data on the client
The data is embedded it in the HTMLHTMLHyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. in a script tag:
<script id="scriptmoduledata_@wordpress/api-fetch" type="application/json">
{ "theData": "JSON Serializable data can be shared" }
</script>
Because modules are always deferred, it should be safe to print these script tags at the bottom of the page. They should have limited impact on page load because the browser will not parse or execute the contents.
Modules read data from the script tag
This script tag doesnโt do anything on its own. The module is responsible for getting the data and performing its initialization when it executes:
if ( typeof document !== 'undefined' ) {
const serializedData = document.getElementById(
'scriptmoduledata_@wordpress/api-fetch'
)?.textContent;
if ( serializedData ) {
let config = null;
try {
config = JSON.parse( serializedData );
} catch {
// there was a problem parsing the serialized data
}
performInitialization( config );
}
}
function performInitialization( config ) {
if ( config?.rootURL ) {
registerMiddleware( createRootURLMiddleware( config.rootURL ) );
}
// etc.
}
Iโve prototyped this proposal in the following PRs:
WordPress-develop PR 6433 applies the filters and adds the necessary filters to expose data to @wordpress/api-fetch. The proposal in this post is contained in this PR.
Gutenberg PR 60952 builds and registers the @wordpress/api-fetch module. This PR is helpful for testing, but is beyond the scope of this post.
Try it in the WordPress Playground here. If you run the following JavaScript in the inspector console โmake sure you pick the JavaScript context, something like wp (scope:abc123)โ youโll see the @wordpress/api-fetch module log some initialization when itโs imported and then work as expected:
As the web continues to evolve, so does our approach to building and managing JavaScriptJavaScriptJavaScript 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/. in WordPress. Looking to the future, a collaborative effort is underway to explore native support for modern JavaScript modules and import maps within the WordPress ecosystem. This exploration is geared towards enhancing the developer experience by embracing the capabilitiescapabilityAย capabilityย is permission to perform one or more types of task. Checking if a user has a capability is performed by the current_user_can function. Each user of a WordPress site might have some permissions but not others, depending on theirย role. For example, users who have the Author role usually have permission to edit their own posts (the โedit_postsโ capability), but not permission to edit other usersโ posts (the โedit_others_postsโ capability). of modern browsers.
Introduction
JavaScript modules have transformed the way developers write and organize JavaScript code. They provide a cleaner and more modular architecture, making code easier to maintain, test, and reuse across projects. Today, the vast majority of web browsers offer native support for JavaScript module syntax, offering performance benefits and unlocking new possibilities in how we develop and manage client-side scripts.
In this realm, it becomes essential for WordPress to keep pace with these advancements and start experimenting with the addition of native support for registering and enqueueing JavaScript modules โ including generating an import map directly within WordPress.
The primary objectives of this initiative are:
To leverage the native JavaScript module system available in modern browsers.
To streamline the development process in WordPress using JavaScript modules.
To determine the most efficient and effective methods for handling dependencies and optimizing loading times.
Prior discussions and experiments
The following links are some preliminary discussions and experiments that touch upon JavaScript modules and related approaches to script loading within the WordPress ecosystem:
However, the journey toward a modern, module-friendly WordPress is still in its early stages, and the next steps will be instrumental in deciding how best to integrate module support in a way that benefits developers and users alike, without disrupting the stability and familiarity of the current WordPress experience.
The experimentation phase
The current plan involves conducting initial experiments within the GutenbergGutenbergThe 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/pluginPluginA 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. By exploring within this semi-contained environment, contributors will gain practical insight into constructing modules that are compatible with WordPressโ existing infrastructure. This experimentation will help make informed decisions on several fronts:
Deciding whether to extend the existing wp_enqueue_script function or introduce a distinct APIAPIAn 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. (like wp_enqueue_module).
Evaluating whether to maintain dependencies on the server vs relying completely on the clientโs native resolution.
Establishing best practices for module identifiers, dependency registration, inline modules, preloading optimizations, and more.
Assessing integration challenges and ensuring backward compatibility.
Itโs worth noting that while the experimentation will be kicked off using a separate API for simplicityโs sake, this doesnโt necessarily predetermine the final form of the proposal.
After conducting experiments, collecting insights, and incorporating the feedback received, an update that will outline a more specific implementation plan will be provided.
Potential enhancements such as dependency auto-detection and additional performance optimizations could be incrementally introduced later on.
Your input is important
Your perspective is crucial to the success of this initiative. Whether you are a plugin author, theme developer, coreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress. contributor, or anyone interested in the future of JavaScript in WordPress, join us in shaping a robust and forward-looking solution.
Get involved!
You are invited to participate in this exploratory phase and contribute your ideas, concerns, and suggestions. Below are some prompts to get the conversation started:
How do you currently manage JavaScript modules within your WordPress projects?
What challenges have you faced with the existing script enqueueing system?
In what ways can native support for JavaScript modules improve your development workflow?
Are there specific use cases or scenarios where you feel this proposal could greatly benefit you or the WordPress community?
Please share your thoughts in the comments below, on Trac, or participate in the ongoing discussions and experiments on GitHub. Your engagement is invaluable to work together toward a more modern, module-friendly WordPress.
This post outlines a proposal to add a script loading strategy enhancementenhancementEnhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature. to coreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress.โs existing Scripts APIAPIAn 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..ย ย
The underlying goal of this effort is to make it easier for WordPress pluginPluginA 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 developers and core to use โmodernโ loading approaches for JavaScriptJavaScriptJavaScript 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/. (like defer and async), which will help WordPress sites load faster and operate more smoothly, giving users a better experience.
Why add a loading strategy?
Data from the Web Almanac project (query) indicates that render blocking JavaScript is a significant problem on the web, with 77% of mobile pages having render-blocking scripts in the document <head> . This query shows that approximately 40% of WordPress sites stand to benefit from deferring additional scripts. Adding defer or async to script tags enables script loading without โblockingโ the rest of the page load, resulting in more responsive sites overall better user experience.
Currently WordPress core as well as plugins and themes register scripts with the wp_enqueue_script and/or wp_register_script functions. Although these functions include the ability to control the placement of the script (with the in_footer parameter), they donโt include support for adding modern attributes such as defer or async to script tags.ย
To add async or defer today, developers must resort to less flexible and more fragile approaches, such as directly filtering the tags at the point of output (usingย the script_loader_tagfilterFilterFilters 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.), or handling the tagtagA 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.) output directly using wp_print_script_tag and the wp_script_attributes filter.
Using the first approach and directly filtering the tag can easily break: for example if two plugins both try to filter a tag, or if a tag has unexpected attributes already (eg. adding defer to a tag that already has async). Using the the second approach developers must carefully handle dependencies and output manually โ things that that the Scripts API usually helps take care of.
How the loading strategy works
Developers specify a loading strategy when registering or enqueueing a script. For example, a defer strategy can be specified when the script isnโt required immediately during the page load cycle. WordPress will then determine which scripts can actually use a strategy based on logic for each strategy. For example, to ensure that scripts are executed in the order they are enqueued, defer can only be used on a script if every script that depends on that script can also be deferred. Inline script tags added with wp_add_inline_script would also be considered to ensure proper execution order.
The implementation would come with several initial built-in loading strategies: defer, async, and the default blocking behavior.
Out of scope for this feature
The loading strategy does not enable direct control of script tag attributes. This idea was originally proposed 10 years ago in #22249 and several approaches were considered on that ticketticketCreated for both bug reports and feature development on the bug tracker. including a script attribute filter. This proposal takes a step back and aims to solve the script loading strategy aspect more comprehensively and directly while avoiding exposing the potential complications of direct attribute control.
It is worth noting that it is already possible to control attributes on wp_enqueue_script tags directly using the script_loader_tag filter. However, this is a bit of a โbrute forceโ approach which is limited and fragile because it doesnโt consider dependencies and multiple plugins can take conflicting actions on the same tag.ย
What are potential concerns with this feature?
One big concern with adding this feature to the WordPress Script API is potentially introducing a breaking change. wp_enqueue_script is a fundamental API in WordPress core, and any breaking changes could have widespread implications. Possible breakage is a possible reason that adding custom attributes as proposed in #22249 was never added to core.
This new proposal aims to ensure that there is 100% backwards compatibility, resulting in zero risk of breakage. The loading strategy will ensure that all existing uses continue to function as expected; for example, passing the boolean in_footer attribute will still control script placement. In addition, it will ensure that scripts continue to be executed in the order they are enqueued โ as described above in the โHow the loading strategy worksโ section.
Conclusion and Next Steps
Giving developers the ability to specify a loading strategy will enable them to use more advanced JavaScript loading methods while still ensuring that enqueued scripts are executed in the correct order. A โstrategyโ approach is also forward thinking: as the web evolves, new strategies can be developed and made available to WordPress developers. After gathering feedback, we will proceed to discussing the implementation approach and, ultimately, proposing a patchpatchA special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing..
Have you tried using defer or async with WordPress (or do you already)? How do you think this enhancement would change that? Please leave your feedback about this proposal in the comments below and if you can, join us at our weekly performance team chats, where we are likely to discuss this proposal in the future.
Thanks to @flixos90, @tweetythierry and @mxbclang for help writing and reviewing this post and for the many contributors who have added to the discussion around this enhancement already.
TLDR; We made WordPress packages publishing to npm more predictable by synchronizing it with bi-weeklyย GutenbergGutenbergThe 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/ย pluginPluginA 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 RC1 release. We no longer have to keep the process tightly coupled with WordPress major releases.
Revised branching strategy for npm publishing
The Gutenberg repository still follows the WordPress SVN repositoryโs branching strategy for every major WordPress release. In addition to that, there are two other special branches that control npm publishing workflows and they are used as follows:
The wp/latestbranchbranchA directory in Subversion. WordPress uses branches to store the latest development code for each major release (3.9, 4.0, etc.). Branches are then updated with code for any minor releases of that branch. Sometimes, a major version of WordPress and its minor versions are collectively referred to as a "branch", such as "the 4.0 branch". contains the same version of packages as those published to npm with the latest distribution tagtagA 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.). The goal here is to have this branch synchronized with the last Gutenberg plugin release, and the only exception would be unplanned Standalone Bugfix Package Releases (read more below).
The wp/next branch contains the same version of packages as those published to npm with the next distribution tag. It always gets synchronized with the trunk branch. Projects should use those packages for development or testing purposes only.
A Gutenberg branch wp/* (example wp/6.0) targeting a specific WordPress major releasemajor releaseA 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. (including its further minor increments) gets created based on the wp/latest Gutenberg branch just after the last Gutenberg release planned for inclusion in the next major WordPress release.
Release types and their schedule:
Synchronizing Gutenberg Plugin (latest dist tag) โ publishing happens automatically every two weeks based on the newly created release/* (example release/12.8) branch with the RC1 version of the Gutenberg plugin.
WordPress Releases (patch dist tag) โ publishing gets triggered manually from the wp/* (example wp/6.0) branch. Once we reach the point in the WordPress major release cycle (usually after BetaBetaA pre-release of software that is given out to a large group of users to trial under real conditions. Beta versions have gone through alpha testing in-house and are generally fairly close in look, feel and function to the final product; however, design changes often occur as part of the process. 1) where we only cherry-pick commits from the Gutenberg repository to the WordPress coreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress., we use wp/* branch (created from wp/latest) for npm publishing with the patch dist-tag. Itโs also possible to use older branches to backportbackportA port is when code from one branch (or trunk) is merged into another branch or trunk. Some changes in WordPress point releases are the result of backporting code from trunk to the release branch. bugs or security fixes to the corresponding older versions of WordPress Core.
Development Releases (next dist tag) โ it is also possible to perform development releases at any time when there is a need to test the upcoming changes.
There is also an option to perform Standalone Bugfix Package Releases at will. It should be reserved only for critical bugbugA bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. fixes or security releases that must be published to npm outside of regular cycles.
The complete documentation is available in the BlockBlockBlock 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. Editor Handbook.
Running npm publishing with GitHubGitHubGitHub 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/ workflows
While the npm publishing got configured to happen automatically every two weeks as part of the Gutenberg plugin release workflow, there might still be cases when other release types need to be executed. To start the process, go to Gutenbergโs GitHub repositoryโs Actions tab, and locate the โPublish npm packagesโ action. Note the blue banner that says โThis workflow has a workflow_dispatch event trigger.โ, and expand the โRun workflowโ dropdown on its right-hand side.
There are three ways to publish packages to npm depending on the their type:
WordPress major release โ select wp from the โRelease typeโ dropdown and enter X.Y (example 5.9) in the โWordPress major releaseโ input field.
Development release โ select development from the โRelease typeโ dropdown and leave โWordPress major releaseโ input field empty.
Bugix release โ select bugfix from the โRelease typeโ dropdown and leave โWordPress major releaseโ input field empty.
Finally, press the green โRun workflowโ button. It triggers the npm publishing job, which needs then to be approved by a Gutenberg Core team member.
Testing JavaScriptJavaScriptJavaScript 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/. code from a specific major WordPress version
An interesting bonus got included with the revised workflow for npm publishing related to WordPress major releases. Itโs now possible to quickly install a version of the individual WordPress package used with a given WordPress version using distribution tags (example for WordPress 5.8.x):
I propose switching to the original version of the Prettier code formatting tool in the GutenbergGutenbergThe 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/ project and updating it to the most recent 2.5 version. Consequently, we should apply the necessary changes to the existing WordPress JavaScript Coding Standards around spacing to respect Prettierโs capabilitiescapabilityAย capabilityย is permission to perform one or more types of task. Checking if a user has a capability is performed by the current_user_can function. Each user of a WordPress site might have some permissions but not others, depending on theirย role. For example, users who have the Author role usually have permission to edit their own posts (the โedit_postsโ capability), but not permission to edit other usersโ posts (the โedit_others_postsโ capability)..
Code formatting challenges
Itโs worth reminding that this topic was discussed several times, beginning in 2017 when the initial exploration of using Prettier started withย WordPress/gutenberg#2819. Throughout all that time, the Prettier maintainers didnโt change their mind about adding support for spaces between parens (()) and brackets ([]) despite many requests shared inย prettier/prettier#1303ย from users (including the WordPress community). Thatโs why we decided to apply the first batch of JavaScript Coding Standards revisions two years later to use the forked version of Prettier developed by developers at Automattic. It allowed us to remain aligned with the coding style conventions used for PHPPHPThe web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher in the WordPress codebase. In particular, to follow these rules:
Use spaces liberally throughout your code. โWhen in doubt, space it out.โ
The WordPress JavaScriptJavaScriptJavaScript 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/. standards prefer slightly broader whitespace rules than the jQuery style guide. These deviations are for consistency between the PHP and JavaScript files in the WordPress codebase.
The issue is that we ended up with an outdated fork of Prettier in the Gutenberg project that didnโt get any updates for more than a year. The only motivation behind using a custom version of Prettier remains its additional functionality overriding formatting behavior for spaces around parens and brackets. In the meantime, there were three minor releases of Prettier with a long list of new features in the last year:
The Gutenberg project no longer uses only JavaScript for development. Some parts of the codebase use TypeScript, whichย we agreed upon a few months back. It means we canโt use improvements added for newer versions of the TypeScript language and potentially for future additions to the JavaScript language. A deprecation was also added to one of the config options we use in the shared Prettier config that the community uses. It turns out that it prevents using theย @wordpress/prettier-configย package with the most recent version of Prettier in 3rd party projects, as explained inย WordPress/gutenberg#37516. Finally, we had multiple reports inย WordPress/Gutenberg#21872ย from the community members usingย @wordpress/scriptsย orย @wordpress/eslint-plugin packagesย that the forked version of Prettier doesnโt install correctly in their projects. The good news is that switching to the original Prettier will resolve all of the above!
It quickly became noticeable that the automatic code formatting saves you so much time and energy when trying to keep a consistent coding style in the project. This is why we also started using Prettier to format other types of files it supports in the Gutenberg project, like JSONJSONJSON, 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., YAML, Markdown. We also consider doing the same for CSSCSSCascading Style Sheets. and SCSS next.
RevisionsRevisionsThe 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. to JavaScript Coding Standards
I propose we apply all the necessary changes to the WordPress JavaScript Coding Standards to switch to the latest available version of Prettier (2.5 as of writing). The excerptExcerptAn excerpt is the description of the blog post or page that will by default show on the blog archive page, in search results (SERPs), and on social media. With an SEO plugin, the excerpt may also be in that pluginโs metabox. of the most significant revisions is included below.
-Some whitespace rules differ, for consistency with the WordPress PHP coding standards.
+Some whitespace rules differ, for consistency with the [Prettier](https://prettier.io) formatting tool.
-All new or updated JavaScript code will be reviewed to ensure it conforms to the standards, and passes JSHint.
+All new or updated JavaScript code will be reviewed to ensure it conforms to the standards, and passes [ESLint](https://eslint.org).
-Use spaces liberally throughout your code. โWhen in doubt, space it out.โ
-Any ! negation operator should have a following space.*
+Any ! negation operator should not have a following space.
-Always include extra spaces around elements and arguments:
-array = [ a, b ];
-foo( arg );
-foo( 'string', object );
-foo( options, object[ property ] );
-foo( node, 'property', 2 );
-prop = object[ 'default' ];
-firstArrayElement = arr[ 0 ];
+Never include extra spaces around elements and arguments:
+arg = [a, b];
+foo(arg);
+foo('string', object);
+foo(options, object[property]);
+foo(node, 'property', 2);
+prop = object['default'];
+firstArrayElement = arr[0];
-var i;
-
-if ( condition ) {
- doSomething( 'with a string' );
-} else if ( otherCondition ) {
- otherThing( {
- key: value,
- otherKey: otherValue
- } );
-} else {
- somethingElse( true );
-}
-
-// Unlike jQuery, WordPress prefers a space after the ! negation operator.
-// This is also done to conform to our PHP standards.
-while ( ! condition ) {
- iterating++;
-}
-
-for ( i = 0; i < 100; i++ ) {
- object[ array[ i ] ] = someFn( i );
- $( '.container' ).val( array[ i ] );
-}
-
-try {
- // Expressions
-} catch ( e ) {
- // Expressions
-}
+var i;
+
+if (condition) {
+ doSomething('with a string');
+} else if (otherCondition) {
+ otherThing({
+ key: value,
+ otherKey: otherValue,
+ });
+} else {
+ somethingElse(true);
+}
+
+while (!condition) {
+ iterating++;
+}
+
+for (i = 0; i < 100; i++) {
+ object[array[i]] = someFn(i);
+ $('.container').val(array[i]);
+}
+
+try {
+ // Expressions
+} catch (e) {
+ // Expressions
+}
You can preview the impact on the Gutenberg codebase on GitHubGitHubGitHub 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/ in the exploratory Pull Request. The same changes would impact the tooling recommended for blockBlockBlock 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. development like @wordpress/create-block and @wordpress/scripts.
When will a decision be made?
Letโs plan for making a decision three five (updated on Jan 25th) weeks from the date of publication of this post. That should give enough time for discussion and questions.
Hi folks! Iโm back again with an update on the TypeScript proposal. Previously in the follow-up post I said that after two weeks we would make a decision about it. Itโs been several months since then, so itโs about time to make that decision!
While there was some feedback to the proposal, nothing was raised that seemed to blockBlockBlock 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. the integration of native TypeScript into the GutenbergGutenbergThe 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/ project. Indeed, some packages (like compose and components) have seen a great deal of native TypeScript introduced. In fact, compose today is fully typed and this would not be the case if it were not for native TypeScript support in Gutenberg.
Therefore, Iโd like to officially announce that the Gutenberg project supports native TypeScript. We will continue to follow the guidelines laid out in the follow-up proposal, reproduced here for posterity.
For existing code:
The default is to use JavaScriptJavaScriptJavaScript 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/.
When it is possible to type something simply with JSDoc, use JSDoc
If there are complex types, but JSDoc is still sufficient generally for consuming those types, you may extract the complex types into a types-only types.ts file to be imported into the JSDoc
If it is not possible to express the types using JSDoc or if the JSDoc will vastly over-complicate the ability to type a function, convert it to TypeScript
For new code:
Use TypeScript when working in a โlow-level packageโ (as defined below) for new code. Otherwise, follow the same pattern laid out for the existing code.
Low level packages:
A low level package is a package that:
Provides a public APIAPIAn 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
Attendance at the CoreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress.JSJSJavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors. Office hours has been low for the last few weeks so at the most recent chat those that were present decided that weโd move to a bi-weekly cadence for now. Hereโs a quick summary of what is happening:
Core JavaScriptJavaScriptJavaScript 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/. office hours will be bi-weekly at the same time slot (15:00UTC) with the next meeting happening July 27th.
A reminder that the #core-js channel and office hour chats are intended to cover JavaScript across all of WordPress core, all JavaScript infrastructure, tools that build, lint, or test JavaScript code and higher-level discussions about coding styles, libraries used, etc. So has some distinction (even though there can be some overlap) from the kinds of discussions that happen within the #core-editor Slack instance which focuses predominately on the GutenbergGutenbergThe 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/ project and its implementation within WordPress.
You must be logged in to post a comment.