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

Improve template loading and rendering #746

Open
11 of 14 tasks
eclarke1 opened this issue Jun 20, 2023 · 12 comments
Open
11 of 14 tasks

Improve template loading and rendering #746

eclarke1 opened this issue Jun 20, 2023 · 12 comments
Assignees
Labels
[Focus] Server Response Time Issues related to the Server Response Time priority focus area [Priority] High [Type] Overview Provides an overview of a specific project WP Core Work relates to inclusion in WP Core only

Comments

@eclarke1
Copy link

eclarke1 commented Jun 20, 2023

Based on a performance analysis taken of WordPress 6.2, the WP Performance Team determined that there was significant opportunity to improve the way that WordPress loads files and executes logic associated with the template rendering process for both classic themes and block themes.

Problem Exploration

Classic Theme Context

Conceptually, when WordPress handles a request for a specific page, it will render the HTML to send back in the response by parsing the request to see which type of page should be rendered, and then build the page by locating and processing the various template parts that make up the page. This includes executing any procedural code, including hook callbacks, present in these template files.

For example, when rendering a post page in the Twenty Twenty-One theme, locate_template is first called by get_query_template, which loads the single.php file, which then loads the header file, which loads a header template-part, which loads two more template-parts, etc. This process is repeated to render the content, and then the footer. The result (in this case) is 4 calls to locate_template, requiring the need to perform file operations, database queries, and procedural logic, just to render the page.

Notably, wp_head—which is called in the header template of most themes in order to render markup inside the <head> tag of the page—is responsible for a bulk of the execution time as of WP 6.3 (an apparent regression from previous versions).

Due to the dynamic nature of WordPress, this whole process is repeated for every request, even though the results of this process rarely change between requests. On high-traffic sites, this overhead is often avoided by putting a full page cache in front of the WordPress application. However, a more granular way of caching and reusing specific template parts or even a whole page closer to the application does not currently exist.

Block Theme Context

For block themes, similar problems exist as described for classic themes. However, the template loading process is slightly different. Instead of locating and executing procedural code in PHP template files, get_query_template will first search for classic theme templates, before calling locate_block_template to see if a block template file exists and if any overrides are present as a custom post type in the database in resolve_block_template.

