WordPress.org

Make WordPress Core

Changeset 47138


Ignore:
Timestamp:
01/30/2020 08:20:30 PM (6 months ago)
Author:
kadamwhite
Message:

REST API: Reuse previously-generated embedded objects when building collection response.

Store each generated embedded object in a temporary cache when querying for linked resources so that repeated links to the same resource do not trigger repeated queries or processing.

Props TimothyBlynJacobs.
Fixes #48838.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/class-wp-rest-server.php

    r47122 r47138  
    7878     */
    7979    protected $route_options = array();
     80
     81    /**
     82     * Caches embedded requests.
     83     *
     84     * @since 5.4.0
     85     * @var array
     86     */
     87    protected $embed_cache = array();
    8088
    8189    /**
     
    463471
    464472        if ( $embed ) {
     473            $this->embed_cache = array();
    465474            // Determine if this is a numeric array.
    466475            if ( wp_is_numeric_array( $data ) ) {
     
    469478                $data = $this->embed_links( $data );
    470479            }
     480            $this->embed_cache = array();
    471481        }
    472482
     
    589599                }
    590600
    591                 // Run through our internal routing and serve.
    592                 $request = WP_REST_Request::from_url( $item['href'] );
    593                 if ( ! $request ) {
    594                     $embeds[] = array();
    595                     continue;
    596                 }
    597 
    598                 // Embedded resources get passed context=embed.
    599                 if ( empty( $request['context'] ) ) {
    600                     $request['context'] = 'embed';
    601                 }
    602 
    603                 $response = $this->dispatch( $request );
    604 
    605                 /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */
    606                 $response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $this, $request );
    607 
    608                 $embeds[] = $this->response_to_data( $response, false );
     601                if ( ! array_key_exists( $item['href'], $this->embed_cache ) ) {
     602                    // Run through our internal routing and serve.
     603                    $request = WP_REST_Request::from_url( $item['href'] );
     604                    if ( ! $request ) {
     605                        $embeds[] = array();
     606                        continue;
     607                    }
     608
     609                    // Embedded resources get passed context=embed.
     610                    if ( empty( $request['context'] ) ) {
     611                        $request['context'] = 'embed';
     612                    }
     613
     614                    $response = $this->dispatch( $request );
     615
     616                    /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */
     617                    $response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $this, $request );
     618
     619                    $this->embed_cache[ $item['href'] ] = $this->response_to_data( $response, false );
     620                }
     621
     622                $embeds[] = $this->embed_cache[ $item['href'] ];
    609623            }
    610624
  • trunk/tests/phpunit/tests/rest-api/rest-server.php

    r47122 r47138  
    676676        $this->assertEquals( 'Test message', $up_data['message'] );
    677677        $this->assertEquals( 403, $up_data['data']['status'] );
     678    }
     679
     680    /**
     681     * @ticket 48838
     682     */
     683    public function test_link_embedding_clears_cache() {
     684        $post_id = self::factory()->post->create();
     685
     686        $response = new WP_REST_Response();
     687        $response->add_link( 'post', rest_url( 'wp/v2/posts/' . $post_id ), array( 'embeddable' => true ) );
     688
     689        $data = rest_get_server()->response_to_data( $response, true );
     690        $this->assertArrayHasKey( 'post', $data['_embedded'] );
     691        $this->assertCount( 1, $data['_embedded']['post'] );
     692
     693        wp_update_post(
     694            array(
     695                'ID'         => $post_id,
     696                'post_title' => 'My Awesome Title',
     697            )
     698        );
     699
     700        $data = rest_get_server()->response_to_data( $response, true );
     701        $this->assertArrayHasKey( 'post', $data['_embedded'] );
     702        $this->assertCount( 1, $data['_embedded']['post'] );
     703        $this->assertEquals( 'My Awesome Title', $data['_embedded']['post'][0]['title']['rendered'] );
     704    }
     705
     706    /**
     707     * @ticket 48838
     708     */
     709    public function test_link_embedding_cache() {
     710        $response = new WP_REST_Response(
     711            array(
     712                'id' => 1,
     713            )
     714        );
     715        $response->add_link(
     716            'author',
     717            rest_url( 'wp/v2/users/1' ),
     718            array( 'embeddable' => true )
     719        );
     720        $response->add_link(
     721            'author',
     722            rest_url( 'wp/v2/users/1' ),
     723            array( 'embeddable' => true )
     724        );
     725
     726        $mock = new MockAction();
     727        add_filter( 'rest_post_dispatch', array( $mock, 'filter' ) );
     728
     729        $data = rest_get_server()->response_to_data( $response, true );
     730
     731        $this->assertArrayHasKey( '_embedded', $data );
     732        $this->assertArrayHasKey( 'author', $data['_embedded'] );
     733        $this->assertCount( 2, $data['_embedded']['author'] );
     734
     735        $this->assertCount( 1, $mock->get_events() );
     736    }
     737
     738    /**
     739     * @ticket 48838
     740     */
     741    public function test_link_embedding_cache_collection() {
     742        $response = new WP_REST_Response(
     743            array(
     744                array(
     745                    'id'     => 1,
     746                    '_links' => array(
     747                        'author' => array(
     748                            array(
     749                                'href'       => rest_url( 'wp/v2/users/1' ),
     750                                'embeddable' => true,
     751                            ),
     752                        ),
     753                    ),
     754                ),
     755                array(
     756                    'id'     => 2,
     757                    '_links' => array(
     758                        'author' => array(
     759                            array(
     760                                'href'       => rest_url( 'wp/v2/users/1' ),
     761                                'embeddable' => true,
     762                            ),
     763                        ),
     764                    ),
     765                ),
     766            )
     767        );
     768
     769        $mock = new MockAction();
     770        add_filter( 'rest_post_dispatch', array( $mock, 'filter' ) );
     771
     772        $data = rest_get_server()->response_to_data( $response, true );
     773
     774        $embeds = wp_list_pluck( $data, '_embedded' );
     775        $this->assertCount( 2, $embeds );
     776        $this->assertArrayHasKey( 'author', $embeds[0] );
     777        $this->assertArrayHasKey( 'author', $embeds[1] );
     778
     779        $this->assertCount( 1, $mock->get_events() );
    678780    }
    679781
Note: See TracChangeset for help on using the changeset viewer.