Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add speculative loading support #7860

Open
wants to merge 16 commits into
base: trunk
Choose a base branch
from

Conversation

felixarntz
Copy link
Member

@felixarntz felixarntz commented Nov 21, 2024

This PR adds speculative loading support to WordPress Core, as outlined in the Trac ticket:

  • Introduce function wp_get_speculation_rules_configuration() to get the current speculation rules configuration (consisting of "mode" and "eagerness").
    • The default values for mode and eagerness are auto, which later is evaluated into whatever the current Core default is. For the initial implementation at least, that default is to "prefetch" with "conservative" eagerness.
    • A new filter wp_speculation_rules_configuration can be used to override the behavior, either to change it to something more eager, or to hard-code it to the current default to force-control it, even if Core's default should change in the future.
    • By default, speculative loading is disabled for logged-in users and for sites that do not use pretty permalinks (see below on why).
  • Introduce function wp_get_speculation_rules() to compute the full data for speculation Rules JSON output, based on the given configuration (return value from wp_get_speculation_rules_configuration()). This function is mostly a copy of the plugin's plsr_get_speculation_rules() function.
    • By default, the configuration will lead to speculative loading of all frontend URLs, while excluding patterns like /wp-admin/*, /wp-*.php, etc which should never be speculatively loaded.
    • All URLs with query parameters are also excluded, as custom query parameters may be used by plugins for custom "action links" that change state and therefore should not be speculatively loaded. If pretty permalinks are disabled, this differentiation is not possible, which is why speculative loading is disabled for those sites by default. The very small portion of sites that this applies to can still opt in to speculative loading via filter, acknowledging that this exclusion will not apply to those sites then.
    • A new filter wp_speculation_rules_href_exclude_paths can be used to add further URL patterns to exclude, relevant for plugins that may want to customize this. This filter receives the mode (prefetch or prerender) as context, which thus allows to add exclusions depending on which mode is currently used.
    • While the filter can be used to add exclusions, it cannot remove any of the default exclusions. This is because they are simply not safe to prefetch / prerender because of their dynamic nature.
    • The default configuration also excludes prefetching links that use a no-prefetch class on their anchor, as well as excludes prerendering links that use a no-prerender class.
  • Introduce function wp_print_speculation_rules() which is hooked into wp_footer to print the default speculation rules JSON, unless the wp_get_speculation_rules_configuration() returns null to indicate that speculative loading is disabled.
  • Introduce internal class WP_URL_Pattern_Prefixer, which is a direct port of the plugin's PLSR_URL_Pattern_Prefixer class that handles safe prefixing of URL patterns with WordPress base paths (like home URL, site URL, plugins directory URL etc.).

Trac ticket: https://core.trac.wordpress.org/ticket/62503


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

Copy link

github-actions bot commented Nov 21, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props flixos90, swissspidy, westonruter, adamsilverstein.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copy link

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

src/wp-includes/speculative-loading.php Outdated Show resolved Hide resolved
src/wp-includes/speculative-loading.php Outdated Show resolved Hide resolved
src/wp-includes/speculative-loading.php Outdated Show resolved Hide resolved
src/wp-includes/speculative-loading.php Outdated Show resolved Hide resolved
src/wp-includes/speculative-loading.php Show resolved Hide resolved
src/wp-includes/speculative-loading.php Outdated Show resolved Hide resolved
src/wp-includes/speculative-loading.php Outdated Show resolved Hide resolved
$base_href_exclude_paths = array(
$prefixer->prefix_path_pattern( '/wp-*.php', 'site' ),
$prefixer->prefix_path_pattern( '/wp-admin/*', 'site' ),
$prefixer->prefix_path_pattern( '/*', 'uploads' ),
Copy link
Member

@adamsilverstein adamsilverstein Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we exclude wp-content/* instead of each of these individual paths (unless they were in non-standard locations without the wp-content prefix)?

Copy link
Member Author

@felixarntz felixarntz Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /wp-*.php and /wp-admin/* paths aren't actually within wp-content. Note that the wp-content directory is already excluded, see line 162.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the uploads path is excluded separately because it's not necessarily under wp-content, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, same with plugins and themes. 99% of times they should be within wp-content, but not guaranteed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plugins/themes/uploads - If they are in wp-content (which is quick to check) we don't need extra entries for them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but it also doesn't hurt.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed it doesn't hurt, checking for that would likely be more expensive to do than including the extra rules unconditionally.

/**
* Tests speculation rules output with prefetch for the different eagerness levels.
*
* @ticket 62503
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these repeating @ticket 62503 annotations seem excessive/extraneous. @ticket annotations are mostly used to run a set of tests while working on a ticket AFAIK. We can already run all of the tests for this ticket using --group= speculative-loading so we can remove all of the @ticket annotations entirely, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think they exist temporarily. They're useful for context, makes it easy to find out as part of which ticket a test was added. Of course right now @ticket 62503 is synonymous with @group speculative-loading, but this will no longer be the case in the near future, as soon as any enhancement or bug is fixed via another ticket.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always understood @ticket as something to be used when adding regression tests for bugs, not enhancements. Also not a fan of adding @ticket everywhere for a new feature like this. But I know some people do that, so 🤷

Copy link
Member

@adamsilverstein adamsilverstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! left some small feedback/question.

felixarntz and others added 2 commits January 10, 2025 10:24
…/wordpress-develop into add/62503-speculative-loading
@felixarntz
Copy link
Member Author

@swissspidy Feedback applied!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Code Review 👀
Development

Successfully merging this pull request may close these issues.

4 participants