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

Add initial API to register patterns from themes and plugins #21074

Merged
merged 5 commits into from Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/designers-developers/developers/block-api/block-patterns.md
@@ -0,0 +1,37 @@
# Patterns (Experimental)

Copy link
Member

Choose a reason for hiding this comment

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

Let's add a disclaimer that this are is still under active development.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thinking of adding __experimental prefix as well.

Patterns are predefined block layouts, ready to insert and tweak.

**Note** Patterns are still under heavy development and the APIs are subject to change.

#### register_pattern

The editor comes with a list of built-in patterns. Theme and plugin authors can register addition custom patterns using the `register_pattern` function.

The `register_pattern` function receives the name of the pattern as the first argument and an array describing properties of the pattern as the second argument.

The properties of the style array must include `name` and `label`:
- `title`: A human-readable title for the pattern.
- `content`: Raw HTML content for the pattern.

```php
register_pattern(
'my-plugin/my-awesome-pattern',
array(
'title' => __( 'Two buttons', 'my-plugin' ),
'content' => "<!-- wp:buttons {\"align\":\"center\"} -->\n<div class=\"wp-block-buttons aligncenter\"><!-- wp:button {\"backgroundColor\":\"very-dark-gray\",\"borderRadius\":0} -->\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link has-background has-very-dark-gray-background-color no-border-radius\">Button One</a></div>\n<!-- /wp:button -->\n\n<!-- wp:button {\"textColor\":\"very-dark-gray\",\"borderRadius\":0,\"className\":\"is-style-outline\"} -->\n<div class=\"wp-block-button is-style-outline\"><a class=\"wp-block-button__link has-text-color has-very-dark-gray-color no-border-radius\">Button Two</a></div>\n<!-- /wp:button --></div>\n<!-- /wp:buttons -->",
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
)
);
```

#### unregister_pattern

`unregister_pattern` allows unregistering a pattern previously registered on the server using `register_pattern`.

The function's argument is the registered name of the pattern.

The following code sample unregisters the style named 'my-plugin/my-awesome-pattern':

