<!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>[54118] trunk: Editor: Backport Elements API updates.</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/54118">54118</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/54118","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>SergeyBiryukov</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2022-09-10 12:37:00 +0000 (Sat, 10 Sep 2022)</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: Backport Elements API updates.
This commit backports the original PRs from Gutenberg repository:
* [https://github.com/WordPress/gutenberg/pull/40260 <a href="https://core.trac.wordpress.org/ticket/40260">#40260</a> Add support for button elements to theme.json]
* [https://github.com/WordPress/gutenberg/pull/40889 <a href="https://core.trac.wordpress.org/ticket/40889">#40889</a> Theme Json: Don't output double selectors for elements inside blocks]
* [https://github.com/WordPress/gutenberg/pull/41140 <a href="https://core.trac.wordpress.org/ticket/41140">#41140</a> Global Styles: Add support for caption elements]
* [https://github.com/WordPress/gutenberg/pull/41160 <a href="https://core.trac.wordpress.org/ticket/41160">#41160</a> Global Styles: Load block CSS conditionally]
* [https://github.com/WordPress/gutenberg/pull/41240 <a href="https://core.trac.wordpress.org/ticket/41240">#41240</a> Global Styles: Button Element: update button element selector]
* [https://github.com/WordPress/gutenberg/pull/41335 <a href="https://core.trac.wordpress.org/ticket/41335">#41335</a> Duotone: Fix CSS Selectors rendered by theme.json duotone/filter settings for blocks on public pages]
* [https://github.com/WordPress/gutenberg/pull/41446 <a href="https://core.trac.wordpress.org/ticket/41446">#41446</a> Block styles: Account for style block nodes that have no name]
* [https://github.com/WordPress/gutenberg/pull/41696 <a href="https://core.trac.wordpress.org/ticket/41696">#41696</a> Global Styles: Allow references to values in other locations in the tree]
* [https://github.com/WordPress/gutenberg/pull/41753 <a href="https://core.trac.wordpress.org/ticket/41753">#41753</a> Elements: Add an API make it easier to get class names]
* [https://github.com/WordPress/gutenberg/pull/41786 <a href="https://core.trac.wordpress.org/ticket/41786">#41786</a> Support pseudo selectors on elements in theme json]
* [https://github.com/WordPress/gutenberg/pull/41822 <a href="https://core.trac.wordpress.org/ticket/41822">#41822</a> Elements: Button - Fix element selectors]
* [https://github.com/WordPress/gutenberg/pull/41981 <a href="https://core.trac.wordpress.org/ticket/41981">#41981</a> Global Styles: Add support for heading elements]
* [https://github.com/WordPress/gutenberg/pull/42072 <a href="https://core.trac.wordpress.org/ticket/42072">#42072</a> Fix link element hover bleeding into button element default styles]
* [https://github.com/WordPress/gutenberg/pull/42096 <a href="https://core.trac.wordpress.org/ticket/42096">#42096</a> Add visited to link element allowed pseudo selector list]
* [https://github.com/WordPress/gutenberg/pull/42669 <a href="https://core.trac.wordpress.org/ticket/42669">#42669</a> Link elements: Add a :where selector to the :not to lower specificity]
* [https://github.com/WordPress/gutenberg/pull/42776 <a href="https://core.trac.wordpress.org/ticket/42776">#42776</a> Theme JSON: Add a static $blocks_metadata data definition to the Gutenberg instance of WP_Theme_JSON]
* [https://github.com/WordPress/gutenberg/pull/43088 <a href="https://core.trac.wordpress.org/ticket/43088">#43088</a> Pseudo elements supports on button elements]
* [https://github.com/WordPress/gutenberg/pull/43167 <a href="https://core.trac.wordpress.org/ticket/43167">#43167</a> Theme_JSON: Use existing append_to_selector for pseudo elements]
* [https://github.com/WordPress/gutenberg/pull/43988 <a href="https://core.trac.wordpress.org/ticket/43988">#43988</a> Styles API: Fixed selectors for nested elements]
Props onemaggie, bernhard-reiter, cbravobernal, mmaattiiaass, scruffian, andraganescu, dpcalhoun, get_dave, Mamaduka, SergeyBiryukov.
See <a href="https://core.trac.wordpress.org/ticket/56467">#56467</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpthemejsonphp">trunk/src/wp-includes/class-wp-theme-json.php</a></li>
<li><a href="#trunksrcwpincludesglobalstylesandsettingsphp">trunk/src/wp-includes/global-styles-and-settings.php</a></li>
<li><a href="#trunksrcwpincludesscriptloaderphp">trunk/src/wp-includes/script-loader.php</a></li>
<li><a href="#trunktestsphpunitteststhemewpThemeJsonphp">trunk/tests/phpunit/tests/theme/wpThemeJson.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpthemejsonphp"></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-theme-json.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-theme-json.php 2022-09-09 12:37:47 UTC (rev 54117)
+++ trunk/src/wp-includes/class-wp-theme-json.php 2022-09-10 12:37:00 UTC (rev 54118)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -344,14 +344,26 @@
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Defines which pseudo selectors are enabled for which elements.
+ *
+ * Note: this will affect both top-level and block-level elements.
+ *
+ * @since 6.1.0
+ */
+ const VALID_ELEMENT_PSEUDO_SELECTORS = array(
+ 'link' => array( ':hover', ':focus', ':active', ':visited' ),
+ 'button' => array( ':hover', ':focus', ':active', ':visited' ),
+ );
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * The valid elements that can be found under styles.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 5.8.0
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @since 6.1.0 Added `heading`, `button`, and `caption` to the elements.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.1.0 Added `heading`, `button`. and `caption` elements.
</ins><span class="cx" style="display: block; padding: 0 10px"> * @var string[]
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> const ELEMENTS = array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'link' => 'a',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'link' => 'a:where(:not(.wp-element-button))', // The `where` is needed to lower the specificity.
</ins><span class="cx" style="display: block; padding: 0 10px"> 'heading' => 'h1, h2, h3, h4, h5, h6',
</span><span class="cx" style="display: block; padding: 0 10px"> 'h1' => 'h1',
</span><span class="cx" style="display: block; padding: 0 10px"> 'h2' => 'h2',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -365,7 +377,30 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'caption' => '.wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption',
</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">+ const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array(
+ 'button' => 'wp-element-button',
+ 'caption' => 'wp-element-caption',
+ );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Returns a class name by an element name.
+ *
+ * @since 6.1.0
+ *
+ * @param string $element The name of the element.
+ * @return string The name of the class.
+ */
+ public static function get_element_class_name( $element ) {
+ $class_name = '';
+
+ if ( array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ) {
+ $class_name = static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ];
+ }
+
+ return $class_name;
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Options that settings.appearanceTools enables.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 6.0.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -488,6 +523,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array The sanitized output.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> protected static function sanitize( $input, $valid_block_names, $valid_element_names ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> $output = array();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! is_array( $input ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -494,10 +530,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> return $output;
</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">+ // Preserve only the top most level keys.
</ins><span class="cx" style="display: block; padding: 0 10px"> $output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- // Some styles are only meant to be available at the top-level (e.g.: blockGap),
- // hence, the schema for blocks & elements should not have them.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /*
+ * Remove any rules that are annotated as "top" in VALID_STYLES constant.
+ * Some styles are only meant to be available at the top-level (e.g.: blockGap),
+ * hence, the schema for blocks & elements should not have them.
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> $styles_non_top_level = static::VALID_STYLES;
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( array_keys( $styles_non_top_level ) as $section ) {
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( array_keys( $styles_non_top_level[ $section ] ) as $prop ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -510,9 +550,24 @@
</span><span class="cx" style="display: block; padding: 0 10px"> // Build the schema based on valid block & element names.
</span><span class="cx" style="display: block; padding: 0 10px"> $schema = array();
</span><span class="cx" style="display: block; padding: 0 10px"> $schema_styles_elements = array();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /*
+ * Set allowed element pseudo selectors based on per element allow list.
+ * Target data structure in schema:
+ * e.g.
+ * - top level elements: `$schema['styles']['elements']['link'][':hover']`.
+ * - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`.
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> foreach ( $valid_element_names as $element ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $schema_styles_elements[ $element ] = $styles_non_top_level;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
+ foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
+ $schema_styles_elements[ $element ][ $pseudo_selector ] = $styles_non_top_level;
+ }
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> $schema_styles_blocks = array();
</span><span class="cx" style="display: block; padding: 0 10px"> $schema_settings_blocks = array();
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( $valid_block_names as $block ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -520,6 +575,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $schema_styles_blocks[ $block ] = $styles_non_top_level;
</span><span class="cx" style="display: block; padding: 0 10px"> $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> $schema['styles'] = static::VALID_STYLES;
</span><span class="cx" style="display: block; padding: 0 10px"> $schema['styles']['blocks'] = $schema_styles_blocks;
</span><span class="cx" style="display: block; padding: 0 10px"> $schema['styles']['elements'] = $schema_styles_elements;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -550,6 +606,30 @@
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Appends a sub-selector to an existing one.
+ *
+ * Given the compounded $selector "h1, h2, h3"
+ * and the $to_append selector ".some-class" the result will be
+ * "h1.some-class, h2.some-class, h3.some-class".
+ *
+ * @since 5.8.0
+ * @since 6.1.0 Added append position.
+ *
+ * @param string $selector Original selector.
+ * @param string $to_append Selector to append.
+ * @param string $position A position sub-selector should be appended. Default 'right'.
+ * @return string
+ */
+ protected static function append_to_selector( $selector, $to_append, $position = 'right' ) {
+ $new_selectors = array();
+ $selectors = explode( ',', $selector );
+ foreach ( $selectors as $sel ) {
+ $new_selectors[] = 'right' === $position ? $sel . $to_append : $to_append . $sel;
+ }
+ return implode( ',', $new_selectors );
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Returns the metadata for each block.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * Example:
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -611,7 +691,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( static::ELEMENTS as $el_name => $el_selector ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $element_selector = array();
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( $block_selectors as $selector ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $element_selector[] = $selector . ' ' . $el_selector;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $selector === $el_selector ) {
+ $element_selector = array( $el_selector );
+ break;
+ }
+ $element_selector[] = static::append_to_selector( $el_selector, $selector . ' ', 'left' );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -810,54 +894,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> if ( null === $metadata['selector'] ) {
</span><span class="cx" style="display: block; padding: 0 10px"> continue;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
- $node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
- $selector = $metadata['selector'];
- $settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
- $declarations = static::compute_style_properties( $node, $settings );
-
- // 1. Separate the ones who use the general selector
- // and the ones who use the duotone selector.
- $declarations_duotone = array();
- foreach ( $declarations as $index => $declaration ) {
- if ( 'filter' === $declaration['name'] ) {
- unset( $declarations[ $index ] );
- $declarations_duotone[] = $declaration;
- }
- }
-
- /*
- * Reset default browser margin on the root body element.
- * This is set on the root selector **before** generating the ruleset
- * from the `theme.json`. This is to ensure that if the `theme.json` declares
- * `margin` in its `spacing` declaration for the `body` element then these
- * user-generated values take precedence in the CSS cascade.
- * @link https://github.com/WordPress/gutenberg/issues/36147.
- */
- if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
- $block_rules .= 'body { margin: 0; }';
- }
-
- // 2. Generate the rules that use the general selector.
- $block_rules .= static::to_ruleset( $selector, $declarations );
-
- // 3. Generate the rules that use the duotone selector.
- if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
- $selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] );
- $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone );
- }
-
- if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
- $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
- $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
- $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
-
- $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
- if ( $has_block_gap_support ) {
- $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
- $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
- }
- }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $block_rules .= static::get_styles_for_block( $metadata );
</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"> return $block_rules;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -973,29 +1010,6 @@
</span><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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Function that appends a sub-selector to a existing one.
- *
- * Given the compounded $selector "h1, h2, h3"
- * and the $to_append selector ".some-class" the result will be
- * "h1.some-class, h2.some-class, h3.some-class".
- *
- * @since 5.8.0
- *
- * @param string $selector Original selector.
- * @param string $to_append Selector to append.
- * @return string
- */
- protected static function append_to_selector( $selector, $to_append ) {
- $new_selectors = array();
- $selectors = explode( ',', $selector );
- foreach ( $selectors as $sel ) {
- $new_selectors[] = $sel . $to_append;
- }
-
- return implode( ',', $new_selectors );
- }
-
- /**
</del><span class="cx" style="display: block; padding: 0 10px"> * Given a settings array, it returns the generated rulesets
</span><span class="cx" style="display: block; padding: 0 10px"> * for the preset classes.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1312,13 +1326,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 5.8.0
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 5.9.0 Added the `$settings` and `$properties` parameters.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.1.0 Added the `$theme_json` parameter.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $styles Styles to process.
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $settings Theme settings.
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $properties Properties metadata.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param array $theme_json Theme JSON array.
</ins><span class="cx" style="display: block; padding: 0 10px"> * @return array Returns the modified $declarations.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- protected static function compute_style_properties( $styles, $settings = array(), $properties = null ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( null === $properties ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $properties = static::PROPERTIES_METADATA;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1329,7 +1345,7 @@
</span><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 ( $properties as $css_property => $value_path ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $value = static::get_property_value( $styles, $value_path );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $value = static::get_property_value( $styles, $value_path, $theme_json );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // Look up protected properties, keyed by value path.
</span><span class="cx" style="display: block; padding: 0 10px"> // Skip protected properties that are explicitly set to `null`.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1365,20 +1381,58 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * "var:preset|color|secondary" to the form
</span><span class="cx" style="display: block; padding: 0 10px"> * "--wp--preset--color--secondary".
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * It also converts references to a path to the value
+ * stored at that location, e.g.
+ * { "ref": "style.color.background" } => "#fff".
+ *
</ins><span class="cx" style="display: block; padding: 0 10px"> * @since 5.8.0
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 5.9.0 Added support for values of array type, which are returned as is.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.1.0 Added the `$theme_json` parameter.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $styles Styles subtree.
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $path Which property to process.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param array $theme_json Theme JSON array.
</ins><span class="cx" style="display: block; padding: 0 10px"> * @return string|array Style property value.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- protected static function get_property_value( $styles, $path ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ protected static function get_property_value( $styles, $path, $theme_json = null ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $value = _wp_array_get( $styles, $path, '' );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /*
+ * This converts references to a path to the value at that path
+ * where the values is an array with a "ref" key, pointing to a path.
+ * For example: { "ref": "style.color.background" } => "#fff".
+ */
+ if ( is_array( $value ) && array_key_exists( 'ref', $value ) ) {
+ $value_path = explode( '.', $value['ref'] );
+ $ref_value = _wp_array_get( $theme_json, $value_path );
+ // Only use the ref value if we find anything.
+ if ( ! empty( $ref_value ) && is_string( $ref_value ) ) {
+ $value = $ref_value;
+ }
+
+ if ( is_array( $ref_value ) && array_key_exists( 'ref', $ref_value ) ) {
+ $path_string = json_encode( $path );
+ $ref_value_string = json_encode( $ref_value );
+ _doing_it_wrong(
+ 'get_property_value',
+ sprintf(
+ /* translators: 1: theme.json, 2: Value name, 3: Value path, 4: Another value name. */
+ __( 'Your %1$s file uses a dynamic value (%2$s) for the path at %3$s. However, the value at %3$s is also a dynamic value (pointing to %4$s) and pointing to another dynamic value is not supported. Please update %3$s to point directly to %4$s.' ),
+ 'theme.json',
+ $ref_value_string,
+ $path_string,
+ $ref_value['ref']
+ ),
+ '6.1.0'
+ );
+ }
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( '' === $value || is_array( $value ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> return $value;
</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">+ // Convert custom CSS properties.
</ins><span class="cx" style="display: block; padding: 0 10px"> $prefix = 'var:';
</span><span class="cx" style="display: block; padding: 0 10px"> $prefix_len = strlen( $prefix );
</span><span class="cx" style="display: block; padding: 0 10px"> $token_in = '|';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1490,6 +1544,19 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'path' => array( 'styles', 'elements', $element ),
</span><span class="cx" style="display: block; padding: 0 10px"> 'selector' => static::ELEMENTS[ $element ],
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ // Handle any pseudo selectors for the element.
+ if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
+ foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
+
+ if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) {
+ $nodes[] = array(
+ 'path' => array( 'styles', 'elements', $element ),
+ 'selector' => static::append_to_selector( static::ELEMENTS[ $element ], $pseudo_selector ),
+ );
+ }
+ }
+ }
</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">@@ -1498,6 +1565,51 @@
</span><span class="cx" style="display: block; padding: 0 10px"> return $nodes;
</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">+ $nodes = array_merge( $nodes, static::get_block_nodes( $theme_json ) );
+
+ /**
+ * Filters the list of style nodes with metadata.
+ *
+ * This allows for things like loading block CSS independently.
+ *
+ * @since 6.1.0
+ *
+ * @param array $nodes Style nodes with metadata.
+ */
+ return apply_filters( 'get_style_nodes', $nodes );
+ }
+
+ /**
+ * A public helper to get the block nodes from a theme.json file.
+ *
+ * @since 6.1.0
+ *
+ * @return array The block nodes in theme.json.
+ */
+ public function get_styles_block_nodes() {
+ return static::get_block_nodes( $this->theme_json );
+ }
+
+ /**
+ * An internal method to get the block nodes from a theme.json file.
+ *
+ * @since 6.1.0
+ *
+ * @param array $theme_json The theme.json converted to an array.
+ * @return array The block nodes in theme.json.
+ */
+ private static function get_block_nodes( $theme_json ) {
+ $selectors = static::get_blocks_metadata();
+ $nodes = array();
+ if ( ! isset( $theme_json['styles'] ) ) {
+ return $nodes;
+ }
+
+ // Blocks.
+ if ( ! isset( $theme_json['styles']['blocks'] ) ) {
+ return $nodes;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> foreach ( $theme_json['styles']['blocks'] as $name => $node ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $selector = null;
</span><span class="cx" style="display: block; padding: 0 10px"> if ( isset( $selectors[ $name ]['selector'] ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1510,6 +1622,7 @@
</span><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"> $nodes[] = array(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'name' => $name,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'path' => array( 'styles', 'blocks', $name ),
</span><span class="cx" style="display: block; padding: 0 10px"> 'selector' => $selector,
</span><span class="cx" style="display: block; padding: 0 10px"> 'duotone' => $duotone_selector,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1521,6 +1634,18 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'path' => array( 'styles', 'blocks', $name, 'elements', $element ),
</span><span class="cx" style="display: block; padding: 0 10px"> 'selector' => $selectors[ $name ]['elements'][ $element ],
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ // Handle any pseudo selectors for the element.
+ if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
+ foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
+ if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) {
+ $nodes[] = array(
+ 'path' => array( 'styles', 'blocks', $name, 'elements', $element ),
+ 'selector' => static::append_to_selector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector ),
+ );
+ }
+ }
+ }
</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">@@ -1529,6 +1654,116 @@
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Gets the CSS rules for a particular block from theme.json.
+ *
+ * @since 6.1.0
+ *
+ * @param array $block_metadata Meta data about the block to get styles for.
+ * @return array Styles for the block.
+ */
+ public function get_styles_for_block( $block_metadata ) {
+
+ $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
+
+ $selector = $block_metadata['selector'];
+ $settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
+
+ /*
+ * Get a reference to element name from path.
+ * $block_metadata['path'] = array( 'styles','elements','link' );
+ * Make sure that $block_metadata['path'] describes an element node, like [ 'styles', 'element', 'link' ].
+ * Skip non-element paths like just ['styles'].
+ */
+ $is_processing_element = in_array( 'elements', $block_metadata['path'], true );
+
+ $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null;
+
+ $element_pseudo_allowed = array();
+
+ if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
+ $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ];
+ }
+
+ /*
+ * Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover").
+ * This also resets the array keys.
+ */
+ $pseudo_matches = array_values(
+ array_filter(
+ $element_pseudo_allowed,
+ function( $pseudo_selector ) use ( $selector ) {
+ return str_contains( $selector, $pseudo_selector );
+ }
+ )
+ );
+
+ $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null;
+
+ /*
+ * If the current selector is a pseudo selector that's defined in the allow list for the current
+ * element then compute the style properties for it.
+ * Otherwise just compute the styles for the default selector as normal.
+ */
+ if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) &&
+ array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS )
+ && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true )
+ ) {
+ $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json );
+ } else {
+ $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json );
+ }
+
+ $block_rules = '';
+
+ /*
+ * 1. Separate the declarations that use the general selector
+ * from the ones using the duotone selector.
+ */
+ $declarations_duotone = array();
+ foreach ( $declarations as $index => $declaration ) {
+ if ( 'filter' === $declaration['name'] ) {
+ unset( $declarations[ $index ] );
+ $declarations_duotone[] = $declaration;
+ }
+ }
+
+ /*
+ * Reset default browser margin on the root body element.
+ * This is set on the root selector **before** generating the ruleset
+ * from the `theme.json`. This is to ensure that if the `theme.json` declares
+ * `margin` in its `spacing` declaration for the `body` element then these
+ * user-generated values take precedence in the CSS cascade.
+ * @link https://github.com/WordPress/gutenberg/issues/36147.
+ */
+ if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
+ $block_rules .= 'body { margin: 0; }';
+ }
+
+ // 2. Generate and append the rules that use the general selector.
+ $block_rules .= static::to_ruleset( $selector, $declarations );
+
+ // 3. Generate and append the rules that use the duotone selector.
+ if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
+ $selector_duotone = static::scope_selector( $block_metadata['selector'], $block_metadata['duotone'] );
+ $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone );
+ }
+
+ if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
+ $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
+ $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
+ $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
+ if ( $has_block_gap_support ) {
+ $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
+ $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
+ }
+ }
+
+ return $block_rules;
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * For metadata values that can either be booleans or paths to booleans, gets the value.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * ```php
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1837,10 +2072,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $valid_block_names = array_keys( static::get_blocks_metadata() );
</span><span class="cx" style="display: block; padding: 0 10px"> $valid_element_names = array_keys( static::ELEMENTS );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names );
</del><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $blocks_metadata = static::get_blocks_metadata();
</span><span class="cx" style="display: block; padding: 0 10px"> $style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> foreach ( $style_nodes as $metadata ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $input = _wp_array_get( $theme_json, $metadata['path'], array() );
</span><span class="cx" style="display: block; padding: 0 10px"> if ( empty( $input ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1848,6 +2085,25 @@
</span><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"> $output = static::remove_insecure_styles( $input );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /*
+ * Get a reference to element name from path.
+ * $metadata['path'] = array( 'styles', 'elements', 'link' );
+ */
+ $current_element = $metadata['path'][ count( $metadata['path'] ) - 1 ];
+
+ /*
+ * $output is stripped of pseudo selectors. Re-add and process them
+ * or insecure styles here.
+ */
+ if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
+ foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) {
+ if ( isset( $input[ $pseudo_selector ] ) ) {
+ $output[ $pseudo_selector ] = static::remove_insecure_styles( $input[ $pseudo_selector ] );
+ }
+ }
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! empty( $output ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> _wp_array_set( $sanitized, $metadata['path'], $output );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpincludesglobalstylesandsettingsphp"></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/global-styles-and-settings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/global-styles-and-settings.php 2022-09-09 12:37:47 UTC (rev 54117)
+++ trunk/src/wp-includes/global-styles-and-settings.php 2022-09-10 12:37:00 UTC (rev 54118)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -192,3 +192,45 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> return $svgs;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Adds global style rules to the inline style for each block.
+ *
+ * @since 6.1.0
+ */
+function wp_add_global_styles_for_blocks() {
+ $tree = WP_Theme_JSON_Resolver::get_merged_data();
+ $block_nodes = $tree->get_styles_block_nodes();
+ foreach ( $block_nodes as $metadata ) {
+ $block_css = $tree->get_styles_for_block( $metadata );
+
+ if ( isset( $metadata['name'] ) ) {
+ $block_name = str_replace( 'core/', '', $metadata['name'] );
+ /*
+ * These block styles are added on block_render.
+ * This hooks inline CSS to them so that they are loaded conditionally
+ * based on whether or not the block is used on the page.
+ */
+ wp_add_inline_style( 'wp-block-' . $block_name, $block_css );
+ }
+
+ // The likes of block element styles from theme.json do not have $metadata['name'] set.
+ if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) {
+ $result = array_values(
+ array_filter(
+ $metadata['path'],
+ function ( $item ) {
+ if ( strpos( $item, 'core/' ) !== false ) {
+ return true;
+ }
+ return false;
+ }
+ )
+ );
+ if ( isset( $result[0] ) ) {
+ $block_name = str_replace( 'core/', '', $result[0] );
+ wp_add_inline_style( 'wp-block-' . $block_name, $block_css );
+ }
+ }
+ }
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesscriptloaderphp"></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/script-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/script-loader.php 2022-09-09 12:37:47 UTC (rev 54117)
+++ trunk/src/wp-includes/script-loader.php 2022-09-10 12:37:00 UTC (rev 54118)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2354,6 +2354,30 @@
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Applies a filter to the list of style nodes that comes from WP_Theme_JSON::get_style_nodes().
+ *
+ * This particular filter removes all of the blocks from the array.
+ *
+ * We want WP_Theme_JSON to be ignorant of the implementation details of how the CSS is being used.
+ * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are
+ * loading separate assets, without making the class aware of that detail.
+ *
+ * @since 6.1.0
+ *
+ * @param array $nodes The nodes to filter.
+ * @return array A filtered array of style nodes.
+ */
+function wp_filter_out_block_nodes( $nodes ) {
+ return array_filter(
+ $nodes,
+ function( $node ) {
+ return ! in_array( 'blocks', $node['path'], true );
+ },
+ ARRAY_FILTER_USE_BOTH
+ );
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Enqueues the global styles defined via theme.json.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 5.8.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2377,6 +2401,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> return;
</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">+ /*
+ * If we are loading CSS for each block separately, then we can load the theme.json CSS conditionally.
+ * This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block.
+ */
+ if ( $separate_assets ) {
+ add_filter( 'get_style_nodes', 'wp_filter_out_block_nodes' );
+ // Add each block as an inline css.
+ wp_add_global_styles_for_blocks();
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $stylesheet = wp_get_global_stylesheet();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> if ( empty( $stylesheet ) ) {
</span></span></pre></div>
<a id="trunktestsphpunitteststhemewpThemeJsonphp"></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/theme/wpThemeJson.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/theme/wpThemeJson.php 2022-09-09 12:37:47 UTC (rev 54117)
+++ trunk/tests/phpunit/tests/theme/wpThemeJson.php 2022-09-10 12:37:00 UTC (rev 54118)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -367,8 +367,8 @@
</span><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"> $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-group{border-radius: 10px;margin: 1em;padding: 24px;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;padding-top: 15px;}';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals( $styles, $theme_json->get_stylesheet() );
- $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame( $styles, $theme_json->get_stylesheet() );
+ $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
</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">@@ -399,8 +399,8 @@
</span><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"> $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals( $expected, $theme_json->get_stylesheet() );
- $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
</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">@@ -424,8 +424,8 @@
</span><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"> $expected = 'body { margin: 0; }body{--wp--style--block-gap: 1em;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals( $expected, $theme_json->get_stylesheet() );
- $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
</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">@@ -458,9 +458,6 @@
</span><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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'spacing' => array(
- 'blockGap' => false,
- ),
</del><span class="cx" style="display: block; padding: 0 10px"> 'misc' => 'value',
</span><span class="cx" style="display: block; padding: 0 10px"> 'blocks' => array(
</span><span class="cx" style="display: block; padding: 0 10px"> 'core/group' => array(
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -553,13 +550,13 @@
</span><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"> $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){back
ground-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}';
</ins><span class="cx" style="display: block; padding: 0 10px"> $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}';
</span><span class="cx" style="display: block; padding: 0 10px"> $all = $variables . $styles . $presets;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals( $all, $theme_json->get_stylesheet() );
- $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
- $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
- $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame( $all, $theme_json->get_stylesheet() );
+ $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
+ $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
</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">@@ -587,7 +584,7 @@
</span><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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame(
</ins><span class="cx" style="display: block; padding: 0 10px"> 'h1.has-white-color,h2.has-white-color,h3.has-white-color,h4.has-white-color,h5.has-white-color,h6.has-white-color{color: var(--wp--preset--color--white) !important;}h1.has-white-background-color,h2.has-white-background-color,h3.has-white-background-color,h4.has-white-background-color,h5.has-white-background-color,h6.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}h1.has-white-border-color,h2.has-white-border-color,h3.has-white-border-color,h4.has-white-border-color,h5.has-white-border-color,h6.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}',
</span><span class="cx" style="display: block; padding: 0 10px"> $theme_json->get_stylesheet( array( 'presets' ) )
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -631,10 +628,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $presets = '.wp-block-group.has-grey-color{color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}';
</span><span class="cx" style="display: block; padding: 0 10px"> $variables = '.wp-block-group{--wp--preset--color--grey: grey;}';
</span><span class="cx" style="display: block; padding: 0 10px"> $all = $variables . $styles . $presets;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals( $all, $theme_json->get_stylesheet() );
- $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
- $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
- $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame( $all, $theme_json->get_stylesheet() );
+ $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
+ $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
</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">@@ -672,11 +669,11 @@
</span><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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame(
</ins><span class="cx" style="display: block; padding: 0 10px"> '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-dark-grey-color{color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-color{color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-color{color: var(--wp--preset--color--white-2-black) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-dark-grey-background-color{background-color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-background-color{background-color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-background-color{background-color: var(--wp--preset--color--white-2-black) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-dark-grey-border-color{border-color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-border-color{border-color: var(--wp--preset--col
or--light-grey) !important;}.has-white-2-black-border-color{border-color: var(--wp--preset--color--white-2-black) !important;}',
</span><span class="cx" style="display: block; padding: 0 10px"> $theme_json->get_stylesheet( array( 'presets' ) )
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame(
</ins><span class="cx" style="display: block; padding: 0 10px"> 'body{--wp--preset--color--grey: grey;--wp--preset--color--dark-grey: grey;--wp--preset--color--light-grey: grey;--wp--preset--color--white-2-black: grey;--wp--custom--white-2-black: value;}',
</span><span class="cx" style="display: block; padding: 0 10px"> $theme_json->get_stylesheet( array( 'variables' ) )
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -719,7 +716,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'default'
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertEquals(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertSame(
</ins><span class="cx" style="display: block; padding: 0 10px"> 'body{--wp--preset--color--grey: grey;}body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }p{background-color: blue;color: red;font-size: 12px;line-height: 1.3;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}',
</span><span class="cx" style="display: block; padding: 0 10px"> $theme_json->get_stylesheet()
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -726,6 +723,279 @@
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @ticket 56467
+ */
+ public function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'link' => array(
+ 'color' => array(
+ 'text' => 'green',
+ 'background' => 'red',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'green',
+ ),
+ 'typography' => array(
+ 'textTransform' => 'uppercase',
+ 'fontSize' => '10em',
+ ),
+ ),
+ ':focus' => array(
+ 'color' => array(
+ 'text' => 'yellow',
+ 'background' => 'black',
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}';
+
+ $expected = $base_styles . $element_styles;
+
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ }
+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_property() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'link' => array(
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'green',
+ ),
+ 'typography' => array(
+ 'textTransform' => 'uppercase',
+ 'fontSize' => '10em',
+ ),
+ ),
+ ':focus' => array(
+ 'color' => array(
+ 'text' => 'yellow',
+ 'background' => 'black',
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $element_styles = 'a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}';
+
+ $expected = $base_styles . $element_styles;
+
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ }
+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'h4' => array(
+ 'color' => array(
+ 'text' => 'green',
+ 'background' => 'red',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'green',
+ ),
+ ),
+ ':focus' => array(
+ 'color' => array(
+ 'text' => 'yellow',
+ 'background' => 'black',
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $element_styles = 'h4{background-color: red;color: green;}';
+
+ $expected = $base_styles . $element_styles;
+
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ }
+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'link' => array(
+ 'color' => array(
+ 'text' => 'green',
+ 'background' => 'red',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'green',
+ ),
+ ),
+ ':levitate' => array(
+ 'color' => array(
+ 'text' => 'yellow',
+ 'background' => 'black',
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}';
+
+ $expected = $base_styles . $element_styles;
+
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ $this->assertStringNotContainsString( 'a:levitate{', $theme_json->get_stylesheet( array( 'styles' ) ) );
+ }
+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'blocks' => array(
+ 'core/group' => array(
+ 'elements' => array(
+ 'link' => array(
+ 'color' => array(
+ 'text' => 'green',
+ 'background' => 'red',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'green',
+ ),
+ 'typography' => array(
+ 'textTransform' => 'uppercase',
+ 'fontSize' => '10em',
+ ),
+ ),
+ ':focus' => array(
+ 'color' => array(
+ 'text' => 'yellow',
+ 'background' => 'black',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $element_styles = '.wp-block-group a:where(:not(.wp-element-button)){background-color: red;color: green;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}';
+
+ $expected = $base_styles . $element_styles;
+
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ }
+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'link' => array(
+ 'color' => array(
+ 'text' => 'green',
+ 'background' => 'red',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'green',
+ ),
+ ),
+ ),
+ ),
+ 'blocks' => array(
+ 'core/group' => array(
+ 'elements' => array(
+ 'link' => array(
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'yellow',
+ 'background' => 'black',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+
+ $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: black;color: yellow;}';
+
+ $expected = $base_styles . $element_styles;
+
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * @ticket 52991
</span><span class="cx" style="display: block; padding: 0 10px"> * @ticket 54336
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2087,6 +2357,56 @@
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @ticket 56467
+ */
+ public function test_remove_invalid_element_pseudo_selectors() {
+ $actual = WP_Theme_JSON::remove_insecure_properties(
+ array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'link' => array(
+ 'color' => array(
+ 'text' => 'hotpink',
+ 'background' => 'yellow',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'blue',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ true
+ );
+
+ $expected = array(
+ 'version' => WP_Theme_JSON::LATEST_SCHEMA,
+ 'styles' => array(
+ 'elements' => array(
+ 'link' => array(
+ 'color' => array(
+ 'text' => 'hotpink',
+ 'background' => 'yellow',
+ ),
+ ':hover' => array(
+ 'color' => array(
+ 'text' => 'red',
+ 'background' => 'blue',
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEqualSetsWithIndex( $expected, $actual );
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * @ticket 54336
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function test_get_custom_templates() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2621,4 +2941,144 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertEqualSetsWithIndex( $expected, $actual );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_element_class_name_button() {
+ $expected = 'wp-element-button';
+ $actual = WP_Theme_JSON::get_element_class_name( 'button' );
+
+ $this->assertSame( $expected, $actual );
+ }
+
+ /**
+ * @ticket 56467
+ */
+ public function test_get_element_class_name_invalid() {
+ $expected = '';
+ $actual = WP_Theme_JSON::get_element_class_name( 'unknown-element' );
+
+ $this->assertSame( $expected, $actual );
+ }
+
+ /**
+ * Testing that dynamic properties in theme.json return the value they refrence,
+ * e.g. array( 'ref' => 'styles.color.background' ) => "#ffffff".
+ *
+ * @ticket 56467
+ */
+ public function test_get_property_value_valid() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => 2,
+ 'styles' => array(
+ 'color' => array(
+ 'background' => '#ffffff',
+ 'text' => '#000000',
+ ),
+ 'elements' => array(
+ 'button' => array(
+ 'color' => array(
+ 'background' => array( 'ref' => 'styles.color.text' ),
+ 'text' => array( 'ref' => 'styles.color.background' ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #000000;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}';
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ }
+
+ /**
+ * Testing that dynamic properties in theme.json that refer to other dynamic properties in a loop
+ * should be left untouched.
+ *
+ * @ticket 56467
+ * @expectedIncorrectUsage get_property_value
+ */
+ public function test_get_property_value_loop() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => 2,
+ 'styles' => array(
+ 'color' => array(
+ 'background' => '#ffffff',
+ 'text' => array( 'ref' => 'styles.elements.button.color.background' ),
+ ),
+ 'elements' => array(
+ 'button' => array(
+ 'color' => array(
+ 'background' => array( 'ref' => 'styles.color.text' ),
+ 'text' => array( 'ref' => 'styles.color.background' ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}';
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ }
+
+ /**
+ * Testing that dynamic properties in theme.json that refer to other dynamic properties
+ * should be left unprocessed.
+ *
+ * @ticket 56467
+ * @expectedIncorrectUsage get_property_value
+ */
+ public function test_get_property_value_recursion() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => 2,
+ 'styles' => array(
+ 'color' => array(
+ 'background' => '#ffffff',
+ 'text' => array( 'ref' => 'styles.color.background' ),
+ ),
+ 'elements' => array(
+ 'button' => array(
+ 'color' => array(
+ 'background' => array( 'ref' => 'styles.color.text' ),
+ 'text' => array( 'ref' => 'styles.color.background' ),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}';
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ }
+
+ /**
+ * Testing that dynamic properties in theme.json that refer to themselves
+ * should be left unprocessed.
+ *
+ * @ticket 56467
+ * @expectedIncorrectUsage get_property_value
+ */
+ public function test_get_property_value_self() {
+ $theme_json = new WP_Theme_JSON(
+ array(
+ 'version' => 2,
+ 'styles' => array(
+ 'color' => array(
+ 'background' => '#ffffff',
+ 'text' => array( 'ref' => 'styles.color.text' ),
+ ),
+ ),
+ )
+ );
+
+ $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
+ $this->assertSame( $expected, $theme_json->get_stylesheet() );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>
</body>
</html>