Make WordPress Core

Changeset 51208


Ignore:
Timestamp:
06/22/2021 09:23:19 PM (3 years ago)
Author:
iandunn
Message:

Block Editor: Move caching to endpoint for unique responses.

Now that the pattern API request includes the locale and version, the cache key needs to contain a hash of the query args.

Props ocean90, dd32, timothyblynjacobs
Fixes #53435

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-patterns.php

    r51021 r51208  
    4646
    4747/**
    48  * Import patterns from wordpress.org/patterns.
     48 * Register Core's official patterns from wordpress.org/patterns.
     49 *
     50 * @since 5.8.0
     51 *
     52 * @param WP_Screen $current_screen The screen that the current request was triggered from.
    4953 */
    5054function _load_remote_block_patterns( $current_screen ) {
     
    6569
    6670    if ( $supports_core_patterns && $should_load_remote ) {
    67         $patterns = get_transient( 'wp_remote_block_patterns' );
    68         if ( ! $patterns ) {
    69             $request         = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
    70             $core_keyword_id = 11; // 11 is the ID for "core".
    71             $request->set_param( 'keyword', $core_keyword_id );
    72             $response = rest_do_request( $request );
    73             if ( $response->is_error() ) {
    74                 return;
    75             }
    76             $patterns = $response->get_data();
    77             set_transient( 'wp_remote_block_patterns', $patterns, HOUR_IN_SECONDS );
     71        $request         = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
     72        $core_keyword_id = 11; // 11 is the ID for "core".
     73        $request->set_param( 'keyword', $core_keyword_id );
     74        $response = rest_do_request( $request );
     75        if ( $response->is_error() ) {
     76            return;
    7877        }
     78        $patterns = $response->get_data();
    7979
    8080        foreach ( $patterns as $settings ) {
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php

    r51206 r51208  
    112112        }
    113113
    114         $api_url = add_query_arg(
    115             array_map( 'rawurlencode', $query_args ),
    116             'http://api.wordpress.org/patterns/1.0/'
    117         );
    118 
    119         if ( wp_http_supports( array( 'ssl' ) ) ) {
    120             $api_url = set_url_scheme( $api_url, 'https' );
    121         }
    122 
    123         $wporg_response = wp_remote_get( $api_url );
    124         $raw_patterns   = json_decode( wp_remote_retrieve_body( $wporg_response ) );
    125 
    126         if ( is_wp_error( $wporg_response ) ) {
    127             $wporg_response->add_data( array( 'status' => 500 ) );
    128 
    129             return $wporg_response;
    130         }
    131 
    132         // Make sure w.org returned valid data.
    133         if ( ! is_array( $raw_patterns ) ) {
    134             return new WP_Error(
    135                 'pattern_api_failed',
    136                 sprintf(
    137                 /* translators: %s: Support forums URL. */
    138                     __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
    139                     __( 'https://wordpress.org/support/forums/' )
    140                 ),
    141                 array(
    142                     'status'   => 500,
    143                     'response' => wp_remote_retrieve_body( $wporg_response ),
    144                 )
     114        /*
     115         * Include a hash of the query args, so that different requests are stored in
     116         * separate caches.
     117         *
     118         * MD5 is chosen for its speed, low-collision rate, universal availability, and to stay
     119         * under the character limit for `_site_transient_timeout_{...}` keys.
     120         *
     121         * @link https://stackoverflow.com/questions/3665247/fastest-hash-for-non-cryptographic-uses
     122         */
     123        $transient_key = 'wp_remote_block_patterns_' . md5( implode( '-', $query_args ) );
     124
     125        /*
     126         * Use network-wide transient to improve performance. The locale is the only site
     127         * configuration that affects the response, and it's included in the transient key.
     128         */
     129        $raw_patterns = get_site_transient( $transient_key );
     130
     131        if ( ! $raw_patterns ) {
     132            $api_url = add_query_arg(
     133                array_map( 'rawurlencode', $query_args ),
     134                'http://api.wordpress.org/patterns/1.0/'
    145135            );
     136
     137            if ( wp_http_supports( array( 'ssl' ) ) ) {
     138                $api_url = set_url_scheme( $api_url, 'https' );
     139            }
     140
     141            /*
     142             * Default to a short TTL, to mitigate cache stampedes on high-traffic sites.
     143             * This assumes that most errors will be short-lived, e.g., packet loss that causes the
     144             * first request to fail, but a follow-up one will succeed. The value should be high
     145             * enough to avoid stampedes, but low enough to not interfere with users manually
     146             * re-trying a failed request.
     147             */
     148            $cache_ttl      = 5;
     149            $wporg_response = wp_remote_get( $api_url );
     150            $raw_patterns   = json_decode( wp_remote_retrieve_body( $wporg_response ) );
     151
     152            if ( is_wp_error( $wporg_response ) ) {
     153                $raw_patterns = $wporg_response;
     154
     155            } elseif ( ! is_array( $raw_patterns ) ) {
     156                // HTTP request succeeded, but response data is invalid.
     157                $raw_patterns = new WP_Error(
     158                    'pattern_api_failed',
     159                    sprintf(
     160                    /* translators: %s: Support forums URL. */
     161                        __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
     162                        __( 'https://wordpress.org/support/forums/' )
     163                    ),
     164                    array(
     165                        'response' => wp_remote_retrieve_body( $wporg_response ),
     166                    )
     167                );
     168
     169            } else {
     170                // Response has valid data.
     171                $cache_ttl = HOUR_IN_SECONDS;
     172            }
     173
     174            set_site_transient( $transient_key, $raw_patterns, $cache_ttl );
     175        }
     176
     177        if ( is_wp_error( $raw_patterns ) ) {
     178            $raw_patterns->add_data( array( 'status' => 500 ) );
     179
     180            return $raw_patterns;
    146181        }
    147182
  • trunk/tests/phpunit/tests/rest-api/rest-pattern-directory-controller.php

    r51021 r51208  
    259259        $this->assertSame( 500, $response->status );
    260260        $this->assertWPError( $response->as_error() );
     261    }
     262
     263    /**
     264     * @covers WP_REST_Pattern_Directory_Controller::get_items
     265     *
     266     * @since 5.8.0
     267     */
     268    public function test_get_items_prepare_filter() {
     269        wp_set_current_user( self::$contributor_id );
     270        self::mock_successful_response( 'browse-all', true );
     271
     272        // Test that filter changes uncached values.
     273        add_filter(
     274            'rest_prepare_block_pattern',
     275            function( $response ) {
     276                return 'initial value';
     277            }
     278        );
     279
     280        $request  = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
     281        $response = rest_do_request( $request );
     282        $patterns = $response->get_data();
     283
     284        $this->assertSame( 'initial value', $patterns[0] );
     285
     286        // Test that filter changes cached values (the previous request primed the cache).
     287        add_filter(
     288            'rest_prepare_block_pattern',
     289            function( $response ) {
     290                return 'modified the cache';
     291            },
     292            11
     293        );
     294
     295        // Test that the filter works against cached values.
     296        $request  = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
     297        $response = rest_do_request( $request );
     298        $patterns = $response->get_data();
     299
     300        $this->assertSame( 'modified the cache', $patterns[0] );
    261301    }
    262302
Note: See TracChangeset for help on using the changeset viewer.