Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ETK][GB 13.x] Fix loading of A8C-specific patterns in WPCOM #62745

Merged
merged 10 commits into from
Apr 15, 2022
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 ) ) {
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
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';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

( new Block_Patterns_From_API() )->register_patterns();
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
}
),
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