Make WordPress Core


Ignore:
Timestamp:
10/20/2026 06:09:21 AM (41 hours ago)
Author:
aaronrobertshaw
Message:

Editor: Add a background clip block support.

Adds a background.backgroundClip block support, so a block can paint its background into the border box, padding box, content box or the text itself. Clipping to the text gives blocks a gradient text fill.

The style engine gains the backgroundClip definition and a VALID_BACKGROUND_CLIP_VALUES constant, WP_Theme_JSON gains the setting and style, and KSES allows background-clip and its vendor prefixed companions. A color clipped to the text no longer adds the has-background class.

Pseudo states and breakpoints that change the clip, or set a text color over a text gradient, now escape the inherited text clip, in both block instance styles and global styles.

This brings in changes from ​https://github.com/WordPress/gutenberg/pull/77141, ​https://github.com/WordPress/gutenberg/pull/77142 and ​https://github.com/WordPress/gutenberg/pull/85057.

Developed in: ​https://github.com/WordPress/wordpress-develop/pull/13491

Props westonruter, isabel_brison, andrewserong, peterwilsoncc, ramonopoly, scruffian, joen, talldanwp.
Fixes #66094.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/theme/wpThemeJson.php

    r64491 r64590  
    13691369                $this->assertStringContainsString(
    13701370                        '@media (640px < width <= 960px){:root :where(.wp-block-group){color: blue;}}',
     1371                        $stylesheet
     1372                );
     1373        }
     1374
     1375        /**
     1376         * Builds a Paragraph stylesheet with a text gradient and the given states.
     1377         *
     1378         * @param array $state_styles State styles to merge into the block styles.
     1379         * @return string Generated stylesheet.
     1380         */
     1381        private function get_text_clip_stylesheet( $state_styles ) {
     1382                $theme_json = new WP_Theme_JSON(
     1383                        array(
     1384                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1385                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1386                                'styles'   => array(
     1387                                        'blocks' => array(
     1388                                                'core/paragraph' => array_merge(
     1389                                                        array(
     1390                                                                'background' => array(
     1391                                                                        'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1392                                                                        'backgroundClip' => 'text',
     1393                                                                ),
     1394                                                        ),
     1395                                                        $state_styles
     1396                                                ),
     1397                                        ),
     1398                                ),
     1399                        )
     1400                );
     1401
     1402                return $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) );
     1403        }
     1404
     1405        /**
     1406         * @ticket 66094
     1407         */
     1408        public function test_breakpoint_escaping_a_text_clip_clears_the_inherited_gradient() {
     1409                $stylesheet = $this->get_text_clip_stylesheet(
     1410                        array(
     1411                                '@mobile' => array(
     1412                                        'background' => array( 'backgroundClip' => 'border-box' ),
     1413                                ),
     1414                        )
     1415                );
     1416
     1417                $this->assertStringContainsString(
     1418                        '@media (width <= 480px){:root :where(p){background-clip: border-box;-webkit-text-fill-color: currentColor;background-image: unset;}}',
     1419                        $stylesheet
     1420                );
     1421        }
     1422
     1423        /**
     1424         * @ticket 66094
     1425         */
     1426        public function test_breakpoint_painting_its_own_background_keeps_it() {
     1427                $stylesheet = $this->get_text_clip_stylesheet(
     1428                        array(
     1429                                '@mobile' => array(
     1430                                        'background' => array(
     1431                                                'gradient'       => 'linear-gradient(135deg,#00ff00,#ffff00)',
     1432                                                'backgroundClip' => 'border-box',
     1433                                        ),
     1434                                ),
     1435                        )
     1436                );
     1437
     1438                $this->assertStringNotContainsString( 'background-image: unset', $stylesheet );
     1439        }
     1440
     1441        /**
     1442         * @ticket 66094
     1443         */
     1444        public function test_breakpoint_text_color_under_a_text_clip_gets_its_fill_back() {
     1445                $stylesheet = $this->get_text_clip_stylesheet(
     1446                        array( '@mobile' => array( 'color' => array( 'text' => '#00ff00' ) ) )
     1447                );
     1448
     1449                $this->assertStringContainsString(
     1450                        '@media (width <= 480px){:root :where(p){color: #00ff00;-webkit-text-fill-color: currentColor;}}',
     1451                        $stylesheet
     1452                );
     1453        }
     1454
     1455        /**
     1456         * @ticket 66094
     1457         */
     1458        public function test_breakpoint_keeping_the_text_clip_needs_no_escape() {
     1459                $stylesheet = $this->get_text_clip_stylesheet(
     1460                        array(
     1461                                '@mobile' => array(
     1462                                        'background' => array(
     1463                                                'gradient'       => 'linear-gradient(135deg,#00ff00,#ffff00)',
     1464                                                'backgroundClip' => 'text',
     1465                                        ),
     1466                                ),
     1467                        )
     1468                );
     1469
     1470                $this->assertStringNotContainsString( 'background-image: unset', $stylesheet );
     1471                $this->assertStringNotContainsString( '-webkit-text-fill-color: currentColor', $stylesheet );
     1472        }
     1473
     1474        /**
     1475         * @ticket 66094
     1476         */
     1477        public function test_breakpoint_element_styles_read_the_element_clip() {
     1478                $theme_json = new WP_Theme_JSON(
     1479                        array(
     1480                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1481                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1482                                'styles'   => array(
     1483                                        'blocks' => array(
     1484                                                'core/group' => array(
     1485                                                        'elements' => array(
     1486                                                                'link' => array(
     1487                                                                        'background' => array(
     1488                                                                                'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1489                                                                                'backgroundClip' => 'text',
     1490                                                                        ),
     1491                                                                ),
     1492                                                        ),
     1493                                                        '@mobile'  => array(
     1494                                                                'elements' => array(
     1495                                                                        'link' => array( 'color' => array( 'text' => '#00ff00' ) ),
     1496                                                                ),
     1497                                                        ),
     1498                                                ),
     1499                                        ),
     1500                                ),
     1501                        )
     1502                );
     1503
     1504                $stylesheet = $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) );
     1505
     1506                // The state key sits in the middle of this node's path, not at its end.
     1507                $this->assertStringContainsString(
     1508                        '@media (width <= 480px){:root :where(.wp-block-group a:where(:not(.wp-element-button))){color: #00ff00;-webkit-text-fill-color: currentColor;}}',
     1509                        $stylesheet
     1510                );
     1511        }
     1512
     1513        /**
     1514         * @ticket 66094
     1515         */
     1516        public function test_breakpoint_variation_styles_read_the_variation_clip() {
     1517                register_block_style(
     1518                        'core/group',
     1519                        array(
     1520                                'name'  => 'flashy',
     1521                                'label' => 'Flashy',
     1522                        )
     1523                );
     1524
     1525                $theme_json = new WP_Theme_JSON(
     1526                        array(
     1527                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1528                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1529                                'styles'   => array(
     1530                                        'blocks' => array(
     1531                                                'core/group' => array(
     1532                                                        'variations' => array(
     1533                                                                'flashy' => array(
     1534                                                                        'background' => array(
     1535                                                                                'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1536                                                                                'backgroundClip' => 'text',
     1537                                                                        ),
     1538                                                                        '@mobile'    => array(
     1539                                                                                'background' => array( 'backgroundClip' => 'border-box' ),
     1540                                                                        ),
     1541                                                                ),
     1542                                                        ),
     1543                                                ),
     1544                                        ),
     1545                                ),
     1546                        )
     1547                );
     1548
     1549                $actual_styles = $theme_json->get_styles_for_block(
     1550                        array(
     1551                                'name'       => 'core/group',
     1552                                'path'       => array( 'styles', 'blocks', 'core/group' ),
     1553                                'selector'   => '.wp-block-group',
     1554                                'css'        => '.wp-block-group',
     1555                                'variations' => array(
     1556                                        array(
     1557                                                'path'     => array( 'styles', 'blocks', 'core/group', 'variations', 'flashy' ),
     1558                                                'selector' => '.is-style-flashy.wp-block-group',
     1559                                        ),
     1560                                ),
     1561                        )
     1562                );
     1563
     1564                unregister_block_style( 'core/group', 'flashy' );
     1565
     1566                $this->assertStringContainsString(
     1567                        '@media (width <= 480px){:root :where(.is-style-flashy.wp-block-group){background-clip: border-box;-webkit-text-fill-color: currentColor;background-image: unset;}}',
     1568                        $actual_styles
     1569                );
     1570        }
     1571
     1572        /**
     1573         * @ticket 66094
     1574         */
     1575        public function test_breakpoint_variation_styles_read_the_block_clip() {
     1576                register_block_style(
     1577                        'core/group',
     1578                        array(
     1579                                'name'  => 'flashy',
     1580                                'label' => 'Flashy',
     1581                        )
     1582                );
     1583
     1584                $theme_json = new WP_Theme_JSON(
     1585                        array(
     1586                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1587                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1588                                'styles'   => array(
     1589                                        'blocks' => array(
     1590                                                'core/group' => array(
     1591                                                        'background' => array(
     1592                                                                'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1593                                                                'backgroundClip' => 'text',
     1594                                                        ),
     1595                                                        'variations' => array(
     1596                                                                'flashy' => array(
     1597                                                                        '@mobile' => array(
     1598                                                                                'background' => array( 'backgroundClip' => 'border-box' ),
     1599                                                                        ),
     1600                                                                ),
     1601                                                        ),
     1602                                                ),
     1603                                        ),
     1604                                ),
     1605                        )
     1606                );
     1607
     1608                $actual_styles = $theme_json->get_styles_for_block(
     1609                        array(
     1610                                'name'       => 'core/group',
     1611                                'path'       => array( 'styles', 'blocks', 'core/group' ),
     1612                                'selector'   => '.wp-block-group',
     1613                                'css'        => '.wp-block-group',
     1614                                'variations' => array(
     1615                                        array(
     1616                                                'path'     => array( 'styles', 'blocks', 'core/group', 'variations', 'flashy' ),
     1617                                                'selector' => '.is-style-flashy.wp-block-group',
     1618                                        ),
     1619                                ),
     1620                        )
     1621                );
     1622
     1623                unregister_block_style( 'core/group', 'flashy' );
     1624
     1625                $this->assertStringContainsString(
     1626                        '@media (width <= 480px){:root :where(.is-style-flashy.wp-block-group){background-clip: border-box;-webkit-text-fill-color: currentColor;background-image: unset;}}',
     1627                        $actual_styles
     1628                );
     1629        }
     1630
     1631        /**
     1632         * @ticket 66094
     1633         */
     1634        public function test_variation_pseudo_state_reads_the_block_clip() {
     1635                register_block_style(
     1636                        'core/button',
     1637                        array(
     1638                                'name'  => 'flashy',
     1639                                'label' => 'Flashy',
     1640                        )
     1641                );
     1642
     1643                $theme_json = new WP_Theme_JSON(
     1644                        array(
     1645                                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     1646                                'styles'  => array(
     1647                                        'blocks' => array(
     1648                                                'core/button' => array(
     1649                                                        'background' => array(
     1650                                                                'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1651                                                                'backgroundClip' => 'text',
     1652                                                        ),
     1653                                                        'variations' => array(
     1654                                                                'flashy' => array(
     1655                                                                        ':hover' => array(
     1656                                                                                'background' => array( 'backgroundClip' => 'border-box' ),
     1657                                                                        ),
     1658                                                                ),
     1659                                                        ),
     1660                                                ),
     1661                                        ),
     1662                                ),
     1663                        )
     1664                );
     1665
     1666                $actual_styles = $theme_json->get_styles_for_block(
     1667                        array(
     1668                                'name'       => 'core/button',
     1669                                'path'       => array( 'styles', 'blocks', 'core/button' ),
     1670                                'selector'   => '.wp-block-button',
     1671                                'css'        => '.wp-block-button',
     1672                                'variations' => array(
     1673                                        array(
     1674                                                'path'     => array( 'styles', 'blocks', 'core/button', 'variations', 'flashy' ),
     1675                                                'selector' => '.is-style-flashy.wp-block-button',
     1676                                        ),
     1677                                ),
     1678                        )
     1679                );
     1680
     1681                unregister_block_style( 'core/button', 'flashy' );
     1682
     1683                $this->assertStringContainsString(
     1684                        ':root :where(.is-style-flashy.wp-block-button:hover){background-clip: border-box;-webkit-text-fill-color: currentColor;background-image: unset;}',
     1685                        $actual_styles
     1686                );
     1687        }
     1688
     1689        /**
     1690         * @ticket 66094
     1691         */
     1692        public function test_variation_breakpoint_pseudo_state_reads_the_block_clip() {
     1693                register_block_style(
     1694                        'core/button',
     1695                        array(
     1696                                'name'  => 'flashy',
     1697                                'label' => 'Flashy',
     1698                        )
     1699                );
     1700
     1701                $theme_json = new WP_Theme_JSON(
     1702                        array(
     1703                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1704                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1705                                'styles'   => array(
     1706                                        'blocks' => array(
     1707                                                'core/button' => array(
     1708                                                        'background' => array(
     1709                                                                'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1710                                                                'backgroundClip' => 'text',
     1711                                                        ),
     1712                                                        'variations' => array(
     1713                                                                'flashy' => array(
     1714                                                                        '@mobile' => array(
     1715                                                                                ':hover' => array(
     1716                                                                                        'background' => array( 'backgroundClip' => 'border-box' ),
     1717                                                                                ),
     1718                                                                        ),
     1719                                                                ),
     1720                                                        ),
     1721                                                ),
     1722                                        ),
     1723                                ),
     1724                        )
     1725                );
     1726
     1727                $actual_styles = $theme_json->get_styles_for_block(
     1728                        array(
     1729                                'name'       => 'core/button',
     1730                                'path'       => array( 'styles', 'blocks', 'core/button' ),
     1731                                'selector'   => '.wp-block-button',
     1732                                'css'        => '.wp-block-button',
     1733                                'variations' => array(
     1734                                        array(
     1735                                                'path'     => array( 'styles', 'blocks', 'core/button', 'variations', 'flashy' ),
     1736                                                'selector' => '.is-style-flashy.wp-block-button',
     1737                                        ),
     1738                                ),
     1739                        )
     1740                );
     1741
     1742                unregister_block_style( 'core/button', 'flashy' );
     1743
     1744                $this->assertStringContainsString(
     1745                        '@media (width <= 480px){:root :where(.is-style-flashy.wp-block-button:hover){background-clip: border-box;-webkit-text-fill-color: currentColor;background-image: unset;}}',
     1746                        $actual_styles
     1747                );
     1748        }
     1749
     1750        /**
     1751         * @ticket 66094
     1752         */
     1753        public function test_pseudo_state_reads_the_clip_its_own_breakpoint_sets() {
     1754                $theme_json = new WP_Theme_JSON(
     1755                        array(
     1756                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1757                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1758                                'styles'   => array(
     1759                                        'blocks' => array(
     1760                                                'core/button' => array(
     1761                                                        'background' => array( 'backgroundClip' => 'border-box' ),
     1762                                                        '@mobile'    => array(
     1763                                                                'background' => array(
     1764                                                                        'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1765                                                                        'backgroundClip' => 'text',
     1766                                                                ),
     1767                                                                ':hover'     => array( 'color' => array( 'text' => '#00ff00' ) ),
     1768                                                        ),
     1769                                                ),
     1770                                        ),
     1771                                ),
     1772                        )
     1773                );
     1774
     1775                $stylesheet = $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) );
     1776
     1777                $this->assertStringContainsString(
     1778                        '@media (width <= 480px){:root :where(.wp-block-button .wp-block-button__link:hover){color: #00ff00;-webkit-text-fill-color: currentColor;}}',
     1779                        $stylesheet
     1780                );
     1781        }
     1782
     1783        /**
     1784         * @ticket 66094
     1785         */
     1786        public function test_pseudo_state_inside_a_breakpoint_reads_the_breakpoint_clip() {
     1787                $theme_json = new WP_Theme_JSON(
     1788                        array(
     1789                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1790                                'settings' => array( 'viewport' => array( 'mobile' => '480px' ) ),
     1791                                'styles'   => array(
     1792                                        'blocks' => array(
     1793                                                'core/button' => array(
     1794                                                        'background' => array(
     1795                                                                'gradient'       => 'linear-gradient(135deg,#ff0000,#0000ff)',
     1796                                                                'backgroundClip' => 'text',
     1797                                                        ),
     1798                                                        '@mobile'    => array(
     1799                                                                'background' => array( 'backgroundClip' => 'border-box' ),
     1800                                                                ':hover'     => array( 'color' => array( 'text' => '#00ff00' ) ),
     1801                                                        ),
     1802                                                ),
     1803                                        ),
     1804                                ),
     1805                        )
     1806                );
     1807
     1808                $stylesheet = $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) );
     1809
     1810                // The breakpoint already escaped the clip, so no fill is needed.
     1811                $this->assertStringContainsString(
     1812                        '@media (width <= 480px){:root :where(.wp-block-button .wp-block-button__link:hover){color: #00ff00;}}',
    13711813                        $stylesheet
    13721814                );
Note: See TracChangeset for help on using the changeset viewer.