Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global Styles: Allow references to values in other locations in the tree #41696

Merged
merged 2 commits into from
Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 117 additions & 4 deletions lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ public static function remove_insecure_properties( $theme_json ) {
return $theme_json;
}


/**
* Returns the metadata for each block.
*
Expand Down Expand Up @@ -451,7 +450,6 @@ private static function get_block_nodes( $theme_json, $selectors = array() ) {
* @return string 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'];
Expand All @@ -474,9 +472,9 @@ public function get_styles_for_block( $block_metadata ) {
// 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 ] ) && isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) ) {
$declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings );
$declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json );
} else {
$declarations = static::compute_style_properties( $node, $settings );
$declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json );
}

$block_rules = '';
Expand Down Expand Up @@ -554,4 +552,119 @@ protected function get_block_classes( $style_nodes ) {

return $block_rules;
}

/**
* Given a styles array, it extracts the style properties
* and adds them to the $declarations array following the format:
*
* ```php
* array(
* 'name' => 'property_name',
* 'value' => 'property_value,
* )
* ```
*
* @param array $styles Styles to process.
* @param array $settings Theme settings.
* @param array $properties Properties metadata.
* @param array $theme_json Theme JSON array.
* @return array Returns the modified $declarations.
*/
protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No change to this function except that we're passing in theme_json.

if ( null === $properties ) {
$properties = static::PROPERTIES_METADATA;
}

$declarations = array();
if ( empty( $styles ) ) {
return $declarations;
}

foreach ( $properties as $css_property => $value_path ) {
$value = static::get_property_value( $styles, $value_path, $theme_json );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

And then passing $theme_json through here...


// Look up protected properties, keyed by value path.
// Skip protected properties that are explicitly set to `null`.
if ( is_array( $value_path ) ) {
$path_string = implode( '.', $value_path );
if (
array_key_exists( $path_string, static::PROTECTED_PROPERTIES ) &&
_wp_array_get( $settings, static::PROTECTED_PROPERTIES[ $path_string ], null ) === null
) {
continue;
}
}

// Skip if empty and not "0" or value represents array of longhand values.
$has_missing_value = empty( $value ) && ! is_numeric( $value );
if ( $has_missing_value || is_array( $value ) ) {
continue;
}

$declarations[] = array(
'name' => $css_property,
'value' => $value,
);
}

return $declarations;
}

/**
* Returns the style property for the given path.
*
* It also converts CSS Custom Property stored as
* "var:preset|color|secondary" to the form
* "--wp--preset--color--secondary".
*
* It also converts references to a path to the value
* stored at that location, e.g.
* { "ref": "style.color.background" } => "#fff".
*
* @param array $styles Styles subtree.
* @param array $path Which property to process.
* @param array $theme_json Theme JSON array.
* @return string Style property value.
*/
protected static function get_property_value( $styles, $path, $theme_json = null ) {
$value = _wp_array_get( $styles, $path, '' );

// 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', "Your theme.json file uses a dynamic value (${ref_value_string}) for the path at ${path_string}. However, the value at ${path_string} is also a dynamic value (pointing to ${ref_value['ref']}) and pointing to another dynamic value is not supported. Please update ${path_string} to point directly to ${ref_value['ref']}.", '6.1.0' );
}
}

if ( '' === $value || is_array( $value ) ) {
return $value;
}

// Convert custom CSS properties.
$prefix = 'var:';
$prefix_len = strlen( $prefix );
$token_in = '|';
$token_out = '--';
if ( 0 === strncmp( $value, $prefix, $prefix_len ) ) {
$unwrapped_name = str_replace(
$token_in,
$token_out,
substr( $value, $prefix_len )
);
$value = "var(--wp--$unwrapped_name)";
}

return $value;
}
}
2 changes: 0 additions & 2 deletions lib/experimental/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,4 @@ public static function get_merged_data( $origin = 'custom' ) {

return $result;
}


}
115 changes: 115 additions & 0 deletions phpunit/class-wp-theme-json-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -2821,4 +2821,119 @@ function test_get_element_class_name_invalid() {

$this->assertEquals( $expected, $actual );
}

/**
* Testing that dynamic properties in theme.json return the value they refrence, e.g.
* array( 'ref' => 'styles.color.background' ) => "#ffffff".
*/
function test_get_property_value_valid() {
$theme_json = new WP_Theme_JSON_Gutenberg(
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->assertEquals( $expected, $theme_json->get_stylesheet() );
}

/**
* Testing that dynamic properties in theme.json that
* refer to other dynamic properties in a loop
* then they should be left untouched.
*
* @expectedIncorrectUsage get_property_value
*/
function test_get_property_value_loop() {
$theme_json = new WP_Theme_JSON_Gutenberg(
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 then they should be left unprocessed.
*
* @expectedIncorrectUsage get_property_value
*/
function test_get_property_value_recursion() {
$theme_json = new WP_Theme_JSON_Gutenberg(
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->assertEquals( $expected, $theme_json->get_stylesheet() );
}

/**
* Testing that dynamic properties in theme.json that
* refer to themselves then they should be left unprocessed.
*
* @expectedIncorrectUsage get_property_value
*/
function test_get_property_value_self() {
$theme_json = new WP_Theme_JSON_Gutenberg(
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->assertEquals( $expected, $theme_json->get_stylesheet() );
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- wp:table {"backgroundColor":"subtle-pale-blue"} -->
<figure class="wp-block-table"><table class="has-subtle-pale-blue-background-color has-background"><thead><tr><th>Version</th><th>Musician</th><th>Date</th></tr></thead><tbody><tr><td><a href="https://wordpress.org/news/2003/05/wordpress-now-available/">.70</a></td><td>No musician chosen.</td><td>May 27, 2003</td></tr><tr><td><a href="https://wordpress.org/news/2004/01/wordpress-10/">1.0</a></td><td>Miles Davis</td><td>January 3, 2004</td></tr><tr><td>Lots of versions skipped, see <a href="https://codex.wordpress.org/WordPress_Versions">the full list</a></td><td>&hellip;</td><td>&hellip;</td></tr><tr><td><a href="https://wordpress.org/news/2015/12/clifford/">4.4</a></td><td>Clifford Brown</td><td>December 8, 2015</td></tr><tr><td><a href="https://wordpress.org/news/2016/04/coleman/">4.5</a></td><td>Coleman Hawkins</td><td>April 12, 2016</td></tr><tr><td><a href="https://wordpress.org/news/2016/08/pepper/">4.6</a></td><td>Pepper Adams</td><td>August 16, 2016</td></tr><tr><td><a href="https://wordpress.org/news/2016/12/vaughan/">4.7</a></td><td>Sarah Vaughan</td><td>December 6, 2016</td></tr></tbody></table><figcaption>Table Caption</figcaption></figure>
<!-- /wp:table -->
<!-- /wp:table -->