diff --git a/lib/compat/wordpress-6.0/block-patterns.php b/lib/compat/wordpress-6.0/block-patterns.php index d5b131c88f5300..b9ca9107fe413c 100644 --- a/lib/compat/wordpress-6.0/block-patterns.php +++ b/lib/compat/wordpress-6.0/block-patterns.php @@ -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.: + * + *

+ * + * 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' );