<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[50527] trunk: Editor: Make block type aware of variations</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/50527">50527</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/50527","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>gziolo</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2021-03-12 13:33:21 +0000 (Fri, 12 Mar 2021)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Editor: Make block type aware of variations

Currently block variations are only defined on the client. In some cases, creating block variations on the server can be very useful, especially when needed data is not exposed in the REST APIs.

Related to https://github.com/WordPress/gutenberg/pull/29095.

Props: gwwar, timothyblynjacobs.
Fixes: <a href="https://core.trac.wordpress.org/ticket/52688">#52688</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludespostphp">trunk/src/wp-admin/includes/post.php</a></li>
<li><a href="#trunksrcwpincludesclasswpblocktypephp">trunk/src/wp-includes/class-wp-block-type.php</a></li>
<li><a href="#trunksrcwpincludespostphp">trunk/src/wp-includes/post.php</a></li>
<li><a href="#trunksrcwpincludesrestapiendpointsclasswprestblocktypescontrollerphp">trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php</a></li>
<li><a href="#trunksrcwpincludestaxonomyphp">trunk/src/wp-includes/taxonomy.php</a></li>
<li><a href="#trunktestsphpunittestsadminincludesPostphp">trunk/tests/phpunit/tests/admin/includesPost.php</a></li>
<li><a href="#trunktestsphpunittestsrestapirestblocktypecontrollerphp">trunk/tests/phpunit/tests/rest-api/rest-block-type-controller.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminincludespostphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/post.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/post.php      2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/src/wp-admin/includes/post.php        2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2257,6 +2257,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'parent'           => 'parent',
</span><span class="cx" style="display: block; padding: 0 10px">                'keywords'         => 'keywords',
</span><span class="cx" style="display: block; padding: 0 10px">                'example'          => 'example',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'variations'       => 'variations',
</ins><span class="cx" style="display: block; padding: 0 10px">         );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpblocktypephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-block-type.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-block-type.php     2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/src/wp-includes/class-wp-block-type.php       2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -100,6 +100,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public $styles = array();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Block variations.
+        * @since 5.8.0
+        * @var array
+        */
+       public $variations = array();
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Supported features.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 5.5.0
</span></span></pre></div>
<a id="trunksrcwpincludespostphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/post.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/post.php    2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/src/wp-includes/post.php      2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1703,6 +1703,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * - `item_scheduled` - Label used when an item is scheduled for publishing. Default is 'Post scheduled.' /
</span><span class="cx" style="display: block; padding: 0 10px">  *                    'Page scheduled.'
</span><span class="cx" style="display: block; padding: 0 10px">  * - `item_updated` - Label used when an item is updated. Default is 'Post updated.' / 'Page updated.'
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * - `item_link` - Title for a navigation link block variation. Default is 'Post Link' / 'Page Link'.
+ * - `item_link_description` - Description for a navigation link block variation. Default is 'A link to a post.' /
+ *                             'A link to a page.'
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Above, the first default value is for non-hierarchical post types (like posts)
</span><span class="cx" style="display: block; padding: 0 10px">  * and the second one is for hierarchical post types (like pages).
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1726,7 +1729,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @return object Object with all the labels as member variables.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_post_type_labels( $post_type_object ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $nohier_vs_hier_defaults              = array(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $nohier_vs_hier_defaults                  = array(
</ins><span class="cx" style="display: block; padding: 0 10px">                 'name'                     => array( _x( 'Posts', 'post type general name' ), _x( 'Pages', 'post type general name' ) ),
</span><span class="cx" style="display: block; padding: 0 10px">                'singular_name'            => array( _x( 'Post', 'post type singular name' ), _x( 'Page', 'post type singular name' ) ),
</span><span class="cx" style="display: block; padding: 0 10px">                'add_new'                  => array( _x( 'Add New', 'post' ), _x( 'Add New', 'page' ) ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1757,6 +1760,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'item_reverted_to_draft'   => array( __( 'Post reverted to draft.' ), __( 'Page reverted to draft.' ) ),
</span><span class="cx" style="display: block; padding: 0 10px">                'item_scheduled'           => array( __( 'Post scheduled.' ), __( 'Page scheduled.' ) ),
</span><span class="cx" style="display: block; padding: 0 10px">                'item_updated'             => array( __( 'Post updated.' ), __( 'Page updated.' ) ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'item_link'                => array(
+                       _x( 'Post Link', 'navigation link block title' ),
+                       _x( 'Page Link', 'navigation link block title' ),
+               ),
+               'item_link_description'    => array(
+                       _x( 'A link to a post.', 'navigation link block description' ),
+                       _x( 'A link to a page.', 'navigation link block description' ),
+               ),
</ins><span class="cx" style="display: block; padding: 0 10px">         );
</span><span class="cx" style="display: block; padding: 0 10px">        $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludesrestapiendpointsclasswprestblocktypescontrollerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php 2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php   2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -274,6 +274,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'script',
</span><span class="cx" style="display: block; padding: 0 10px">                        'editor_style',
</span><span class="cx" style="display: block; padding: 0 10px">                        'style',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'variations',
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $extra_fields as $extra_field ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( rest_is_field_included( $extra_field, $fields ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -361,6 +362,71 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        return $this->add_additional_fields_schema( $this->schema );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                //rest_validate_value_from_schema doesn't understand $refs, pull out reused definitions for readability.
+               $inner_blocks_definition = array(
+                       'description' => __( 'The list of inner blocks used in the example.' ),
+                       'type'        => 'array',
+                       'items'       => array(
+                               'type'       => 'object',
+                               'properties' => array(
+                                       'name'        => array(
+                                               'description' => __( 'The name of the inner block.' ),
+                                               'type'        => 'string',
+                                       ),
+                                       'attributes'  => array(
+                                               'description' => __( 'The attributes of the inner block.' ),
+                                               'type'        => 'object',
+                                       ),
+                                       'innerBlocks' => array(
+                                               'description' => __( "A list of the inner block's own inner blocks. This is a recursive definition following the parent innerBlocks schema." ),
+                                               'type'        => 'array',
+                                       ),
+                               ),
+                       ),
+               );
+
+               $example_definition      = array(
+                       'description' => __( 'Block example.' ),
+                       'type'        => array( 'object', 'null' ),
+                       'default'     => null,
+                       'properties'  => array(
+                               'attributes'  => array(
+                                       'description' => __( 'The attributes used in the example.' ),
+                                       'type'        => 'object',
+                               ),
+                               'innerBlocks' => $inner_blocks_definition,
+                       ),
+                       'context'     => array( 'embed', 'view', 'edit' ),
+                       'readonly'    => true,
+               );
+
+               $keywords_definition = array(
+                       'description' => __( 'Block keywords.' ),
+                       'type'        => 'array',
+                       'items'       => array(
+                               'type' => 'string',
+                       ),
+                       'default'     => array(),
+                       'context'     => array( 'embed', 'view', 'edit' ),
+                       'readonly'    => true,
+               );
+
+               $icon_definition = array(
+                       'description' => __( 'Icon of block type.' ),
+                       'type'        => array( 'string', 'null' ),
+                       'default'     => null,
+                       'context'     => array( 'embed', 'view', 'edit' ),
+                       'readonly'    => true,
+               );
+
+               $category_definition = array(
+                       'description' => __( 'Block category.' ),
+                       'type'        => array( 'string', 'null' ),
+                       'default'     => null,
+                       'context'     => array( 'embed', 'view', 'edit' ),
+                       'readonly'    => true,
+               );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $schema = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        '$schema'    => 'http://json-schema.org/draft-04/schema#',
</span><span class="cx" style="display: block; padding: 0 10px">                        'title'      => 'block-type',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -394,13 +460,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'context'     => array( 'embed', 'view', 'edit' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'readonly'    => true,
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'icon'             => array(
-                                       'description' => __( 'Icon of block type.' ),
-                                       'type'        => array( 'string', 'null' ),
-                                       'default'     => null,
-                                       'context'     => array( 'embed', 'view', 'edit' ),
-                                       'readonly'    => true,
-                               ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'icon'             => $icon_definition,
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'attributes'       => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'description'          => __( 'Block attributes.' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'type'                 => array( 'object', 'null' ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -441,13 +501,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'context'     => array( 'embed', 'view', 'edit' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'readonly'    => true,
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'category'         => array(
-                                       'description' => __( 'Block category.' ),
-                                       'type'        => array( 'string', 'null' ),
-                                       'default'     => null,
-                                       'context'     => array( 'embed', 'view', 'edit' ),
-                                       'readonly'    => true,
-                               ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'category'         => $category_definition,
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'is_dynamic'       => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'description' => __( 'Is the block dynamically rendered.' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'type'        => 'boolean',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -512,6 +566,58 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'context'     => array( 'embed', 'view', 'edit' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'readonly'    => true,
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                'variations'       => array(
+                                       'description' => __( 'Block variations.' ),
+                                       'type'        => 'array',
+                                       'items'       => array(
+                                               'type'       => 'object',
+                                               'properties' => array(
+                                                       'name'        => array(
+                                                               'description' => __( 'The unique and machine-readable name.' ),
+                                                               'type'        => 'string',
+                                                               'required'    => true,
+                                                       ),
+                                                       'title'       => array(
+                                                               'description' => __( 'A human-readable variation title.' ),
+                                                               'type'        => 'string',
+                                                               'required'    => true,
+                                                       ),
+                                                       'description' => array(
+                                                               'description' => __( 'A detailed variation description.' ),
+                                                               'type'        => 'string',
+                                                               'required'    => false,
+                                                       ),
+                                                       'category'    => $category_definition,
+                                                       'icon'        => $icon_definition,
+                                                       'isDefault'   => array(
+                                                               'description' => __( 'Indicates whether the current variation is the default one.' ),
+                                                               'type'        => 'boolean',
+                                                               'required'    => false,
+                                                               'default'     => false,
+                                                       ),
+                                                       'attributes'  => array(
+                                                               'description' => __( 'The initial values for attributes.' ),
+                                                               'type'        => 'object',
+                                                       ),
+                                                       'innerBlocks' => $inner_blocks_definition,
+                                                       'example'     => $example_definition,
+                                                       'scope'       => array(
+                                                               'description' => __( 'The list of scopes where the variation is applicable. When not provided, it assumes all available scopes.' ),
+                                                               'type'        => array( 'array', 'null' ),
+                                                               'default'     => null,
+                                                               'items'       => array(
+                                                                       'type' => 'string',
+                                                                       'enum' => array( 'block', 'inserter', 'transform' ),
+                                                               ),
+                                                               'readonly'    => true,
+                                                       ),
+                                                       'keywords'    => $keywords_definition,
+                                               ),
+                                       ),
+                                       'readonly'    => true,
+                                       'context'     => array( 'embed', 'view', 'edit' ),
+                                       'default'     => null,
+                               ),
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'textdomain'       => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'description' => __( 'Public text domain.' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'type'        => array( 'string', 'null' ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -529,50 +635,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'context'     => array( 'embed', 'view', 'edit' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'readonly'    => true,
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'keywords'         => array(
-                                       'description' => __( 'Block keywords.' ),
-                                       'type'        => 'array',
-                                       'items'       => array(
-                                               'type' => 'string',
-                                       ),
-                                       'default'     => array(),
-                                       'context'     => array( 'embed', 'view', 'edit' ),
-                                       'readonly'    => true,
-                               ),
-                               'example'          => array(
-                                       'description' => __( 'Block example.' ),
-                                       'type'        => array( 'object', 'null' ),
-                                       'default'     => null,
-                                       'properties'  => array(
-                                               'attributes'  => array(
-                                                       'description' => __( 'The attributes used in the example.' ),
-                                                       'type'        => 'object',
-                                               ),
-                                               'innerBlocks' => array(
-                                                       'description' => __( 'The list of inner blocks used in the example.' ),
-                                                       'type'        => 'array',
-                                                       'items'       => array(
-                                                               'type'       => 'object',
-                                                               'properties' => array(
-                                                                       'name'        => array(
-                                                                               'description' => __( 'The name of the inner block.' ),
-                                                                               'type'        => 'string',
-                                                                       ),
-                                                                       'attributes'  => array(
-                                                                               'description' => __( 'The attributes of the inner block.' ),
-                                                                               'type'        => 'object',
-                                                                       ),
-                                                                       'innerBlocks' => array(
-                                                                               'description' => __( "A list of the inner block's own inner blocks. This is a recursive definition following the parent innerBlocks schema." ),
-                                                                               'type'        => 'array',
-                                                                       ),
-                                                               ),
-                                                       ),
-                                               ),
-                                       ),
-                                       'context'     => array( 'embed', 'view', 'edit' ),
-                                       'readonly'    => true,
-                               ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'keywords'         => $keywords_definition,
+                               'example'          => $example_definition,
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludestaxonomyphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/taxonomy.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/taxonomy.php        2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/src/wp-includes/taxonomy.php  2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -576,6 +576,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *     @type string $items_list                 Label for the table hidden heading.
</span><span class="cx" style="display: block; padding: 0 10px">  *     @type string $most_used                  Title for the Most Used tab. Default 'Most Used'.
</span><span class="cx" style="display: block; padding: 0 10px">  *     @type string $back_to_items              Label displayed after a term has been updated.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *     @type string $item_link                  Used in the block editor. Title for a navigation link block variation.
+ *                                              Default 'Tag Link'/'Category Link'.
+ *     @type string $item_link_description      Used in the block editor. Description for a navigation link block
+ *                                              variation. Default 'A link to a tag.'/'A link to a category'.
</ins><span class="cx" style="display: block; padding: 0 10px">  * }
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_taxonomy_labels( $tax ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -613,6 +617,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: Tab heading when selecting from the most used terms. */
</span><span class="cx" style="display: block; padding: 0 10px">                'most_used'                  => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ),
</span><span class="cx" style="display: block; padding: 0 10px">                'back_to_items'              => array( __( '&larr; Go to Tags' ), __( '&larr; Go to Categories' ) ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'item_link'                  => array(
+                       _x( 'Tag Link', 'navigation link block title' ),
+                       _x( 'Category Link', 'navigation link block description' ),
+               ),
+               'item_link_description'      => array(
+                       _x( 'A link to a tag.', 'navigation link block description' ),
+                       _x( 'A link to a category.', 'navigation link block description' ),
+               ),
</ins><span class="cx" style="display: block; padding: 0 10px">         );
</span><span class="cx" style="display: block; padding: 0 10px">        $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsphpunittestsadminincludesPostphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/admin/includesPost.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/admin/includesPost.php  2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/tests/phpunit/tests/admin/includesPost.php    2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -847,6 +847,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                'category'    => 'common',
</span><span class="cx" style="display: block; padding: 0 10px">                                'styles'      => array(),
</span><span class="cx" style="display: block; padding: 0 10px">                                'keywords'    => array(),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                'variations'  => array(),
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                        $blocks[ $name ]
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span></span></pre></div>
<a id="trunktestsphpunittestsrestapirestblocktypecontrollerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/rest-api/rest-block-type-controller.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/rest-api/rest-block-type-controller.php 2021-03-12 12:06:25 UTC (rev 50526)
+++ trunk/tests/phpunit/tests/rest-api/rest-block-type-controller.php   2021-03-12 13:33:21 UTC (rev 50527)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -224,6 +224,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'styles'           => 'invalid_styles',
</span><span class="cx" style="display: block; padding: 0 10px">                        'render_callback'  => 'invalid_callback',
</span><span class="cx" style="display: block; padding: 0 10px">                        'textdomain'       => true,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'variations'       => 'invalid_variations',
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                register_block_type( $block_type, $settings );
</span><span class="cx" style="display: block; padding: 0 10px">                wp_set_current_user( self::$admin_id );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -249,6 +250,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertNull( $data['category'] );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertNull( $data['textdomain'] );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $data['is_dynamic'] );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->assertSameSets( array( array() ), $data['variations'] );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -275,6 +277,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'render_callback'  => false,
</span><span class="cx" style="display: block; padding: 0 10px">                        'textdomain'       => false,
</span><span class="cx" style="display: block; padding: 0 10px">                        'example'          => false,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'variations'       => false,
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                register_block_type( $block_type, $settings );
</span><span class="cx" style="display: block; padding: 0 10px">                wp_set_current_user( self::$admin_id );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -301,8 +304,67 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertNull( $data['example'] );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertNull( $data['textdomain'] );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $data['is_dynamic'] );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->assertSameSets( array(), $data['variations'] );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        public function test_get_variation() {
+               $block_type = 'fake/variations';
+               $settings   = array(
+                       'title'       => 'variations block test',
+                       'description' => 'a variations block test',
+                       'attributes'  => array( 'kind' => array( 'type' => 'string' ) ),
+                       'variations'  => array(
+                               array(
+                                       'name'        => 'variation',
+                                       'title'       => 'variation title',
+                                       'description' => 'variation description',
+                                       'category'    => 'media',
+                                       'icon'        => 'checkmark',
+                                       'attributes'  => array( 'kind' => 'foo' ),
+                                       'isDefault'   => true,
+                                       'example'     => array( 'attributes' => array( 'kind' => 'example' ) ),
+                                       'scope'       => array( 'inserter', 'block' ),
+                                       'keywords'    => array( 'dogs', 'cats', 'mice' ),
+                                       'innerBlocks' => array(
+                                               array(
+                                                       'name'       => 'fake/bar',
+                                                       'attributes' => array( 'label' => 'hi' ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               register_block_type( $block_type, $settings );
+               wp_set_current_user( self::$admin_id );
+               $request  = new WP_REST_Request( 'GET', '/wp/v2/block-types/' . $block_type );
+               $response = rest_get_server()->dispatch( $request );
+               $data     = $response->get_data();
+               $this->assertSame( $block_type, $data['name'] );
+               $this->assertArrayHasKey( 'variations', $data );
+               $this->assertSame( 1, count( $data['variations'] ) );
+               $variation = $data['variations'][0];
+               $this->assertSame( 'variation title', $variation['title'] );
+               $this->assertSame( 'variation description', $variation['description'] );
+               $this->assertSame( 'media', $variation['category'] );
+               $this->assertSame( 'checkmark', $variation['icon'] );
+               $this->assertSameSets( array( 'inserter', 'block' ), $variation['scope'] );
+               $this->assertSameSets( array( 'dogs', 'cats', 'mice' ), $variation['keywords'] );
+               $this->assertSameSets( array( 'attributes' => array( 'kind' => 'example' ) ), $variation['example'] );
+               $this->assertSameSets(
+                       array(
+                               array(
+                                       'name'       => 'fake/bar',
+                                       'attributes' => array( 'label' => 'hi' ),
+                               ),
+                       ),
+                       $variation['innerBlocks']
+               );
+               $this->assertSameSets(
+                       array( 'kind' => 'foo' ),
+                       $variation['attributes']
+               );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 47620
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -312,7 +374,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $response   = rest_get_server()->dispatch( $request );
</span><span class="cx" style="display: block; padding: 0 10px">                $data       = $response->get_data();
</span><span class="cx" style="display: block; padding: 0 10px">                $properties = $data['schema']['properties'];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertCount( 20, $properties );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertCount( 21, $properties );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertArrayHasKey( 'api_version', $properties );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertArrayHasKey( 'title', $properties );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertArrayHasKey( 'icon', $properties );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -333,6 +395,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertArrayHasKey( 'example', $properties );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertArrayHasKey( 'uses_context', $properties );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertArrayHasKey( 'provides_context', $properties );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->assertArrayHasKey( 'variations', $properties );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span></span></pre>
</div>
</div>

</body>
</html>