Skip to content

Commit

Permalink
[ETK][GB 13.x] Fix loading of A8C-specific patterns in WPCOM (#62745)
Browse files Browse the repository at this point in the history
* Fix A8C block pattern loading in Gutenberg 13+ by selectively loading all of them before the new API rest requests

* Revert changes to .wp-env.json

* Add tests

* Support Atomic rest API and move tests to block patterns category

* Use correct class for test mock

* Fix test

* Add back-compat function for older Gutenberg and WP versions

* Move block patterns file inclusion to callback

* Remove typo from package.json

* Add back edit site check

Co-authored-by: Noah Allen <[email protected]>
  • Loading branch information
fullofcaffeine and noahtallen authored Apr 15, 2022
1 parent a7c0f15 commit 9b70cf3
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,16 @@ class Block_Patterns_From_API {
*/
private $core_to_wpcom_categories_dictionary;

/**
* This is the current editor type. One of `block_editor` (default), `site_editor`.
*
* @var string
*/
private $editor_type;

/**
* Block_Patterns constructor.
*
* @param string $editor_type The current editor. One of `block_editor` (default), `site_editor`.
* @param Block_Patterns_Utils|null $utils A class dependency containing utils methods.
*/
public function __construct( $editor_type, Block_Patterns_Utils $utils = null ) {
if ( ! $editor_type || ! is_string( $editor_type ) ) {
$editor_type = 'block_editor';
}

$this->editor_type = $editor_type;
public function __construct( Block_Patterns_Utils $utils = null ) {
$this->patterns_sources = array( 'block_patterns' );

// While we're still testing the FSE patterns, limit activation via a filter.
if ( 'site_editor' === $this->editor_type && apply_filters( 'a8c_enable_fse_block_patterns_api', false ) ) {
// Switch the patterns source based on whether we're using a block-based theme.
if ( apply_filters( 'a8c_enable_fse_block_patterns_api', false ) ) {
$this->patterns_sources[] = 'fse_block_patterns';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,13 @@

use PHPUnit\Framework\TestCase;

require_once __DIR__ . '/../../full-site-editing-plugin.php';
require_once __DIR__ . '/../class-block-patterns-from-api.php';

/**
* Class Coming_Soon_Test
* Tests block pattern registration in the API context.
*/
class Block_Patterns_From_Api_Test extends TestCase {
/**
* PHPUnit_Framework_MockObject_MockObject.
*
* @var object
*/
protected $utils_mock;

/**
* Representation of a Pattern as returned by the API.
*
Expand Down Expand Up @@ -90,7 +84,7 @@ public function createBlockPatternsUtilsMock( $pattern_mock_response, $cache_get
*/
public function test_patterns_request_succeeds_with_empty_cache() {
$utils_mock = $this->createBlockPatternsUtilsMock( array( $this->pattern_mock_object ) );
$block_patterns_from_api = new Block_Patterns_From_API( '', $utils_mock );
$block_patterns_from_api = new Block_Patterns_From_API( $utils_mock );

$utils_mock->expects( $this->once() )
->method( 'cache_get' )
Expand All @@ -108,13 +102,13 @@ public function test_patterns_request_succeeds_with_empty_cache() {
}

/**
* Tests that we're making two requests when we specify that we're on the site editor.
* Tests that we're making two requests and `a8c_enable_fse_block_patterns_api` is `true`
*/
public function test_patterns_site_editor_source_site() {
add_filter( 'a8c_enable_fse_block_patterns_api', '__return_true' );

$utils_mock = $this->createBlockPatternsUtilsMock( array( $this->pattern_mock_object ) );
$block_patterns_from_api = new Block_Patterns_From_API( 'site_editor', $utils_mock );
$block_patterns_from_api = new Block_Patterns_From_API( $utils_mock );

$utils_mock->expects( $this->exactly( 2 ) )
->method( 'remote_get' )
Expand All @@ -133,7 +127,7 @@ public function test_patterns_site_editor_source_site() {
*/
public function test_patterns_request_succeeds_with_set_cache() {
$utils_mock = $this->createBlockPatternsUtilsMock( array( $this->pattern_mock_object ), array( $this->pattern_mock_object ) );
$block_patterns_from_api = new Block_Patterns_From_API( '', $utils_mock );
$block_patterns_from_api = new Block_Patterns_From_API( $utils_mock );

$utils_mock->expects( $this->once() )
->method( 'cache_get' )
Expand All @@ -158,7 +152,7 @@ public function test_patterns_request_succeeds_with_override_source_site() {

add_filter( 'a8c_override_patterns_source_site', $example_site );
$utils_mock = $this->createBlockPatternsUtilsMock( array( $this->pattern_mock_object ) );
$block_patterns_from_api = new Block_Patterns_From_API( '', $utils_mock );
$block_patterns_from_api = new Block_Patterns_From_API( $utils_mock );

$utils_mock->expects( $this->never() )
->method( 'cache_get' );
Expand All @@ -174,4 +168,66 @@ public function test_patterns_request_succeeds_with_override_source_site() {

remove_filter( 'a8c_override_patterns_source_site', $example_site );
}

/**
* Tests the given patterns registration mock against multiple REST API routes.
*
* @param object $patterns_from_api_mock A mock object for the block pattern from API class.
* @param array $test_routes An array of strings of routes to test.
*/
public function multiple_route_pattern_registration( $patterns_from_api_mock, $test_routes ) {
foreach ( $test_routes as $route ) {
$request_mock = $this->createMock( \WP_REST_Request::class );
$request_mock->method( 'get_route' )->willReturn( $route );

register_patterns_on_api_request(
function () use ( $patterns_from_api_mock ) {
$patterns_from_api_mock->register_patterns();
}
)( null, $request_mock );
}
}

/**
* Tests that pattern registration does occur on API routes related to block patterns.
*/
public function test_load_block_patterns_from_api_runs_in_correct_request_context() {
add_filter( 'a8c_enable_block_patterns_api', '__return_true' );
$test_routes = array(
'/wp/v2/block-patterns/categories',
'/wp/v2/block-patterns/patterns',
'/wp/v2/sites/178915379/block-patterns/categories',
'/wp/v2/sites/178915379/block-patterns/patterns',
);

$patterns_mock = $this->createMock( Block_Patterns_From_API::class );
$patterns_mock->expects( $this->exactly( count( $test_routes ) ) )->method( 'register_patterns' );

$this->multiple_route_pattern_registration( $patterns_mock, $test_routes );
}

/**
* Tests that pattern registration does not occur on rest API routes unrelated
* to block patterns.
*/
public function test_load_block_patterns_from_api_is_skipped_in_wrong_request_context() {
add_filter( 'a8c_enable_block_patterns_api', '__return_true' );

$test_routes = array(
'/rest/v1.1/help/olark/mine',
'/wpcom/v2/sites/178915379/post-counts',
'/rest/v1.1/me/shopping-cart/',
'/wpcom/v3/sites/178915379/gutenberg',
'/wp/v2/sites/178915379/types',
'/wp/v2/sites/178915379/block-patterns/3ategories',
'/wp/v2//block-patterns/patterns',
'/wp/v2block-patterns/categories',
'/wp/v2/123/block-patterns/categories',
);

$patterns_mock = $this->createMock( Block_Patterns_From_API::class );
$patterns_mock->expects( $this->never() )->method( 'register_patterns' );

$this->multiple_route_pattern_registration( $patterns_mock, $test_routes );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,32 +232,77 @@ function load_wpcom_block_editor_nux() {
add_action( 'plugins_loaded', __NAMESPACE__ . '\load_wpcom_block_editor_nux' );

/**
* Load editing toolkit block patterns from the API
* Return a function that loads and register block patterns from the API. This
* function can be registered to the `rest_dispatch_request` filter.
*
* @param obj $current_screen The current screen object.
* @param Function $register_patterns_func A function that when called will
* register the relevant block patterns in the registry.
*/
function load_block_patterns_from_api( $current_screen ) {
if ( ! apply_filters( 'a8c_enable_block_patterns_api', false ) ) {
function register_patterns_on_api_request( $register_patterns_func ) {
/**
* Load editing toolkit block patterns from the API.
*
* It will only register the patterns for certain allowed requests and
* return early otherwise.
*
* @param mixed $response
* @param WP_REST_Request $request
*/
return function ( $response, $request ) use ( $register_patterns_func ) {
$route = $request->get_route();
// Matches either /wp/v2/sites/123/block-patterns/patterns or /wp/v2/block-patterns/patterns
// to handle the API format of both WordPress.com and WordPress core.
$request_allowed = preg_match( '/^\/wp\/v2\/(sites\/[0-9]+\/)?block\-patterns\/(patterns|categories)$/', $route );

if ( ! $request_allowed || ! apply_filters( 'a8c_enable_block_patterns_api', false ) ) {
return $response;
};

$register_patterns_func();

return $response;
};
}
add_filter(
'rest_dispatch_request',
register_patterns_on_api_request(
function () {
require_once __DIR__ . '/block-patterns/class-block-patterns-from-api.php';
( new Block_Patterns_From_API() )->register_patterns();
}
),
10,
2
);

/**
* This function exists for back-compatibility. Patterns in Gutenberg v13.0.0 and
* newer are loaded over the API instead of injected into the document. While we
* register patterns in the API above, we still need to maintain compatibility
* with older Gutenberg versions and WP 5.9 without Gutenberg.
*
* This can be removed once the rest API approach is in core WordPress and available
* on Atomic and Simple sites. (Note that Atomic sites may disable the Gutenberg
* plugin, so we cannot guarantee its availability.)
*
* @param object $current_screen An object describing the wp-admin screen properties.
*/
function register_patterns_on_screen_load( $current_screen ) {
// No need to use this when the REST API approach is available.
if ( class_exists( 'WP_REST_Block_Pattern_Categories_Controller' ) || ! apply_filters( 'a8c_enable_block_patterns_api', false ) ) {
return;
}

$is_site_editor = ( function_exists( 'gutenberg_is_edit_site_page' ) && gutenberg_is_edit_site_page( $current_screen->id ) );

if ( ! $current_screen->is_block_editor && ! $is_site_editor ) {
return;
}

$editor_type = 'block_editor';

if ( $is_site_editor ) {
$editor_type = 'site_editor';
}

require_once __DIR__ . '/block-patterns/class-block-patterns-from-api.php';
$block_patterns_from_api = new Block_Patterns_From_API( $editor_type );
$block_patterns_from_api = new Block_Patterns_From_API();
$block_patterns_from_api->register_patterns();
}
add_action( 'current_screen', __NAMESPACE__ . '\load_block_patterns_from_api' );
add_action( 'current_screen', __NAMESPACE__ . '\register_patterns_on_screen_load' );

/**
* Load Block Inserter Modifications module.
Expand Down

0 comments on commit 9b70cf3

Please sign in to comment.