Opened 47 minutes ago
#66644 new enhancement
WP_REST_Blocks_Controller renders pattern content that it then removes from the response
| Reported by: | sanchothefat | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | REST API | Version: | |
| Severity: | normal | Keywords: | |
| Cc: | Focuses: |
Description
WP_REST_Blocks_Controller removes title.rendered and content.rendered from its schema and from every response, because a pattern has no rendered content on its own - only when it's within a post, page, or template on output. The rendering still happens, though and can be slow depending what hooks into the_content filter.
get_fields_for_response() only lists top-level fields, so it returns content. rest_is_field_included( 'content.rendered', $fields ) then returns true because its parent is included. So WP_REST_Posts_Controller::prepare_item_for_response() runs the_content on every pattern, and filter_response_by_context() throws the result away. The same happens with title.rendered and the_title.
The block editor requests /wp/v2/blocks?context=edit&per_page=100 without _fields each time it loads. That runs every block render callback and content filter for up to 100 patterns per page. On a site with image-heavy patterns, this was most of the request time.
Steps to reproduce
- Create a few synced patterns that contain blocks.
- Hook a counter onto
the_content. - Request
/wp/v2/blocks?context=edit. the_contentruns once for each pattern, but the response has nocontent.rendered.
Suggested fix
Override get_fields_for_response() in WP_REST_Blocks_Controller. Replace title and content with the sub-fields left in the controller's schema: title.raw, content.raw, content.protected and content.block_version. The response doesn't change, because rest_is_field_included() still treats a parent field as included when one of its children is listed.
<?php public function get_fields_for_response( $request ) { $fields = parent::get_fields_for_response( $request ); $schema = $this->get_item_schema(); foreach ( array( 'title', 'content' ) as $field ) { $index = array_search( $field, $fields, true ); if ( false === $index || empty( $schema['properties'][ $field ]['properties'] ) ) { continue; } unset( $fields[ $index ] ); foreach ( array_keys( $schema['properties'][ $field ]['properties'] ) as $sub_field ) { $fields[] = "{$field}.{$sub_field}"; } } return array_values( $fields ); }
Props to @rayhatron for the initial find here.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)