Make WordPress Core

Changeset 54118


Ignore:
Timestamp:
09/10/2022 12:37:00 PM (21 months ago)
Author:
SergeyBiryukov
Message:

Editor: Backport Elements API updates.

This commit backports the original PRs from Gutenberg repository:

Props onemaggie, bernhard-reiter, cbravobernal, mmaattiiaass, scruffian, andraganescu, dpcalhoun, get_dave, Mamaduka, SergeyBiryukov.
See #56467.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-theme-json.php

    r54105 r54118  
    345345
    346346    /**
     347     * Defines which pseudo selectors are enabled for which elements.
     348     *
     349     * Note: this will affect both top-level and block-level elements.
     350     *
     351     * @since 6.1.0
     352     */
     353    const VALID_ELEMENT_PSEUDO_SELECTORS = array(
     354        'link'   => array( ':hover', ':focus', ':active', ':visited' ),
     355        'button' => array( ':hover', ':focus', ':active', ':visited' ),
     356    );
     357
     358    /**
    347359     * The valid elements that can be found under styles.
    348360     *
    349361     * @since 5.8.0
    350      * @since 6.1.0 Added `heading`, `button`, and `caption` to the elements.
     362     * @since 6.1.0 Added `heading`, `button`. and `caption` elements.
    351363     * @var string[]
    352364     */
    353365    const ELEMENTS = array(
    354         'link'    => 'a',
     366        'link'    => 'a:where(:not(.wp-element-button))', // The `where` is needed to lower the specificity.
    355367        'heading' => 'h1, h2, h3, h4, h5, h6',
    356368        'h1'      => 'h1',
     
    366378    );
    367379
     380    const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array(
     381        'button'  => 'wp-element-button',
     382        'caption' => 'wp-element-caption',
     383    );
     384
     385    /**
     386     * Returns a class name by an element name.
     387     *
     388     * @since 6.1.0
     389     *
     390     * @param string $element The name of the element.
     391     * @return string The name of the class.
     392     */
     393    public static function get_element_class_name( $element ) {
     394        $class_name = '';
     395
     396        if ( array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ) {
     397            $class_name = static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ];
     398        }
     399
     400        return $class_name;
     401    }
     402
    368403    /**
    369404     * Options that settings.appearanceTools enables.
     
    489524     */
    490525    protected static function sanitize( $input, $valid_block_names, $valid_element_names ) {
     526
    491527        $output = array();
    492528
     
    495531        }
    496532
     533        // Preserve only the top most level keys.
    497534        $output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) );
    498535
    499         // Some styles are only meant to be available at the top-level (e.g.: blockGap),
    500         // hence, the schema for blocks & elements should not have them.
     536        /*
     537         * Remove any rules that are annotated as "top" in VALID_STYLES constant.
     538         * Some styles are only meant to be available at the top-level (e.g.: blockGap),
     539         * hence, the schema for blocks & elements should not have them.
     540         */
    501541        $styles_non_top_level = static::VALID_STYLES;
    502542        foreach ( array_keys( $styles_non_top_level ) as $section ) {
     
    511551        $schema                 = array();
    512552        $schema_styles_elements = array();
     553
     554        /*
     555         * Set allowed element pseudo selectors based on per element allow list.
     556         * Target data structure in schema:
     557         * e.g.
     558         * - top level elements: `$schema['styles']['elements']['link'][':hover']`.
     559         * - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`.
     560         */
    513561        foreach ( $valid_element_names as $element ) {
    514562            $schema_styles_elements[ $element ] = $styles_non_top_level;
    515         }
     563
     564            if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
     565                foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
     566                    $schema_styles_elements[ $element ][ $pseudo_selector ] = $styles_non_top_level;
     567                }
     568            }
     569        }
     570
    516571        $schema_styles_blocks   = array();
    517572        $schema_settings_blocks = array();
     
    521576            $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
    522577        }
     578
    523579        $schema['styles']             = static::VALID_STYLES;
    524580        $schema['styles']['blocks']   = $schema_styles_blocks;
     
    548604
    549605        return $output;
     606    }
     607
     608    /**
     609     * Appends a sub-selector to an existing one.
     610     *
     611     * Given the compounded $selector "h1, h2, h3"
     612     * and the $to_append selector ".some-class" the result will be
     613     * "h1.some-class, h2.some-class, h3.some-class".
     614     *
     615     * @since 5.8.0
     616     * @since 6.1.0 Added append position.
     617     *
     618     * @param string $selector  Original selector.
     619     * @param string $to_append Selector to append.
     620     * @param string $position  A position sub-selector should be appended. Default 'right'.
     621     * @return string
     622     */
     623    protected static function append_to_selector( $selector, $to_append, $position = 'right' ) {
     624        $new_selectors = array();
     625        $selectors     = explode( ',', $selector );
     626        foreach ( $selectors as $sel ) {
     627            $new_selectors[] = 'right' === $position ? $sel . $to_append : $to_append . $sel;
     628        }
     629        return implode( ',', $new_selectors );
    550630    }
    551631
     
    612692                $element_selector = array();
    613693                foreach ( $block_selectors as $selector ) {
    614                     $element_selector[] = $selector . ' ' . $el_selector;
     694                    if ( $selector === $el_selector ) {
     695                        $element_selector = array( $el_selector );
     696                        break;
     697                    }
     698                    $element_selector[] = static::append_to_selector( $el_selector, $selector . ' ', 'left' );
    615699                }
    616700                static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector );
     
    811895                continue;
    812896            }
    813 
    814             $node         = _wp_array_get( $this->theme_json, $metadata['path'], array() );
    815             $selector     = $metadata['selector'];
    816             $settings     = _wp_array_get( $this->theme_json, array( 'settings' ) );
    817             $declarations = static::compute_style_properties( $node, $settings );
    818 
    819             // 1. Separate the ones who use the general selector
    820             // and the ones who use the duotone selector.
    821             $declarations_duotone = array();
    822             foreach ( $declarations as $index => $declaration ) {
    823                 if ( 'filter' === $declaration['name'] ) {
    824                     unset( $declarations[ $index ] );
    825                     $declarations_duotone[] = $declaration;
    826                 }
    827             }
    828 
    829             /*
    830              * Reset default browser margin on the root body element.
    831              * This is set on the root selector **before** generating the ruleset
    832              * from the `theme.json`. This is to ensure that if the `theme.json` declares
    833              * `margin` in its `spacing` declaration for the `body` element then these
    834              * user-generated values take precedence in the CSS cascade.
    835              * @link https://github.com/WordPress/gutenberg/issues/36147.
    836              */
    837             if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
    838                 $block_rules .= 'body { margin: 0; }';
    839             }
    840 
    841             // 2. Generate the rules that use the general selector.
    842             $block_rules .= static::to_ruleset( $selector, $declarations );
    843 
    844             // 3. Generate the rules that use the duotone selector.
    845             if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
    846                 $selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] );
    847                 $block_rules     .= static::to_ruleset( $selector_duotone, $declarations_duotone );
    848             }
    849 
    850             if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
    851                 $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
    852                 $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
    853                 $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
    854 
    855                 $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
    856                 if ( $has_block_gap_support ) {
    857                     $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
    858                     $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
    859                 }
    860             }
     897            $block_rules .= static::get_styles_for_block( $metadata );
    861898        }
    862899
     
    9711008
    9721009        return $selector . '{' . $declaration_block . '}';
    973     }
    974 
    975     /**
    976      * Function that appends a sub-selector to a existing one.
    977      *
    978      * Given the compounded $selector "h1, h2, h3"
    979      * and the $to_append selector ".some-class" the result will be
    980      * "h1.some-class, h2.some-class, h3.some-class".
    981      *
    982      * @since 5.8.0
    983      *
    984      * @param string $selector  Original selector.
    985      * @param string $to_append Selector to append.
    986      * @return string
    987      */
    988     protected static function append_to_selector( $selector, $to_append ) {
    989         $new_selectors = array();
    990         $selectors     = explode( ',', $selector );
    991         foreach ( $selectors as $sel ) {
    992             $new_selectors[] = $sel . $to_append;
    993         }
    994 
    995         return implode( ',', $new_selectors );
    9961010    }
    9971011
     
    13131327     * @since 5.8.0
    13141328     * @since 5.9.0 Added the `$settings` and `$properties` parameters.
     1329     * @since 6.1.0 Added the `$theme_json` parameter.
    13151330     *
    13161331     * @param array $styles    Styles to process.
    13171332     * @param array $settings  Theme settings.
    13181333     * @param array $properties Properties metadata.
     1334     * @param array $theme_json Theme JSON array.
    13191335     * @return array Returns the modified $declarations.
    13201336     */
    1321     protected static function compute_style_properties( $styles, $settings = array(), $properties = null ) {
     1337    protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) {
    13221338        if ( null === $properties ) {
    13231339            $properties = static::PROPERTIES_METADATA;
     
    13301346
    13311347        foreach ( $properties as $css_property => $value_path ) {
    1332             $value = static::get_property_value( $styles, $value_path );
     1348            $value = static::get_property_value( $styles, $value_path, $theme_json );
    13331349
    13341350            // Look up protected properties, keyed by value path.
     
    13661382     * "--wp--preset--color--secondary".
    13671383     *
     1384     * It also converts references to a path to the value
     1385     * stored at that location, e.g.
     1386     * { "ref": "style.color.background" } => "#fff".
     1387     *
    13681388     * @since 5.8.0
    13691389     * @since 5.9.0 Added support for values of array type, which are returned as is.
     1390     * @since 6.1.0 Added the `$theme_json` parameter.
    13701391     *
    13711392     * @param array $styles Styles subtree.
    13721393     * @param array $path   Which property to process.
     1394     * @param array $theme_json Theme JSON array.
    13731395     * @return string|array Style property value.
    13741396     */
    1375     protected static function get_property_value( $styles, $path ) {
     1397    protected static function get_property_value( $styles, $path, $theme_json = null ) {
    13761398        $value = _wp_array_get( $styles, $path, '' );
     1399
     1400        /*
     1401         * This converts references to a path to the value at that path
     1402         * where the values is an array with a "ref" key, pointing to a path.
     1403         * For example: { "ref": "style.color.background" } => "#fff".
     1404         */
     1405        if ( is_array( $value ) && array_key_exists( 'ref', $value ) ) {
     1406            $value_path = explode( '.', $value['ref'] );
     1407            $ref_value  = _wp_array_get( $theme_json, $value_path );
     1408            // Only use the ref value if we find anything.
     1409            if ( ! empty( $ref_value ) && is_string( $ref_value ) ) {
     1410                $value = $ref_value;
     1411            }
     1412
     1413            if ( is_array( $ref_value ) && array_key_exists( 'ref', $ref_value ) ) {
     1414                $path_string      = json_encode( $path );
     1415                $ref_value_string = json_encode( $ref_value );
     1416                _doing_it_wrong(
     1417                    'get_property_value',
     1418                    sprintf(
     1419                        /* translators: 1: theme.json, 2: Value name, 3: Value path, 4: Another value name. */
     1420                        __( '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.' ),
     1421                        'theme.json',
     1422                        $ref_value_string,
     1423                        $path_string,
     1424                        $ref_value['ref']
     1425                    ),
     1426                    '6.1.0'
     1427                );
     1428            }
     1429        }
    13771430
    13781431        if ( '' === $value || is_array( $value ) ) {
     
    13801433        }
    13811434
     1435        // Convert custom CSS properties.
    13821436        $prefix     = 'var:';
    13831437        $prefix_len = strlen( $prefix );
     
    14911545                    'selector' => static::ELEMENTS[ $element ],
    14921546                );
    1493             }
     1547
     1548                // Handle any pseudo selectors for the element.
     1549                if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
     1550                    foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
     1551
     1552                        if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) {
     1553                            $nodes[] = array(
     1554                                'path'     => array( 'styles', 'elements', $element ),
     1555                                'selector' => static::append_to_selector( static::ELEMENTS[ $element ], $pseudo_selector ),
     1556                            );
     1557                        }
     1558                    }
     1559                }
     1560            }
     1561        }
     1562
     1563        // Blocks.
     1564        if ( ! isset( $theme_json['styles']['blocks'] ) ) {
     1565            return $nodes;
     1566        }
     1567
     1568        $nodes = array_merge( $nodes, static::get_block_nodes( $theme_json ) );
     1569
     1570        /**
     1571         * Filters the list of style nodes with metadata.
     1572         *
     1573         * This allows for things like loading block CSS independently.
     1574         *
     1575         * @since 6.1.0
     1576         *
     1577         * @param array $nodes Style nodes with metadata.
     1578         */
     1579        return apply_filters( 'get_style_nodes', $nodes );
     1580    }
     1581
     1582    /**
     1583     * A public helper to get the block nodes from a theme.json file.
     1584     *
     1585     * @since 6.1.0
     1586     *
     1587     * @return array The block nodes in theme.json.
     1588     */
     1589    public function get_styles_block_nodes() {
     1590        return static::get_block_nodes( $this->theme_json );
     1591    }
     1592
     1593    /**
     1594     * An internal method to get the block nodes from a theme.json file.
     1595     *
     1596     * @since 6.1.0
     1597     *
     1598     * @param array $theme_json The theme.json converted to an array.
     1599     * @return array The block nodes in theme.json.
     1600     */
     1601    private static function get_block_nodes( $theme_json ) {
     1602        $selectors = static::get_blocks_metadata();
     1603        $nodes     = array();
     1604        if ( ! isset( $theme_json['styles'] ) ) {
     1605            return $nodes;
    14941606        }
    14951607
     
    15111623
    15121624            $nodes[] = array(
     1625                'name'     => $name,
    15131626                'path'     => array( 'styles', 'blocks', $name ),
    15141627                'selector' => $selector,
     
    15221635                        'selector' => $selectors[ $name ]['elements'][ $element ],
    15231636                    );
     1637
     1638                    // Handle any pseudo selectors for the element.
     1639                    if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
     1640                        foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
     1641                            if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) {
     1642                                $nodes[] = array(
     1643                                    'path'     => array( 'styles', 'blocks', $name, 'elements', $element ),
     1644                                    'selector' => static::append_to_selector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector ),
     1645                                );
     1646                            }
     1647                        }
     1648                    }
    15241649                }
    15251650            }
     
    15271652
    15281653        return $nodes;
     1654    }
     1655
     1656    /**
     1657     * Gets the CSS rules for a particular block from theme.json.
     1658     *
     1659     * @since 6.1.0
     1660     *
     1661     * @param array $block_metadata Meta data about the block to get styles for.
     1662     * @return array Styles for the block.
     1663     */
     1664    public function get_styles_for_block( $block_metadata ) {
     1665
     1666        $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
     1667
     1668        $selector = $block_metadata['selector'];
     1669        $settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
     1670
     1671        /*
     1672         * Get a reference to element name from path.
     1673         * $block_metadata['path'] = array( 'styles','elements','link' );
     1674         * Make sure that $block_metadata['path'] describes an element node, like [ 'styles', 'element', 'link' ].
     1675         * Skip non-element paths like just ['styles'].
     1676         */
     1677        $is_processing_element = in_array( 'elements', $block_metadata['path'], true );
     1678
     1679        $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null;
     1680
     1681        $element_pseudo_allowed = array();
     1682
     1683        if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
     1684            $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ];
     1685        }
     1686
     1687        /*
     1688         * Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover").
     1689         * This also resets the array keys.
     1690         */
     1691        $pseudo_matches = array_values(
     1692            array_filter(
     1693                $element_pseudo_allowed,
     1694                function( $pseudo_selector ) use ( $selector ) {
     1695                    return str_contains( $selector, $pseudo_selector );
     1696                }
     1697            )
     1698        );
     1699
     1700        $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null;
     1701
     1702        /*
     1703         * If the current selector is a pseudo selector that's defined in the allow list for the current
     1704         * element then compute the style properties for it.
     1705         * Otherwise just compute the styles for the default selector as normal.
     1706         */
     1707        if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) &&
     1708            array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS )
     1709            && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true )
     1710        ) {
     1711            $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json );
     1712        } else {
     1713            $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json );
     1714        }
     1715
     1716        $block_rules = '';
     1717
     1718        /*
     1719         * 1. Separate the declarations that use the general selector
     1720         * from the ones using the duotone selector.
     1721         */
     1722        $declarations_duotone = array();
     1723        foreach ( $declarations as $index => $declaration ) {
     1724            if ( 'filter' === $declaration['name'] ) {
     1725                unset( $declarations[ $index ] );
     1726                $declarations_duotone[] = $declaration;
     1727            }
     1728        }
     1729
     1730        /*
     1731         * Reset default browser margin on the root body element.
     1732         * This is set on the root selector **before** generating the ruleset
     1733         * from the `theme.json`. This is to ensure that if the `theme.json` declares
     1734         * `margin` in its `spacing` declaration for the `body` element then these
     1735         * user-generated values take precedence in the CSS cascade.
     1736         * @link https://github.com/WordPress/gutenberg/issues/36147.
     1737         */
     1738        if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
     1739            $block_rules .= 'body { margin: 0; }';
     1740        }
     1741
     1742        // 2. Generate and append the rules that use the general selector.
     1743        $block_rules .= static::to_ruleset( $selector, $declarations );
     1744
     1745        // 3. Generate and append the rules that use the duotone selector.
     1746        if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
     1747            $selector_duotone = static::scope_selector( $block_metadata['selector'], $block_metadata['duotone'] );
     1748            $block_rules     .= static::to_ruleset( $selector_duotone, $declarations_duotone );
     1749        }
     1750
     1751        if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
     1752            $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
     1753            $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
     1754            $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
     1755
     1756            $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
     1757            if ( $has_block_gap_support ) {
     1758                $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
     1759                $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
     1760            }
     1761        }
     1762
     1763        return $block_rules;
    15291764    }
    15301765
     
    18382073        $valid_block_names   = array_keys( static::get_blocks_metadata() );
    18392074        $valid_element_names = array_keys( static::ELEMENTS );
    1840         $theme_json          = static::sanitize( $theme_json, $valid_block_names, $valid_element_names );
     2075
     2076        $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names );
    18412077
    18422078        $blocks_metadata = static::get_blocks_metadata();
    18432079        $style_nodes     = static::get_style_nodes( $theme_json, $blocks_metadata );
     2080
    18442081        foreach ( $style_nodes as $metadata ) {
    18452082            $input = _wp_array_get( $theme_json, $metadata['path'], array() );
     
    18492086
    18502087            $output = static::remove_insecure_styles( $input );
     2088
     2089            /*
     2090             * Get a reference to element name from path.
     2091             * $metadata['path'] = array( 'styles', 'elements', 'link' );
     2092             */
     2093            $current_element = $metadata['path'][ count( $metadata['path'] ) - 1 ];
     2094
     2095            /*
     2096             * $output is stripped of pseudo selectors. Re-add and process them
     2097             * or insecure styles here.
     2098             */
     2099            if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
     2100                foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) {
     2101                    if ( isset( $input[ $pseudo_selector ] ) ) {
     2102                        $output[ $pseudo_selector ] = static::remove_insecure_styles( $input[ $pseudo_selector ] );
     2103                    }
     2104                }
     2105            }
     2106
    18512107            if ( ! empty( $output ) ) {
    18522108                _wp_array_set( $sanitized, $metadata['path'], $output );
  • trunk/src/wp-includes/global-styles-and-settings.php

    r52757 r54118  
    193193    return $svgs;
    194194}
     195
     196/**
     197 * Adds global style rules to the inline style for each block.
     198 *
     199 * @since 6.1.0
     200 */
     201function wp_add_global_styles_for_blocks() {
     202    $tree        = WP_Theme_JSON_Resolver::get_merged_data();
     203    $block_nodes = $tree->get_styles_block_nodes();
     204    foreach ( $block_nodes as $metadata ) {
     205        $block_css = $tree->get_styles_for_block( $metadata );
     206
     207        if ( isset( $metadata['name'] ) ) {
     208            $block_name = str_replace( 'core/', '', $metadata['name'] );
     209            /*
     210             * These block styles are added on block_render.
     211             * This hooks inline CSS to them so that they are loaded conditionally
     212             * based on whether or not the block is used on the page.
     213             */
     214            wp_add_inline_style( 'wp-block-' . $block_name, $block_css );
     215        }
     216
     217        // The likes of block element styles from theme.json do not have  $metadata['name'] set.
     218        if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) {
     219            $result = array_values(
     220                array_filter(
     221                    $metadata['path'],
     222                    function ( $item ) {
     223                        if ( strpos( $item, 'core/' ) !== false ) {
     224                            return true;
     225                        }
     226                        return false;
     227                    }
     228                )
     229            );
     230            if ( isset( $result[0] ) ) {
     231                $block_name = str_replace( 'core/', '', $result[0] );
     232                wp_add_inline_style( 'wp-block-' . $block_name, $block_css );
     233            }
     234        }
     235    }
     236}
  • trunk/src/wp-includes/script-loader.php

    r54079 r54118  
    23552355
    23562356/**
     2357 * Applies a filter to the list of style nodes that comes from WP_Theme_JSON::get_style_nodes().
     2358 *
     2359 * This particular filter removes all of the blocks from the array.
     2360 *
     2361 * We want WP_Theme_JSON to be ignorant of the implementation details of how the CSS is being used.
     2362 * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are
     2363 * loading separate assets, without making the class aware of that detail.
     2364 *
     2365 * @since 6.1.0
     2366 *
     2367 * @param array $nodes The nodes to filter.
     2368 * @return array A filtered array of style nodes.
     2369 */
     2370function wp_filter_out_block_nodes( $nodes ) {
     2371    return array_filter(
     2372        $nodes,
     2373        function( $node ) {
     2374            return ! in_array( 'blocks', $node['path'], true );
     2375        },
     2376        ARRAY_FILTER_USE_BOTH
     2377    );
     2378}
     2379
     2380/**
    23572381 * Enqueues the global styles defined via theme.json.
    23582382 *
     
    23762400    ) {
    23772401        return;
     2402    }
     2403
     2404    /*
     2405     * If we are loading CSS for each block separately, then we can load the theme.json CSS conditionally.
     2406     * This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block.
     2407     */
     2408    if ( $separate_assets ) {
     2409        add_filter( 'get_style_nodes', 'wp_filter_out_block_nodes' );
     2410        // Add each block as an inline css.
     2411        wp_add_global_styles_for_blocks();
    23782412    }
    23792413
  • trunk/tests/phpunit/tests/theme/wpThemeJson.php

    r54100 r54118  
    368368
    369369        $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;}';
    370         $this->assertEquals( $styles, $theme_json->get_stylesheet() );
    371         $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
     370        $this->assertSame( $styles, $theme_json->get_stylesheet() );
     371        $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
    372372    }
    373373
     
    400400
    401401        $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; }';
    402         $this->assertEquals( $expected, $theme_json->get_stylesheet() );
    403         $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     402        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     403        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    404404    }
    405405
     
    425425
    426426        $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 ); }';
    427         $this->assertEquals( $expected, $theme_json->get_stylesheet() );
    428         $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     427        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     428        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    429429    }
    430430
     
    458458                            ),
    459459                        ),
    460                     ),
    461                     'spacing'    => array(
    462                         'blockGap' => false,
    463460                    ),
    464461                    'misc'       => 'value',
     
    554551
    555552        $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;}';
    556         $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;}';
     553        $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)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}';
    557554        $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;}';
    558555        $all       = $variables . $styles . $presets;
    559         $this->assertEquals( $all, $theme_json->get_stylesheet() );
    560         $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
    561         $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
    562         $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
     556        $this->assertSame( $all, $theme_json->get_stylesheet() );
     557        $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
     558        $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
     559        $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
    563560    }
    564561
     
    588585        );
    589586
    590         $this->assertEquals(
     587        $this->assertSame(
    591588            '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;}',
    592589            $theme_json->get_stylesheet( array( 'presets' ) )
     
    632629        $variables = '.wp-block-group{--wp--preset--color--grey: grey;}';
    633630        $all       = $variables . $styles . $presets;
    634         $this->assertEquals( $all, $theme_json->get_stylesheet() );
    635         $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
    636         $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
    637         $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
     631        $this->assertSame( $all, $theme_json->get_stylesheet() );
     632        $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
     633        $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
     634        $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
    638635    }
    639636
     
    673670        );
    674671
    675         $this->assertEquals(
     672        $this->assertSame(
    676673            '.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--color--light-grey) !important;}.has-white-2-black-border-color{border-color: var(--wp--preset--color--white-2-black) !important;}',
    677674            $theme_json->get_stylesheet( array( 'presets' ) )
    678675        );
    679         $this->assertEquals(
     676        $this->assertSame(
    680677            '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;}',
    681678            $theme_json->get_stylesheet( array( 'variables' ) )
     
    720717        );
    721718
    722         $this->assertEquals(
     719        $this->assertSame(
    723720            '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;}',
    724721            $theme_json->get_stylesheet()
    725722        );
     723    }
     724
     725    /**
     726     * @ticket 56467
     727     */
     728    public function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() {
     729        $theme_json = new WP_Theme_JSON(
     730            array(
     731                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     732                'styles'  => array(
     733                    'elements' => array(
     734                        'link' => array(
     735                            'color'  => array(
     736                                'text'       => 'green',
     737                                'background' => 'red',
     738                            ),
     739                            ':hover' => array(
     740                                'color'      => array(
     741                                    'text'       => 'red',
     742                                    'background' => 'green',
     743                                ),
     744                                'typography' => array(
     745                                    'textTransform' => 'uppercase',
     746                                    'fontSize'      => '10em',
     747                                ),
     748                            ),
     749                            ':focus' => array(
     750                                'color' => array(
     751                                    'text'       => 'yellow',
     752                                    'background' => 'black',
     753                                ),
     754                            ),
     755                        ),
     756                    ),
     757                ),
     758            )
     759        );
     760
     761        $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; }';
     762
     763        $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;}';
     764
     765        $expected = $base_styles . $element_styles;
     766
     767        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     768        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     769    }
     770
     771    /**
     772     * @ticket 56467
     773     */
     774    public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_property() {
     775        $theme_json = new WP_Theme_JSON(
     776            array(
     777                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     778                'styles'  => array(
     779                    'elements' => array(
     780                        'link' => array(
     781                            ':hover' => array(
     782                                'color'      => array(
     783                                    'text'       => 'red',
     784                                    'background' => 'green',
     785                                ),
     786                                'typography' => array(
     787                                    'textTransform' => 'uppercase',
     788                                    'fontSize'      => '10em',
     789                                ),
     790                            ),
     791                            ':focus' => array(
     792                                'color' => array(
     793                                    'text'       => 'yellow',
     794                                    'background' => 'black',
     795                                ),
     796                            ),
     797                        ),
     798                    ),
     799                ),
     800            )
     801        );
     802
     803        $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; }';
     804
     805        $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;}';
     806
     807        $expected = $base_styles . $element_styles;
     808
     809        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     810        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     811    }
     812
     813    /**
     814     * @ticket 56467
     815     */
     816    public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() {
     817        $theme_json = new WP_Theme_JSON(
     818            array(
     819                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     820                'styles'  => array(
     821                    'elements' => array(
     822                        'h4' => array(
     823                            'color'  => array(
     824                                'text'       => 'green',
     825                                'background' => 'red',
     826                            ),
     827                            ':hover' => array(
     828                                'color' => array(
     829                                    'text'       => 'red',
     830                                    'background' => 'green',
     831                                ),
     832                            ),
     833                            ':focus' => array(
     834                                'color' => array(
     835                                    'text'       => 'yellow',
     836                                    'background' => 'black',
     837                                ),
     838                            ),
     839                        ),
     840                    ),
     841                ),
     842            )
     843        );
     844
     845        $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; }';
     846
     847        $element_styles = 'h4{background-color: red;color: green;}';
     848
     849        $expected = $base_styles . $element_styles;
     850
     851        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     852        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     853    }
     854
     855    /**
     856     * @ticket 56467
     857     */
     858    public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() {
     859        $theme_json = new WP_Theme_JSON(
     860            array(
     861                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     862                'styles'  => array(
     863                    'elements' => array(
     864                        'link' => array(
     865                            'color'     => array(
     866                                'text'       => 'green',
     867                                'background' => 'red',
     868                            ),
     869                            ':hover'    => array(
     870                                'color' => array(
     871                                    'text'       => 'red',
     872                                    'background' => 'green',
     873                                ),
     874                            ),
     875                            ':levitate' => array(
     876                                'color' => array(
     877                                    'text'       => 'yellow',
     878                                    'background' => 'black',
     879                                ),
     880                            ),
     881                        ),
     882                    ),
     883                ),
     884            )
     885        );
     886
     887        $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; }';
     888
     889        $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;}';
     890
     891        $expected = $base_styles . $element_styles;
     892
     893        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     894        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     895        $this->assertStringNotContainsString( 'a:levitate{', $theme_json->get_stylesheet( array( 'styles' ) ) );
     896    }
     897
     898    /**
     899     * @ticket 56467
     900     */
     901    public function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors() {
     902        $theme_json = new WP_Theme_JSON(
     903            array(
     904                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     905                'styles'  => array(
     906                    'blocks' => array(
     907                        'core/group' => array(
     908                            'elements' => array(
     909                                'link' => array(
     910                                    'color'  => array(
     911                                        'text'       => 'green',
     912                                        'background' => 'red',
     913                                    ),
     914                                    ':hover' => array(
     915                                        'color'      => array(
     916                                            'text'       => 'red',
     917                                            'background' => 'green',
     918                                        ),
     919                                        'typography' => array(
     920                                            'textTransform' => 'uppercase',
     921                                            'fontSize' => '10em',
     922                                        ),
     923                                    ),
     924                                    ':focus' => array(
     925                                        'color' => array(
     926                                            'text'       => 'yellow',
     927                                            'background' => 'black',
     928                                        ),
     929                                    ),
     930                                ),
     931                            ),
     932                        ),
     933                    ),
     934                ),
     935            )
     936        );
     937
     938        $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; }';
     939
     940        $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;}';
     941
     942        $expected = $base_styles . $element_styles;
     943
     944        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     945        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     946    }
     947
     948    /**
     949     * @ticket 56467
     950     */
     951    public function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors() {
     952        $theme_json = new WP_Theme_JSON(
     953            array(
     954                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     955                'styles'  => array(
     956                    'elements' => array(
     957                        'link' => array(
     958                            'color'  => array(
     959                                'text'       => 'green',
     960                                'background' => 'red',
     961                            ),
     962                            ':hover' => array(
     963                                'color' => array(
     964                                    'text'       => 'red',
     965                                    'background' => 'green',
     966                                ),
     967                            ),
     968                        ),
     969                    ),
     970                    'blocks'   => array(
     971                        'core/group' => array(
     972                            'elements' => array(
     973                                'link' => array(
     974                                    ':hover' => array(
     975                                        'color' => array(
     976                                            'text'       => 'yellow',
     977                                            'background' => 'black',
     978                                        ),
     979                                    ),
     980                                ),
     981                            ),
     982                        ),
     983                    ),
     984                ),
     985            )
     986        );
     987
     988        $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; }';
     989
     990        $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;}';
     991
     992        $expected = $base_styles . $element_styles;
     993
     994        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     995        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    726996    }
    727997
     
    20882358
    20892359    /**
     2360     * @ticket 56467
     2361     */
     2362    public function test_remove_invalid_element_pseudo_selectors() {
     2363        $actual = WP_Theme_JSON::remove_insecure_properties(
     2364            array(
     2365                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     2366                'styles'  => array(
     2367                    'elements' => array(
     2368                        'link' => array(
     2369                            'color'  => array(
     2370                                'text'       => 'hotpink',
     2371                                'background' => 'yellow',
     2372                            ),
     2373                            ':hover' => array(
     2374                                'color' => array(
     2375                                    'text'       => 'red',
     2376                                    'background' => 'blue',
     2377                                ),
     2378                            ),
     2379                        ),
     2380                    ),
     2381                ),
     2382            ),
     2383            true
     2384        );
     2385
     2386        $expected = array(
     2387            'version' => WP_Theme_JSON::LATEST_SCHEMA,
     2388            'styles'  => array(
     2389                'elements' => array(
     2390                    'link' => array(
     2391                        'color'  => array(
     2392                            'text'       => 'hotpink',
     2393                            'background' => 'yellow',
     2394                        ),
     2395                        ':hover' => array(
     2396                            'color' => array(
     2397                                'text'       => 'red',
     2398                                'background' => 'blue',
     2399                            ),
     2400                        ),
     2401                    ),
     2402                ),
     2403            ),
     2404        );
     2405
     2406        $this->assertEqualSetsWithIndex( $expected, $actual );
     2407    }
     2408
     2409    /**
    20902410     * @ticket 54336
    20912411     */
     
    26222942        $this->assertEqualSetsWithIndex( $expected, $actual );
    26232943    }
     2944
     2945    /**
     2946     * @ticket 56467
     2947     */
     2948    public function test_get_element_class_name_button() {
     2949        $expected = 'wp-element-button';
     2950        $actual   = WP_Theme_JSON::get_element_class_name( 'button' );
     2951
     2952        $this->assertSame( $expected, $actual );
     2953    }
     2954
     2955    /**
     2956     * @ticket 56467
     2957     */
     2958    public function test_get_element_class_name_invalid() {
     2959        $expected = '';
     2960        $actual   = WP_Theme_JSON::get_element_class_name( 'unknown-element' );
     2961
     2962        $this->assertSame( $expected, $actual );
     2963    }
     2964
     2965    /**
     2966     * Testing that dynamic properties in theme.json return the value they refrence,
     2967     * e.g. array( 'ref' => 'styles.color.background' ) => "#ffffff".
     2968     *
     2969     * @ticket 56467
     2970     */
     2971    public function test_get_property_value_valid() {
     2972        $theme_json = new WP_Theme_JSON(
     2973            array(
     2974                'version' => 2,
     2975                'styles'  => array(
     2976                    'color'    => array(
     2977                        'background' => '#ffffff',
     2978                        'text'       => '#000000',
     2979                    ),
     2980                    'elements' => array(
     2981                        'button' => array(
     2982                            'color' => array(
     2983                                'background' => array( 'ref' => 'styles.color.text' ),
     2984                                'text'       => array( 'ref' => 'styles.color.background' ),
     2985                            ),
     2986                        ),
     2987                    ),
     2988                ),
     2989            )
     2990        );
     2991
     2992        $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;}';
     2993        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     2994    }
     2995
     2996    /**
     2997     * Testing that dynamic properties in theme.json that refer to other dynamic properties in a loop
     2998     * should be left untouched.
     2999     *
     3000     * @ticket 56467
     3001     * @expectedIncorrectUsage get_property_value
     3002     */
     3003    public function test_get_property_value_loop() {
     3004        $theme_json = new WP_Theme_JSON(
     3005            array(
     3006                'version' => 2,
     3007                'styles'  => array(
     3008                    'color'    => array(
     3009                        'background' => '#ffffff',
     3010                        'text'       => array( 'ref' => 'styles.elements.button.color.background' ),
     3011                    ),
     3012                    'elements' => array(
     3013                        'button' => array(
     3014                            'color' => array(
     3015                                'background' => array( 'ref' => 'styles.color.text' ),
     3016                                'text'       => array( 'ref' => 'styles.color.background' ),
     3017                            ),
     3018                        ),
     3019                    ),
     3020                ),
     3021            )
     3022        );
     3023
     3024        $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;}';
     3025        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     3026    }
     3027
     3028    /**
     3029     * Testing that dynamic properties in theme.json that refer to other dynamic properties
     3030     * should be left unprocessed.
     3031     *
     3032     * @ticket 56467
     3033     * @expectedIncorrectUsage get_property_value
     3034     */
     3035    public function test_get_property_value_recursion() {
     3036        $theme_json = new WP_Theme_JSON(
     3037            array(
     3038                'version' => 2,
     3039                'styles'  => array(
     3040                    'color'    => array(
     3041                        'background' => '#ffffff',
     3042                        'text'       => array( 'ref' => 'styles.color.background' ),
     3043                    ),
     3044                    'elements' => array(
     3045                        'button' => array(
     3046                            'color' => array(
     3047                                'background' => array( 'ref' => 'styles.color.text' ),
     3048                                'text'       => array( 'ref' => 'styles.color.background' ),
     3049                            ),
     3050                        ),
     3051                    ),
     3052                ),
     3053            )
     3054        );
     3055
     3056        $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;}';
     3057        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     3058    }
     3059
     3060    /**
     3061     * Testing that dynamic properties in theme.json that refer to themselves
     3062     * should be left unprocessed.
     3063     *
     3064     * @ticket 56467
     3065     * @expectedIncorrectUsage get_property_value
     3066     */
     3067    public function test_get_property_value_self() {
     3068        $theme_json = new WP_Theme_JSON(
     3069            array(
     3070                'version' => 2,
     3071                'styles'  => array(
     3072                    'color' => array(
     3073                        'background' => '#ffffff',
     3074                        'text'       => array( 'ref' => 'styles.color.text' ),
     3075                    ),
     3076                ),
     3077            )
     3078        );
     3079
     3080        $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; }';
     3081        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     3082    }
     3083
    26243084}
Note: See TracChangeset for help on using the changeset viewer.