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.
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 5.6.20 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:
WordPress 4.6 added support for Resource Hints, a W3CW3CThe World Wide Web Consortium (W3C) is an international community where Member organizations, a full-time staff, and the public work together to develop Web standards.https://www.w3.org/. specification that “defines the dns-prefetch, preconnect, prefetch, and prerender relationships of the HTMLHTMLHyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. Link Element (<link>)”. These can be used to assist the browser in the decision process of which origins it should connect to, and which resources it should fetch and preprocess to improve page performance.
With WordPress 4.7, you’re now able to pass specific HTML attributes to these resource hints to make even better use of them. Namely, the as, crossorigin, pr, and type attributes can now be defined when using the wp_resource_hintsfilterFilterFilters 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.. See #38121 for more information.
Here’s an example of how one can use this new feature:
While crossorigin can be used to set the CORS settings for a resource, pr indicates the expected probability that the specified resource hint will be used. The official W3C specification has more information about these attributes.
Note: preload is not yet supported by wp_resource_hints(), mainly because of a lack of browser support and benefit for coreCoreCore is the set of software required to run WordPress. The Core Development Team builds WordPress.. This will continue to be reevaluated as browser support evolves for these emerging features.
The admin_print_footer_scripts action hook is the last chance to localize adminadmin(and super admin) scripts; but it is a generic one. If you ever wanted to do something for specific admin pages only, you would either have to hook into another dynamic action, or hook into admin_print_footer_scripts and check the $hook_suffix (which is not even passed, but that’s not an issue) yourself. The problem with the former is that there might be happening a lot between the chosen action and when your script gets enqueued (admin_print_footer_scripts); and maybe you need to be aware of what has happened. The problem with the latter is that you would have to register possibly a lot of functions, maybe check the current admin page inside several of these, and eventually bail most of the times. That’s why WordPress 4.6 brings the dynamic footer action admin_print_footer_scripts-$hook_suffix. See [37279].
The following pre-4.6 code
add_action( 'admin_print_footer_scripts', function() {
global $hook_suffix;
if ( 'some_admin_page' !== $hook_suffix ) {
return;
}
// Whatever it is that you want to do...
} );
can now be simplified like this:
add_action( 'admin_print_footer_scripts-some_admin_page', function() {
// Whatever it is that you want to do...
} );
Resource Hints is a rather new W3C specification that “defines the dns-prefetch, preconnect, prefetch, and prerender relationships of the HTMLHTMLHyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. Link Element (<link>)”. These can be used to assist the browser in the decision process of which origins it should connect to, and which resources it should fetch and preprocess to improve page performance.
Introduced with [37920], WordPress now has a simple 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 register and use resource hints. The relevant ticketticketCreated for both bug reports and feature development on the bug tracker. is #34292
By default, wp_resource_hints() prints hints for s.w.org (the WordPress.orgWordPress.orgThe 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/ CDN) and for all scripts and styles which are enqueued from external hosts.
Developers can use the wp_resource_hintsfilterFilterFilters 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 add custom domains and URLs for dns-prefetch, preconnect, prefetch or prerender. One needs to be careful to not add too many resource hints as they could quite easily negatively impact performance, especially on mobile, but the filter works like this:
This post summarizes some of the changes to the script loader and script/style dependencies in WordPress 4.5.
Individual stylesheets instead of wp-admin.min.css
TicketticketCreated for both bug reports and feature development on the bug tracker.: #35229
Currently, WordPress generates and ships relatively large 235KB wp-admin.min.css and wp-admin-rtl.min.css files which are created from source files which we also ship.
With WordPress 4.5 we stop generating these files and instead rely upon load-styles.php to combine them. This removes the requirement from shipping for commits such as [35896] 510KB of CSSCSSCascading Style Sheets.. Instead, we only have to ship the 4 dashboard.css files which are around 72KB.
For 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 nothing should change because the script loader takes care of the new dependency for the wp-admin handle. Also, wp-admin.* files are still generated for compatibility purposes, however, they only include the @import() lines.
Breaking Change: If your plugin or theme is still using the deprecated media functionality please note that in [36869] the style handle was changed from media to media-deprecated.
HTTPHTTPHTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. ETag 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. for load-scripts.php and load-styles.php
Both loaders for script and style concatenation are now sending an ETag header which includes the value of $wp_version. This improves performance since browsers won’t re-download the scripts and styles when they send the HTTP_IF_NONE_MATCH header and there was no change in $wp_version. ⚡️
For quite some time wp_add_inline_style() has been available to add extra CSS styles to a registered stylesheet. Now there’s an equivalent function to do the same for inline 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/.. wp_add_inline_script() can be used to add extra scripts either before or after a registered script using the optional third $position argument.
For example, the following code can be used to easily add Typekit’s JavaScript to your theme:
Alias handles are handles without a $src parameter. Those can be used to group dependencies, like core is doing for jQuery. [36550] changes how those handles are loaded, more specifically, they are no longer skipped early in WP_Dependencies.
Now, inline styles and scripts attached to alias handles will do something important — get printed out. This change was required by the switch to an alias handle for wp-admin to provide backwards compatibility for plugins which are adding inline styles to the wp-admin handle.
Support for scripts with dependencies in different groups
Scripts can be registered in two groups: head or footer. Previously, dependencies of registered scripts were moved to the header, even when the script that depends on them is loaded in the footer. This was fixed in [36871]. The changeset includes some expressive tests to demonstrate how complex dependencies, like “grandchild” dependencies, can be enqueued.
You must be logged in to post a comment.