-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Block Patterns: Automatically load headered files from a theme's /patterns directory
#36751
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
Changes from all commits
ba1bbc6
98fb903
a585298
fb8cce6
f666088
388e8d1
72ab526
a915083
f06c16b
2e2fa4c
556e1e2
7b5a086
3df71d9
bc8471f
288e7f5
cd97aef
5d4594d
1f06b8a
4c48632
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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' ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Registering the patterns on Other pattern registration functions run on
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has been tried to be solved above but apparently we need the patters also on frontend, so checking current screen doesn't work here #36751 (comment)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, a template can contain a But what about remote patterns? A When the Seems we'll need to draw some sharp line between bundled and remote patterns. One can work with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is meant for themes essentially as a way to allow i18n for block templates. So the main use-cases is for the patterns registered by themes (like the current PR). This is a potential decent solution for the problem mentioned here #36751 (comment)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree that there's a strong need for the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there are three kind of remote patterns:
I think for 1 and 2, I'm not sure if there should be any difference in behavior with bundled patterns. The directory there just serves as a shortcut to avoid building these in the theme or core itself. For 3. We don't need any action or any specific treatment, we just load these on demand from the editor. So I think in the end, only one action should be needed.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I generally agree:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Remote patterns, however, are quite different in terms of performance and reliability. When serving a request to render, say, a site homepage, rendering a When rendering a frontend page, a reasonable expectation is that the server needs to access only reliable "local" resources, like filesystem or the MySQL database?
The pattern directory responses are cached for one hour with Ideally, there should be some autoupdate job that would download and sync the patterns to local FS or database, decoupled from serving frontend requests. Then the frontend request processing always works with local resources, and is more consistent and reliable. |
||
Uh oh!
There was an error while loading. Please reload this page.