Skip to content

Commit

Permalink
Block Patterns: Automatically load headered files from a theme's `/pa…
Browse files Browse the repository at this point in the history
…tterns` directory (WordPress#36751)

* Try: Block Patterns: Automatically load headered files from a theme's /patterns directory

* Bump 'since' version

Props gziolo

Co-authored-by: Greg Ziółkowski <grzegorz@gziolo.pl>

* Move to compat/wordpress-6.0, prefix with "gutenberg_"

Per feedback from oandregal

* Support "Inserter" param

* Revert to hooking to 'init'

The Pattern block, which block templates can use, is dynamic, sourcing
patterns from WP_Block_Patterns_Registry. So we need a much broader
hook, such as `init`, to make sure file-based patterns are still
registered on the front end.

* Add notice reporting

* Try making Slug mandatory instead

* Misc. code quality and style fixes
  • Loading branch information
mcsf authored and jostnes committed Mar 23, 2022
1 parent fdc24ac commit 9ebd623
Showing 1 changed file with 142 additions and 0 deletions.
142 changes: 142 additions & 0 deletions lib/compat/wordpress-6.0/block-patterns.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,145 @@ function( $current_screen ) {
}
}
);

/**
* Register any patterns that the active theme may provide under its
* `./patterns/` directory. Each pattern is defined as a PHP file and defines
* its metadata using plugin-style headers. The minimum required definition is:
*
* /**
* * Title: My Pattern
* * Slug: my-theme/my-pattern
* *
*
* The output of the PHP source corresponds to the content of the pattern, e.g.:
*
* <main><p><?php echo "Hello"; ?></p></main>
*
* If applicable, this will collect from both parent and child theme.
*
* Other settable fields include:
*
* - Description
* - Viewport Width
* - Categories (comma-separated values)
* - Keywords (comma-separated values)
* - Block Types (comma-separated values)
* - Inserter (yes/no)
*
* @since 6.0.0
* @access private
* @internal
*/
function gutenberg_register_theme_block_patterns() {
$default_headers = array(
'title' => 'Title',
'slug' => 'Slug',
'description' => 'Description',
'viewportWidth' => 'Viewport Width',
'categories' => 'Categories',
'keywords' => 'Keywords',
'blockTypes' => 'Block Types',
'inserter' => 'Inserter',
);

// Register patterns for the active theme. If the theme is a child theme,
// let it override any patterns from the parent theme that shares the same
// slug.
foreach ( wp_get_active_and_valid_themes() as $theme ) {
$dirpath = $theme . '/patterns/';
if ( file_exists( $dirpath ) ) {
$files = glob( $dirpath . '*.php' );
if ( $files ) {
foreach ( $files as $file ) {
$pattern_data = get_file_data( $file, $default_headers );

if ( empty( $pattern_data['slug'] ) ) {
trigger_error(
sprintf(
/* translators: %s: file name. */
__( 'Could not register file "%s" as a block pattern ("Slug" field missing)', 'gutenberg' ),
$file
)
);
continue;
}

if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern_data['slug'] ) ) {
trigger_error(
sprintf(
/* translators: %1s: file name; %2s: slug value found. */
__( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")', 'gutenberg' ),
$file,
$pattern_data['slug']
)
);
}

if ( WP_Block_Patterns_Registry::get_instance()->is_registered( $pattern_data['slug'] ) ) {
continue;
}

// Title is a required property.
if ( ! $pattern_data['title'] ) {
trigger_error(
sprintf(
/* translators: %1s: file name; %2s: slug value found. */
__( 'Could not register file "%s" as a block pattern ("Title" field missing)', 'gutenberg' ),
$file
)
);
continue;
}

// For properties of type array, parse data as comma-separated.
foreach ( array( 'categories', 'keywords', 'blockTypes' ) as $property ) {
if ( ! empty( $pattern_data[ $property ] ) ) {
$pattern_data[ $property ] = array_filter(
preg_split(
'/[\s,]+/',
(string) $pattern_data[ $property ]
)
);
} else {
unset( $pattern_data[ $property ] );
}
}

// Parse properties of type int.
foreach ( array( 'viewportWidth' ) as $property ) {
if ( ! empty( $pattern_data[ $property ] ) ) {
$pattern_data[ $property ] = (int) $pattern_data[ $property ];
} else {
unset( $pattern_data[ $property ] );
}
}

// Parse properties of type bool.
foreach ( array( 'inserter' ) as $property ) {
if ( ! empty( $pattern_data[ $property ] ) ) {
$pattern_data[ $property ] = in_array(
strtolower( $pattern_data[ $property ] ),
array( 'yes', 'true' ),
true
);
} else {
unset( $pattern_data[ $property ] );
}
}

// The actual pattern content is the output of the file.
ob_start();
include $file;
$pattern_data['content'] = ob_get_clean();
if ( ! $pattern_data['content'] ) {
continue;
}

register_block_pattern( $pattern_data['slug'], $pattern_data );
}
}
}
}
}
add_action( 'init', 'gutenberg_register_theme_block_patterns' );

0 comments on commit 9ebd623

Please sign in to comment.