```php
unregister_pattern( 'my-plugin/my-awesome-pattern' );
```
6 changes: 6 additions & 0 deletions docs/manifest.json
Expand Up @@ -83,6 +83,12 @@
"markdown_source": "../docs/designers-developers/developers/block-api/block-templates.md",
"parent": "block-api"
},
{
"title": "Patterns",
"slug": "block-patterns",
"markdown_source": "../docs/designers-developers/developers/block-api/block-patterns.md",
"parent": "block-api"
},
{
"title": "Annotations",
"slug": "block-annotations",
Expand Down
1 change: 1 addition & 0 deletions docs/toc.json
Expand Up @@ -15,6 +15,7 @@
{ "docs/designers-developers/developers/block-api/block-attributes.md": [] },
{"docs/designers-developers/developers/block-api/block-deprecation.md": [] },
{ "docs/designers-developers/developers/block-api/block-templates.md": [] },
{ "docs/designers-developers/developers/block-api/block-patterns.md": [] },
{ "docs/designers-developers/developers/block-api/block-annotations.md": [] }
] },
{ "docs/designers-developers/developers/filters/README.md": [
Expand Down
137 changes: 137 additions & 0 deletions lib/class-wp-patterns-registry.php
@@ -0,0 +1,137 @@
<?php
/**
* Blocks API: WP_Patterns_Registry class
*
* @package Gutenberg
*/

/**
* Class used for interacting with patterns.
*/
final class WP_Patterns_Registry {
/**
* Registered patterns array.
*
* @var array
*/
private $registered_patterns = array();

/**
* Container for the main instance of the class.
*
* @var WP_Patterns_Registry|null
*/
private static $instance = null;

/**
* Registers a pattern.
*
* @param string $pattern_name Pattern name including namespace.
* @param array $pattern_properties Array containing the properties of the pattern: label, content.
* @return boolean True if the pattern was registered with success and false otherwise.
*/
public function register( $pattern_name, $pattern_properties ) {
if ( ! isset( $pattern_name ) || ! is_string( $pattern_name ) ) {
$message = __( 'Pattern name must be a string.', 'gutenberg' );
_doing_it_wrong( __METHOD__, $message, '7.8.0' );
return false;
}

$this->registered_patterns[ $pattern_name ] = $pattern_properties;

return true;
}

/**
* Unregisters a pattern.
*
* @param string $pattern_name Pattern name including namespace.
* @return boolean True if the pattern was unregistered with success and false otherwise.
*/
public function unregister( $pattern_name ) {
if ( ! $this->is_registered( $pattern_name ) ) {
/* translators: 1: Pattern name. */
$message = sprintf( __( 'Pattern "%1$s" not found.', 'gutenberg' ), $pattern_name );
_doing_it_wrong( __METHOD__, $message, '7.8.0' );
return false;
}

unset( $this->registered_patterns[ $pattern_name ] );

return true;
}

/**
* Retrieves an array containing the properties of a registered pattern.
*
* @param string $pattern_name Pattern name including namespace.
* @return array Registered pattern properties.
*/
public function get_registered( $pattern_name ) {
if ( ! $this->is_registered( $pattern_name ) ) {
return null;
}

return $this->registered_patterns[ $pattern_name ];
}

/**
* Retrieves all registered patterns.
*
* @return array Array of arrays containing the registered patterns properties,
* and per style.
*/
public function get_all_registered() {
return array_values( $this->registered_patterns );
}

/**
* Checks if a pattern is registered.
*
* @param string $pattern_name Pattern name including namespace.
* @return bool True if the pattern is registered, false otherwise.
*/
public function is_registered( $pattern_name ) {
return isset( $this->registered_patterns[ $pattern_name ] );
}

/**
* Utility method to retrieve the main instance of the class.
*
* The instance will be created if it does not exist yet.
*
* @since 5.3.0
*
* @return WP_Patterns_Registry The main instance.
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}

return self::$instance;
}
}

/**
* Registers a new pattern.
*
* @param string $pattern_name Pattern name including namespace.
* @param array $pattern_properties Array containing the properties of the pattern.
*
* @return boolean True if the pattern was registered with success and false otherwise.
*/
function register_pattern( $pattern_name, $pattern_properties ) {
return WP_Patterns_Registry::get_instance()->register( $pattern_name, $pattern_properties );
}
Comment on lines +124 to +126
Copy link
Member

@aduth aduth Mar 27, 2020

Choose a reason for hiding this comment

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

Would it be better to have named this as specific to blocks: register_block_pattern ?

Same goes for:

  • unregister_pattern
  • WP_Patterns_Registry

When considering the WordPress function API broadly, it's not obvious by these names they have anything to do with blocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it was decided to name these "Patterns" and not "Block Patterns". cc @mtias


/**
* Unregisters a pattern.
*
* @param string $pattern_name Pattern name including namespace.
*
* @return boolean True if the pattern was unregistered with success and false otherwise.
*/
function unregister_pattern( $pattern_name ) {
return WP_Patterns_Registry::get_instance()->unregister( $pattern_name );
}
18 changes: 12 additions & 6 deletions lib/client-assets.php
Expand Up @@ -639,15 +639,21 @@ function gutenberg_extend_settings_block_patterns( $settings ) {
}

$settings['__experimentalBlockPatterns'] = array_merge(
[
gutenberg_load_block_pattern( 'text-two-columns' ),
gutenberg_load_block_pattern( 'two-buttons' ),
gutenberg_load_block_pattern( 'cover-abc' ),
gutenberg_load_block_pattern( 'two-images' ),
],
WP_Patterns_Registry::get_instance()->get_all_registered(),
$settings['__experimentalBlockPatterns']
);

return $settings;
}
add_filter( 'block_editor_settings', 'gutenberg_extend_settings_block_patterns', 0 );


/*
* Register default patterns if not registered in Core already.
*/
if ( ! WP_Patterns_Registry::get_instance()->is_registered( 'text-two-columns' ) ) {
register_pattern( 'core/text-two-columns', gutenberg_load_block_pattern( 'text-two-columns' ) );
register_pattern( 'core/two-buttons', gutenberg_load_block_pattern( 'two-buttons' ) );
register_pattern( 'core/cover-abc', gutenberg_load_block_pattern( 'cover-abc' ) );
register_pattern( 'core/two-images', gutenberg_load_block_pattern( 'two-images' ) );
}
Comment on lines +651 to +659
Copy link
Member

Choose a reason for hiding this comment

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

4 changes: 4 additions & 0 deletions lib/load.php
Expand Up @@ -59,6 +59,10 @@ function gutenberg_is_experiment_enabled( $name ) {
require dirname( __FILE__ ) . '/class-wp-block-styles-registry.php';
}

if ( ! class_exists( 'WP_Patterns_Registry' ) ) {
require dirname( __FILE__ ) . '/class-wp-patterns-registry.php';
}

require dirname( __FILE__ ) . '/compat.php';

require dirname( __FILE__ ) . '/blocks.php';
Expand Down