Once a block template is located, the content is stored in the $_wp_current_template_content global variable, where it is parsed into rendered block markup, and post processing is applied all within the get_the_block_template_html function. This leads to two potential problems:

  1. By separating the process of locating PHP templates and block templates in totally separate operations, unnecessary file operations can be run to locate a PHP template file that will be overridden by a block template of equal or higher specificity.
  2. By manually running post-processing filters on rendered block content in get_the_block_template_html, the same default filters that are added to hooks like the_content can get run twice, causing unnecessary double processing which adds performance overhead and even sometimes leads to bugs (see: https://core.trac.wordpress.org/ticket/55996).

Projects for WP 6.4/6.5

Add caching for template file lookups

To avoid repeated file_exists operations for the same templates that rarely change, we could cache the result of get_query_template and load them directly on subsequent requests.

Note: This effort should initially be time-boxed to include a discovery of whether PHPs internal stat cache renders the impact of these changes insignificant. See related conversation in: https://core.trac.wordpress.org/ticket/40731.

Related tickets:

Merge consideration of block-templates with classic template hierarchy

For block themes, WordPress will first attempt to locate the appropriate PHP template in the theme for the request before considering a block template. However, any block template that is found at an equal or higher priority takes precedence over the PHP templates. This means that block themes perform several unnecessary file_exists checks to look for a PHP template, when a block template is the desired result.

Related tickets:

Reduce or eliminate cost of template part block instance variations

The function build_template_part_block_instance_variations is called when the template part block is registered, and is responsible for ~10% of the total server time for rendering a page in a block theme in WP 6.3 (profiling analysis). This is primarily due to get_block_templates(), which is called internally by this function. That function performs two tasks that make up a bulk of the time: performing an expensive query and getting block template files (via _get_block_template_files() which eventually results in an expensive call to WP_Theme_JSON_Resolver::get_theme_data.

Related tickets:

Make caching for global style sheets persistent

The function wp_get_global_stylesheet is responsible for ~10% of server execution time (WP 6.3 profiling data) in classic themes. While it is cached in some scenarios, it may not be a persistent cache, which creates a large server response time regression since WP 6.1 when the function was introduced.

Related tickets:

Miscellaneous improvements to template loading

While the above solutions focus on specific solutions, additional optimizations that reduce or eliminate unnecessary file operations are also worth pursuing.

Related tickets:

@eclarke1 eclarke1 added [Type] Overview Provides an overview of a specific project [Focus] Server Response Time Issues related to the Server Response Time priority focus area [Priority] High labels Jun 20, 2023
@felixarntz felixarntz added the WP Core Work relates to inclusion in WP Core only label Jul 19, 2023
@joemcgill joemcgill changed the title Improve template loading for classic themes Improve template loading and rendering Sep 7, 2023
@eclarke1
Copy link
Author

@joemcgill @kt-12 should we update the title here to say "Solutions to pursue for WP 6.5" instead of 6.4 now?

@kt-12
Copy link
Member

kt-12 commented Oct 16, 2023

Yes, I think so.

@kt-12 kt-12 self-assigned this Oct 24, 2023
@mukeshpanchal27
Copy link
Member

@joemcgill Could we add https://core.trac.wordpress.org/ticket/59595 in the list?

@joemcgill
Copy link
Member

@mukeshpanchal27 yes, I think that makes sense. I'll add it to the misc section

@kt-12
Copy link
Member

kt-12 commented Nov 6, 2023

@joemcgill I started analysing WordPress/gutenberg#45601

But the original ticket(related work) seems to be fixed. I see a PR for this but there is no Trac Ticket for this can you check I might be missing something here

@joemcgill
Copy link
Member

@kt-12 I don't think there was ever a Trac ticket for that issue. The GB issue came out of profiling that showed the function, build_template_part_block_instance_variations was responsible for a large amount of the overall response time. It's possible that things were refactored in a way since that time that this function is no longer responsible for that much time. It could also be that the root cause of the performance bottleneck in that function is actually located elsewhere, so avoiding unnecessary calls to that function won't actually reduce any time. A good first step here would be to verify whether this function still accounts for a large percentage of execution time and whether it is responsible for the slowdown or if it in fact is an issue with one of it's child functions and then create a new Trac ticket to address the identified issue.

@mukeshpanchal27
Copy link
Member

For Core-59315 the overall cost of file lookups for PHP template files are minimal and not worth trying to refactor. Closing as a wontfix.

@joemcgill
Copy link
Member

Similarly, Core-59314 is a wontfix for lack of measurable impact.

@kt-12
Copy link
Member

kt-12 commented Nov 21, 2023

Issue - WordPress/gutenberg#45601

register_block_core_template_part accounts for ~7% of load time ~80ms. The function calls
build_template_part_block_variations, which accounts for 99% of the function time. This function is called in almost every page. The root reason for this is deep down in the call stack, it calls WP_Theme_JSON_Resolver::get_merged_data, which calls WP_Theme_JSON::__construct for parsing theme json.
Another interesting thing we found is that by disabling build_template_part_block_variations, for pages that don’t require it, we found there is an improvement of ~80ms which align to the total time needed for register_block_core_template_part.
Disabling change that was made - WordPress/gutenberg#45601 (comment) tested on default homepage of TT4
Before Change - https://blackfire.io/profiles/933e16a5-0932-41e3-8fb7-a21c10dc3811/graph
After Change- https://blackfire.io/profiles/c225c202-974c-4a9c-886f-ef731273461c/graph
The challenge is how to tell apart pages that have variations from pages that don’t.

@joemcgill
Copy link
Member

@kt-12 I've added https://core.trac.wordpress.org/ticket/59532 to the "misc improvements" section of this ticket, since it's closely related to the work you're planning to pick up on https://core.trac.wordpress.org/ticket/60120.

@kt-12
Copy link
Member

kt-12 commented Jan 8, 2024

@joemcgill Should we mark https://core.trac.wordpress.org/ticket/58196 as done, given that we have a static variable approach in place?

Also, should we create a ticket to study _get_block_templates_files in favour of https://core.trac.wordpress.org/ticket/58196#comment:30

@joemcgill
Copy link
Member

Should we mark https://core.trac.wordpress.org/ticket/58196 as done, given that we have a static variable approach in place?

Yup! Should have done when I closed that ticket. Thanks for spotting, @kt-12!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Focus] Server Response Time Issues related to the Server Response Time priority focus area [Priority] High [Type] Overview Provides an overview of a specific project WP Core Work relates to inclusion in WP Core only
Projects
Development

No branches or pull requests

5 participants