Cache block pattern data (#51802)

* Cache block pattern data to optimize pattern registration

* Add tests around block pattern registration

* Test cached block pattern registration

* Add tests around invalid cached data

* Remove unused mock package

* Add changelog entry

* Fix up linting issues

* Bump transient time up to one month
This commit is contained in:
Joshua T Flowers 2024-10-07 22:33:57 -04:00 committed by GitHub
parent 9d2ab83b8a
commit ee9074c8a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 285 additions and 5 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: performance
Cache block pattern data

View File

@ -1,4 +1,6 @@
<?php
declare(strict_types=1);
namespace Automattic\WooCommerce\Blocks;
use Automattic\WooCommerce\Admin\Features\Features;
@ -99,6 +101,24 @@ class BlockPatterns {
return;
}
$patterns = $this->get_block_patterns();
foreach ( $patterns as $pattern ) {
$this->pattern_registry->register_block_pattern( $pattern['source'], $pattern, $this->dictionary );
}
}
/**
* Gets block pattern data from the cache if available
*
* @return array Block pattern data.
*/
private function get_block_patterns() {
$pattern_data = $this->get_pattern_cache();
if ( is_array( $pattern_data ) ) {
return $pattern_data;
}
$default_headers = array(
'title' => 'Title',
'slug' => 'Slug',
@ -112,19 +132,53 @@ class BlockPatterns {
);
if ( ! file_exists( $this->patterns_path ) ) {
return;
return array();
}
$files = glob( $this->patterns_path . '/*.php' );
if ( ! $files ) {
return;
return array();
}
$patterns = array();
foreach ( $files as $file ) {
$pattern_data = get_file_data( $file, $default_headers );
$this->pattern_registry->register_block_pattern( $file, $pattern_data, $this->dictionary );
$data = get_file_data( $file, $default_headers );
$data['source'] = $file;
$patterns[] = $data;
}
$this->set_pattern_cache( $patterns );
return $patterns;
}
/**
* Gets block pattern cache.
*
* @return array|false Returns an array of patterns if cache is found, otherwise false.
*/
private function get_pattern_cache() {
$pattern_data = get_site_transient( 'woocommerce_blocks_patterns' );
if ( is_array( $pattern_data ) && WOOCOMMERCE_VERSION === $pattern_data['version'] ) {
return $pattern_data['patterns'];
}
return false;
}
/**
* Sets block pattern cache.
*
* @param array $patterns Block patterns data to set in cache.
*/
private function set_pattern_cache( array $patterns ) {
$pattern_data = array(
'version' => WOOCOMMERCE_VERSION,
'patterns' => $patterns,
);
set_site_transient( 'woocommerce_blocks_patterns', $pattern_data, MONTH_IN_SECONDS );
}
/**

View File

@ -0,0 +1,190 @@
<?php
declare( strict_types = 1 );
namespace Automattic\WooCommerce\Tests\Blocks\BlockPatterns;
use Automattic\WooCommerce\Blocks\Patterns\PatternRegistry;
use Automattic\WooCommerce\Blocks\BlockPatterns as TestedBlockPatterns;
use Automattic\WooCommerce\Blocks\Patterns\PTKPatternsStore;
use Automattic\WooCommerce\Blocks\Domain\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
use Automattic\WooCommerce\Blocks\AIContent\PatternsHelper;
/**
* Unit tests for the BlockPatterns class.
*/
class BlockPatterns extends \WP_UnitTestCase {
/**
* Holds the BlockPatterns under test.
*
* @var TestedBlockPatterns The BlockPatterns under test.
*/
private $block_patterns;
/**
* Holds the mock PatternRegistry instance.
*
* @var PatternRegistry The mock PatternRegistry.
*/
private $pattern_registry;
/**
* Holds the mock PTKPatternsStore instance.
*
* @var PTKPatternsStore The mock PTKPatternsStore.
*/
private $ptk_patterns_store;
/**
* Sets up a new TestedBlockPatterns so it can be tested.
*/
protected function setUp(): void {
parent::setUp();
delete_site_transient( 'woocommerce_blocks_patterns' );
$package = new Package( '0.1.0', __DIR__, new FeatureGating() );
$this->pattern_registry = $this->createMock( PatternRegistry::class );
$this->ptk_patterns_store = $this->createMock( PTKPatternsStore::class );
$this->block_patterns = new TestedBlockPatterns(
$package,
$this->pattern_registry,
$this->ptk_patterns_store
);
}
/**
* Tests if patterns are registered with the correct pattern data.
*/
public function test_block_patterns_registration() {
$this->pattern_registry
->expects( $this->exactly( 2 ) )
->method( 'register_block_pattern' )
->withConsecutive(
array(
__DIR__ . '/patterns/mock-footer.php',
array(
'title' => 'Mock Footer',
'slug' => 'woocommerce-blocks/mock-footer',
'description' => '',
'viewportWidth' => '',
'categories' => 'WooCommerce',
'keywords' => '',
'blockTypes' => 'core/template-part/footer',
'inserter' => '',
'featureFlag' => '',
'source' => __DIR__ . '/patterns/mock-footer.php',
),
PatternsHelper::get_patterns_dictionary(),
),
array(
__DIR__ . '/patterns/mock-header.php',
array(
'title' => 'Mock Header',
'slug' => 'woocommerce-blocks/mock-header',
'description' => '',
'viewportWidth' => '',
'categories' => 'WooCommerce',
'keywords' => '',
'blockTypes' => 'core/template-part/header',
'inserter' => '',
'featureFlag' => '',
'source' => __DIR__ . '/patterns/mock-header.php',
),
PatternsHelper::get_patterns_dictionary(),
),
);
$this->block_patterns->register_block_patterns();
}
/**
* Tests if patterns are registered with the cached data.
*/
public function test_cached_block_patterns_registration() {
$mock_patterns = array(
array(
'title' => 'Mock Cached',
'source' => __DIR__ . '/patterns/mock-cached.php',
),
);
$pattern_data = array(
'version' => WOOCOMMERCE_VERSION,
'patterns' => $mock_patterns,
);
set_site_transient( 'woocommerce_blocks_patterns', $pattern_data );
$this->pattern_registry
->expects( $this->exactly( 1 ) )
->method( 'register_block_pattern' )
->with(
__DIR__ . '/patterns/mock-cached.php',
$mock_patterns[0],
PatternsHelper::get_patterns_dictionary()
);
$this->block_patterns->register_block_patterns();
}
/**
* Tests if patterns are registered with the cached data.
*/
public function test_invalid_cached_block_patterns_registration() {
$mock_patterns = array(
array(
'title' => 'Mock Cached',
'source' => __DIR__ . '/patterns/mock-cached.php',
),
);
$pattern_data = array(
'version' => '1.0.0-old',
'patterns' => $mock_patterns,
);
set_site_transient( 'woocommerce_blocks_patterns', $pattern_data );
$this->pattern_registry
->expects( $this->exactly( 2 ) )
->method( 'register_block_pattern' )
->withConsecutive(
array(
__DIR__ . '/patterns/mock-footer.php',
array(
'title' => 'Mock Footer',
'slug' => 'woocommerce-blocks/mock-footer',
'description' => '',
'viewportWidth' => '',
'categories' => 'WooCommerce',
'keywords' => '',
'blockTypes' => 'core/template-part/footer',
'inserter' => '',
'featureFlag' => '',
'source' => __DIR__ . '/patterns/mock-footer.php',
),
PatternsHelper::get_patterns_dictionary(),
),
array(
__DIR__ . '/patterns/mock-header.php',
array(
'title' => 'Mock Header',
'slug' => 'woocommerce-blocks/mock-header',
'description' => '',
'viewportWidth' => '',
'categories' => 'WooCommerce',
'keywords' => '',
'blockTypes' => 'core/template-part/header',
'inserter' => '',
'featureFlag' => '',
'source' => __DIR__ . '/patterns/mock-header.php',
),
PatternsHelper::get_patterns_dictionary(),
),
);
$this->block_patterns->register_block_patterns();
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* Title: Mock Footer
* Slug: woocommerce-blocks/mock-footer
* Categories: WooCommerce
* Block Types: core/template-part/footer
*/
declare( strict_types = 1 );
?>
<!-- wp:group {"style":{"spacing":{"blockGap":"20px"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
Mock footer
</div>
<!-- /wp:group -->

View File

@ -0,0 +1,16 @@
<?php
/**
* Title: Mock Header
* Slug: woocommerce-blocks/mock-header
* Categories: WooCommerce
* Block Types: core/template-part/header
*/
declare( strict_types = 1 );
?>
<!-- wp:group {"style":{"spacing":{"blockGap":"20px"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
Mock header
</div>
<!-- /wp:group -->