[wp-trac] [WordPress Trac] #62187: Optimize Theme JSON Sanitization for Better Performance Scaling

WordPress Trac noreply at wordpress.org
Mon Oct 7 23:04:37 UTC 2024


#62187: Optimize Theme JSON Sanitization for Better Performance Scaling
-------------------------+-----------------------------
 Reporter:  mreishus     |      Owner:  (none)
     Type:  enhancement  |     Status:  new
 Priority:  normal       |  Milestone:  Awaiting Review
Component:  Themes       |    Version:
 Severity:  normal       |   Keywords:
  Focuses:  performance  |
-------------------------+-----------------------------
 This ticket introduces a optimization to the `WP_Theme_JSON::sanitize()`
 method to address a performance scaling issue.

 == Current Issue ==
 The `sanitize()` method's performance is affected by the number of
 registered blocks, even when those blocks are unused in the rendered
 content. A contributor to this inefficiency is the schema building, which
 scales at O(N), where N is the number of registered blocks. This schema is
 then built when `sanitize()` is called up to 3 times for each block
 rendered, contributing to an overall performance impact that approaches
 O(M * N), where M is the number of blocks rendered.

 Specifically:
 1. The `sanitize()` method builds a `$schema` that includes data for every
 possible registered block, regardless of whether it's used in the input.
    - It loops over all valid block names, populating
 `$schema_settings_blocks` and `$schema_styles_blocks`.
    - For each block, it checks for style variations and builds
 `$schema_styles_variations`.
    - This results in a large, complex schema even for unused blocks.

 2. The comprehensive schema is then used in the sanitization process when
 calling `static::remove_keys_not_in_schema( $input[ $subtree ], $schema[
 $subtree ] );`.

 3. Although the `remove_keys_not_in_schema` operation itself is relatively
 fast (as it uses direct array key access), the overall process is slowed
 by the initial creation of the unnecessarily large `$schema`.

 4. As a result, even unused blocks contribute to the processing time,
 leading to scaling issues.

 == Proposed Solution ==
 Our optimization focuses on building only the parts of the schema that we
 will actually need before calling the `remove_keys_not_in_schema`
 function. Here's how it works:

 1. We introduce a new `get_used_blocks()` method to identify which blocks
 are actually present in the input data.
 2. We then intersect this list of used blocks with the list of valid
 blocks.
 3. The `$schema` is then built using only these valid, used blocks.

 This approach significantly reduces both the time to build the `$schema`
 array and its final size in most cases, as it only processes blocks that
 are actually used in the input.

 == Changes ==
 1. Add a new `get_used_blocks()` method to extract block names from the
 input.
 2. Modify `sanitize()` to build the schema using only the intersection of
 valid and used blocks.

 == Benefits ==
 * Improved performance scaling.
 * Reduced unnecessary iterations in the sanitization process.

 == Expected Impact ==
 This optimization reduces the performance penalty associated with
 registering many blocks, allowing for better scalability of block-based
 themes and plugins. Our testing methodology and results are as follows:

 Testing Method:
 - Environment: WordPress site using the Twenty Twenty-Four theme
 - Procedure: Visited the home page 10 times for each scenario
 - Measurement: Time spent in the sanitize() function
 - Result: Median of the 10 measurements

 Scenarios and Results:

 1. No plugins active (94 blocks registered):
  * Before: ~4.50 ms
  * After: ~2.52 ms
  * Improvement: Approximately 44% faster

 2. With WooCommerce active (223 blocks registered):
  * Before: ~7.52 ms
  * After: ~3.20 ms
  * Improvement: Approximately 57% faster

 3. With an artificial plugin registering an unusually high number of
 blocks (2104 blocks registered):
  * Before: ~55 ms
  * After: ~11.83 ms
  * Improvement: Approximately 78% faster

 The improvement is particularly notable for sites using plugins that
 register numerous custom blocks, as shown in the third scenario.

 Note: Actual performance gains may vary depending on the specific
 WordPress setup, server configuration, and other factors.

 == Testing ==
 Verify that theme JSON sanitization still works correctly for various
 inputs.
 Benchmark performance improvements, especially for plugins that register
 many blocks.

 I was using:

 {{{
 ./vendor/bin/phpunit --filter Tests_Block_Template ; ./vendor/bin/phpunit
 --filter Tests_Interactivity_API_wpInteractivityAPIFunctions ;
 ./vendor/bin/phpunit --filter Tests_Theme_wpThemeJson ;
 ./vendor/bin/phpunit --filter WP_REST_Global_Styles_Controller_Test
 }}}

 But obviously all unit tests are important. :)

 Performance testing should focus on measuring the time taken by the
 `sanitize()` method under various scenarios.

 This change maintains the integrity of the sanitization process while
 providing performance improvements, especially for complex WordPress
 setups with many registered blocks.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/62187>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list