Make WordPress Core

Changeset 58935


Ignore:
Timestamp:
08/25/2024 11:47:01 PM (2 years ago)
Author:
peterwilsoncc
Message:

Script Loader: Refactor Etag generation for concatenated assets.

Move Etag HTTP header generation in load-scripts.php and load-styles.php to WP_Dependencies.

Introduces the method WP_Dependencies::get_etag() and associated unit tests.

Follow up to [57943].

Props vrajadas, martinkrcho, mukesh27.
Fixes #61485.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/load-scripts.php

    r58905 r58935  
    5353wp_default_packages_scripts( $wp_scripts );
    5454
    55 $etag = "WP:{$wp_version};";
    56 
    57 foreach ( $load as $handle ) {
    58         if ( ! array_key_exists( $handle, $wp_scripts->registered ) ) {
    59                 continue;
    60         }
    61 
    62         $ver   = $wp_scripts->registered[ $handle ]->ver ? $wp_scripts->registered[ $handle ]->ver : $wp_version;
    63         $etag .= "{$handle}:{$ver};";
    64 }
    65 
    66 /*
    67  * This is not intended to be cryptographically secure, just a fast way to get
    68  * a fixed length string based on the script versions. As this file does not
    69  * load the full WordPress environment, it is not possible to use the salted
    70  * wp_hash() function.
    71  */
    72 $etag = 'W/"' . md5( $etag ) . '"';
     55$etag = $wp_scripts->get_etag( $load );
    7356
    7457if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) && stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) === $etag ) {
  • trunk/src/wp-admin/load-styles.php

    r58905 r58935  
    5656wp_default_styles( $wp_styles );
    5757
    58 $etag = "WP:{$wp_version};";
    59 
    60 foreach ( $load as $handle ) {
    61         if ( ! array_key_exists( $handle, $wp_styles->registered ) ) {
    62                 continue;
    63         }
    64 
    65         $ver   = $wp_styles->registered[ $handle ]->ver ? $wp_styles->registered[ $handle ]->ver : $wp_version;
    66         $etag .= "{$handle}:{$ver};";
    67 }
    68 
    69 /*
    70  * This is not intended to be cryptographically secure, just a fast way to get
    71  * a fixed length string based on the script versions. As this file does not
    72  * load the full WordPress environment, it is not possible to use the salted
    73  * wp_hash() function.
    74  */
    75 $etag = 'W/"' . md5( $etag ) . '"';
     58$etag = $wp_styles->get_etag( $wp_version, $load );
    7659
    7760if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) && stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) === $etag ) {
  • trunk/src/wp-includes/class-wp-dependencies.php

    r56547 r58935  
    491491                return true;
    492492        }
     493
     494        /**
     495         * Get etag header for cache validation.
     496         *
     497         * @since 6.7.0
     498         *
     499         * @global string $wp_version The WordPress version string.
     500         *
     501         * @param string[] $load Array of script or style handles to load.
     502         * @return string Etag header.
     503         */
     504        public function get_etag( $load ) {
     505                /*
     506                 * Note: wp_get_wp_version() is not used here, as this file can be included
     507                 * via wp-admin/load-scripts.php or wp-admin/load-styles.php, in which case
     508                 * wp-includes/functions.php is not loaded.
     509                 */
     510                global $wp_version;
     511
     512                $etag = "WP:{$wp_version};";
     513
     514                foreach ( $load as $handle ) {
     515                        if ( ! array_key_exists( $handle, $this->registered ) ) {
     516                                continue;
     517                        }
     518
     519                        $ver   = $this->registered[ $handle ]->ver ?? $wp_version;
     520                        $etag .= "{$handle}:{$ver};";
     521                }
     522
     523                /*
     524                 * This is not intended to be cryptographically secure, just a fast way to get
     525                 * a fixed length string based on the script versions. As this file does not
     526                 * load the full WordPress environment, it is not possible to use the salted
     527                 * wp_hash() function.
     528                 */
     529                return 'W/"' . md5( $etag ) . '"';
     530        }
    493531}
  • trunk/tests/phpunit/tests/dependencies.php

    r56548 r58935  
    149149                $this->assertContains( 'one', $dep->queue );
    150150        }
     151
     152        /**
     153         * Data provider for test_get_etag.
     154         *
     155         * @return array[]
     156         */
     157        public function data_provider_get_etag() {
     158                return array(
     159                        'should accept one dependency'              => array(
     160                                'load'               => array(
     161                                        'abcd' => '1.0.2',
     162                                ),
     163                                'hash_source_string' => 'WP:6.7;abcd:1.0.2;',
     164                                'expected'           => 'W/"8145d7e3c41d5a9cc2bccba4afa861fc"',
     165                        ),
     166                        'should accept empty array of dependencies' => array(
     167                                'load'               => array(),
     168                                'hash_source_string' => 'WP:6.7;',
     169                                'expected'           => 'W/"7ee896c19250a3d174f11469a4ad0b1e"',
     170                        ),
     171                );
     172        }
     173
     174        /**
     175         * Tests get_etag method for WP_Scripts.
     176         *
     177         * @ticket 58433
     178         * @ticket 61485
     179         *
     180         * @covers WP_Dependencies::get_etag
     181         *
     182         * @dataProvider data_provider_get_etag
     183         *
     184         * @param array  $load               List of scripts to load.
     185         * @param string $hash_source_string Hash source string.
     186         * @param string $expected           Expected etag.
     187         */
     188        public function test_get_etag_scripts( $load, $hash_source_string, $expected ) {
     189                global $wp_version;
     190                // Modify global to avoid tests needing to change with each new version of WordPress.
     191                $original_wp_version = $wp_version;
     192                $wp_version          = '6.7';
     193                $instance            = wp_scripts();
     194
     195                foreach ( $load as $handle => $ver ) {
     196                        // The src should not be empty.
     197                        wp_enqueue_script( $handle, 'https://example.org', array(), $ver );
     198                }
     199
     200                $result = $instance->get_etag( array_keys( $load ) );
     201
     202                // Restore global prior to making assertions.
     203                $wp_version = $original_wp_version;
     204
     205                $this->assertSame( $expected, $result, "Expected MD hash: $expected for $hash_source_string, but got: $result." );
     206        }
     207
     208        /**
     209         * Tests get_etag method for WP_Styles.
     210         *
     211         * @ticket 58433
     212         * @ticket 61485
     213         *
     214         * @covers WP_Dependencies::get_etag
     215         *
     216         * @dataProvider data_provider_get_etag
     217         *
     218         * @param array  $load               List of styles to load.
     219         * @param string $hash_source_string Hash source string.
     220         * @param string $expected           Expected etag.
     221         */
     222        public function test_get_etag_styles( $load, $hash_source_string, $expected ) {
     223                global $wp_version;
     224                // Modify global to avoid tests needing to change with each new version of WordPress.
     225                $original_wp_version = $wp_version;
     226                $wp_version          = '6.7';
     227                $instance            = wp_scripts();
     228
     229                foreach ( $load as $handle => $ver ) {
     230                        // The src should not be empty.
     231                        wp_enqueue_style( $handle, 'https://example.cdn', array(), $ver );
     232                }
     233
     234                $result = $instance->get_etag( array_keys( $load ) );
     235
     236                // Restore global prior to making assertions.
     237                $wp_version = $original_wp_version;
     238
     239                $this->assertSame( $expected, $result, "Expected MD hash: $expected for $hash_source_string, but got: $result." );
     240        }
    151241}
Note: See TracChangeset for help on using the changeset viewer.