diff --git a/.npmrc b/.npmrc index 1dab4ed4c3020..aafab1669bf72 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ save-exact = true +engine-strict = true diff --git a/package.json b/package.json index 825a5714bfe1e..6429aea0b1c93 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "engines": { "node": ">=14.15.0", - "npm": ">=6.14.8" + "npm": ">=6.14.8 <7" }, "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/src/js/_enqueues/admin/site-health.js b/src/js/_enqueues/admin/site-health.js index 9c4ee5c8b760f..893ca0c462c22 100644 --- a/src/js/_enqueues/admin/site-health.js +++ b/src/js/_enqueues/admin/site-health.js @@ -15,6 +15,8 @@ jQuery( function( $ ) { isStatusTab = $( '.health-check-body.health-check-status-tab' ).length, isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length, pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ), + menuCounterWrapper = $( '#adminmenu .site-health-counter' ), + menuCounter = $( '#adminmenu .site-health-counter .count' ), successTimeout; // Debug information copy section. @@ -164,8 +166,14 @@ jQuery( function( $ ) { $( '.site-health-issue-count-title', issueWrapper ).html( heading ); } + menuCounter.text( SiteHealth.site_status.issues.critical ); + if ( 0 < parseInt( SiteHealth.site_status.issues.critical, 0 ) ) { $( '#health-check-issues-critical' ).removeClass( 'hidden' ); + + menuCounterWrapper.removeClass( 'count-0' ); + } else { + menuCounterWrapper.addClass( 'count-0' ); } if ( 0 < parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) { $( '#health-check-issues-recommended' ).removeClass( 'hidden' ); diff --git a/src/wp-admin/css/admin-menu.css b/src/wp-admin/css/admin-menu.css index 48f2ecce9b4ef..0dc59c6e6b2c2 100644 --- a/src/wp-admin/css/admin-menu.css +++ b/src/wp-admin/css/admin-menu.css @@ -427,6 +427,7 @@ ul#adminmenu > li.current > a.current:after { } /* @todo: consider to use a single rule for these counters and the list table comments counters. */ +#adminmenu .menu-counter, #adminmenu .awaiting-mod, #adminmenu .update-plugins { display: inline-block; diff --git a/src/wp-admin/css/colors/_admin.scss b/src/wp-admin/css/colors/_admin.scss index e80b62acc9a52..eaa4732db2f5d 100644 --- a/src/wp-admin/css/colors/_admin.scss +++ b/src/wp-admin/css/colors/_admin.scss @@ -350,6 +350,7 @@ ul#adminmenu > li.current > a.current:after { /* Admin Menu: bubble */ +#adminmenu .menu-counter, #adminmenu .awaiting-mod, #adminmenu .update-plugins { color: $menu-bubble-text; diff --git a/src/wp-admin/css/dashboard.css b/src/wp-admin/css/dashboard.css index 5a11e1273b878..c9967c78e0f25 100644 --- a/src/wp-admin/css/dashboard.css +++ b/src/wp-admin/css/dashboard.css @@ -1186,7 +1186,8 @@ a.rsswidget { padding-right: 6px; } -#dashboard_php_nag.php-insecure .dashicons-warning { +#dashboard_php_nag.php-no-security-updates .dashicons-warning, +#dashboard_php_nag.php-version-lower-than-future-minimum .dashicons-warning { color: #d63638; } @@ -1198,14 +1199,15 @@ a.rsswidget { margin: 12px 0; } -#dashboard_php_nag h3 { - font-weight: 600; -} - #dashboard_php_nag .button .dashicons-external { line-height: 25px; } +.bigger-bolder-text { + font-weight: 600; + font-size: 14px; +} + /* =Media Queries -------------------------------------------------------------- */ diff --git a/src/wp-admin/css/list-tables.css b/src/wp-admin/css/list-tables.css index 423c725c3984e..97b258b183817 100644 --- a/src/wp-admin/css/list-tables.css +++ b/src/wp-admin/css/list-tables.css @@ -1398,6 +1398,17 @@ ul.cat-checklist { content: "\f147"; } +.plugin-install-php #the-list { + display: flex; + flex-wrap: wrap; +} + +.plugin-install-php .plugin-card { + display: flex; + flex-direction: column; + justify-content: space-between; +} + .plugin-install-php h2 { clear: both; } diff --git a/src/wp-admin/includes/admin-filters.php b/src/wp-admin/includes/admin-filters.php index e80c111dde33f..33354cb073e32 100644 --- a/src/wp-admin/includes/admin-filters.php +++ b/src/wp-admin/includes/admin-filters.php @@ -80,6 +80,7 @@ add_filter( 'heartbeat_received', 'heartbeat_autosave', 500, 2 ); add_filter( 'wp_refresh_nonces', 'wp_refresh_post_nonces', 10, 3 ); +add_filter( 'wp_refresh_nonces', 'wp_refresh_metabox_loader_nonces', 10, 2 ); add_filter( 'wp_refresh_nonces', 'wp_refresh_heartbeat_nonces' ); add_filter( 'heartbeat_settings', 'wp_heartbeat_set_suspension' ); diff --git a/src/wp-admin/includes/class-custom-background.php b/src/wp-admin/includes/class-custom-background.php index fa89e10e420b8..07a72dd1b1e41 100644 --- a/src/wp-admin/includes/class-custom-background.php +++ b/src/wp-admin/includes/class-custom-background.php @@ -11,6 +11,7 @@ * * @since 3.0.0 */ +#[AllowDynamicProperties] class Custom_Background { /** diff --git a/src/wp-admin/includes/class-custom-image-header.php b/src/wp-admin/includes/class-custom-image-header.php index e59cd16284886..c8809ade2ff20 100644 --- a/src/wp-admin/includes/class-custom-image-header.php +++ b/src/wp-admin/includes/class-custom-image-header.php @@ -11,6 +11,7 @@ * * @since 2.1.0 */ +#[AllowDynamicProperties] class Custom_Image_Header { /** diff --git a/src/wp-admin/includes/class-file-upload-upgrader.php b/src/wp-admin/includes/class-file-upload-upgrader.php index 28cc4402c7ed0..d7c459dd60ef1 100644 --- a/src/wp-admin/includes/class-file-upload-upgrader.php +++ b/src/wp-admin/includes/class-file-upload-upgrader.php @@ -16,6 +16,7 @@ * @since 2.8.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader.php. */ +#[AllowDynamicProperties] class File_Upload_Upgrader { /** diff --git a/src/wp-admin/includes/class-wp-automatic-updater.php b/src/wp-admin/includes/class-wp-automatic-updater.php index c8227c3fc3388..e453539deb274 100644 --- a/src/wp-admin/includes/class-wp-automatic-updater.php +++ b/src/wp-admin/includes/class-wp-automatic-updater.php @@ -13,6 +13,7 @@ * @since 3.7.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader.php. */ +#[AllowDynamicProperties] class WP_Automatic_Updater { /** diff --git a/src/wp-admin/includes/class-wp-community-events.php b/src/wp-admin/includes/class-wp-community-events.php index 3f43f8d1db6ba..1a09bec848707 100644 --- a/src/wp-admin/includes/class-wp-community-events.php +++ b/src/wp-admin/includes/class-wp-community-events.php @@ -14,6 +14,7 @@ * * @since 4.8.0 */ +#[AllowDynamicProperties] class WP_Community_Events { /** * ID for a WordPress user account. diff --git a/src/wp-admin/includes/class-wp-debug-data.php b/src/wp-admin/includes/class-wp-debug-data.php index a921fc4dcb77c..ab0926d3acf5f 100644 --- a/src/wp-admin/includes/class-wp-debug-data.php +++ b/src/wp-admin/includes/class-wp-debug-data.php @@ -7,6 +7,7 @@ * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Debug_Data { /** * Calls all core functions to check for updates. diff --git a/src/wp-admin/includes/class-wp-filesystem-base.php b/src/wp-admin/includes/class-wp-filesystem-base.php index 8d83b24dd6959..aae09e8dfa53c 100644 --- a/src/wp-admin/includes/class-wp-filesystem-base.php +++ b/src/wp-admin/includes/class-wp-filesystem-base.php @@ -11,6 +11,7 @@ * * @since 2.5.0 */ +#[AllowDynamicProperties] class WP_Filesystem_Base { /** diff --git a/src/wp-admin/includes/class-wp-importer.php b/src/wp-admin/includes/class-wp-importer.php index 4c6d518f97eed..4804c888b23f3 100644 --- a/src/wp-admin/includes/class-wp-importer.php +++ b/src/wp-admin/includes/class-wp-importer.php @@ -2,6 +2,7 @@ /** * WP_Importer base class */ +#[AllowDynamicProperties] class WP_Importer { /** * Class Constructor diff --git a/src/wp-admin/includes/class-wp-internal-pointers.php b/src/wp-admin/includes/class-wp-internal-pointers.php index 08cf8177445ee..884f27ea1f247 100644 --- a/src/wp-admin/includes/class-wp-internal-pointers.php +++ b/src/wp-admin/includes/class-wp-internal-pointers.php @@ -12,6 +12,7 @@ * * @since 3.3.0 */ +#[AllowDynamicProperties] final class WP_Internal_Pointers { /** * Initializes the new feature pointers. diff --git a/src/wp-admin/includes/class-wp-list-table.php b/src/wp-admin/includes/class-wp-list-table.php index 599c69d2ad711..046e9515d861e 100644 --- a/src/wp-admin/includes/class-wp-list-table.php +++ b/src/wp-admin/includes/class-wp-list-table.php @@ -13,6 +13,7 @@ * @since 3.1.0 * @access private */ +#[AllowDynamicProperties] class WP_List_Table { /** diff --git a/src/wp-admin/includes/class-wp-privacy-policy-content.php b/src/wp-admin/includes/class-wp-privacy-policy-content.php index bbc46c0a704de..9b11d09a66f02 100644 --- a/src/wp-admin/includes/class-wp-privacy-policy-content.php +++ b/src/wp-admin/includes/class-wp-privacy-policy-content.php @@ -7,6 +7,7 @@ * @since 4.9.6 */ +#[AllowDynamicProperties] final class WP_Privacy_Policy_Content { private static $policy_content = array(); diff --git a/src/wp-admin/includes/class-wp-screen.php b/src/wp-admin/includes/class-wp-screen.php index 7caf17beb5c31..7b7290011c67a 100644 --- a/src/wp-admin/includes/class-wp-screen.php +++ b/src/wp-admin/includes/class-wp-screen.php @@ -12,6 +12,7 @@ * * @since 3.3.0 */ +#[AllowDynamicProperties] final class WP_Screen { /** * Any action associated with the screen. diff --git a/src/wp-admin/includes/class-wp-site-health-auto-updates.php b/src/wp-admin/includes/class-wp-site-health-auto-updates.php index 5393b6f3c9bf6..4880d023021cb 100644 --- a/src/wp-admin/includes/class-wp-site-health-auto-updates.php +++ b/src/wp-admin/includes/class-wp-site-health-auto-updates.php @@ -7,6 +7,7 @@ * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Site_Health_Auto_Updates { /** * WP_Site_Health_Auto_Updates constructor. diff --git a/src/wp-admin/includes/class-wp-site-health.php b/src/wp-admin/includes/class-wp-site-health.php index 7c94e8be1084c..141745c97a188 100644 --- a/src/wp-admin/includes/class-wp-site-health.php +++ b/src/wp-admin/includes/class-wp-site-health.php @@ -7,6 +7,7 @@ * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Site_Health { private static $instance = null; @@ -740,7 +741,7 @@ public function get_test_php_version() { '

%s

', sprintf( /* translators: %s: The minimum recommended PHP version. */ - __( 'PHP is the programming language used to build and maintain WordPress. Newer versions of PHP are created with increased performance in mind, so you may see a positive effect on your site’s performance. The minimum recommended version of PHP is %s.' ), + __( 'PHP is one of the programming languages used to build WordPress. Newer versions of PHP receive regular security updates and may increase your site’s performance. The minimum recommended version of PHP is %s.' ), $response ? $response['recommended_version'] : '' ) ), @@ -763,7 +764,7 @@ public function get_test_php_version() { if ( $response['is_supported'] ) { $result['label'] = sprintf( /* translators: %s: The server PHP version. */ - __( 'Your site is running an older version of PHP (%s)' ), + __( 'Your site is running on an older version of PHP (%s)' ), PHP_VERSION ); $result['status'] = 'recommended'; @@ -771,11 +772,28 @@ public function get_test_php_version() { return $result; } + // The PHP version is still receiving security fixes, but is lower than + // the expected minimum version that will be required by WordPress in the near future. + if ( $response['is_secure'] && $response['is_lower_than_future_minimum'] ) { + // The `is_secure` array key name doesn't actually imply this is a secure version of PHP. It only means it receives security updates. + + $result['label'] = sprintf( + /* translators: %s: The server PHP version. */ + __( 'Your site is running on an outdated version of PHP (%s), which soon will not be supported by WordPress.' ), + PHP_VERSION + ); + + $result['status'] = 'critical'; + $result['badge']['label'] = __( 'Requirements' ); + + return $result; + } + // The PHP version is only receiving security fixes. if ( $response['is_secure'] ) { $result['label'] = sprintf( /* translators: %s: The server PHP version. */ - __( 'Your site is running an older version of PHP (%s), which should be updated' ), + __( 'Your site is running on an older version of PHP (%s), which should be updated' ), PHP_VERSION ); $result['status'] = 'recommended'; @@ -783,13 +801,25 @@ public function get_test_php_version() { return $result; } - // Anything no longer secure must be updated. - $result['label'] = sprintf( - /* translators: %s: The server PHP version. */ - __( 'Your site is running an outdated version of PHP (%s), which requires an update' ), - PHP_VERSION - ); - $result['status'] = 'critical'; + // No more security updates for the PHP version, and lower than the expected minimum version required by WordPress. + if ( $response['is_lower_than_future_minimum'] ) { + $message = sprintf( + /* translators: %s: The server PHP version. */ + __( 'Your site is running on an outdated version of PHP (%s), which does not receive security updates and soon will not be supported by WordPress.' ), + PHP_VERSION + ); + } else { + // No more security updates for the PHP version, must be updated. + $message = sprintf( + /* translators: %s: The server PHP version. */ + __( 'Your site is running on an outdated version of PHP (%s), which does not receive security updates. It should be updated.' ), + PHP_VERSION + ); + } + + $result['label'] = $message; + $result['status'] = 'critical'; + $result['badge']['label'] = __( 'Security' ); return $result; diff --git a/src/wp-admin/includes/class-wp-site-icon.php b/src/wp-admin/includes/class-wp-site-icon.php index d153b6f8263a7..e799c7fb7980d 100644 --- a/src/wp-admin/includes/class-wp-site-icon.php +++ b/src/wp-admin/includes/class-wp-site-icon.php @@ -12,6 +12,7 @@ * * @since 4.3.0 */ +#[AllowDynamicProperties] class WP_Site_Icon { /** diff --git a/src/wp-admin/includes/class-wp-upgrader-skin.php b/src/wp-admin/includes/class-wp-upgrader-skin.php index bb7e7bbf3b9e6..d0d2a39b01dd3 100644 --- a/src/wp-admin/includes/class-wp-upgrader-skin.php +++ b/src/wp-admin/includes/class-wp-upgrader-skin.php @@ -13,6 +13,7 @@ * @since 2.8.0 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader-skins.php. */ +#[AllowDynamicProperties] class WP_Upgrader_Skin { /** diff --git a/src/wp-admin/includes/class-wp-upgrader.php b/src/wp-admin/includes/class-wp-upgrader.php index 412b383abec39..a2b2c9ed06fca 100644 --- a/src/wp-admin/includes/class-wp-upgrader.php +++ b/src/wp-admin/includes/class-wp-upgrader.php @@ -48,6 +48,7 @@ * * @since 2.8.0 */ +#[AllowDynamicProperties] class WP_Upgrader { /** diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index d3dcfceaae659..20759e7c9d2f8 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -20,17 +20,18 @@ function wp_dashboard_setup() { global $wp_registered_widgets, $wp_registered_widget_controls, $wp_dashboard_control_callbacks; - $wp_dashboard_control_callbacks = array(); - $screen = get_current_screen(); + $screen = get_current_screen(); /* Register Widgets and Controls */ + $wp_dashboard_control_callbacks = array(); - $response = wp_check_browser_version(); + // Browser version + $check_browser = wp_check_browser_version(); - if ( $response && $response['upgrade'] ) { + if ( $check_browser && $check_browser['upgrade'] ) { add_filter( 'postbox_classes_dashboard_dashboard_browser_nag', 'dashboard_browser_nag_class' ); - if ( $response['insecure'] ) { + if ( $check_browser['insecure'] ) { wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'You are using an insecure browser!' ), 'wp_dashboard_browser_nag' ); } else { wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'Your browser is out of date!' ), 'wp_dashboard_browser_nag' ); @@ -38,14 +39,19 @@ function wp_dashboard_setup() { } // PHP Version. - $response = wp_check_php_version(); + $check_php = wp_check_php_version(); - if ( $response && isset( $response['is_acceptable'] ) && ! $response['is_acceptable'] - && current_user_can( 'update_php' ) - ) { - add_filter( 'postbox_classes_dashboard_dashboard_php_nag', 'dashboard_php_nag_class' ); + if ( $check_php && current_user_can( 'update_php' ) ) { + // If "not acceptable" the widget will be shown. + if ( isset( $check_php['is_acceptable'] ) && ! $check_php['is_acceptable'] ) { + add_filter( 'postbox_classes_dashboard_dashboard_php_nag', 'dashboard_php_nag_class' ); - wp_add_dashboard_widget( 'dashboard_php_nag', __( 'PHP Update Recommended' ), 'wp_dashboard_php_nag' ); + if ( $check_php['is_lower_than_future_minimum'] ) { + wp_add_dashboard_widget( 'dashboard_php_nag', __( 'PHP Update Required' ), 'wp_dashboard_php_nag' ); + } else { + wp_add_dashboard_widget( 'dashboard_php_nag', __( 'PHP Update Recommended' ), 'wp_dashboard_php_nag' ); + } + } } // Site Health. @@ -1825,29 +1831,48 @@ function wp_dashboard_php_nag() { } if ( isset( $response['is_secure'] ) && ! $response['is_secure'] ) { - $msg = sprintf( + // The `is_secure` array key name doesn't actually imply this is a secure version of PHP. It only means it receives security updates. + + if ( $response['is_lower_than_future_minimum'] ) { + $message = sprintf( + /* translators: %s: The server PHP version. */ + __( 'Your site is running on an outdated version of PHP (%s), which does not receive security updates and soon will not be supported by WordPress. Ensure that PHP is updated on your server as soon as possible. Otherwise you will not be able to upgrade WordPress.' ), + PHP_VERSION + ); + } else { + $message = sprintf( + /* translators: %s: The server PHP version. */ + __( 'Your site is running on an outdated version of PHP (%s), which does not receive security updates. It should be updated.' ), + PHP_VERSION + ); + } + } elseif ( $response['is_lower_than_future_minimum'] ) { + $message = sprintf( /* translators: %s: The server PHP version. */ - __( 'Your site is running an insecure version of PHP (%s), which should be updated.' ), + __( 'Your site is running on an outdated version of PHP (%s), which soon will not be supported by WordPress. Ensure that PHP is updated on your server as soon as possible. Otherwise you will not be able to upgrade WordPress.' ), PHP_VERSION ); } else { - $msg = sprintf( + $message = sprintf( /* translators: %s: The server PHP version. */ - __( 'Your site is running an outdated version of PHP (%s), which should be updated.' ), + __( 'Your site is running on an outdated version of PHP (%s), which should be updated.' ), PHP_VERSION ); } ?> -

+

-

+

+

@@ -1879,8 +1904,14 @@ function wp_dashboard_php_nag() { function dashboard_php_nag_class( $classes ) { $response = wp_check_php_version(); - if ( $response && isset( $response['is_secure'] ) && ! $response['is_secure'] ) { - $classes[] = 'php-insecure'; + if ( ! $response ) { + return $classes; + } + + if ( isset( $response['is_secure'] ) && ! $response['is_secure'] ) { + $classes[] = 'php-no-security-updates'; + } elseif ( $response['is_lower_than_future_minimum'] ) { + $classes[] = 'php-version-lower-than-future-minimum'; } return $classes; diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index e7083b7999b2b..e8fb7a6951165 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -21,6 +21,7 @@ 'searchform.php' => __( 'Search Form' ), '404.php' => __( '404 Template' ), 'link.php' => __( 'Links Template' ), + 'theme.json' => __( 'Theme Styles & Block Settings' ), // Archives. 'index.php' => __( 'Main Index Template' ), 'archive.php' => __( 'Archives' ), diff --git a/src/wp-admin/includes/misc.php b/src/wp-admin/includes/misc.php index 94337fee7d3ff..78c1aab1c8298 100644 --- a/src/wp-admin/includes/misc.php +++ b/src/wp-admin/includes/misc.php @@ -1255,6 +1255,41 @@ function wp_refresh_post_nonces( $response, $data, $screen_id ) { return $response; } +/** + * Refresh nonces used with meta boxes in the block editor. + * + * @since 6.1.0 + * + * @param array $response The Heartbeat response. + * @param array $data The $_POST data sent. + * @return array The Heartbeat response. + */ +function wp_refresh_metabox_loader_nonces( $response, $data ) { + if ( empty( $data['wp-refresh-metabox-loader-nonces'] ) ) { + return $response; + } + + $received = $data['wp-refresh-metabox-loader-nonces']; + $post_id = (int) $received['post_id']; + + if ( ! $post_id ) { + return $response; + } + + if ( ! current_user_can( 'edit_post', $post_id ) ) { + return $response; + } + + $response['wp-refresh-metabox-loader-nonces'] = array( + 'replace' => array( + 'metabox_loader_nonce' => wp_create_nonce( 'meta-box-loader' ), + '_wpnonce' => wp_create_nonce( 'update-post_' . $post_id ), + ), + ); + + return $response; +} + /** * Adds the latest Heartbeat and REST-API nonce to the Heartbeat response. * @@ -1550,7 +1585,8 @@ function wp_check_php_version() { * 'recommended_version' - string - The PHP version recommended by WordPress. * 'is_supported' - boolean - Whether the PHP version is actively supported. * 'is_secure' - boolean - Whether the PHP version receives security updates. - * 'is_acceptable' - boolean - Whether the PHP version is still acceptable for WordPress. + * 'is_acceptable' - boolean - Whether the PHP version is still acceptable or warnings + * should be shown and an update recommended. */ $response = json_decode( wp_remote_retrieve_body( $response ), true ); @@ -1578,5 +1614,15 @@ function wp_check_php_version() { $response['is_acceptable'] = (bool) apply_filters( 'wp_is_php_version_acceptable', true, $version ); } + $response['is_lower_than_future_minimum'] = false; + + // The minimum supported PHP version will be updated to 7.2. Check if the current version is lower. + if ( version_compare( $version, '7.2', '<' ) ) { + $response['is_lower_than_future_minimum'] = true; + + // Force showing of warnings. + $response['is_acceptable'] = false; + } + return $response; } diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index 8eb0368220e83..1abe5423166b5 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -2334,6 +2334,50 @@ function the_block_editor_meta_boxes() { wp_add_inline_script( 'wp-lists', $script ); } + /* + * Refresh nonces used by the meta box loader. + * + * The logic is very similar to that provided by post.js for the classic editor. + */ + $script = "( function( $ ) { + var check, timeout; + + function schedule() { + check = false; + window.clearTimeout( timeout ); + timeout = window.setTimeout( function() { check = true; }, 300000 ); + } + + $( document ).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) { + var post_id, \$authCheck = $( '#wp-auth-check-wrap' ); + + if ( check || ( \$authCheck.length && ! \$authCheck.hasClass( 'hidden' ) ) ) { + if ( ( post_id = $( '#post_ID' ).val() ) && $( '#_wpnonce' ).val() ) { + data['wp-refresh-metabox-loader-nonces'] = { + post_id: post_id + }; + } + } + }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) { + var nonces = data['wp-refresh-metabox-loader-nonces']; + + if ( nonces ) { + if ( nonces.replace ) { + if ( nonces.replace.metabox_loader_nonce && window._wpMetaBoxUrl && wp.url ) { + window._wpMetaBoxUrl= wp.url.addQueryArgs( window._wpMetaBoxUrl, { 'meta-box-loader-nonce': nonces.replace.metabox_loader_nonce } ); + } + + if ( nonces.replace._wpnonce ) { + $( '#_wpnonce' ).val( nonces.replace._wpnonce ); + } + } + } + }).ready( function() { + schedule(); + }); + } )( jQuery );"; + wp_add_inline_script( 'heartbeat', $script ); + // Reset meta box data. $wp_meta_boxes = $_original_meta_boxes; } diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php index 2ccea37caaaf3..adc32de5b9c13 100644 --- a/src/wp-admin/includes/update-core.php +++ b/src/wp-admin/includes/update-core.php @@ -1188,7 +1188,7 @@ function update_core( $from, $to ) { apply_filters( 'update_feedback', __( 'Copying the required files…' ) ); // Copy new versions of WP files into place. - $result = _copy_dir( $from . $distro, $to, $skip ); + $result = copy_dir( $from . $distro, $to, $skip ); if ( is_wp_error( $result ) ) { $result = new WP_Error( @@ -1266,7 +1266,7 @@ function update_core( $from, $to ) { if ( $available_space && $total_size >= $available_space ) { $result = new WP_Error( 'disk_full', __( 'There is not enough free disk space to complete the update.' ) ); } else { - $result = _copy_dir( $from . $distro, $to, $skip ); + $result = copy_dir( $from . $distro, $to, $skip ); if ( is_wp_error( $result ) ) { $result = new WP_Error( @@ -1459,95 +1459,6 @@ function update_core( $from, $to ) { return $wp_version; } -/** - * Copies a directory from one location to another via the WordPress Filesystem Abstraction. - * - * Assumes that WP_Filesystem() has already been called and setup. - * - * This is a standalone copy of the `copy_dir()` function that is used to - * upgrade the core files. It is placed here so that the version of this - * function from the *new* WordPress version will be called. - * - * It was initially added for the 3.1 -> 3.2 upgrade. - * - * @ignore - * @since 3.2.0 - * @since 3.7.0 Updated not to use a regular expression for the skip list. - * - * @see copy_dir() - * @link https://core.trac.wordpress.org/ticket/17173 - * - * @global WP_Filesystem_Base $wp_filesystem - * - * @param string $from Source directory. - * @param string $to Destination directory. - * @param string[] $skip_list Array of files/folders to skip copying. - * @return true|WP_Error True on success, WP_Error on failure. - */ -function _copy_dir( $from, $to, $skip_list = array() ) { - global $wp_filesystem; - - $dirlist = $wp_filesystem->dirlist( $from ); - - if ( false === $dirlist ) { - return new WP_Error( 'dirlist_failed__copy_dir', __( 'Directory listing failed.' ), basename( $to ) ); - } - - $from = trailingslashit( $from ); - $to = trailingslashit( $to ); - - foreach ( (array) $dirlist as $filename => $fileinfo ) { - if ( in_array( $filename, $skip_list, true ) ) { - continue; - } - - if ( 'f' === $fileinfo['type'] ) { - if ( ! $wp_filesystem->copy( $from . $filename, $to . $filename, true, FS_CHMOD_FILE ) ) { - // If copy failed, chmod file to 0644 and try again. - $wp_filesystem->chmod( $to . $filename, FS_CHMOD_FILE ); - - if ( ! $wp_filesystem->copy( $from . $filename, $to . $filename, true, FS_CHMOD_FILE ) ) { - return new WP_Error( 'copy_failed__copy_dir', __( 'Could not copy file.' ), $to . $filename ); - } - } - - /* - * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later, - * so don't run it when upgrading from older versions. - */ - if ( function_exists( 'wp_opcache_invalidate' ) ) { - wp_opcache_invalidate( $to . $filename ); - } - } elseif ( 'd' === $fileinfo['type'] ) { - if ( ! $wp_filesystem->is_dir( $to . $filename ) ) { - if ( ! $wp_filesystem->mkdir( $to . $filename, FS_CHMOD_DIR ) ) { - return new WP_Error( 'mkdir_failed__copy_dir', __( 'Could not create directory.' ), $to . $filename ); - } - } - - /* - * Generate the $sub_skip_list for the subdirectory as a sub-set - * of the existing $skip_list. - */ - $sub_skip_list = array(); - - foreach ( $skip_list as $skip_item ) { - if ( 0 === strpos( $skip_item, $filename . '/' ) ) { - $sub_skip_list[] = preg_replace( '!^' . preg_quote( $filename, '!' ) . '/!i', '', $skip_item ); - } - } - - $result = _copy_dir( $from . $filename, $to . $filename, $sub_skip_list ); - - if ( is_wp_error( $result ) ) { - return $result; - } - } - } - - return true; -} - /** * Redirect to the About WordPress page after a successful upgrade. * diff --git a/src/wp-admin/menu.php b/src/wp-admin/menu.php index 5d550fb55d856..05da5f213a9e1 100644 --- a/src/wp-admin/menu.php +++ b/src/wp-admin/menu.php @@ -214,12 +214,20 @@ ); } +if ( ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ) ) { + $submenu['themes.php'][6] = array( + __( 'Template Parts' ), + 'edit_theme_options', + 'site-editor.php?postType=wp_template_part', + ); +} + $customize_url = add_query_arg( 'return', urlencode( remove_query_arg( wp_removable_query_args(), wp_unslash( $_SERVER['REQUEST_URI'] ) ) ), 'customize.php' ); // Hide Customize link on block themes unless a plugin or theme // is using 'customize_register' to add a setting. if ( ! wp_is_block_theme() || has_action( 'customize_register' ) ) { - $position = wp_is_block_theme() ? 7 : 6; + $position = ( wp_is_block_theme() || current_theme_supports( 'block-template-parts' ) ) ? 7 : 6; $submenu['themes.php'][ $position ] = array( __( 'Customize' ), 'customize', esc_url( $customize_url ), '', 'hide-if-no-customize' ); } @@ -342,11 +350,37 @@ function _add_plugin_file_editor_to_tools() { } } +$site_health_count = ''; +if ( ! is_multisite() && current_user_can( 'view_site_health_checks' ) ) { + $get_issues = get_transient( 'health-check-site-status-result' ); + + $issue_counts = array(); + + if ( false !== $get_issues ) { + $issue_counts = json_decode( $get_issues, true ); + } + + if ( ! is_array( $issue_counts ) || ! $issue_counts ) { + $issue_counts = array( + 'good' => 0, + 'recommended' => 0, + 'critical' => 0, + ); + } + + $site_health_count = sprintf( + '%s', + $issue_counts['critical'], + number_format_i18n( $issue_counts['critical'] ) + ); +} + $menu[75] = array( __( 'Tools' ), 'edit_posts', 'tools.php', '', 'menu-top menu-icon-tools', 'menu-tools', 'dashicons-admin-tools' ); $submenu['tools.php'][5] = array( __( 'Available Tools' ), 'edit_posts', 'tools.php' ); $submenu['tools.php'][10] = array( __( 'Import' ), 'import', 'import.php' ); $submenu['tools.php'][15] = array( __( 'Export' ), 'export', 'export.php' ); - $submenu['tools.php'][20] = array( __( 'Site Health' ), 'view_site_health_checks', 'site-health.php' ); + /* translators: %s: Number of critical Site Health checks. */ + $submenu['tools.php'][20] = array( sprintf( __( 'Site Health %s' ), $site_health_count ), 'view_site_health_checks', 'site-health.php' ); $submenu['tools.php'][25] = array( __( 'Export Personal Data' ), 'export_others_personal_data', 'export-personal-data.php' ); $submenu['tools.php'][30] = array( __( 'Erase Personal Data' ), 'erase_others_personal_data', 'erase-personal-data.php' ); if ( is_multisite() && ! is_main_site() ) { diff --git a/src/wp-admin/site-editor.php b/src/wp-admin/site-editor.php index 365c6d701eaf1..64ed4b9c27cad 100644 --- a/src/wp-admin/site-editor.php +++ b/src/wp-admin/site-editor.php @@ -19,10 +19,15 @@ ); } -if ( ! wp_is_block_theme() ) { +if ( ! ( current_theme_supports( 'block-template-parts' ) || wp_is_block_theme() ) ) { wp_die( __( 'The theme you are currently using is not compatible with Full Site Editing.' ) ); } +$is_template_part_editor = isset( $_GET['postType'] ) && 'wp_template_part' === sanitize_key( $_GET['postType'] ); +if ( ! wp_is_block_theme() && ! $is_template_part_editor ) { + wp_die( __( 'The theme you are currently using is not compatible with the Site Editor.' ) ); +} + /** * Do a server-side redirection if missing `postType` and `postId` * query args when visiting Site Editor. @@ -64,14 +69,24 @@ static function( $classes ) { $block_editor_context = new WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); $custom_settings = array( - 'siteUrl' => site_url(), - 'postsPerPage' => get_option( 'posts_per_page' ), - 'styles' => get_block_editor_theme_styles(), - 'defaultTemplateTypes' => $indexed_template_types, - 'defaultTemplatePartAreas' => get_allowed_block_template_part_areas(), - '__unstableHomeTemplate' => $home_template, + 'siteUrl' => site_url(), + 'postsPerPage' => get_option( 'posts_per_page' ), + 'styles' => get_block_editor_theme_styles(), + 'defaultTemplateTypes' => $indexed_template_types, + 'defaultTemplatePartAreas' => get_allowed_block_template_part_areas(), + 'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(), + 'supportsTemplatePartsMode' => ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ), + '__unstableHomeTemplate' => $home_template, ); +/** + * Home template resolution is not needed when block template parts are supported. + * Set the value to `true` to satisfy the editor initialization guard clause. + */ +if ( $custom_settings['supportsTemplatePartsMode'] ) { + $custom_settings['__unstableHomeTemplate'] = true; +} + // Add additional back-compat patterns registered by `current_screen` et al. $custom_settings['__experimentalAdditionalBlockPatterns'] = WP_Block_Patterns_Registry::get_instance()->get_all_registered( true ); $custom_settings['__experimentalAdditionalBlockPatternCategories'] = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered( true ); diff --git a/src/wp-content/themes/twentyfifteen/css/blocks.css b/src/wp-content/themes/twentyfifteen/css/blocks.css index e5b3af47b8d59..be2d8ffef6655 100644 --- a/src/wp-content/themes/twentyfifteen/css/blocks.css +++ b/src/wp-content/themes/twentyfifteen/css/blocks.css @@ -395,6 +395,10 @@ p.has-drop-cap:not(:focus)::first-letter { vertical-align: baseline; } +.is-style-outline .wp-block-button__link { + border: 2px solid; +} + .entry-content .wp-block-button:not(.is-style-outline) .wp-block-button__link { border: 0; } diff --git a/src/wp-content/themes/twentynineteen/sass/elements/_elements.scss b/src/wp-content/themes/twentynineteen/sass/elements/_elements.scss index b1fad05838bff..edc11cdf91eb3 100644 --- a/src/wp-content/themes/twentynineteen/sass/elements/_elements.scss +++ b/src/wp-content/themes/twentynineteen/sass/elements/_elements.scss @@ -40,6 +40,7 @@ a:focus { outline: thin; outline-style: dotted; text-decoration: underline; + text-decoration-thickness: 2px; } h1, diff --git a/src/wp-content/themes/twentynineteen/sass/navigation/_links.scss b/src/wp-content/themes/twentynineteen/sass/navigation/_links.scss index cbee4579d6947..ed801e7764894 100644 --- a/src/wp-content/themes/twentynineteen/sass/navigation/_links.scss +++ b/src/wp-content/themes/twentynineteen/sass/navigation/_links.scss @@ -17,5 +17,6 @@ a { &:focus { outline: thin dotted; text-decoration: underline; + text-decoration-thickness: 2px; } } diff --git a/src/wp-content/themes/twentynineteen/sass/site/primary/_comments.scss b/src/wp-content/themes/twentynineteen/sass/site/primary/_comments.scss index dc7b80c15b22b..fa4000e304ffa 100644 --- a/src/wp-content/themes/twentynineteen/sass/site/primary/_comments.scss +++ b/src/wp-content/themes/twentynineteen/sass/site/primary/_comments.scss @@ -323,6 +323,7 @@ a { text-decoration: underline; + text-decoration-thickness: 2px; &:hover { text-decoration: none; diff --git a/src/wp-content/themes/twentynineteen/sass/site/primary/_posts-and-pages.scss b/src/wp-content/themes/twentynineteen/sass/site/primary/_posts-and-pages.scss index ce1c6f2909226..a940d218dde53 100644 --- a/src/wp-content/themes/twentynineteen/sass/site/primary/_posts-and-pages.scss +++ b/src/wp-content/themes/twentynineteen/sass/site/primary/_posts-and-pages.scss @@ -212,6 +212,7 @@ a { text-decoration: underline; + text-decoration-thickness: 2px; &.button, &:hover { diff --git a/src/wp-content/themes/twentynineteen/sass/site/secondary/_widgets.scss b/src/wp-content/themes/twentynineteen/sass/site/secondary/_widgets.scss index 9447d428889c4..968e1774bc4bd 100644 --- a/src/wp-content/themes/twentynineteen/sass/site/secondary/_widgets.scss +++ b/src/wp-content/themes/twentynineteen/sass/site/secondary/_widgets.scss @@ -81,6 +81,7 @@ a { text-decoration: underline; + text-decoration-thickness: 2px; } .wp-calendar-table { diff --git a/src/wp-content/themes/twentynineteen/sass/typography/_copy.scss b/src/wp-content/themes/twentynineteen/sass/typography/_copy.scss index bfbd0feb463f8..37e08dfd2d8aa 100644 --- a/src/wp-content/themes/twentynineteen/sass/typography/_copy.scss +++ b/src/wp-content/themes/twentynineteen/sass/typography/_copy.scss @@ -58,5 +58,6 @@ a { &:focus { text-decoration: underline; + text-decoration-thickness: 2px; } } diff --git a/src/wp-content/themes/twentynineteen/style-rtl.css b/src/wp-content/themes/twentynineteen/style-rtl.css index 29f011976564a..c18f66b66c64b 100644 --- a/src/wp-content/themes/twentynineteen/style-rtl.css +++ b/src/wp-content/themes/twentynineteen/style-rtl.css @@ -2471,6 +2471,7 @@ a:hover { a:focus { text-decoration: underline; + text-decoration-thickness: 2px; } /* Elements */ @@ -2512,6 +2513,7 @@ a:focus { outline: thin; outline-style: dotted; text-decoration: underline; + text-decoration-thickness: 2px; } h1, @@ -2760,6 +2762,7 @@ a:active { a:focus { outline: thin dotted; text-decoration: underline; + text-decoration-thickness: 2px; } /*-------------------------------------------------------------- @@ -4423,6 +4426,7 @@ body.page .main-navigation { .entry .entry-content a { text-decoration: underline; + text-decoration-thickness: 2px; } .entry .entry-content a.button, .entry .entry-content a:hover { @@ -4900,6 +4904,7 @@ body.page .main-navigation { .comment .comment-content a { text-decoration: underline; + text-decoration-thickness: 2px; } .comment .comment-content a:hover { @@ -5225,6 +5230,7 @@ body.page .main-navigation { .widget_calendar .calendar_wrap a { text-decoration: underline; + text-decoration-thickness: 2px; } .widget_calendar .calendar_wrap .wp-calendar-table { diff --git a/src/wp-content/themes/twentynineteen/style.css b/src/wp-content/themes/twentynineteen/style.css index 9d68322d74425..f4c87a3b07884 100644 --- a/src/wp-content/themes/twentynineteen/style.css +++ b/src/wp-content/themes/twentynineteen/style.css @@ -2471,6 +2471,7 @@ a:hover { a:focus { text-decoration: underline; + text-decoration-thickness: 2px; } /* Elements */ @@ -2512,6 +2513,7 @@ a:focus { outline: thin; outline-style: dotted; text-decoration: underline; + text-decoration-thickness: 2px; } h1, @@ -2760,6 +2762,7 @@ a:active { a:focus { outline: thin dotted; text-decoration: underline; + text-decoration-thickness: 2px; } /*-------------------------------------------------------------- @@ -4429,6 +4432,7 @@ body.page .main-navigation { .entry .entry-content a { text-decoration: underline; + text-decoration-thickness: 2px; } .entry .entry-content a.button, .entry .entry-content a:hover { @@ -4906,6 +4910,7 @@ body.page .main-navigation { .comment .comment-content a { text-decoration: underline; + text-decoration-thickness: 2px; } .comment .comment-content a:hover { @@ -5231,6 +5236,7 @@ body.page .main-navigation { .widget_calendar .calendar_wrap a { text-decoration: underline; + text-decoration-thickness: 2px; } .widget_calendar .calendar_wrap .wp-calendar-table { diff --git a/src/wp-content/themes/twentyseventeen/assets/css/blocks.css b/src/wp-content/themes/twentyseventeen/assets/css/blocks.css index a64b1d3458712..d8c34349ab463 100644 --- a/src/wp-content/themes/twentyseventeen/assets/css/blocks.css +++ b/src/wp-content/themes/twentyseventeen/assets/css/blocks.css @@ -137,7 +137,7 @@ p.has-drop-cap:not(:focus)::first-letter { padding: 0.7em 2em; -webkit-transition: background-color 0.2s ease-in-out; transition: background-color 0.2s ease-in-out; - white-space: nowrap; + white-space: pre-line; } .wp-block-file .wp-block-file__button:hover, @@ -214,7 +214,7 @@ p.has-drop-cap:not(:focus)::first-letter { padding: 0.7em 2em; -webkit-transition: background-color 0.2s ease-in-out; transition: background-color 0.2s ease-in-out; - white-space: nowrap; + white-space: pre-line; } .entry-content .wp-block-button__link { diff --git a/src/wp-content/themes/twentyseventeen/assets/css/editor-blocks.css b/src/wp-content/themes/twentyseventeen/assets/css/editor-blocks.css index 3e4971b619ff6..69bd59492a90b 100644 --- a/src/wp-content/themes/twentyseventeen/assets/css/editor-blocks.css +++ b/src/wp-content/themes/twentyseventeen/assets/css/editor-blocks.css @@ -608,7 +608,7 @@ html[lang="th"] .edit-post-visual-editor * { padding: 0.7em 2em; -webkit-transition: background-color 0.2s ease-in-out; transition: background-color 0.2s ease-in-out; - white-space: nowrap; + white-space: pre-line; } /*-------------------------------------------------------------- @@ -735,7 +735,7 @@ table.wp-block-table td:last-child { padding: 0.7em 2em; -webkit-transition: background-color 0.2s ease-in-out; transition: background-color 0.2s ease-in-out; - white-space: nowrap; + white-space: pre-line; } .wp-block-button .wp-block-button__link[data-is-placeholder-visible="true"] { diff --git a/src/wp-content/themes/twentytwenty/assets/css/editor-style-block-rtl.css b/src/wp-content/themes/twentytwenty/assets/css/editor-style-block-rtl.css index 041c0524d8b1b..a9e120b555184 100644 --- a/src/wp-content/themes/twentytwenty/assets/css/editor-style-block-rtl.css +++ b/src/wp-content/themes/twentytwenty/assets/css/editor-style-block-rtl.css @@ -121,12 +121,12 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, -.editor-styles-wrapper .wp-block h1, -.editor-styles-wrapper .wp-block h2, -.editor-styles-wrapper .wp-block h3, -.editor-styles-wrapper .wp-block h4, -.editor-styles-wrapper .wp-block h5, -.editor-styles-wrapper .wp-block h6, +.editor-styles-wrapper h1, +.editor-styles-wrapper h2, +.editor-styles-wrapper h3, +.editor-styles-wrapper h4, +.editor-styles-wrapper h5, +.editor-styles-wrapper h6, .editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter, .editor-styles-wrapper cite, .editor-styles-wrapper figcaption, @@ -138,12 +138,12 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, - .editor-styles-wrapper .wp-block h1, - .editor-styles-wrapper .wp-block h2, - .editor-styles-wrapper .wp-block h3, - .editor-styles-wrapper .wp-block h4, - .editor-styles-wrapper .wp-block h5, - .editor-styles-wrapper .wp-block h6, + .editor-styles-wrapper h1, + .editor-styles-wrapper h2, + .editor-styles-wrapper h3, + .editor-styles-wrapper h4, + .editor-styles-wrapper h5, + .editor-styles-wrapper h6, .editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter, .editor-styles-wrapper cite, .editor-styles-wrapper figcaption, @@ -156,6 +156,10 @@ Inter variable font. Usage: /* Colors ------------------------------------ */ +.editor-styles-wrapper .has-text-color a { + color: inherit; +} + /* CUSTOM COLORS */ :root .has-accent-color { @@ -238,12 +242,12 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, -.editor-styles-wrapper .wp-block h1, -.editor-styles-wrapper .wp-block h2, -.editor-styles-wrapper .wp-block h3, -.editor-styles-wrapper .wp-block h4, -.editor-styles-wrapper .wp-block h5, -.editor-styles-wrapper .wp-block h6 { +.editor-styles-wrapper h1, +.editor-styles-wrapper h2, +.editor-styles-wrapper h3, +.editor-styles-wrapper h4, +.editor-styles-wrapper h5, +.editor-styles-wrapper h6 { font-feature-settings: "lnum"; font-variant-numeric: lining-nums; font-weight: 700; @@ -255,29 +259,35 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, -.editor-styles-wrapper .wp-block h1 { +.editor-styles-wrapper h1, +.editor-styles-wrapper .heading-size-1 { font-size: 36px; font-weight: 800; line-height: 1.138888889; } -.editor-styles-wrapper .wp-block h2 { +.editor-styles-wrapper h2, +.editor-styles-wrapper .heading-size-2 { font-size: 32px; } -.editor-styles-wrapper .wp-block h3 { +.editor-styles-wrapper h3, +.editor-styles-wrapper .heading-size-3 { font-size: 28px; } -.editor-styles-wrapper .wp-block h4 { +.editor-styles-wrapper h4, +.editor-styles-wrapper .heading-size-4 { font-size: 24px; } -.editor-styles-wrapper .wp-block h5 { +.editor-styles-wrapper h5, +.editor-styles-wrapper .heading-size-5 { font-size: 21px; } -.editor-styles-wrapper .wp-block h6 { +.editor-styles-wrapper h6, +.editor-styles-wrapper .heading-size-6 { font-size: 16px; letter-spacing: 0.03125em; text-transform: uppercase; @@ -306,6 +316,14 @@ Inter variable font. Usage: text-align: center; } +.editor-styles-wrapper .wp-block-post-title.has-text-align-left { + text-align: left; +} + +.editor-styles-wrapper .wp-block-post-title.has-text-align-right { + text-align: right; +} + /* DROP CAP */ .editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter { @@ -747,8 +765,7 @@ hr.wp-block-separator.is-style-dots::before { .wp-block-cover-image .wp-block-cover-text, .wp-block-cover-image h2, .wp-block-cover .wp-block-cover-image-text, -.wp-block-cover .wp-block-cover-text, -.wp-block-cover h2 { +.wp-block-cover .wp-block-cover-text { max-width: 100%; } @@ -1009,7 +1026,7 @@ hr.wp-block-separator.is-style-dots::before { border-style: solid; border-width: 2px 0 0; line-height: 1.25; - margin: 20px 0 16px 16px; + margin: 20px 0 16px 10px; padding-top: 12px; } @@ -1098,6 +1115,10 @@ hr.wp-block-separator.is-style-dots::before { padding-right: 1.3em; } +.editor-styles-wrapper ul.block-editor-block-list__block.wp-block-social-links { + padding-left: 0; +} + /* Block: Post Template ---------------- */ .editor-styles-wrapper ul.wp-block-post-template { @@ -1232,23 +1253,28 @@ hr.wp-block-separator.is-style-dots::before { .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, - .editor-styles-wrapper .wp-block h1 { + .editor-styles-wrapper h1, + .editor-styles-wrapper .heading-size-1 { font-size: 64px; } - .editor-styles-wrapper .wp-block h2 { + .editor-styles-wrapper h2, + .editor-styles-wrapper .heading-size-2 { font-size: 48px; } - .editor-styles-wrapper .wp-block h3 { + .editor-styles-wrapper h3, + .editor-styles-wrapper .heading-size-3 { font-size: 40px; } - .editor-styles-wrapper .wp-block h4 { + .editor-styles-wrapper h4, + .editor-styles-wrapper .heading-size-4 { font-size: 32px; } - .editor-styles-wrapper .wp-block h5 { + .editor-styles-wrapper h5, + .editor-styles-wrapper .heading-size-5 { font-size: 24px; } @@ -1411,11 +1437,13 @@ hr.wp-block-separator.is-style-dots::before { .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, - .editor-styles-wrapper .wp-block h1 { + .editor-styles-wrapper h1, + .editor-styles-wrapper .heading-size-1 { font-size: 84px; } - .editor-styles-wrapper .wp-block h6 { + .editor-styles-wrapper h6, + .editor-styles-wrapper .heading-size-6 { font-size: 18px; } diff --git a/src/wp-content/themes/twentytwenty/assets/css/editor-style-block.css b/src/wp-content/themes/twentytwenty/assets/css/editor-style-block.css index 270035ce704bd..352a59f399478 100644 --- a/src/wp-content/themes/twentytwenty/assets/css/editor-style-block.css +++ b/src/wp-content/themes/twentytwenty/assets/css/editor-style-block.css @@ -121,12 +121,12 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, -.editor-styles-wrapper .wp-block h1, -.editor-styles-wrapper .wp-block h2, -.editor-styles-wrapper .wp-block h3, -.editor-styles-wrapper .wp-block h4, -.editor-styles-wrapper .wp-block h5, -.editor-styles-wrapper .wp-block h6, +.editor-styles-wrapper h1, +.editor-styles-wrapper h2, +.editor-styles-wrapper h3, +.editor-styles-wrapper h4, +.editor-styles-wrapper h5, +.editor-styles-wrapper h6, .editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter, .editor-styles-wrapper cite, .editor-styles-wrapper figcaption, @@ -138,12 +138,12 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, - .editor-styles-wrapper .wp-block h1, - .editor-styles-wrapper .wp-block h2, - .editor-styles-wrapper .wp-block h3, - .editor-styles-wrapper .wp-block h4, - .editor-styles-wrapper .wp-block h5, - .editor-styles-wrapper .wp-block h6, + .editor-styles-wrapper h1, + .editor-styles-wrapper h2, + .editor-styles-wrapper h3, + .editor-styles-wrapper h4, + .editor-styles-wrapper h5, + .editor-styles-wrapper h6, .editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter, .editor-styles-wrapper cite, .editor-styles-wrapper figcaption, @@ -156,6 +156,10 @@ Inter variable font. Usage: /* Colors ------------------------------------ */ +.editor-styles-wrapper .has-text-color a { + color: inherit; +} + /* CUSTOM COLORS */ :root .has-accent-color { @@ -238,12 +242,12 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, -.editor-styles-wrapper .wp-block h1, -.editor-styles-wrapper .wp-block h2, -.editor-styles-wrapper .wp-block h3, -.editor-styles-wrapper .wp-block h4, -.editor-styles-wrapper .wp-block h5, -.editor-styles-wrapper .wp-block h6 { +.editor-styles-wrapper h1, +.editor-styles-wrapper h2, +.editor-styles-wrapper h3, +.editor-styles-wrapper h4, +.editor-styles-wrapper h5, +.editor-styles-wrapper h6 { font-feature-settings: "lnum"; font-variant-numeric: lining-nums; font-weight: 700; @@ -255,29 +259,35 @@ Inter variable font. Usage: .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, -.editor-styles-wrapper .wp-block h1 { +.editor-styles-wrapper h1, +.editor-styles-wrapper .heading-size-1 { font-size: 36px; font-weight: 800; line-height: 1.138888889; } -.editor-styles-wrapper .wp-block h2 { +.editor-styles-wrapper h2, +.editor-styles-wrapper .heading-size-2 { font-size: 32px; } -.editor-styles-wrapper .wp-block h3 { +.editor-styles-wrapper h3, +.editor-styles-wrapper .heading-size-3 { font-size: 28px; } -.editor-styles-wrapper .wp-block h4 { +.editor-styles-wrapper h4, +.editor-styles-wrapper .heading-size-4 { font-size: 24px; } -.editor-styles-wrapper .wp-block h5 { +.editor-styles-wrapper h5, +.editor-styles-wrapper .heading-size-5 { font-size: 21px; } -.editor-styles-wrapper .wp-block h6 { +.editor-styles-wrapper h6, +.editor-styles-wrapper .heading-size-6 { font-size: 16px; letter-spacing: 0.03125em; text-transform: uppercase; @@ -306,6 +316,18 @@ Inter variable font. Usage: text-align: center; } +.editor-styles-wrapper .wp-block-post-title.has-text-align-left { + + /*rtl:ignore*/ + text-align: left; +} + +.editor-styles-wrapper .wp-block-post-title.has-text-align-right { + + /*rtl:ignore*/ + text-align: right; +} + /* DROP CAP */ .editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter { @@ -747,8 +769,7 @@ hr.wp-block-separator.is-style-dots::before { .wp-block-cover-image .wp-block-cover-text, .wp-block-cover-image h2, .wp-block-cover .wp-block-cover-image-text, -.wp-block-cover .wp-block-cover-text, -.wp-block-cover h2 { +.wp-block-cover .wp-block-cover-text { max-width: 100%; } @@ -1009,7 +1030,7 @@ hr.wp-block-separator.is-style-dots::before { border-style: solid; border-width: 2px 0 0; line-height: 1.25; - margin: 20px 16px 16px 0; + margin: 20px 10px 16px 0; padding-top: 12px; } @@ -1098,6 +1119,10 @@ hr.wp-block-separator.is-style-dots::before { padding-left: 1.3em; } +.editor-styles-wrapper ul.block-editor-block-list__block.wp-block-social-links { + padding-left: 0; +} + /* Block: Post Template ---------------- */ .editor-styles-wrapper ul.wp-block-post-template { @@ -1232,23 +1257,28 @@ hr.wp-block-separator.is-style-dots::before { .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, - .editor-styles-wrapper .wp-block h1 { + .editor-styles-wrapper h1, + .editor-styles-wrapper .heading-size-1 { font-size: 64px; } - .editor-styles-wrapper .wp-block h2 { + .editor-styles-wrapper h2, + .editor-styles-wrapper .heading-size-2 { font-size: 48px; } - .editor-styles-wrapper .wp-block h3 { + .editor-styles-wrapper h3, + .editor-styles-wrapper .heading-size-3 { font-size: 40px; } - .editor-styles-wrapper .wp-block h4 { + .editor-styles-wrapper h4, + .editor-styles-wrapper .heading-size-4 { font-size: 32px; } - .editor-styles-wrapper .wp-block h5 { + .editor-styles-wrapper h5, + .editor-styles-wrapper .heading-size-5 { font-size: 24px; } @@ -1411,11 +1441,13 @@ hr.wp-block-separator.is-style-dots::before { .editor-post-title__block .editor-post-title__input, .editor-styles-wrapper .wp-block-post-title, - .editor-styles-wrapper .wp-block h1 { + .editor-styles-wrapper h1, + .editor-styles-wrapper .heading-size-1 { font-size: 84px; } - .editor-styles-wrapper .wp-block h6 { + .editor-styles-wrapper h6, + .editor-styles-wrapper .heading-size-6 { font-size: 18px; } diff --git a/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic-rtl.css b/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic-rtl.css index 89ec55a63a5c2..de2d9f87ddb76 100644 --- a/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic-rtl.css +++ b/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic-rtl.css @@ -215,29 +215,35 @@ body#tinymce.wp-editor.content h6 { margin: 40px 0 25px; } -body#tinymce.wp-editor.content h1 { +body#tinymce.wp-editor.content h1, +body#tinymce.wp-editor.content .heading-size-1 { font-size: 84px; font-weight: 800; line-height: 1.138888889; } -body#tinymce.wp-editor.content h2 { +body#tinymce.wp-editor.content h2, +body#tinymce.wp-editor.content .heading-size-2 { font-size: 48px; } -body#tinymce.wp-editor.content h3 { +body#tinymce.wp-editor.content h3, +body#tinymce.wp-editor.content .heading-size-3 { font-size: 40px; } -body#tinymce.wp-editor.content h4 { +body#tinymce.wp-editor.content h4, +body#tinymce.wp-editor.content .heading-size-4 { font-size: 32px; } -body#tinymce.wp-editor.content h5 { +body#tinymce.wp-editor.content h5, +body#tinymce.wp-editor.content .heading-size-5 { font-size: 24px; } -body#tinymce.wp-editor.content h6 { +body#tinymce.wp-editor.content h6, +body#tinymce.wp-editor.content .heading-size-6 { font-size: 18px; letter-spacing: 0.03125em; text-transform: uppercase; diff --git a/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic.css b/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic.css index 4a4a00e967627..d471b3723382c 100644 --- a/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic.css +++ b/src/wp-content/themes/twentytwenty/assets/css/editor-style-classic.css @@ -215,29 +215,35 @@ body#tinymce.wp-editor.content h6 { margin: 40px 0 25px; } -body#tinymce.wp-editor.content h1 { +body#tinymce.wp-editor.content h1, +body#tinymce.wp-editor.content .heading-size-1 { font-size: 84px; font-weight: 800; line-height: 1.138888889; } -body#tinymce.wp-editor.content h2 { +body#tinymce.wp-editor.content h2, +body#tinymce.wp-editor.content .heading-size-2 { font-size: 48px; } -body#tinymce.wp-editor.content h3 { +body#tinymce.wp-editor.content h3, +body#tinymce.wp-editor.content .heading-size-3 { font-size: 40px; } -body#tinymce.wp-editor.content h4 { +body#tinymce.wp-editor.content h4, +body#tinymce.wp-editor.content .heading-size-4 { font-size: 32px; } -body#tinymce.wp-editor.content h5 { +body#tinymce.wp-editor.content h5, +body#tinymce.wp-editor.content .heading-size-5 { font-size: 24px; } -body#tinymce.wp-editor.content h6 { +body#tinymce.wp-editor.content h6, +body#tinymce.wp-editor.content .heading-size-6 { font-size: 18px; letter-spacing: 0.03125em; text-transform: uppercase; diff --git a/src/wp-content/themes/twentytwenty/classes/class-twentytwenty-non-latin-languages.php b/src/wp-content/themes/twentytwenty/classes/class-twentytwenty-non-latin-languages.php index 731064eda3880..c7d4896096eaf 100644 --- a/src/wp-content/themes/twentytwenty/classes/class-twentytwenty-non-latin-languages.php +++ b/src/wp-content/themes/twentytwenty/classes/class-twentytwenty-non-latin-languages.php @@ -119,7 +119,7 @@ public static function get_non_latin_css( $type = 'front-end' ) { 'twentytwenty_get_localized_font_family_elements', array( 'front-end' => array( 'body', 'input', 'textarea', 'button', '.button', '.faux-button', '.wp-block-button__link', '.wp-block-file__button', '.has-drop-cap:not(:focus)::first-letter', '.entry-content .wp-block-archives', '.entry-content .wp-block-categories', '.entry-content .wp-block-cover-image', '.entry-content .wp-block-latest-comments', '.entry-content .wp-block-latest-posts', '.entry-content .wp-block-pullquote', '.entry-content .wp-block-quote.is-large', '.entry-content .wp-block-quote.is-style-large', '.entry-content .wp-block-archives *', '.entry-content .wp-block-categories *', '.entry-content .wp-block-latest-posts *', '.entry-content .wp-block-latest-comments *', '.entry-content p', '.entry-content ol', '.entry-content ul', '.entry-content dl', '.entry-content dt', '.entry-content cite', '.entry-content figcaption', '.entry-content .wp-caption-text', '.comment-content p', '.comment-content ol', '.comment-content ul', '.comment-content dl', '.comment-content dt', '.comment-content cite', '.comment-content figcaption', '.comment-content .wp-caption-text', '.widget_text p', '.widget_text ol', '.widget_text ul', '.widget_text dl', '.widget_text dt', '.widget-content .rssSummary', '.widget-content cite', '.widget-content figcaption', '.widget-content .wp-caption-text' ), - 'block-editor' => array( '.editor-styles-wrapper > *', '.editor-styles-wrapper p', '.editor-styles-wrapper ol', '.editor-styles-wrapper ul', '.editor-styles-wrapper dl', '.editor-styles-wrapper dt', '.editor-post-title__block .editor-post-title__input', '.editor-styles-wrapper .wp-block-post-title', '.editor-styles-wrapper .wp-block h1', '.editor-styles-wrapper .wp-block h2', '.editor-styles-wrapper .wp-block h3', '.editor-styles-wrapper .wp-block h4', '.editor-styles-wrapper .wp-block h5', '.editor-styles-wrapper .wp-block h6', '.editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter', '.editor-styles-wrapper cite', '.editor-styles-wrapper figcaption', '.editor-styles-wrapper .wp-caption-text' ), + 'block-editor' => array( '.editor-styles-wrapper > *', '.editor-styles-wrapper p', '.editor-styles-wrapper ol', '.editor-styles-wrapper ul', '.editor-styles-wrapper dl', '.editor-styles-wrapper dt', '.editor-post-title__block .editor-post-title__input', '.editor-styles-wrapper .wp-block-post-title', '.editor-styles-wrapper h1', '.editor-styles-wrapper h2', '.editor-styles-wrapper h3', '.editor-styles-wrapper h4', '.editor-styles-wrapper h5', '.editor-styles-wrapper h6', '.editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter', '.editor-styles-wrapper cite', '.editor-styles-wrapper figcaption', '.editor-styles-wrapper .wp-caption-text' ), 'classic-editor' => array( 'body#tinymce.wp-editor', 'body#tinymce.wp-editor p', 'body#tinymce.wp-editor ol', 'body#tinymce.wp-editor ul', 'body#tinymce.wp-editor dl', 'body#tinymce.wp-editor dt', 'body#tinymce.wp-editor figcaption', 'body#tinymce.wp-editor .wp-caption-text', 'body#tinymce.wp-editor .wp-caption-dd', 'body#tinymce.wp-editor cite', 'body#tinymce.wp-editor table' ), ) ); diff --git a/src/wp-content/themes/twentytwenty/style-rtl.css b/src/wp-content/themes/twentytwenty/style-rtl.css index c101569225624..9d164e8f4dce1 100644 --- a/src/wp-content/themes/twentytwenty/style-rtl.css +++ b/src/wp-content/themes/twentytwenty/style-rtl.css @@ -4330,6 +4330,12 @@ div.comment:first-of-type { /* Widget: Text ------------------------------ */ +/* Widget: Blocks ---------------------------- */ + +.widget .wp-block-social-links li { + margin-top: 0; +} + /* -------------------------------------------------------------------------- */ diff --git a/src/wp-content/themes/twentytwenty/style.css b/src/wp-content/themes/twentytwenty/style.css index 246038500a4ce..03968d6155569 100644 --- a/src/wp-content/themes/twentytwenty/style.css +++ b/src/wp-content/themes/twentytwenty/style.css @@ -4366,6 +4366,12 @@ div.comment:first-of-type { /* Widget: Text ------------------------------ */ +/* Widget: Blocks ---------------------------- */ + +.widget .wp-block-social-links li { + margin-top: 0; +} + /* -------------------------------------------------------------------------- */ diff --git a/src/wp-content/themes/twentytwentyone/assets/css/ie.css b/src/wp-content/themes/twentytwentyone/assets/css/ie.css index 66f010512b758..8ed4b2e29acb5 100644 --- a/src/wp-content/themes/twentytwentyone/assets/css/ie.css +++ b/src/wp-content/themes/twentytwentyone/assets/css/ie.css @@ -516,38 +516,38 @@ template { } } -.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { +.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { max-width: calc(100vw - 30px); margin-left: auto; margin-right: auto; } @media only screen and (min-width: 482px) { - .entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { + .entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { max-width: min(calc(100vw - 100px), 610px); } } @media only screen and (min-width: 822px) { - .entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { + .entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { max-width: min(calc(100vw - 200px), 610px); } } -*[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { +*[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { max-width: calc(100vw - 30px); margin-left: auto; margin-right: auto; } @media only screen and (min-width: 482px) { - *[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { + *[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { max-width: min(calc(100vw - 100px), 610px); } } @media only screen and (min-width: 822px) { - *[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { + *[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { max-width: min(calc(100vw - 200px), 610px); } } diff --git a/src/wp-content/themes/twentytwentyone/assets/css/style-editor.css b/src/wp-content/themes/twentytwentyone/assets/css/style-editor.css index 44b4a17b0ee22..d6f1bd7819fb1 100644 --- a/src/wp-content/themes/twentytwentyone/assets/css/style-editor.css +++ b/src/wp-content/themes/twentytwentyone/assets/css/style-editor.css @@ -764,7 +764,6 @@ a:hover { letter-spacing: var(--heading--letter-spacing-h2); line-height: var(--heading--line-height-h2); padding: 0; - max-width: inherit; text-align: inherit; } diff --git a/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/cover/_editor.scss b/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/cover/_editor.scss index b0c5b9a5e9de8..0512b2c220a88 100644 --- a/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/cover/_editor.scss +++ b/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/cover/_editor.scss @@ -49,7 +49,6 @@ letter-spacing: var(--heading--letter-spacing-h2); line-height: var(--heading--line-height-h2); padding: 0; - max-width: inherit; // undo opinionated styles text-align: inherit; &.has-text-align-left { diff --git a/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/utilities/_style.scss b/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/utilities/_style.scss index 07d06d2e238aa..b747a2fda0e54 100644 --- a/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/utilities/_style.scss +++ b/src/wp-content/themes/twentytwentyone/assets/sass/05-blocks/utilities/_style.scss @@ -3,8 +3,8 @@ /** * These selectors set the default max width for content appearing inside a post or page. */ -.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce), -*[class*="inner-container"] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce) { +.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator), +*[class*="inner-container"] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator) { @extend %responsive-aligndefault-width; } diff --git a/src/wp-content/themes/twentytwentyone/style-rtl.css b/src/wp-content/themes/twentytwentyone/style-rtl.css index 62fd8d6008993..d1ae63bd11d8a 100644 --- a/src/wp-content/themes/twentytwentyone/style-rtl.css +++ b/src/wp-content/themes/twentytwentyone/style-rtl.css @@ -693,8 +693,8 @@ template { */ .post-thumbnail, .entry-content .wp-audio-shortcode, -.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce), -*[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce), +.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator), +*[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator), .default-max-width { max-width: var(--responsive--aligndefault-width); margin-right: auto; diff --git a/src/wp-content/themes/twentytwentyone/style.css b/src/wp-content/themes/twentytwentyone/style.css index d48b7a4929266..a6be5688ea82c 100644 --- a/src/wp-content/themes/twentytwentyone/style.css +++ b/src/wp-content/themes/twentytwentyone/style.css @@ -693,8 +693,8 @@ template { */ .post-thumbnail, .entry-content .wp-audio-shortcode, -.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce), -*[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator):not(.woocommerce), +.entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator), +*[class*=inner-container] > *:not(.entry-content):not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.wp-block-separator), .default-max-width { max-width: var(--responsive--aligndefault-width); margin-left: auto; diff --git a/src/wp-content/themes/twentytwentytwo/style.css b/src/wp-content/themes/twentytwentytwo/style.css index a002276a07c43..31360b47b1df2 100644 --- a/src/wp-content/themes/twentytwentytwo/style.css +++ b/src/wp-content/themes/twentytwentytwo/style.css @@ -11,7 +11,7 @@ Version: 1.2 License: GNU General Public License v2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html Text Domain: twentytwentytwo -Tags: one-column, custom-colors, custom-menu, custom-logo, editor-style, featured-images, full-site-editing, block-patterns, rtl-language-support, sticky-post, threaded-comments +Tags: one-column, custom-colors, custom-menu, custom-logo, editor-style, featured-images, full-site-editing, block-patterns, rtl-language-support, sticky-post, threaded-comments, accessibility-ready Twenty Twenty-Two WordPress Theme, (C) 2021 WordPress.org Twenty Twenty-Two is distributed under the terms of the GNU GPL. diff --git a/src/wp-includes/block-editor.php b/src/wp-includes/block-editor.php index 11df4c9a100c6..2977afbeb8cb9 100644 --- a/src/wp-includes/block-editor.php +++ b/src/wp-includes/block-editor.php @@ -209,6 +209,7 @@ function get_default_block_editor_settings() { 'disableCustomColors' => get_theme_support( 'disable-custom-colors' ), 'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ), 'disableCustomGradients' => get_theme_support( 'disable-custom-gradients' ), + 'disableLayoutStyles' => get_theme_support( 'disable-layout-styles' ), 'enableCustomLineHeight' => get_theme_support( 'custom-line-height' ), 'enableCustomSpacing' => get_theme_support( 'custom-spacing' ), 'enableCustomUnits' => get_theme_support( 'custom-units' ), @@ -324,17 +325,16 @@ function _wp_get_iframed_editor_assets() { $block_registry = WP_Block_Type_Registry::get_instance(); foreach ( $block_registry->get_all_registered() as $block_type ) { - if ( ! empty( $block_type->style ) ) { - $style_handles[] = $block_type->style; - } - - if ( ! empty( $block_type->editor_style ) ) { - $style_handles[] = $block_type->editor_style; - } + $style_handles = array_merge( + $style_handles, + $block_type->style_handles, + $block_type->editor_style_handles + ); - if ( ! empty( $block_type->script ) ) { - $script_handles[] = $block_type->script; - } + $script_handles = array_merge( + $script_handles, + $block_type->script_handles + ); } $style_handles = array_unique( $style_handles ); @@ -418,6 +418,18 @@ function get_block_editor_settings( array $custom_settings, $block_editor_contex $block_classes['css'] = $actual_css; $global_styles[] = $block_classes; } + } else { + // If there is no `theme.json` file, ensure base layout styles are still available. + $block_classes = array( + 'css' => 'base-layout-styles', + '__unstableType' => 'base-layout', + 'isGlobalStyles' => true, + ); + $actual_css = wp_get_global_stylesheet( array( $block_classes['css'] ) ); + if ( '' !== $actual_css ) { + $block_classes['css'] = $actual_css; + $global_styles[] = $block_classes; + } } $editor_settings['styles'] = array_merge( $global_styles, get_block_editor_theme_styles() ); @@ -475,9 +487,24 @@ function get_block_editor_settings( array $custom_settings, $block_editor_contex $editor_settings['enableCustomSpacing'] = $editor_settings['__experimentalFeatures']['spacing']['padding']; unset( $editor_settings['__experimentalFeatures']['spacing']['padding'] ); } + if ( isset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] ) ) { + $editor_settings['disableCustomSpacingSizes'] = ! $editor_ettings['__experimentalFeatures']['spacing']['customSpacingSize']; + unset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] ); + } + + if ( isset( $editor_settings['__experimentalFeatures']['spacing']['spacingSizes'] ) ) { + $spacing_sizes_by_origin = $editor_settings['__experimentalFeatures']['spacing']['spacingSizes']; + $editor_settings['spacingSizes'] = isset( $spacing_sizes_by_origin['custom'] ) ? + $spacing_sizes_by_origin['custom'] : ( + isset( $spacing_sizes_by_origin['theme'] ) ? + $spacing_sizes_by_origin['theme'] : + $spacing_sizes_by_origin['default'] + ); + } $editor_settings['__unstableResolvedAssets'] = _wp_get_iframed_editor_assets(); $editor_settings['localAutosaveInterval'] = 15; + $editor_settings['disableLayoutStyles'] = current_theme_supports( 'disable-layout-styles' ); $editor_settings['__experimentalDiscussionSettings'] = array( 'commentOrder' => get_option( 'comment_order' ), 'commentsPerPage' => get_option( 'comments_per_page' ), diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index e731f5bd5b834..b18e88d47b050 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -35,12 +35,15 @@ function remove_block_asset_path_prefix( $asset_handle_or_path ) { * and the field name provided. * * @since 5.5.0 + * @since 6.1.0 Added `$index` parameter. * * @param string $block_name Name of the block. * @param string $field_name Name of the metadata field. + * @param int $index Optional. Index of the asset when multiple items passed. + * Default 0. * @return string Generated asset name for the block's field. */ -function generate_block_asset_handle( $block_name, $field_name ) { +function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { if ( 0 === strpos( $block_name, 'core/' ) ) { $asset_handle = str_replace( 'core/', 'wp-block-', $block_name ); if ( 0 === strpos( $field_name, 'editor' ) ) { @@ -49,6 +52,9 @@ function generate_block_asset_handle( $block_name, $field_name ) { if ( 0 === strpos( $field_name, 'view' ) ) { $asset_handle .= '-view'; } + if ( $index > 0 ) { + $asset_handle .= '-' . ( $index + 1 ); + } return $asset_handle; } @@ -59,8 +65,12 @@ function generate_block_asset_handle( $block_name, $field_name ) { 'editorStyle' => 'editor-style', 'style' => 'style', ); - return str_replace( '/', '-', $block_name ) . + $asset_handle = str_replace( '/', '-', $block_name ) . '-' . $field_mappings[ $field_name ]; + if ( $index > 0 ) { + $asset_handle .= '-' . ( $index + 1 ); + } + return $asset_handle; } /** @@ -70,23 +80,34 @@ function generate_block_asset_handle( $block_name, $field_name ) { * generated handle name. It returns unprocessed script handle otherwise. * * @since 5.5.0 + * @since 6.1.0 Added `$index` parameter. * * @param array $metadata Block metadata. * @param string $field_name Field name to pick from metadata. + * @param int $index Optional. Index of the script to register when multiple items passed. + * Default 0. * @return string|false Script handle provided directly or created through * script's registration, or false on failure. */ -function register_block_script_handle( $metadata, $field_name ) { +function register_block_script_handle( $metadata, $field_name, $index = 0 ) { if ( empty( $metadata[ $field_name ] ) ) { return false; } + $script_handle = $metadata[ $field_name ]; - $script_path = remove_block_asset_path_prefix( $metadata[ $field_name ] ); + if ( is_array( $script_handle ) ) { + if ( empty( $script_handle[ $index ] ) ) { + return false; + } + $script_handle = $script_handle[ $index ]; + } + + $script_path = remove_block_asset_path_prefix( $script_handle ); if ( $script_handle === $script_path ) { return $script_handle; } - $script_handle = generate_block_asset_handle( $metadata['name'], $field_name ); + $script_handle = generate_block_asset_handle( $metadata['name'], $field_name, $index ); $script_asset_path = wp_normalize_path( realpath( dirname( $metadata['file'] ) . '/' . @@ -145,33 +166,49 @@ function register_block_script_handle( $metadata, $field_name ) { * generated handle name. It returns unprocessed style handle otherwise. * * @since 5.5.0 + * @since 6.1.0 Added `$index` parameter. * * @param array $metadata Block metadata. * @param string $field_name Field name to pick from metadata. + * @param int $index Optional. Index of the style to register when multiple items passed. + * Default 0. * @return string|false Style handle provided directly or created through * style's registration, or false on failure. */ -function register_block_style_handle( $metadata, $field_name ) { +function register_block_style_handle( $metadata, $field_name, $index = 0 ) { if ( empty( $metadata[ $field_name ] ) ) { return false; } + $wpinc_path_norm = wp_normalize_path( realpath( ABSPATH . WPINC ) ); $theme_path_norm = wp_normalize_path( get_theme_file_path() ); $is_core_block = isset( $metadata['file'] ) && 0 === strpos( $metadata['file'], $wpinc_path_norm ); + // Skip registering individual styles for each core block when a bundled version provided. if ( $is_core_block && ! wp_should_load_separate_core_block_assets() ) { return false; } - // Check whether styles should have a ".min" suffix or not. - $suffix = SCRIPT_DEBUG ? '' : '.min'; - $style_handle = $metadata[ $field_name ]; - $style_path = remove_block_asset_path_prefix( $metadata[ $field_name ] ); + if ( is_array( $style_handle ) ) { + if ( empty( $style_handle[ $index ] ) ) { + return false; + } + $style_handle = $style_handle[ $index ]; + } - if ( $style_handle === $style_path && ! $is_core_block ) { + $style_path = remove_block_asset_path_prefix( $style_handle ); + $is_style_handle = $style_handle === $style_path; + // Allow only passing style handles for core blocks. + if ( $is_core_block && ! $is_style_handle ) { + return false; + } + // Return the style handle unless it's the first item for every core block that requires special treatment. + if ( $is_style_handle && ! ( $is_core_block && 0 === $index ) ) { return $style_handle; } + // Check whether styles should have a ".min" suffix or not. + $suffix = SCRIPT_DEBUG ? '' : '.min'; $style_uri = plugins_url( $style_path, $metadata['file'] ); if ( $is_core_block ) { $style_path = "style$suffix.css"; @@ -185,9 +222,9 @@ function register_block_style_handle( $metadata, $field_name ) { $style_uri = get_theme_file_uri( str_replace( $theme_path_norm, '', $style_path_norm ) ); } - $style_handle = generate_block_asset_handle( $metadata['name'], $field_name ); + $style_handle = generate_block_asset_handle( $metadata['name'], $field_name, $index ); $block_dir = dirname( $metadata['file'] ); - $style_file = realpath( "$block_dir/$style_path" ); + $style_file = wp_normalize_path( realpath( "$block_dir/$style_path" ) ); $has_style_file = false !== $style_file; $version = ! $is_core_block && isset( $metadata['version'] ) ? $metadata['version'] : false; $style_uri = $has_style_file ? $style_uri : false; @@ -235,6 +272,7 @@ function get_block_metadata_i18n_schema() { * @since 5.5.0 * @since 5.7.0 Added support for `textdomain` field and i18n handling for all translatable fields. * @since 5.9.0 Added support for `variations` and `viewScript` fields. + * @since 6.1.0 Added support for `render` field. * * @param string $file_or_folder Path to the JSON file with metadata definition for * the block or path to the folder where the `block.json` file is located. @@ -310,39 +348,96 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { } } - if ( ! empty( $metadata['editorScript'] ) ) { - $settings['editor_script'] = register_block_script_handle( - $metadata, - 'editorScript' - ); - } - - if ( ! empty( $metadata['script'] ) ) { - $settings['script'] = register_block_script_handle( - $metadata, - 'script' - ); - } - - if ( ! empty( $metadata['viewScript'] ) ) { - $settings['view_script'] = register_block_script_handle( - $metadata, - 'viewScript' - ); + $script_fields = array( + 'editorScript' => 'editor_script_handles', + 'script' => 'script_handles', + 'viewScript' => 'view_script_handles', + ); + foreach ( $script_fields as $metadata_field_name => $settings_field_name ) { + if ( ! empty( $metadata[ $metadata_field_name ] ) ) { + $scripts = $metadata[ $metadata_field_name ]; + $processed_scripts = array(); + if ( is_array( $scripts ) ) { + for ( $index = 0; $index < count( $scripts ); $index++ ) { + $result = register_block_script_handle( + $metadata, + $metadata_field_name, + $index + ); + if ( $result ) { + $processed_scripts[] = $result; + } + } + } else { + $result = register_block_script_handle( + $metadata, + $metadata_field_name + ); + if ( $result ) { + $processed_scripts[] = $result; + } + } + $settings[ $settings_field_name ] = $processed_scripts; + } } - if ( ! empty( $metadata['editorStyle'] ) ) { - $settings['editor_style'] = register_block_style_handle( - $metadata, - 'editorStyle' - ); + $style_fields = array( + 'editorStyle' => 'editor_style_handles', + 'style' => 'style_handles', + ); + foreach ( $style_fields as $metadata_field_name => $settings_field_name ) { + if ( ! empty( $metadata[ $metadata_field_name ] ) ) { + $styles = $metadata[ $metadata_field_name ]; + $processed_styles = array(); + if ( is_array( $styles ) ) { + for ( $index = 0; $index < count( $styles ); $index++ ) { + $result = register_block_style_handle( + $metadata, + $metadata_field_name, + $index + ); + if ( $result ) { + $processed_styles[] = $result; + } + } + } else { + $result = register_block_style_handle( + $metadata, + $metadata_field_name + ); + if ( $result ) { + $processed_styles[] = $result; + } + } + $settings[ $settings_field_name ] = $processed_styles; + } } - if ( ! empty( $metadata['style'] ) ) { - $settings['style'] = register_block_style_handle( - $metadata, - 'style' + if ( ! empty( $metadata['render'] ) ) { + $template_path = wp_normalize_path( + realpath( + dirname( $metadata['file'] ) . '/' . + remove_block_asset_path_prefix( $metadata['render'] ) + ) ); + if ( file_exists( $template_path ) ) { + /** + * Renders the block on the server. + * + * @since 6.1.0 + * + * @param array $attributes Block attributes. + * @param string $content Block default content. + * @param WP_Block $block Block instance. + * + * @return string Returns the block content. + */ + $settings['render_callback'] = function( $attributes, $content, $block ) use ( $template_path ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + ob_start(); + require $template_path; + return ob_get_clean(); + }; + } } /** @@ -1094,6 +1189,7 @@ function wp_migrate_old_typography_shape( $metadata ) { * It's used in Query Loop, Query Pagination Numbers and Query Pagination Next blocks. * * @since 5.8.0 + * @since 6.1.0 Added `query_loop_block_query_vars` filter and `parents` support in query. * * @param WP_Block $block Block instance. * @param int $page Current query's page. @@ -1194,8 +1290,32 @@ function build_query_vars_from_query_block( $block, $page ) { if ( ! empty( $block->context['query']['search'] ) ) { $query['s'] = $block->context['query']['search']; } + if ( ! empty( $block->context['query']['parents'] ) && is_post_type_hierarchical( $query['post_type'] ) ) { + $query['post_parent__in'] = array_filter( array_map( 'intval', $block->context['query']['parents'] ) ); + } } - return $query; + + /** + * Filters the arguments which will be passed to `WP_Query` for the Query Loop Block. + * + * Anything to this filter should be compatible with the `WP_Query` API to form + * the query context which will be passed down to the Query Loop Block's children. + * This can help, for example, to include additional settings or meta queries not + * directly supported by the core Query Loop Block, and extend its capabilities. + * + * Please note that this will only influence the query that will be rendered on the + * front-end. The editor preview is not affected by this filter. Also, worth noting + * that the editor preview uses the REST API, so, ideally, one should aim to provide + * attributes which are also compatible with the REST API, in order to be able to + * implement identical queries on both sides. + * + * @since 6.1.0 + * + * @param array $query Array containing parameters for `WP_Query` as parsed by the block context. + * @param WP_Block $block Block instance. + * @param int $page Current query's page. + */ + return apply_filters( 'query_loop_block_query_vars', $query, $block, $page ); } /** @@ -1228,54 +1348,11 @@ function get_query_pagination_arrow( $block, $is_next ) { $arrow_attribute = $block->context['paginationArrow']; $arrow = $arrow_map[ $block->context['paginationArrow'] ][ $pagination_type ]; $arrow_classes = "wp-block-query-pagination-$pagination_type-arrow is-arrow-$arrow_attribute"; - return "$arrow"; + return ""; } return null; } -/** - * Allows multiple block styles. - * - * @since 5.9.0 - * - * @param array $metadata Metadata for registering a block type. - * @return array Metadata for registering a block type. - */ -function _wp_multiple_block_styles( $metadata ) { - foreach ( array( 'style', 'editorStyle' ) as $key ) { - if ( ! empty( $metadata[ $key ] ) && is_array( $metadata[ $key ] ) ) { - $default_style = array_shift( $metadata[ $key ] ); - foreach ( $metadata[ $key ] as $handle ) { - $args = array( 'handle' => $handle ); - if ( 0 === strpos( $handle, 'file:' ) && isset( $metadata['file'] ) ) { - $style_path = remove_block_asset_path_prefix( $handle ); - $theme_path_norm = wp_normalize_path( get_theme_file_path() ); - $style_path_norm = wp_normalize_path( realpath( dirname( $metadata['file'] ) . '/' . $style_path ) ); - $is_theme_block = isset( $metadata['file'] ) && 0 === strpos( $metadata['file'], $theme_path_norm ); - - $style_uri = plugins_url( $style_path, $metadata['file'] ); - - if ( $is_theme_block ) { - $style_uri = get_theme_file_uri( str_replace( $theme_path_norm, '', $style_path_norm ) ); - } - - $args = array( - 'handle' => sanitize_key( "{$metadata['name']}-{$style_path}" ), - 'src' => $style_uri, - ); - } - - wp_enqueue_block_style( $metadata['name'], $args ); - } - - // Only return the 1st item in the array. - $metadata[ $key ] = $default_style; - } - } - return $metadata; -} -add_filter( 'block_type_metadata', '_wp_multiple_block_styles' ); - /** * Helper function that constructs a comment query vars array from the passed * block properties. @@ -1377,7 +1454,7 @@ function get_comments_pagination_arrow( $block, $pagination_type = 'next' ) { $arrow_attribute = $block->context['comments/paginationArrow']; $arrow = $arrow_map[ $block->context['comments/paginationArrow'] ][ $pagination_type ]; $arrow_classes = "wp-block-comments-pagination-$pagination_type-arrow is-arrow-$arrow_attribute"; - return "$arrow"; + return ""; } return null; } diff --git a/src/wp-includes/class-wp-admin-bar.php b/src/wp-includes/class-wp-admin-bar.php index 6eab9c3fdb194..406d76459be01 100644 --- a/src/wp-includes/class-wp-admin-bar.php +++ b/src/wp-includes/class-wp-admin-bar.php @@ -12,6 +12,7 @@ * * @since 3.1.0 */ +#[AllowDynamicProperties] class WP_Admin_Bar { private $nodes = array(); private $bound = false; diff --git a/src/wp-includes/class-wp-ajax-response.php b/src/wp-includes/class-wp-ajax-response.php index e4024102a821f..fb90d2ddace2e 100644 --- a/src/wp-includes/class-wp-ajax-response.php +++ b/src/wp-includes/class-wp-ajax-response.php @@ -5,6 +5,7 @@ * @package WordPress * @since 2.1.0 */ +#[AllowDynamicProperties] class WP_Ajax_Response { /** * Store XML responses to send. diff --git a/src/wp-includes/class-wp-application-passwords.php b/src/wp-includes/class-wp-application-passwords.php index c41f8ad372a04..c4e34350fc40a 100644 --- a/src/wp-includes/class-wp-application-passwords.php +++ b/src/wp-includes/class-wp-application-passwords.php @@ -11,6 +11,7 @@ * * @package WordPress */ +#[AllowDynamicProperties] class WP_Application_Passwords { /** diff --git a/src/wp-includes/class-wp-block-editor-context.php b/src/wp-includes/class-wp-block-editor-context.php index fd594bcad0e57..bb2d44e5a19c6 100644 --- a/src/wp-includes/class-wp-block-editor-context.php +++ b/src/wp-includes/class-wp-block-editor-context.php @@ -11,6 +11,7 @@ * * @since 5.8.0 */ +#[AllowDynamicProperties] final class WP_Block_Editor_Context { /** * String that identifies the block editor being rendered. Can be one of: diff --git a/src/wp-includes/class-wp-block-list.php b/src/wp-includes/class-wp-block-list.php index 2b0750bfee163..9b7caaf01f7e1 100644 --- a/src/wp-includes/class-wp-block-list.php +++ b/src/wp-includes/class-wp-block-list.php @@ -11,6 +11,7 @@ * * @since 5.5.0 */ +#[AllowDynamicProperties] class WP_Block_List implements Iterator, ArrayAccess, Countable { /** diff --git a/src/wp-includes/class-wp-block-pattern-categories-registry.php b/src/wp-includes/class-wp-block-pattern-categories-registry.php index f4d881c4e26b2..3d37a5940a642 100644 --- a/src/wp-includes/class-wp-block-pattern-categories-registry.php +++ b/src/wp-includes/class-wp-block-pattern-categories-registry.php @@ -10,6 +10,7 @@ /** * Class used for interacting with block pattern categories. */ +#[AllowDynamicProperties] final class WP_Block_Pattern_Categories_Registry { /** * Registered block pattern categories array. diff --git a/src/wp-includes/class-wp-block-patterns-registry.php b/src/wp-includes/class-wp-block-patterns-registry.php index 8b312d56c2ab6..bfbc651341acf 100644 --- a/src/wp-includes/class-wp-block-patterns-registry.php +++ b/src/wp-includes/class-wp-block-patterns-registry.php @@ -12,6 +12,7 @@ * * @since 5.5.0 */ +#[AllowDynamicProperties] final class WP_Block_Patterns_Registry { /** * Registered block patterns array. diff --git a/src/wp-includes/class-wp-block-styles-registry.php b/src/wp-includes/class-wp-block-styles-registry.php index b9a59f6d6e2ff..317c6489b2d47 100644 --- a/src/wp-includes/class-wp-block-styles-registry.php +++ b/src/wp-includes/class-wp-block-styles-registry.php @@ -12,6 +12,7 @@ * * @since 5.3.0 */ +#[AllowDynamicProperties] final class WP_Block_Styles_Registry { /** * Registered block styles, as `$block_name => $block_style_name => $block_style_properties` multidimensional arrays. diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 703d03a6297e6..a8e2ecb36bd42 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -14,6 +14,7 @@ * * @access private */ +#[AllowDynamicProperties] class WP_Block_Supports { /** diff --git a/src/wp-includes/class-wp-block-template.php b/src/wp-includes/class-wp-block-template.php index 51dbdbfbc3d4a..898ddf0dd316b 100644 --- a/src/wp-includes/class-wp-block-template.php +++ b/src/wp-includes/class-wp-block-template.php @@ -11,6 +11,7 @@ * * @since 5.8.0 */ +#[AllowDynamicProperties] class WP_Block_Template { /** diff --git a/src/wp-includes/class-wp-block-type-registry.php b/src/wp-includes/class-wp-block-type-registry.php index c9a5776c551c0..84adecd5d0774 100644 --- a/src/wp-includes/class-wp-block-type-registry.php +++ b/src/wp-includes/class-wp-block-type-registry.php @@ -12,6 +12,7 @@ * * @since 5.0.0 */ +#[AllowDynamicProperties] final class WP_Block_Type_Registry { /** * Registered block types, as `$name => $instance` pairs. diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index 1c01120f87117..b0ca475315841 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -14,6 +14,7 @@ * * @see register_block_type() */ +#[AllowDynamicProperties] class WP_Block_Type { /** @@ -165,44 +166,58 @@ class WP_Block_Type { public $provides_context = null; /** - * Block type editor only script handle. + * Block type editor only script handles. * - * @since 5.0.0 - * @var string|null + * @since 6.1.0 + * @var string[] */ - public $editor_script = null; + public $editor_script_handles = array(); /** - * Block type front end and editor script handle. + * Block type front end and editor script handles. * - * @since 5.0.0 - * @var string|null + * @since 6.1.0 + * @var string[] */ - public $script = null; + public $script_handles = array(); /** - * Block type front end only script handle. + * Block type front end only script handles. * - * @since 5.9.0 - * @var string|null + * @since 6.1.0 + * @var string[] */ - public $view_script = null; + public $view_script_handles = array(); /** - * Block type editor only style handle. + * Block type editor only style handles. * - * @since 5.0.0 - * @var string|null + * @since 6.1.0 + * @var string[] */ - public $editor_style = null; + public $editor_style_handles = array(); /** - * Block type front end and editor style handle. + * Block type front end and editor style handles. * - * @since 5.0.0 - * @var string|null + * @since 6.1.0 + * @var string[] + */ + public $style_handles = array(); + + /** + * Deprecated block type properties for script and style handles. + * + * @since 6.1.0 + * @var string[] */ - public $style = null; + private $deprecated_properties = array( + 'editor_script', + 'script', + 'view_script', + 'editor_style', + 'style', + ); /** * Attributes supported by every block. @@ -227,6 +242,9 @@ class WP_Block_Type { * @since 5.8.0 Added the `variations` property. * @since 5.9.0 Added the `view_script` property. * @since 6.0.0 Added the `ancestor` property. + * @since 6.1.0 Added the `editor_script_handles`, `script_handles`, `view_script_handles, + * `editor_style_handles`, and `style_handles` properties. + * Deprecated the `editor_script`, `script`, `view_script`, `editor_style`, and `style` properties. * * @see register_block_type() * @@ -235,32 +253,32 @@ class WP_Block_Type { * Optional. Array or string of arguments for registering a block type. Any arguments may be defined, * however the ones described below are supported by default. Default empty array. * - * @type string $api_version Block API version. - * @type string $title Human-readable block type label. - * @type string|null $category Block type category classification, used in - * search interfaces to arrange block types by category. - * @type string[]|null $parent Setting parent lets a block require that it is only - * available when nested within the specified blocks. - * @type string[]|null $ancestor Setting ancestor makes a block available only inside the specified - * block types at any position of the ancestor's block subtree. - * @type string|null $icon Block type icon. - * @type string $description A detailed block type description. - * @type string[] $keywords Additional keywords to produce block type as - * result in search interfaces. - * @type string|null $textdomain The translation textdomain. - * @type array[] $styles Alternative block styles. - * @type array[] $variations Block variations. - * @type array|null $supports Supported features. - * @type array|null $example Structured data for the block preview. - * @type callable|null $render_callback Block type render callback. - * @type array|null $attributes Block type attributes property schemas. - * @type string[] $uses_context Context values inherited by blocks of this type. - * @type string[]|null $provides_context Context provided by blocks of this type. - * @type string|null $editor_script Block type editor only script handle. - * @type string|null $script Block type front end and editor script handle. - * @type string|null $view_script Block type front end only script handle. - * @type string|null $editor_style Block type editor only style handle. - * @type string|null $style Block type front end and editor style handle. + * @type string $api_version Block API version. + * @type string $title Human-readable block type label. + * @type string|null $category Block type category classification, used in + * search interfaces to arrange block types by category. + * @type string[]|null $parent Setting parent lets a block require that it is only + * available when nested within the specified blocks. + * @type string[]|null $ancestor Setting ancestor makes a block available only inside the specified + * block types at any position of the ancestor's block subtree. + * @type string|null $icon Block type icon. + * @type string $description A detailed block type description. + * @type string[] $keywords Additional keywords to produce block type as + * result in search interfaces. + * @type string|null $textdomain The translation textdomain. + * @type array[] $styles Alternative block styles. + * @type array[] $variations Block variations. + * @type array|null $supports Supported features. + * @type array|null $example Structured data for the block preview. + * @type callable|null $render_callback Block type render callback. + * @type array|null $attributes Block type attributes property schemas. + * @type string[] $uses_context Context values inherited by blocks of this type. + * @type string[]|null $provides_context Context provided by blocks of this type. + * @type string[] $editor_script_handles Block type editor only script handles. + * @type string[] $script_handles Block type front end and editor script handles. + * @type string[] $view_script_handles Block type front end only script handles. + * @type string[] $editor_style_handles Block type editor only style handles. + * @type string[] $style_handles Block type front end and editor style handles. * } */ public function __construct( $block_type, $args = array() ) { @@ -269,6 +287,70 @@ public function __construct( $block_type, $args = array() ) { $this->set_props( $args ); } + /** + * Proxies getting values for deprecated properties for script and style handles for backward compatibility. + * Gets the value for the corresponding new property if the first item in the array provided. + * + * @since 6.1.0 + * + * @param string $name Deprecated property name. + * + * @return string|null|void The value read from the new property if the first item in the array provided, + * null when value not found, or void when unknown property name provided. + */ + public function __get( $name ) { + if ( ! in_array( $name, $this->deprecated_properties ) ) { + return; + } + + $new_name = $name . '_handles'; + return isset( $this->{$new_name}[0] ) ? $this->{$new_name}[0] : null; + } + + /** + * Proxies checking for deprecated properties for script and style handles for backward compatibility. + * Checks whether the corresponding new property has the first item in the array provided. + * + * @since 6.1.0 + * + * @param string $name Deprecated property name. + * + * @return boolean Returns true when for the new property the first item in the array exists, + * or false otherwise. + */ + public function __isset( $name ) { + if ( ! in_array( $name, $this->deprecated_properties ) ) { + return false; + } + + $new_name = $name . '_handles'; + return isset( $this->{$new_name}[0] ); + } + + /** + * Proxies setting values for deprecated properties for script and style handles for backward compatibility. + * Sets the value for the corresponding new property as the first item in the array. + * It also allows setting custom properties for backward compatibility. + * + * @since 6.1.0 + * + * @param string $name Property name. + * @param mixed $value Property value. + */ + public function __set( $name, $value ) { + if ( ! in_array( $name, $this->deprecated_properties ) ) { + $this->{$name} = $value; + return; + } + + if ( ! is_string( $value ) ) { + return; + } + + $new_name = $name . '_handles'; + $this->{$new_name}[0] = $value; + } + /** * Renders the block type output for given attributes. * diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 33c0e6a3552ac..02b5b3d5bc518 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -12,6 +12,7 @@ * @since 5.5.0 * @property array $attributes */ +#[AllowDynamicProperties] class WP_Block { /** @@ -259,16 +260,22 @@ public function render( $options = array() ) { $post = $global_post; } - if ( ! empty( $this->block_type->script ) ) { - wp_enqueue_script( $this->block_type->script ); + if ( ( ! empty( $this->block_type->script_handles ) ) ) { + foreach ( $this->block_type->script_handles as $script_handle ) { + wp_enqueue_script( $script_handle ); + } } - if ( ! empty( $this->block_type->view_script ) && empty( $this->block_type->render_callback ) ) { - wp_enqueue_script( $this->block_type->view_script ); + if ( ! empty( $this->block_type->view_script_handles ) && empty( $this->block_type->render_callback ) ) { + foreach ( $this->block_type->view_script_handles as $view_script_handle ) { + wp_enqueue_script( $view_script_handle ); + } } - if ( ! empty( $this->block_type->style ) ) { - wp_enqueue_style( $this->block_type->style ); + if ( ( ! empty( $this->block_type->style_handles ) ) ) { + foreach ( $this->block_type->style_handles as $style_handle ) { + wp_enqueue_style( $style_handle ); + } } /** diff --git a/src/wp-includes/class-wp-comment-query.php b/src/wp-includes/class-wp-comment-query.php index 5b0ce51dab102..dad512c419122 100644 --- a/src/wp-includes/class-wp-comment-query.php +++ b/src/wp-includes/class-wp-comment-query.php @@ -14,6 +14,7 @@ * * @see WP_Comment_Query::__construct() for accepted arguments. */ +#[AllowDynamicProperties] class WP_Comment_Query { /** diff --git a/src/wp-includes/class-wp-comment.php b/src/wp-includes/class-wp-comment.php index 864065b7ec7d3..c5f8cc49f4076 100644 --- a/src/wp-includes/class-wp-comment.php +++ b/src/wp-includes/class-wp-comment.php @@ -12,6 +12,7 @@ * * @since 4.4.0 */ +#[AllowDynamicProperties] final class WP_Comment { /** diff --git a/src/wp-includes/class-wp-customize-control.php b/src/wp-includes/class-wp-customize-control.php index 63cc5f65ae00f..64ed528cc29fc 100644 --- a/src/wp-includes/class-wp-customize-control.php +++ b/src/wp-includes/class-wp-customize-control.php @@ -12,6 +12,7 @@ * * @since 3.4.0 */ +#[AllowDynamicProperties] class WP_Customize_Control { /** diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index 3b3259c5736ae..fe03a93c1eee9 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -20,6 +20,7 @@ * * @since 3.4.0 */ +#[AllowDynamicProperties] final class WP_Customize_Manager { /** * An instance of the theme being previewed. @@ -4685,6 +4686,21 @@ public function get_return_url() { if ( $this->return_url ) { $return_url = $this->return_url; + + $return_url_basename = wp_basename( parse_url( $this->return_url, PHP_URL_PATH ) ); + $return_url_query = parse_url( $this->return_url, PHP_URL_QUERY ); + + if ( 'themes.php' === $return_url_basename && $return_url_query ) { + parse_str( $return_url_query, $query_vars ); + + /* + * If the return URL is a page added by a theme to the Appearance menu via add_submenu_page(), + * verify that it belongs to the active theme, otherwise fall back to the Themes screen. + */ + if ( isset( $query_vars['page'] ) && ! isset( $_registered_pages[ "appearance_page_{$query_vars['page']}" ] ) ) { + $return_url = admin_url( 'themes.php' ); + } + } } elseif ( $referer && ! in_array( wp_basename( parse_url( $referer, PHP_URL_PATH ) ), $excluded_referer_basenames, true ) ) { $return_url = $referer; } elseif ( $this->preview_url ) { @@ -4693,21 +4709,6 @@ public function get_return_url() { $return_url = home_url( '/' ); } - $return_url_basename = wp_basename( parse_url( $this->return_url, PHP_URL_PATH ) ); - $return_url_query = parse_url( $this->return_url, PHP_URL_QUERY ); - - if ( 'themes.php' === $return_url_basename && $return_url_query ) { - parse_str( $return_url_query, $query_vars ); - - /* - * If the return URL is a page added by a theme to the Appearance menu via add_submenu_page(), - * verify that it belongs to the active theme, otherwise fall back to the Themes screen. - */ - if ( isset( $query_vars['page'] ) && ! isset( $_registered_pages[ "appearance_page_{$query_vars['page']}" ] ) ) { - $return_url = admin_url( 'themes.php' ); - } - } - return $return_url; } diff --git a/src/wp-includes/class-wp-customize-nav-menus.php b/src/wp-includes/class-wp-customize-nav-menus.php index ae0925fe02be3..d34fc59b97c2e 100644 --- a/src/wp-includes/class-wp-customize-nav-menus.php +++ b/src/wp-includes/class-wp-customize-nav-menus.php @@ -16,6 +16,7 @@ * * @see WP_Customize_Manager */ +#[AllowDynamicProperties] final class WP_Customize_Nav_Menus { /** @@ -1322,7 +1323,7 @@ public function customize_preview_init() { add_action( 'wp_enqueue_scripts', array( $this, 'customize_preview_enqueue_deps' ) ); add_filter( 'wp_nav_menu_args', array( $this, 'filter_wp_nav_menu_args' ), 1000 ); add_filter( 'wp_nav_menu', array( $this, 'filter_wp_nav_menu' ), 10, 2 ); - add_filter( 'wp_footer', array( $this, 'export_preview_data' ), 1 ); + add_action( 'wp_footer', array( $this, 'export_preview_data' ), 1 ); add_filter( 'customize_render_partials_response', array( $this, 'export_partial_rendered_nav_menu_instances' ) ); } diff --git a/src/wp-includes/class-wp-customize-panel.php b/src/wp-includes/class-wp-customize-panel.php index 88d72f83fc07d..14ec8aad467c8 100644 --- a/src/wp-includes/class-wp-customize-panel.php +++ b/src/wp-includes/class-wp-customize-panel.php @@ -16,6 +16,7 @@ * * @see WP_Customize_Manager */ +#[AllowDynamicProperties] class WP_Customize_Panel { /** diff --git a/src/wp-includes/class-wp-customize-section.php b/src/wp-includes/class-wp-customize-section.php index 97da8a9e35491..87b176c301719 100644 --- a/src/wp-includes/class-wp-customize-section.php +++ b/src/wp-includes/class-wp-customize-section.php @@ -16,6 +16,7 @@ * * @see WP_Customize_Manager */ +#[AllowDynamicProperties] class WP_Customize_Section { /** diff --git a/src/wp-includes/class-wp-customize-setting.php b/src/wp-includes/class-wp-customize-setting.php index e7a1030c76511..33b9436f859f6 100644 --- a/src/wp-includes/class-wp-customize-setting.php +++ b/src/wp-includes/class-wp-customize-setting.php @@ -17,6 +17,7 @@ * @see WP_Customize_Manager * @link https://developer.wordpress.org/themes/customize-api */ +#[AllowDynamicProperties] class WP_Customize_Setting { /** * Customizer bootstrap instance. diff --git a/src/wp-includes/class-wp-customize-widgets.php b/src/wp-includes/class-wp-customize-widgets.php index 9b4a0fa1c5edf..2bf8a39a25ba5 100644 --- a/src/wp-includes/class-wp-customize-widgets.php +++ b/src/wp-includes/class-wp-customize-widgets.php @@ -16,6 +16,7 @@ * * @see WP_Customize_Manager */ +#[AllowDynamicProperties] final class WP_Customize_Widgets { /** diff --git a/src/wp-includes/class-wp-date-query.php b/src/wp-includes/class-wp-date-query.php index 1fa3652176eb1..faa657dde5108 100644 --- a/src/wp-includes/class-wp-date-query.php +++ b/src/wp-includes/class-wp-date-query.php @@ -14,6 +14,7 @@ * * @since 3.7.0 */ +#[AllowDynamicProperties] class WP_Date_Query { /** * Array of date queries. diff --git a/src/wp-includes/class-wp-dependency.php b/src/wp-includes/class-wp-dependency.php index ad4cd11caa763..c4335b9bab77c 100644 --- a/src/wp-includes/class-wp-dependency.php +++ b/src/wp-includes/class-wp-dependency.php @@ -16,6 +16,7 @@ * @access private * @since 2.6.0 */ +#[AllowDynamicProperties] class _WP_Dependency { /** * The handle name. diff --git a/src/wp-includes/class-wp-editor.php b/src/wp-includes/class-wp-editor.php index 9a772d909c238..41f379a8384b1 100644 --- a/src/wp-includes/class-wp-editor.php +++ b/src/wp-includes/class-wp-editor.php @@ -8,6 +8,7 @@ * Private, not included by default. See wp_editor() in wp-includes/general-template.php. */ +#[AllowDynamicProperties] final class _WP_Editors { public static $mce_locale; diff --git a/src/wp-includes/class-wp-embed.php b/src/wp-includes/class-wp-embed.php index 677a5944c4d67..8ce34832289e3 100644 --- a/src/wp-includes/class-wp-embed.php +++ b/src/wp-includes/class-wp-embed.php @@ -6,6 +6,7 @@ * @subpackage Embed * @since 2.9.0 */ +#[AllowDynamicProperties] class WP_Embed { public $handlers = array(); public $post_ID; diff --git a/src/wp-includes/class-wp-error.php b/src/wp-includes/class-wp-error.php index d34c70a2e96a8..c8a976fb148be 100644 --- a/src/wp-includes/class-wp-error.php +++ b/src/wp-includes/class-wp-error.php @@ -15,6 +15,7 @@ * * @since 2.1.0 */ +#[AllowDynamicProperties] class WP_Error { /** * Stores the list of errors. diff --git a/src/wp-includes/class-wp-fatal-error-handler.php b/src/wp-includes/class-wp-fatal-error-handler.php index 1fc5e0b968991..55d328fbab31e 100644 --- a/src/wp-includes/class-wp-fatal-error-handler.php +++ b/src/wp-includes/class-wp-fatal-error-handler.php @@ -16,6 +16,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Fatal_Error_Handler { /** diff --git a/src/wp-includes/class-wp-feed-cache-transient.php b/src/wp-includes/class-wp-feed-cache-transient.php index f304ef8a6edbc..1d39932af4303 100644 --- a/src/wp-includes/class-wp-feed-cache-transient.php +++ b/src/wp-includes/class-wp-feed-cache-transient.php @@ -12,6 +12,7 @@ * * @since 2.8.0 */ +#[AllowDynamicProperties] class WP_Feed_Cache_Transient { /** diff --git a/src/wp-includes/class-wp-feed-cache.php b/src/wp-includes/class-wp-feed-cache.php index b3d03ab422d19..d86b0fb7dbf05 100644 --- a/src/wp-includes/class-wp-feed-cache.php +++ b/src/wp-includes/class-wp-feed-cache.php @@ -22,6 +22,7 @@ * * @see SimplePie_Cache */ +#[AllowDynamicProperties] class WP_Feed_Cache extends SimplePie_Cache { /** diff --git a/src/wp-includes/class-wp-hook.php b/src/wp-includes/class-wp-hook.php index 018db1c96707a..4796503dcc2a9 100644 --- a/src/wp-includes/class-wp-hook.php +++ b/src/wp-includes/class-wp-hook.php @@ -15,6 +15,7 @@ * @see Iterator * @see ArrayAccess */ +#[AllowDynamicProperties] final class WP_Hook implements Iterator, ArrayAccess { /** diff --git a/src/wp-includes/class-wp-http-cookie.php b/src/wp-includes/class-wp-http-cookie.php index 5fa2de7644082..7f5a64d0234fa 100644 --- a/src/wp-includes/class-wp-http-cookie.php +++ b/src/wp-includes/class-wp-http-cookie.php @@ -18,6 +18,7 @@ * * @since 2.8.0 */ +#[AllowDynamicProperties] class WP_Http_Cookie { /** diff --git a/src/wp-includes/class-wp-http-curl.php b/src/wp-includes/class-wp-http-curl.php index 0e389c45639e9..9b201af110b3b 100644 --- a/src/wp-includes/class-wp-http-curl.php +++ b/src/wp-includes/class-wp-http-curl.php @@ -16,6 +16,7 @@ * * @since 2.7.0 */ +#[AllowDynamicProperties] class WP_Http_Curl { /** diff --git a/src/wp-includes/class-wp-http-encoding.php b/src/wp-includes/class-wp-http-encoding.php index e9e94e4d77051..255b2114ea87f 100644 --- a/src/wp-includes/class-wp-http-encoding.php +++ b/src/wp-includes/class-wp-http-encoding.php @@ -14,6 +14,7 @@ * * @since 2.8.0 */ +#[AllowDynamicProperties] class WP_Http_Encoding { /** diff --git a/src/wp-includes/class-wp-http-ixr-client.php b/src/wp-includes/class-wp-http-ixr-client.php index fef16e831d98b..d45ca150eb2a6 100644 --- a/src/wp-includes/class-wp-http-ixr-client.php +++ b/src/wp-includes/class-wp-http-ixr-client.php @@ -5,6 +5,7 @@ * @package WordPress * @since 3.1.0 */ +#[AllowDynamicProperties] class WP_HTTP_IXR_Client extends IXR_Client { public $scheme; /** diff --git a/src/wp-includes/class-wp-http-proxy.php b/src/wp-includes/class-wp-http-proxy.php index 4408b9ba262ad..3e3d1f684e277 100644 --- a/src/wp-includes/class-wp-http-proxy.php +++ b/src/wp-includes/class-wp-http-proxy.php @@ -39,6 +39,7 @@ * * @since 2.8.0 */ +#[AllowDynamicProperties] class WP_HTTP_Proxy { /** diff --git a/src/wp-includes/class-wp-http-requests-hooks.php b/src/wp-includes/class-wp-http-requests-hooks.php index c54fdc0b8f88c..dac64dd6eb847 100644 --- a/src/wp-includes/class-wp-http-requests-hooks.php +++ b/src/wp-includes/class-wp-http-requests-hooks.php @@ -14,6 +14,7 @@ * * @see Requests_Hooks */ +#[AllowDynamicProperties] class WP_HTTP_Requests_Hooks extends Requests_Hooks { /** * Requested URL. diff --git a/src/wp-includes/class-wp-http-response.php b/src/wp-includes/class-wp-http-response.php index ae28d8954b538..d102877885b7c 100644 --- a/src/wp-includes/class-wp-http-response.php +++ b/src/wp-includes/class-wp-http-response.php @@ -12,6 +12,7 @@ * * @since 4.4.0 */ +#[AllowDynamicProperties] class WP_HTTP_Response { /** diff --git a/src/wp-includes/class-wp-http-streams.php b/src/wp-includes/class-wp-http-streams.php index a5d0694da3f28..48078cfafa5e4 100644 --- a/src/wp-includes/class-wp-http-streams.php +++ b/src/wp-includes/class-wp-http-streams.php @@ -13,6 +13,7 @@ * @since 2.7.0 * @since 3.7.0 Combined with the fsockopen transport and switched to `stream_socket_client()`. */ +#[AllowDynamicProperties] class WP_Http_Streams { /** * Send a HTTP request to a URI using PHP Streams. diff --git a/src/wp-includes/class-wp-http.php b/src/wp-includes/class-wp-http.php index 73be956f4d8ac..e96713e718194 100644 --- a/src/wp-includes/class-wp-http.php +++ b/src/wp-includes/class-wp-http.php @@ -25,6 +25,7 @@ * * @since 2.7.0 */ +#[AllowDynamicProperties] class WP_Http { // Aliases for HTTP response codes. diff --git a/src/wp-includes/class-wp-image-editor.php b/src/wp-includes/class-wp-image-editor.php index db94fc7dfe937..67d1bda83f21c 100644 --- a/src/wp-includes/class-wp-image-editor.php +++ b/src/wp-includes/class-wp-image-editor.php @@ -11,6 +11,7 @@ * * @since 3.5.0 */ +#[AllowDynamicProperties] abstract class WP_Image_Editor { protected $file = null; protected $size = null; diff --git a/src/wp-includes/class-wp-list-util.php b/src/wp-includes/class-wp-list-util.php index 49fd3a00af56e..a2ccfb541259f 100644 --- a/src/wp-includes/class-wp-list-util.php +++ b/src/wp-includes/class-wp-list-util.php @@ -13,6 +13,7 @@ * * @since 4.7.0 */ +#[AllowDynamicProperties] class WP_List_Util { /** * The input array. diff --git a/src/wp-includes/class-wp-locale-switcher.php b/src/wp-includes/class-wp-locale-switcher.php index 3cbd613a43a94..028ad48d55ad2 100644 --- a/src/wp-includes/class-wp-locale-switcher.php +++ b/src/wp-includes/class-wp-locale-switcher.php @@ -12,6 +12,7 @@ * * @since 4.7.0 */ +#[AllowDynamicProperties] class WP_Locale_Switcher { /** * Locale stack. diff --git a/src/wp-includes/class-wp-locale.php b/src/wp-includes/class-wp-locale.php index 962fc9f2ca0db..ca98f9d301fcd 100644 --- a/src/wp-includes/class-wp-locale.php +++ b/src/wp-includes/class-wp-locale.php @@ -13,6 +13,7 @@ * @since 2.1.0 * @since 4.6.0 Moved to its own file from wp-includes/locale.php. */ +#[AllowDynamicProperties] class WP_Locale { /** * Stores the translated strings for the full weekday names. diff --git a/src/wp-includes/class-wp-matchesmapregex.php b/src/wp-includes/class-wp-matchesmapregex.php index cdb39077e2e45..558bd9866781c 100644 --- a/src/wp-includes/class-wp-matchesmapregex.php +++ b/src/wp-includes/class-wp-matchesmapregex.php @@ -11,6 +11,7 @@ * * @since 2.9.0 */ +#[AllowDynamicProperties] class WP_MatchesMapRegex { /** * store for matches diff --git a/src/wp-includes/class-wp-meta-query.php b/src/wp-includes/class-wp-meta-query.php index f66b2fac5f0f3..41b5f02f089ec 100644 --- a/src/wp-includes/class-wp-meta-query.php +++ b/src/wp-includes/class-wp-meta-query.php @@ -19,6 +19,7 @@ * * @since 3.2.0 */ +#[AllowDynamicProperties] class WP_Meta_Query { /** * Array of metadata queries. diff --git a/src/wp-includes/class-wp-metadata-lazyloader.php b/src/wp-includes/class-wp-metadata-lazyloader.php index 67eacc99ae617..4a03633de0abf 100644 --- a/src/wp-includes/class-wp-metadata-lazyloader.php +++ b/src/wp-includes/class-wp-metadata-lazyloader.php @@ -28,6 +28,7 @@ * * @since 4.5.0 */ +#[AllowDynamicProperties] class WP_Metadata_Lazyloader { /** * Pending objects queue. diff --git a/src/wp-includes/class-wp-network-query.php b/src/wp-includes/class-wp-network-query.php index 269b960303219..4f8a2a3a2ece9 100644 --- a/src/wp-includes/class-wp-network-query.php +++ b/src/wp-includes/class-wp-network-query.php @@ -14,6 +14,7 @@ * * @see WP_Network_Query::__construct() for accepted arguments. */ +#[AllowDynamicProperties] class WP_Network_Query { /** diff --git a/src/wp-includes/class-wp-network.php b/src/wp-includes/class-wp-network.php index f9dfad0957d8c..75b407e541154 100644 --- a/src/wp-includes/class-wp-network.php +++ b/src/wp-includes/class-wp-network.php @@ -21,6 +21,7 @@ * @property int $id * @property int $site_id */ +#[AllowDynamicProperties] class WP_Network { /** diff --git a/src/wp-includes/class-wp-object-cache.php b/src/wp-includes/class-wp-object-cache.php index c22fd6298dc55..6ca91a34fde87 100644 --- a/src/wp-includes/class-wp-object-cache.php +++ b/src/wp-includes/class-wp-object-cache.php @@ -21,6 +21,7 @@ * * @since 2.0.0 */ +#[AllowDynamicProperties] class WP_Object_Cache { /** diff --git a/src/wp-includes/class-wp-oembed-controller.php b/src/wp-includes/class-wp-oembed-controller.php index 046c5c0a3ada6..22fceb54a9aa1 100644 --- a/src/wp-includes/class-wp-oembed-controller.php +++ b/src/wp-includes/class-wp-oembed-controller.php @@ -15,6 +15,7 @@ * * @since 4.4.0 */ +#[AllowDynamicProperties] final class WP_oEmbed_Controller { /** * Register the oEmbed REST API route. diff --git a/src/wp-includes/class-wp-oembed.php b/src/wp-includes/class-wp-oembed.php index ce75a4f196bee..ea666c1442855 100644 --- a/src/wp-includes/class-wp-oembed.php +++ b/src/wp-includes/class-wp-oembed.php @@ -16,6 +16,7 @@ * * @since 2.9.0 */ +#[AllowDynamicProperties] class WP_oEmbed { /** @@ -105,6 +106,7 @@ public function __construct() { '#https?://([a-z]{2}|www)\.pinterest\.com(\.(au|mx))?/.*#i' => array( 'https://www.pinterest.com/oembed.json', true ), '#https?://(www\.)?wolframcloud\.com/obj/.+#i' => array( 'https://www.wolframcloud.com/oembed', true ), '#https?://pca\.st/.+#i' => array( 'https://pca.st/oembed.json', true ), + '#https?://datastudio\.google\.com/c/u/0/reporting/.+#i' => array( 'https://datastudio.google.com/oembed', true ), ); if ( ! empty( self::$early_providers['add'] ) ) { @@ -183,6 +185,7 @@ public function __construct() { * | Pinterest | pinterest.com | 5.9.0 | * | WolframCloud | wolframcloud.com | 5.9.0 | * | Pocket Casts | pocketcasts.com | 6.1.0 | + * | Data Studio | datastudio.google.com | 6.1.0 | * * No longer supported providers: * diff --git a/src/wp-includes/class-wp-paused-extensions-storage.php b/src/wp-includes/class-wp-paused-extensions-storage.php index a2859d308f448..4658277289e49 100644 --- a/src/wp-includes/class-wp-paused-extensions-storage.php +++ b/src/wp-includes/class-wp-paused-extensions-storage.php @@ -11,6 +11,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Paused_Extensions_Storage { /** diff --git a/src/wp-includes/class-wp-post-type.php b/src/wp-includes/class-wp-post-type.php index 3c3ec0e3ab31d..ab9fccc681630 100644 --- a/src/wp-includes/class-wp-post-type.php +++ b/src/wp-includes/class-wp-post-type.php @@ -14,6 +14,7 @@ * * @see register_post_type() */ +#[AllowDynamicProperties] final class WP_Post_Type { /** * Post type key. diff --git a/src/wp-includes/class-wp-post.php b/src/wp-includes/class-wp-post.php index fe059d00aa849..682b000f397a6 100644 --- a/src/wp-includes/class-wp-post.php +++ b/src/wp-includes/class-wp-post.php @@ -18,6 +18,7 @@ * @property-read int[] $post_category * @property-read string[] $tags_input */ +#[AllowDynamicProperties] final class WP_Post { /** diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 32b5fafaf3ccc..4b1761890725c 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -15,6 +15,7 @@ * @since 1.5.0 * @since 4.5.0 Removed the `$comments_popup` property. */ +#[AllowDynamicProperties] class WP_Query { /** diff --git a/src/wp-includes/class-wp-recovery-mode-cookie-service.php b/src/wp-includes/class-wp-recovery-mode-cookie-service.php index 47329d6c64b19..df59b35780df4 100644 --- a/src/wp-includes/class-wp-recovery-mode-cookie-service.php +++ b/src/wp-includes/class-wp-recovery-mode-cookie-service.php @@ -11,6 +11,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] final class WP_Recovery_Mode_Cookie_Service { /** diff --git a/src/wp-includes/class-wp-recovery-mode-email-service.php b/src/wp-includes/class-wp-recovery-mode-email-service.php index e375f38bf1626..013901f90e7d4 100644 --- a/src/wp-includes/class-wp-recovery-mode-email-service.php +++ b/src/wp-includes/class-wp-recovery-mode-email-service.php @@ -11,6 +11,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] final class WP_Recovery_Mode_Email_Service { const RATE_LIMIT_OPTION = 'recovery_mode_email_last_sent'; diff --git a/src/wp-includes/class-wp-recovery-mode-key-service.php b/src/wp-includes/class-wp-recovery-mode-key-service.php index 6e533d04a9cdb..5ab0f8c3f9fc8 100644 --- a/src/wp-includes/class-wp-recovery-mode-key-service.php +++ b/src/wp-includes/class-wp-recovery-mode-key-service.php @@ -11,6 +11,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] final class WP_Recovery_Mode_Key_Service { /** diff --git a/src/wp-includes/class-wp-recovery-mode-link-service.php b/src/wp-includes/class-wp-recovery-mode-link-service.php index 1b4b96373a199..4fb888c5d6ad1 100644 --- a/src/wp-includes/class-wp-recovery-mode-link-service.php +++ b/src/wp-includes/class-wp-recovery-mode-link-service.php @@ -11,6 +11,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Recovery_Mode_Link_Service { const LOGIN_ACTION_ENTER = 'enter_recovery_mode'; const LOGIN_ACTION_ENTERED = 'entered_recovery_mode'; diff --git a/src/wp-includes/class-wp-recovery-mode.php b/src/wp-includes/class-wp-recovery-mode.php index e61290090e841..b30eb408e3500 100644 --- a/src/wp-includes/class-wp-recovery-mode.php +++ b/src/wp-includes/class-wp-recovery-mode.php @@ -11,6 +11,7 @@ * * @since 5.2.0 */ +#[AllowDynamicProperties] class WP_Recovery_Mode { const EXIT_ACTION = 'exit_recovery_mode'; diff --git a/src/wp-includes/class-wp-rewrite.php b/src/wp-includes/class-wp-rewrite.php index a1a262aa7b260..a20de7128e450 100644 --- a/src/wp-includes/class-wp-rewrite.php +++ b/src/wp-includes/class-wp-rewrite.php @@ -22,6 +22,7 @@ * * @since 1.5.0 */ +#[AllowDynamicProperties] class WP_Rewrite { /** * Permalink structure for posts. diff --git a/src/wp-includes/class-wp-role.php b/src/wp-includes/class-wp-role.php index 33f484ac97234..6f25c3cb0342a 100644 --- a/src/wp-includes/class-wp-role.php +++ b/src/wp-includes/class-wp-role.php @@ -12,6 +12,7 @@ * * @since 2.0.0 */ +#[AllowDynamicProperties] class WP_Role { /** * Role name. diff --git a/src/wp-includes/class-wp-roles.php b/src/wp-includes/class-wp-roles.php index 23d5d76723f2e..f224250fa27b7 100644 --- a/src/wp-includes/class-wp-roles.php +++ b/src/wp-includes/class-wp-roles.php @@ -23,6 +23,7 @@ * * @since 2.0.0 */ +#[AllowDynamicProperties] class WP_Roles { /** * List of roles and capabilities. diff --git a/src/wp-includes/class-wp-session-tokens.php b/src/wp-includes/class-wp-session-tokens.php index a1a779b236eaa..feabf698b7467 100644 --- a/src/wp-includes/class-wp-session-tokens.php +++ b/src/wp-includes/class-wp-session-tokens.php @@ -12,6 +12,7 @@ * * @since 4.0.0 */ +#[AllowDynamicProperties] abstract class WP_Session_Tokens { /** diff --git a/src/wp-includes/class-wp-simplepie-file.php b/src/wp-includes/class-wp-simplepie-file.php index 83cc3248631e5..a0125aaf1dcee 100644 --- a/src/wp-includes/class-wp-simplepie-file.php +++ b/src/wp-includes/class-wp-simplepie-file.php @@ -17,6 +17,7 @@ * * @see SimplePie_File */ +#[AllowDynamicProperties] class WP_SimplePie_File extends SimplePie_File { /** diff --git a/src/wp-includes/class-wp-simplepie-sanitize-kses.php b/src/wp-includes/class-wp-simplepie-sanitize-kses.php index 183fe07ca78e1..4e7602cda435b 100644 --- a/src/wp-includes/class-wp-simplepie-sanitize-kses.php +++ b/src/wp-includes/class-wp-simplepie-sanitize-kses.php @@ -17,6 +17,7 @@ * * @see SimplePie_Sanitize */ +#[AllowDynamicProperties] class WP_SimplePie_Sanitize_KSES extends SimplePie_Sanitize { /** diff --git a/src/wp-includes/class-wp-site-query.php b/src/wp-includes/class-wp-site-query.php index b6207139895ef..a90cc9de8df0b 100644 --- a/src/wp-includes/class-wp-site-query.php +++ b/src/wp-includes/class-wp-site-query.php @@ -14,6 +14,7 @@ * * @see WP_Site_Query::__construct() for accepted arguments. */ +#[AllowDynamicProperties] class WP_Site_Query { /** diff --git a/src/wp-includes/class-wp-site.php b/src/wp-includes/class-wp-site.php index 1e253ec63611e..fcd07cd5e3175 100644 --- a/src/wp-includes/class-wp-site.php +++ b/src/wp-includes/class-wp-site.php @@ -22,6 +22,7 @@ * @property int $post_count * @property string $home */ +#[AllowDynamicProperties] final class WP_Site { /** diff --git a/src/wp-includes/class-wp-tax-query.php b/src/wp-includes/class-wp-tax-query.php index 9f4aeaaa76b7f..e7b1e2a95a551 100644 --- a/src/wp-includes/class-wp-tax-query.php +++ b/src/wp-includes/class-wp-tax-query.php @@ -19,6 +19,7 @@ * * @since 3.1.0 */ +#[AllowDynamicProperties] class WP_Tax_Query { /** diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 0fac7a0501f04..1f7eed96f6b51 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -12,6 +12,7 @@ * * @since 4.7.0 */ +#[AllowDynamicProperties] final class WP_Taxonomy { /** * Taxonomy key. diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 5c430c8459c51..18c85e89b28d7 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -15,6 +15,7 @@ * * @see WP_Term_Query::__construct() for accepted arguments. */ +#[AllowDynamicProperties] class WP_Term_Query { /** diff --git a/src/wp-includes/class-wp-term.php b/src/wp-includes/class-wp-term.php index f79ab8633bb87..0f5631353e876 100644 --- a/src/wp-includes/class-wp-term.php +++ b/src/wp-includes/class-wp-term.php @@ -14,6 +14,7 @@ * * @property-read object $data Sanitized term data. */ +#[AllowDynamicProperties] final class WP_Term { /** diff --git a/src/wp-includes/class-wp-text-diff-renderer-inline.php b/src/wp-includes/class-wp-text-diff-renderer-inline.php index 62a33033e3d84..eaba1b61edd94 100644 --- a/src/wp-includes/class-wp-text-diff-renderer-inline.php +++ b/src/wp-includes/class-wp-text-diff-renderer-inline.php @@ -13,6 +13,7 @@ * @since 2.6.0 * @uses Text_Diff_Renderer_inline Extends */ +#[AllowDynamicProperties] class WP_Text_Diff_Renderer_inline extends Text_Diff_Renderer_inline { /** diff --git a/src/wp-includes/class-wp-text-diff-renderer-table.php b/src/wp-includes/class-wp-text-diff-renderer-table.php index 43c0d0e422a8b..a74b8019f4eb8 100644 --- a/src/wp-includes/class-wp-text-diff-renderer-table.php +++ b/src/wp-includes/class-wp-text-diff-renderer-table.php @@ -13,6 +13,7 @@ * @since 2.6.0 * @uses Text_Diff_Renderer Extends */ +#[AllowDynamicProperties] class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { /** diff --git a/src/wp-includes/class-wp-textdomain-registry.php b/src/wp-includes/class-wp-textdomain-registry.php index d4d8968ac91cf..403fff9813601 100644 --- a/src/wp-includes/class-wp-textdomain-registry.php +++ b/src/wp-includes/class-wp-textdomain-registry.php @@ -12,6 +12,7 @@ * * @since 6.1.0 */ +#[AllowDynamicProperties] class WP_Textdomain_Registry { /** * List of domains and all their language directory paths for each locale. diff --git a/src/wp-includes/class-wp-theme-json-resolver.php b/src/wp-includes/class-wp-theme-json-resolver.php index c9bb42cac5b2f..5d0dd099c20e5 100644 --- a/src/wp-includes/class-wp-theme-json-resolver.php +++ b/src/wp-includes/class-wp-theme-json-resolver.php @@ -17,6 +17,7 @@ * * @access private */ +#[AllowDynamicProperties] class WP_Theme_JSON_Resolver { /** @@ -231,6 +232,54 @@ public static function get_theme_data( $deprecated = array(), $options = array() return $with_theme_supports; } + /** + * Gets the styles for blocks from the block.json file. + * + * @since 6.1.0 + * + * @return WP_Theme_JSON + */ + public static function get_block_data() { + $registry = WP_Block_Type_Registry::get_instance(); + $blocks = $registry->get_all_registered(); + $config = array( 'version' => 1 ); + foreach ( $blocks as $block_name => $block_type ) { + if ( isset( $block_type->supports['__experimentalStyle'] ) ) { + $config['styles']['blocks'][ $block_name ] = static::remove_json_comments( $block_type->supports['__experimentalStyle'] ); + } + + if ( + isset( $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ) && + null === _wp_array_get( $config, array( 'styles', 'blocks', $block_name, 'spacing', 'blockGap' ), null ) + ) { + // Ensure an empty placeholder value exists for the block, if it provides a default blockGap value. + // The real blockGap value to be used will be determined when the styles are rendered for output. + $config['styles']['blocks'][ $block_name ]['spacing']['blockGap'] = null; + } + } + + // Core here means it's the lower level part of the styles chain. + // It can be a core or a third-party block. + return new WP_Theme_JSON( $config, 'core' ); + } + + /** + * When given an array, this will remove any keys with the name `//`. + * + * @param array $array The array to filter. + * @return array The filtered array. + */ + private static function remove_json_comments( $array ) { + unset( $array['//'] ); + foreach ( $array as $k => $v ) { + if ( is_array( $v ) ) { + $array[ $k ] = static::remove_json_comments( $v ); + } + } + + return $array; + } + /** * Returns the custom post type that contains the user's origin config * for the active theme or a void array if none are found. @@ -369,6 +418,7 @@ public static function get_user_data() { * @since 5.8.0 * @since 5.9.0 Added user data, removed the `$settings` parameter, * added the `$origin` parameter. + * @since 6.1.0 Added block data. * * @param string $origin Optional. To what level should we merge data. * Valid values are 'theme' or 'custom'. Default 'custom'. @@ -381,6 +431,7 @@ public static function get_merged_data( $origin = 'custom' ) { $result = new WP_Theme_JSON(); $result->merge( static::get_core_data() ); + $result->merge( static::get_block_data() ); $result->merge( static::get_theme_data() ); if ( 'custom' === $origin ) { diff --git a/src/wp-includes/class-wp-theme-json-schema.php b/src/wp-includes/class-wp-theme-json-schema.php index 462af763763d3..2e35a12c2ba5d 100644 --- a/src/wp-includes/class-wp-theme-json-schema.php +++ b/src/wp-includes/class-wp-theme-json-schema.php @@ -17,6 +17,7 @@ * @since 5.9.0 * @access private */ +#[AllowDynamicProperties] class WP_Theme_JSON_Schema { /** diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 2833e8be9c94d..4e7c704cce16b 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -16,6 +16,7 @@ * * @access private */ +#[AllowDynamicProperties] class WP_Theme_JSON { /** @@ -176,40 +177,60 @@ class WP_Theme_JSON { * `letter-spacing`, `margin-*`, `padding-*`, `--wp--style--block-gap`, * `text-decoration`, `text-transform`, and `filter` properties, * simplified the metadata structure. + * @since 6.1.0 Added the `border-*-color`, `border-*-width`, `border-*-style`, + * `--wp--style--root--padding-*`, and `box-shadow` properties, + * removed the `--wp--style--block-gap` property. * @var array */ const PROPERTIES_METADATA = array( - 'background' => array( 'color', 'gradient' ), - 'background-color' => array( 'color', 'background' ), - 'border-radius' => array( 'border', 'radius' ), - 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), - 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), - 'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ), - 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ), - 'border-color' => array( 'border', 'color' ), - 'border-width' => array( 'border', 'width' ), - 'border-style' => array( 'border', 'style' ), - 'color' => array( 'color', 'text' ), - 'font-family' => array( 'typography', 'fontFamily' ), - 'font-size' => array( 'typography', 'fontSize' ), - 'font-style' => array( 'typography', 'fontStyle' ), - 'font-weight' => array( 'typography', 'fontWeight' ), - 'letter-spacing' => array( 'typography', 'letterSpacing' ), - 'line-height' => array( 'typography', 'lineHeight' ), - 'margin' => array( 'spacing', 'margin' ), - 'margin-top' => array( 'spacing', 'margin', 'top' ), - 'margin-right' => array( 'spacing', 'margin', 'right' ), - 'margin-bottom' => array( 'spacing', 'margin', 'bottom' ), - 'margin-left' => array( 'spacing', 'margin', 'left' ), - 'padding' => array( 'spacing', 'padding' ), - 'padding-top' => array( 'spacing', 'padding', 'top' ), - 'padding-right' => array( 'spacing', 'padding', 'right' ), - 'padding-bottom' => array( 'spacing', 'padding', 'bottom' ), - 'padding-left' => array( 'spacing', 'padding', 'left' ), - '--wp--style--block-gap' => array( 'spacing', 'blockGap' ), - 'text-decoration' => array( 'typography', 'textDecoration' ), - 'text-transform' => array( 'typography', 'textTransform' ), - 'filter' => array( 'filter', 'duotone' ), + 'background' => array( 'color', 'gradient' ), + 'background-color' => array( 'color', 'background' ), + 'border-radius' => array( 'border', 'radius' ), + 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), + 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), + 'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ), + 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ), + 'border-color' => array( 'border', 'color' ), + 'border-width' => array( 'border', 'width' ), + 'border-style' => array( 'border', 'style' ), + 'border-top-color' => array( 'border', 'top', 'color' ), + 'border-top-width' => array( 'border', 'top', 'width' ), + 'border-top-style' => array( 'border', 'top', 'style' ), + 'border-right-color' => array( 'border', 'right', 'color' ), + 'border-right-width' => array( 'border', 'right', 'width' ), + 'border-right-style' => array( 'border', 'right', 'style' ), + 'border-bottom-color' => array( 'border', 'bottom', 'color' ), + 'border-bottom-width' => array( 'border', 'bottom', 'width' ), + 'border-bottom-style' => array( 'border', 'bottom', 'style' ), + 'border-left-color' => array( 'border', 'left', 'color' ), + 'border-left-width' => array( 'border', 'left', 'width' ), + 'border-left-style' => array( 'border', 'left', 'style' ), + 'color' => array( 'color', 'text' ), + 'font-family' => array( 'typography', 'fontFamily' ), + 'font-size' => array( 'typography', 'fontSize' ), + 'font-style' => array( 'typography', 'fontStyle' ), + 'font-weight' => array( 'typography', 'fontWeight' ), + 'letter-spacing' => array( 'typography', 'letterSpacing' ), + 'line-height' => array( 'typography', 'lineHeight' ), + 'margin' => array( 'spacing', 'margin' ), + 'margin-top' => array( 'spacing', 'margin', 'top' ), + 'margin-right' => array( 'spacing', 'margin', 'right' ), + 'margin-bottom' => array( 'spacing', 'margin', 'bottom' ), + 'margin-left' => array( 'spacing', 'margin', 'left' ), + 'padding' => array( 'spacing', 'padding' ), + 'padding-top' => array( 'spacing', 'padding', 'top' ), + 'padding-right' => array( 'spacing', 'padding', 'right' ), + 'padding-bottom' => array( 'spacing', 'padding', 'bottom' ), + 'padding-left' => array( 'spacing', 'padding', 'left' ), + '--wp--style--root--padding' => array( 'spacing', 'padding' ), + '--wp--style--root--padding-top' => array( 'spacing', 'padding', 'top' ), + '--wp--style--root--padding-right' => array( 'spacing', 'padding', 'right' ), + '--wp--style--root--padding-bottom' => array( 'spacing', 'padding', 'bottom' ), + '--wp--style--root--padding-left' => array( 'spacing', 'padding', 'left' ), + 'text-decoration' => array( 'typography', 'textDecoration' ), + 'text-transform' => array( 'typography', 'textTransform' ), + 'filter' => array( 'filter', 'duotone' ), + 'box-shadow' => array( 'shadow' ), ); /** @@ -253,17 +274,19 @@ class WP_Theme_JSON { * added new properties for `border`, `color`, `spacing`, * and `typography`, and renamed others according to the new schema. * @since 6.0.0 Added `color.defaultDuotone`. + * @since 6.1.0 Added `layout.definitions` and `useRootPaddingAwareAlignments`. * @var array */ const VALID_SETTINGS = array( - 'appearanceTools' => null, - 'border' => array( + 'appearanceTools' => null, + 'useRootPaddingAwareAlignments' => null, + 'border' => array( 'color' => null, 'radius' => null, 'style' => null, 'width' => null, ), - 'color' => array( + 'color' => array( 'background' => null, 'custom' => null, 'customDuotone' => null, @@ -277,18 +300,19 @@ class WP_Theme_JSON { 'palette' => null, 'text' => null, ), - 'custom' => null, - 'layout' => array( + 'custom' => null, + 'layout' => array( 'contentSize' => null, + 'definitions' => null, 'wideSize' => null, ), - 'spacing' => array( + 'spacing' => array( 'blockGap' => null, 'margin' => null, 'padding' => null, 'units' => null, ), - 'typography' => array( + 'typography' => array( 'customFontSize' => null, 'dropCap' => null, 'fontFamilies' => null, @@ -309,6 +333,8 @@ class WP_Theme_JSON { * @since 5.9.0 Renamed from `ALLOWED_STYLES` to `VALID_STYLES`, * added new properties for `border`, `filter`, `spacing`, * and `typography`. + * @since 6.1.0 Added new side properties for `border`, + * updated `blockGap` to be allowed at any level. * @var array */ const VALID_STYLES = array( @@ -317,6 +343,10 @@ class WP_Theme_JSON { 'radius' => null, 'style' => null, 'width' => null, + 'top' => null, + 'right' => null, + 'bottom' => null, + 'left' => null, ), 'color' => array( 'background' => null, @@ -329,7 +359,7 @@ class WP_Theme_JSON { 'spacing' => array( 'margin' => null, 'padding' => null, - 'blockGap' => 'top', + 'blockGap' => null, ), 'typography' => array( 'fontFamily' => null, @@ -343,15 +373,27 @@ class WP_Theme_JSON { ), ); + /** + * Defines which pseudo selectors are enabled for which elements. + * + * Note: this will affect both top-level and block-level elements. + * + * @since 6.1.0 + */ + const VALID_ELEMENT_PSEUDO_SELECTORS = array( + 'link' => array( ':hover', ':focus', ':active', ':visited' ), + 'button' => array( ':hover', ':focus', ':active', ':visited' ), + ); + /** * The valid elements that can be found under styles. * * @since 5.8.0 - * @since 6.1.0 Added `heading`, `button`, and `caption` to the elements. + * @since 6.1.0 Added `heading`, `button`. and `caption` elements. * @var string[] */ const ELEMENTS = array( - 'link' => 'a', + 'link' => 'a:where(:not(.wp-element-button))', // The `where` is needed to lower the specificity. 'heading' => 'h1, h2, h3, h4, h5, h6', 'h1' => 'h1', 'h2' => 'h2', @@ -365,6 +407,43 @@ class WP_Theme_JSON { 'caption' => '.wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption', ); + const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array( + 'button' => 'wp-element-button', + 'caption' => 'wp-element-caption', + ); + + /** + * List of block support features that can have their related styles + * generated under their own feature level selector rather than the block's. + * + * @since 6.1.0 + * @var string[] + */ + const BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS = array( + '__experimentalBorder' => 'border', + 'color' => 'color', + 'spacing' => 'spacing', + 'typography' => 'typography', + ); + + /** + * Returns a class name by an element name. + * + * @since 6.1.0 + * + * @param string $element The name of the element. + * @return string The name of the class. + */ + public static function get_element_class_name( $element ) { + $class_name = ''; + + if ( array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ) { + $class_name = static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ]; + } + + return $class_name; + } + /** * Options that settings.appearanceTools enables. * @@ -488,16 +567,21 @@ protected static function do_opt_in_into_settings( &$context ) { * @return array The sanitized output. */ protected static function sanitize( $input, $valid_block_names, $valid_element_names ) { + $output = array(); if ( ! is_array( $input ) ) { return $output; } + // Preserve only the top most level keys. $output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) ); - // Some styles are only meant to be available at the top-level (e.g.: blockGap), - // hence, the schema for blocks & elements should not have them. + /* + * Remove any rules that are annotated as "top" in VALID_STYLES constant. + * Some styles are only meant to be available at the top-level (e.g.: blockGap), + * hence, the schema for blocks & elements should not have them. + */ $styles_non_top_level = static::VALID_STYLES; foreach ( array_keys( $styles_non_top_level ) as $section ) { foreach ( array_keys( $styles_non_top_level[ $section ] ) as $prop ) { @@ -510,9 +594,24 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n // Build the schema based on valid block & element names. $schema = array(); $schema_styles_elements = array(); + + /* + * Set allowed element pseudo selectors based on per element allow list. + * Target data structure in schema: + * e.g. + * - top level elements: `$schema['styles']['elements']['link'][':hover']`. + * - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`. + */ foreach ( $valid_element_names as $element ) { $schema_styles_elements[ $element ] = $styles_non_top_level; + + if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { + $schema_styles_elements[ $element ][ $pseudo_selector ] = $styles_non_top_level; + } + } } + $schema_styles_blocks = array(); $schema_settings_blocks = array(); foreach ( $valid_block_names as $block ) { @@ -520,6 +619,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n $schema_styles_blocks[ $block ] = $styles_non_top_level; $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements; } + $schema['styles'] = static::VALID_STYLES; $schema['styles']['blocks'] = $schema_styles_blocks; $schema['styles']['elements'] = $schema_styles_elements; @@ -549,6 +649,30 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n return $output; } + /** + * Appends a sub-selector to an existing one. + * + * Given the compounded $selector "h1, h2, h3" + * and the $to_append selector ".some-class" the result will be + * "h1.some-class, h2.some-class, h3.some-class". + * + * @since 5.8.0 + * @since 6.1.0 Added append position. + * + * @param string $selector Original selector. + * @param string $to_append Selector to append. + * @param string $position A position sub-selector should be appended. Default 'right'. + * @return string + */ + protected static function append_to_selector( $selector, $to_append, $position = 'right' ) { + $new_selectors = array(); + $selectors = explode( ',', $selector ); + foreach ( $selectors as $sel ) { + $new_selectors[] = 'right' === $position ? $sel . $to_append : $to_append . $sel; + } + return implode( ',', $new_selectors ); + } + /** * Returns the metadata for each block. * @@ -575,6 +699,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n * * @since 5.8.0 * @since 5.9.0 Added `duotone` key with CSS selector. + * @since 6.1.0 Added `features` key with block support feature level selectors. * * @return array Block metadata. */ @@ -604,6 +729,25 @@ protected static function get_blocks_metadata() { static::$blocks_metadata[ $block_name ]['duotone'] = $block_type->supports['color']['__experimentalDuotone']; } + // Generate block support feature level selectors if opted into + // for the current block. + $features = array(); + foreach ( static::BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS as $key => $feature ) { + if ( + isset( $block_type->supports[ $key ]['__experimentalSelector'] ) && + $block_type->supports[ $key ]['__experimentalSelector'] + ) { + $features[ $feature ] = static::scope_selector( + static::$blocks_metadata[ $block_name ]['selector'], + $block_type->supports[ $key ]['__experimentalSelector'] + ); + } + } + + if ( ! empty( $features ) ) { + static::$blocks_metadata[ $block_name ]['features'] = $features; + } + // Assign defaults, then overwrite those that the block sets by itself. // If the block selector is compounded, will append the element to each // individual block selector. @@ -611,7 +755,11 @@ protected static function get_blocks_metadata() { foreach ( static::ELEMENTS as $el_name => $el_selector ) { $element_selector = array(); foreach ( $block_selectors as $selector ) { - $element_selector[] = $selector . ' ' . $el_selector; + if ( $selector === $el_selector ) { + $element_selector = array( $el_selector ); + break; + } + $element_selector[] = static::append_to_selector( $el_selector, $selector . ' ', 'left' ); } static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector ); } @@ -725,7 +873,30 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' } if ( in_array( 'styles', $types, true ) ) { + $root_block_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $style_nodes, 'selector' ), true ); + + if ( false !== $root_block_key ) { + $stylesheet .= $this->get_root_layout_rules( static::ROOT_BLOCK_SELECTOR, $style_nodes[ $root_block_key ] ); + } $stylesheet .= $this->get_block_classes( $style_nodes ); + } elseif ( in_array( 'base-layout-styles', $types, true ) ) { + // Base layout styles are provided as part of `styles`, so only output separately if explicitly requested. + // For backwards compatibility, the Columns block is explicitly included, to support a different default gap value. + $base_styles_nodes = array( + array( + 'path' => array( 'styles' ), + 'selector' => static::ROOT_BLOCK_SELECTOR, + ), + array( + 'path' => array( 'styles', 'blocks', 'core/columns' ), + 'selector' => '.wp-block-columns', + 'name' => 'core/columns', + ), + ); + + foreach ( $base_styles_nodes as $base_style_node ) { + $stylesheet .= $this->get_layout_styles( $base_style_node ); + } } if ( in_array( 'presets', $types, true ) ) { @@ -799,6 +970,7 @@ public function get_template_parts() { * @since 5.9.0 Renamed from `get_block_styles()` to `get_block_classes()` * and no longer returns preset classes. * Removed the `$setting_nodes` parameter. + * @since 6.1.0 Moved most internal logic to `get_styles_for_block()`. * * @param array $style_nodes Nodes with styles. * @return string The new stylesheet. @@ -810,56 +982,193 @@ protected function get_block_classes( $style_nodes ) { if ( null === $metadata['selector'] ) { continue; } + $block_rules .= static::get_styles_for_block( $metadata ); + } - $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); - $selector = $metadata['selector']; - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); - $declarations = static::compute_style_properties( $node, $settings ); - - // 1. Separate the ones who use the general selector - // and the ones who use the duotone selector. - $declarations_duotone = array(); - foreach ( $declarations as $index => $declaration ) { - if ( 'filter' === $declaration['name'] ) { - unset( $declarations[ $index ] ); - $declarations_duotone[] = $declaration; + return $block_rules; + } + + /** + * Get the CSS layout rules for a particular block from theme.json layout definitions. + * + * @since 6.1.0 + * + * @param array $block_metadata Metadata about the block to get styles for. + * + * @return string Layout styles for the block. + */ + protected function get_layout_styles( $block_metadata ) { + $block_rules = ''; + $block_type = null; + + // Skip outputting layout styles if explicitly disabled. + if ( current_theme_supports( 'disable-layout-styles' ) ) { + return $block_rules; + } + + if ( isset( $block_metadata['name'] ) ) { + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_metadata['name'] ); + if ( ! block_has_support( $block_type, array( '__experimentalLayout' ), false ) ) { + return $block_rules; + } + } + + $selector = isset( $block_metadata['selector'] ) ? $block_metadata['selector'] : ''; + $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; + $has_fallback_gap_support = ! $has_block_gap_support; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback gap styles support. + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + $layout_definitions = _wp_array_get( $this->theme_json, array( 'settings', 'layout', 'definitions' ), array() ); + $layout_selector_pattern = '/^[a-zA-Z0-9\-\.\ *+>:\(\)]*$/'; // Allow alphanumeric classnames, spaces, wildcard, sibling, child combinator and pseudo class selectors. + + // Gap styles will only be output if the theme has block gap support, or supports a fallback gap. + // Default layout gap styles will be skipped for themes that do not explicitly opt-in to blockGap with a `true` or `false` value. + if ( $has_block_gap_support || $has_fallback_gap_support ) { + $block_gap_value = null; + // Use a fallback gap value if block gap support is not available. + if ( ! $has_block_gap_support ) { + $block_gap_value = static::ROOT_BLOCK_SELECTOR === $selector ? '0.5em' : null; + if ( ! empty( $block_type ) ) { + $block_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), null ); } + } else { + $block_gap_value = static::get_property_value( $node, array( 'spacing', 'blockGap' ) ); } - /* - * Reset default browser margin on the root body element. - * This is set on the root selector **before** generating the ruleset - * from the `theme.json`. This is to ensure that if the `theme.json` declares - * `margin` in its `spacing` declaration for the `body` element then these - * user-generated values take precedence in the CSS cascade. - * @link https://github.com/WordPress/gutenberg/issues/36147. - */ - if ( static::ROOT_BLOCK_SELECTOR === $selector ) { - $block_rules .= 'body { margin: 0; }'; + // Support split row / column values and concatenate to a shorthand value. + if ( is_array( $block_gap_value ) ) { + if ( isset( $block_gap_value['top'] ) && isset( $block_gap_value['left'] ) ) { + $gap_row = static::get_property_value( $node, array( 'spacing', 'blockGap', 'top' ) ); + $gap_column = static::get_property_value( $node, array( 'spacing', 'blockGap', 'left' ) ); + $block_gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; + } else { + // Skip outputting gap value if not all sides are provided. + $block_gap_value = null; + } } - // 2. Generate the rules that use the general selector. - $block_rules .= static::to_ruleset( $selector, $declarations ); + // If the block should have custom gap, add the gap styles. + if ( null !== $block_gap_value && false !== $block_gap_value && '' !== $block_gap_value ) { + foreach ( $layout_definitions as $layout_definition_key => $layout_definition ) { + // Allow outputting fallback gap styles for flex layout type when block gap support isn't available. + if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key ) { + continue; + } - // 3. Generate the rules that use the duotone selector. - if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { - $selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] ); - $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone ); - } + $class_name = sanitize_title( _wp_array_get( $layout_definition, array( 'className' ), false ) ); + $spacing_rules = _wp_array_get( $layout_definition, array( 'spacingStyles' ), array() ); - if ( static::ROOT_BLOCK_SELECTOR === $selector ) { - $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; - $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; - $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + if ( + ! empty( $class_name ) && + ! empty( $spacing_rules ) + ) { + foreach ( $spacing_rules as $spacing_rule ) { + $declarations = array(); + if ( + isset( $spacing_rule['selector'] ) && + preg_match( $layout_selector_pattern, $spacing_rule['selector'] ) && + ! empty( $spacing_rule['rules'] ) + ) { + // Iterate over each of the styling rules and substitute non-string values such as `null` with the real `blockGap` value. + foreach ( $spacing_rule['rules'] as $css_property => $css_value ) { + $current_css_value = is_string( $css_value ) ? $css_value : $block_gap_value; + if ( static::is_safe_css_declaration( $css_property, $current_css_value ) ) { + $declarations[] = array( + 'name' => $css_property, + 'value' => $current_css_value, + ); + } + } - $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; - if ( $has_block_gap_support ) { - $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; - $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; + if ( ! $has_block_gap_support ) { + // For fallback gap styles, use lower specificity, to ensure styles do not unintentionally override theme styles. + $format = static::ROOT_BLOCK_SELECTOR === $selector ? ':where(.%2$s%3$s)' : ':where(%1$s.%2$s%3$s)'; + $layout_selector = sprintf( + $format, + $selector, + $class_name, + $spacing_rule['selector'] + ); + } else { + $format = static::ROOT_BLOCK_SELECTOR === $selector ? '%s .%s%s' : '%s.%s%s'; + $layout_selector = sprintf( + $format, + $selector, + $class_name, + $spacing_rule['selector'] + ); + } + $block_rules .= static::to_ruleset( $layout_selector, $declarations ); + } + } + } } } } + // Output base styles. + if ( + static::ROOT_BLOCK_SELECTOR === $selector + ) { + $valid_display_modes = array( 'block', 'flex', 'grid' ); + foreach ( $layout_definitions as $layout_definition ) { + $class_name = sanitize_title( _wp_array_get( $layout_definition, array( 'className' ), false ) ); + $base_style_rules = _wp_array_get( $layout_definition, array( 'baseStyles' ), array() ); + + if ( + ! empty( $class_name ) && + ! empty( $base_style_rules ) + ) { + // Output display mode. This requires special handling as `display` is not exposed in `safe_style_css_filter`. + if ( + ! empty( $layout_definition['displayMode'] ) && + is_string( $layout_definition['displayMode'] ) && + in_array( $layout_definition['displayMode'], $valid_display_modes, true ) + ) { + $layout_selector = sprintf( + '%s .%s', + $selector, + $class_name + ); + $block_rules .= static::to_ruleset( + $layout_selector, + array( + array( + 'name' => 'display', + 'value' => $layout_definition['displayMode'], + ), + ) + ); + } + + foreach ( $base_style_rules as $base_style_rule ) { + $declarations = array(); + + if ( + isset( $base_style_rule['selector'] ) && + preg_match( $layout_selector_pattern, $base_style_rule['selector'] ) && + ! empty( $base_style_rule['rules'] ) + ) { + foreach ( $base_style_rule['rules'] as $css_property => $css_value ) { + if ( static::is_safe_css_declaration( $css_property, $css_value ) ) { + $declarations[] = array( + 'name' => $css_property, + 'value' => $css_value, + ); + } + } + + $layout_selector = sprintf( + '%s .%s%s', + $selector, + $class_name, + $base_style_rule['selector'] + ); + $block_rules .= static::to_ruleset( $layout_selector, $declarations ); + } + } + } + } + } return $block_rules; } @@ -972,29 +1281,6 @@ static function ( $carry, $element ) { return $selector . '{' . $declaration_block . '}'; } - /** - * Function that appends a sub-selector to a existing one. - * - * Given the compounded $selector "h1, h2, h3" - * and the $to_append selector ".some-class" the result will be - * "h1.some-class, h2.some-class, h3.some-class". - * - * @since 5.8.0 - * - * @param string $selector Original selector. - * @param string $to_append Selector to append. - * @return string - */ - protected static function append_to_selector( $selector, $to_append ) { - $new_selectors = array(); - $selectors = explode( ',', $selector ); - foreach ( $selectors as $sel ) { - $new_selectors[] = $sel . $to_append; - } - - return implode( ',', $new_selectors ); - } - /** * Given a settings array, it returns the generated rulesets * for the preset classes. @@ -1312,13 +1598,17 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) { * * @since 5.8.0 * @since 5.9.0 Added the `$settings` and `$properties` parameters. - * - * @param array $styles Styles to process. - * @param array $settings Theme settings. - * @param array $properties Properties metadata. - * @return array Returns the modified $declarations. + * @since 6.1.0 Added `$theme_json`, `$selector`, and `$use_root_padding` parameters. + * + * @param array $styles Styles to process. + * @param array $settings Theme settings. + * @param array $properties Properties metadata. + * @param array $theme_json Theme JSON array. + * @param string $selector The style block selector. + * @param boolean $use_root_padding Whether to add custom properties at root level. + * @return array Returns the modified $declarations. */ - protected static function compute_style_properties( $styles, $settings = array(), $properties = null ) { + protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null, $selector = null, $use_root_padding = null ) { if ( null === $properties ) { $properties = static::PROPERTIES_METADATA; } @@ -1328,8 +1618,23 @@ protected static function compute_style_properties( $styles, $settings = array() return $declarations; } + $root_variable_duplicates = array(); + foreach ( $properties as $css_property => $value_path ) { - $value = static::get_property_value( $styles, $value_path ); + $value = static::get_property_value( $styles, $value_path, $theme_json ); + + if ( str_starts_with( $css_property, '--wp--style--root--' ) && ( static::ROOT_BLOCK_SELECTOR !== $selector || ! $use_root_padding ) ) { + continue; + } + // Root-level padding styles don't currently support strings with CSS shorthand values. + // This may change: https://github.com/WordPress/gutenberg/issues/40132. + if ( '--wp--style--root--padding' === $css_property && is_string( $value ) ) { + continue; + } + + if ( str_starts_with( $css_property, '--wp--style--root--' ) && $use_root_padding ) { + $root_variable_duplicates[] = substr( $css_property, strlen( '--wp--style--root--' ) ); + } // Look up protected properties, keyed by value path. // Skip protected properties that are explicitly set to `null`. @@ -1355,6 +1660,14 @@ protected static function compute_style_properties( $styles, $settings = array() ); } + // If a variable value is added to the root, the corresponding property should be removed. + foreach ( $root_variable_duplicates as $duplicate ) { + $discard = array_search( $duplicate, array_column( $declarations, 'name' ), true ); + if ( is_numeric( $discard ) ) { + array_splice( $declarations, $discard, 1 ); + } + } + return $declarations; } @@ -1365,20 +1678,58 @@ protected static function compute_style_properties( $styles, $settings = array() * "var:preset|color|secondary" to the form * "--wp--preset--color--secondary". * + * It also converts references to a path to the value + * stored at that location, e.g. + * { "ref": "style.color.background" } => "#fff". + * * @since 5.8.0 * @since 5.9.0 Added support for values of array type, which are returned as is. + * @since 6.1.0 Added the `$theme_json` parameter. * * @param array $styles Styles subtree. * @param array $path Which property to process. + * @param array $theme_json Theme JSON array. * @return string|array Style property value. */ - protected static function get_property_value( $styles, $path ) { - $value = _wp_array_get( $styles, $path, '' ); + protected static function get_property_value( $styles, $path, $theme_json = null ) { + $value = _wp_array_get( $styles, $path ); - if ( '' === $value || is_array( $value ) ) { + /* + * This converts references to a path to the value at that path + * where the values is an array with a "ref" key, pointing to a path. + * For example: { "ref": "style.color.background" } => "#fff". + */ + if ( is_array( $value ) && array_key_exists( 'ref', $value ) ) { + $value_path = explode( '.', $value['ref'] ); + $ref_value = _wp_array_get( $theme_json, $value_path ); + // Only use the ref value if we find anything. + if ( ! empty( $ref_value ) && is_string( $ref_value ) ) { + $value = $ref_value; + } + + if ( is_array( $ref_value ) && array_key_exists( 'ref', $ref_value ) ) { + $path_string = json_encode( $path ); + $ref_value_string = json_encode( $ref_value ); + _doing_it_wrong( + 'get_property_value', + sprintf( + /* translators: 1: theme.json, 2: Value name, 3: Value path, 4: Another value name. */ + __( 'Your %1$s file uses a dynamic value (%2$s) for the path at %3$s. However, the value at %3$s is also a dynamic value (pointing to %4$s) and pointing to another dynamic value is not supported. Please update %3$s to point directly to %4$s.' ), + 'theme.json', + $ref_value_string, + $path_string, + $ref_value['ref'] + ), + '6.1.0' + ); + } + } + + if ( is_array( $value ) ) { return $value; } + // Convert custom CSS properties. $prefix = 'var:'; $prefix_len = strlen( $prefix ); $token_in = '|'; @@ -1490,6 +1841,19 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { 'path' => array( 'styles', 'elements', $element ), 'selector' => static::ELEMENTS[ $element ], ); + + // Handle any pseudo selectors for the element. + if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { + + if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) { + $nodes[] = array( + 'path' => array( 'styles', 'elements', $element ), + 'selector' => static::append_to_selector( static::ELEMENTS[ $element ], $pseudo_selector ), + ); + } + } + } } } @@ -1498,6 +1862,51 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { return $nodes; } + $nodes = array_merge( $nodes, static::get_block_nodes( $theme_json ) ); + + /** + * Filters the list of style nodes with metadata. + * + * This allows for things like loading block CSS independently. + * + * @since 6.1.0 + * + * @param array $nodes Style nodes with metadata. + */ + return apply_filters( 'get_style_nodes', $nodes ); + } + + /** + * A public helper to get the block nodes from a theme.json file. + * + * @since 6.1.0 + * + * @return array The block nodes in theme.json. + */ + public function get_styles_block_nodes() { + return static::get_block_nodes( $this->theme_json ); + } + + /** + * An internal method to get the block nodes from a theme.json file. + * + * @since 6.1.0 + * + * @param array $theme_json The theme.json converted to an array. + * @return array The block nodes in theme.json. + */ + private static function get_block_nodes( $theme_json ) { + $selectors = static::get_blocks_metadata(); + $nodes = array(); + if ( ! isset( $theme_json['styles'] ) ) { + return $nodes; + } + + // Blocks. + if ( ! isset( $theme_json['styles']['blocks'] ) ) { + return $nodes; + } + foreach ( $theme_json['styles']['blocks'] as $name => $node ) { $selector = null; if ( isset( $selectors[ $name ]['selector'] ) ) { @@ -1509,10 +1918,17 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { $duotone_selector = $selectors[ $name ]['duotone']; } + $feature_selectors = null; + if ( isset( $selectors[ $name ]['features'] ) ) { + $feature_selectors = $selectors[ $name ]['features']; + } + $nodes[] = array( + 'name' => $name, 'path' => array( 'styles', 'blocks', $name ), 'selector' => $selector, 'duotone' => $duotone_selector, + 'features' => $feature_selectors, ); if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'] ) ) { @@ -1521,6 +1937,18 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), 'selector' => $selectors[ $name ]['elements'][ $element ], ); + + // Handle any pseudo selectors for the element. + if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { + if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) { + $nodes[] = array( + 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), + 'selector' => static::append_to_selector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector ), + ); + } + } + } } } } @@ -1528,6 +1956,213 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { return $nodes; } + /** + * Gets the CSS rules for a particular block from theme.json. + * + * @since 6.1.0 + * + * @param array $block_metadata Metadata about the block to get styles for. + * + * @return string Styles for the block. + */ + public function get_styles_for_block( $block_metadata ) { + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; + $selector = $block_metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + + /* + * Process style declarations for block support features the current + * block contains selectors for. Values for a feature with a custom + * selector are filtered from the theme.json node before it is + * processed as normal. + */ + $feature_declarations = array(); + + if ( ! empty( $block_metadata['features'] ) ) { + foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) { + if ( ! empty( $node[ $feature_name ] ) ) { + // Create temporary node containing only the feature data + // to leverage existing `compute_style_properties` function. + $feature = array( $feature_name => $node[ $feature_name ] ); + // Generate the feature's declarations only. + $new_feature_declarations = static::compute_style_properties( $feature, $settings, null, $this->theme_json ); + + // Merge new declarations with any that already exist for + // the feature selector. This may occur when multiple block + // support features use the same custom selector. + if ( isset( $feature_declarations[ $feature_selector ] ) ) { + $feature_declarations[ $feature_selector ] = array_merge( $feature_declarations[ $feature_selector ], $new_feature_declarations ); + } else { + $feature_declarations[ $feature_selector ] = $new_feature_declarations; + } + + // Remove the feature from the block's node now the + // styles will be included under the feature level selector. + unset( $node[ $feature_name ] ); + } + } + } + + /* + * Get a reference to element name from path. + * $block_metadata['path'] = array( 'styles','elements','link' ); + * Make sure that $block_metadata['path'] describes an element node, like [ 'styles', 'element', 'link' ]. + * Skip non-element paths like just ['styles']. + */ + $is_processing_element = in_array( 'elements', $block_metadata['path'], true ); + + $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null; + + $element_pseudo_allowed = array(); + + if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ]; + } + + /* + * Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). + * This also resets the array keys. + */ + $pseudo_matches = array_values( + array_filter( + $element_pseudo_allowed, + function( $pseudo_selector ) use ( $selector ) { + return str_contains( $selector, $pseudo_selector ); + } + ) + ); + + $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null; + + /* + * If the current selector is a pseudo selector that's defined in the allow list for the current + * element then compute the style properties for it. + * Otherwise just compute the styles for the default selector as normal. + */ + if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && + array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) + && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) + ) { + $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json, $selector, $use_root_padding ); + } else { + $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding ); + } + + $block_rules = ''; + + /* + * 1. Separate the declarations that use the general selector + * from the ones using the duotone selector. + */ + $declarations_duotone = array(); + foreach ( $declarations as $index => $declaration ) { + if ( 'filter' === $declaration['name'] ) { + unset( $declarations[ $index ] ); + $declarations_duotone[] = $declaration; + } + } + + // 2. Generate and append the rules that use the general selector. + $block_rules .= static::to_ruleset( $selector, $declarations ); + + // 3. Generate and append the rules that use the duotone selector. + if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { + $selector_duotone = static::scope_selector( $block_metadata['selector'], $block_metadata['duotone'] ); + $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone ); + } + + // 4. Generate Layout block gap styles. + if ( + static::ROOT_BLOCK_SELECTOR !== $selector && + ! empty( $block_metadata['name'] ) + ) { + $block_rules .= $this->get_layout_styles( $block_metadata ); + } + + // 5. Generate and append the feature level rulesets. + foreach ( $feature_declarations as $feature_selector => $individual_feature_declarations ) { + $block_rules .= static::to_ruleset( $feature_selector, $individual_feature_declarations ); + } + + return $block_rules; + } + + /** + * Outputs the CSS for layout rules on the root. + * + * @since 6.1.0 + * + * @param string $selector The root node selector. + * @param array $block_metadata The metadata for the root block. + * @return string The additional root rules CSS. + */ + public function get_root_layout_rules( $selector, $block_metadata ) { + $css = ''; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; + + /* + * Reset default browser margin on the root body element. + * This is set on the root selector **before** generating the ruleset + * from the `theme.json`. This is to ensure that if the `theme.json` declares + * `margin` in its `spacing` declaration for the `body` element then these + * user-generated values take precedence in the CSS cascade. + * @link https://github.com/WordPress/gutenberg/issues/36147. + */ + $css .= 'body { margin: 0;'; + + /* + * If there are content and wide widths in theme.json, output them + * as custom properties on the body element so all blocks can use them. + */ + if ( isset( $settings['layout']['contentSize'] ) || isset( $settings['layout']['wideSize'] ) ) { + $content_size = isset( $settings['layout']['contentSize'] ) ? $settings['layout']['contentSize'] : $settings['layout']['wideSize']; + $content_size = static::is_safe_css_declaration( 'max-width', $content_size ) ? $content_size : 'initial'; + $wide_size = isset( $settings['layout']['wideSize'] ) ? $settings['layout']['wideSize'] : $settings['layout']['contentSize']; + $wide_size = static::is_safe_css_declaration( 'max-width', $wide_size ) ? $wide_size : 'initial'; + $css .= '--wp--style--global--content-size: ' . $content_size . ';'; + $css .= '--wp--style--global--wide-size: ' . $wide_size . ';'; + } + + $css .= ' }'; + + if ( $use_root_padding ) { + // Top and bottom padding are applied to the outer block container. + $css .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; + // Right and left padding are applied to the first container with `.has-global-padding` class. + $css .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + // Nested containers with `.has-global-padding` class do not get padding. + $css .= '.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }'; + // Alignfull children of the container with left and right padding have negative margins so they can still be full width. + $css .= '.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }'; + // The above rule is negated for alignfull children of nested containers. + $css .= '.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }'; + // Some of the children of alignfull blocks without content width should also get padding: text blocks and non-alignfull container blocks. + $css .= '.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + // The above rule also has to be negated for blocks inside nested `.has-global-padding` blocks. + $css .= '.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }'; + } + + $css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; + $css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; + $css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $block_gap_value = _wp_array_get( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ), '0.5em' ); + $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; + if ( $has_block_gap_support ) { + $block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) ); + $css .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; + $css .= ".wp-site-blocks > * + * { margin-block-start: $block_gap_value; }"; + + // For backwards compatibility, ensure the legacy block gap CSS variable is still available. + $css .= "$selector { --wp--style--block-gap: $block_gap_value; }"; + } + $css .= $this->get_layout_styles( $block_metadata ); + + return $css; + } + /** * For metadata values that can either be booleans or paths to booleans, gets the value. * @@ -1837,10 +2472,12 @@ public static function remove_insecure_properties( $theme_json ) { $valid_block_names = array_keys( static::get_blocks_metadata() ); $valid_element_names = array_keys( static::ELEMENTS ); - $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names ); + + $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names ); $blocks_metadata = static::get_blocks_metadata(); $style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata ); + foreach ( $style_nodes as $metadata ) { $input = _wp_array_get( $theme_json, $metadata['path'], array() ); if ( empty( $input ) ) { @@ -1848,6 +2485,25 @@ public static function remove_insecure_properties( $theme_json ) { } $output = static::remove_insecure_styles( $input ); + + /* + * Get a reference to element name from path. + * $metadata['path'] = array( 'styles', 'elements', 'link' ); + */ + $current_element = $metadata['path'][ count( $metadata['path'] ) - 1 ]; + + /* + * $output is stripped of pseudo selectors. Re-add and process them + * or insecure styles here. + */ + if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) { + if ( isset( $input[ $pseudo_selector ] ) ) { + $output[ $pseudo_selector ] = static::remove_insecure_styles( $input[ $pseudo_selector ] ); + } + } + } + if ( ! empty( $output ) ) { _wp_array_set( $sanitized, $metadata['path'], $output ); } diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index 55a9359a139a7..84e7d1f5718ae 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -6,6 +6,7 @@ * @subpackage Theme * @since 3.4.0 */ +#[AllowDynamicProperties] final class WP_Theme implements ArrayAccess { /** diff --git a/src/wp-includes/class-wp-user-query.php b/src/wp-includes/class-wp-user-query.php index 9b9087dcebde8..330882494e3b9 100644 --- a/src/wp-includes/class-wp-user-query.php +++ b/src/wp-includes/class-wp-user-query.php @@ -14,6 +14,7 @@ * * @see WP_User_Query::prepare_query() for information on accepted arguments. */ +#[AllowDynamicProperties] class WP_User_Query { /** @@ -140,8 +141,8 @@ public static function fill_query_vars( $args ) { * @since 5.3.0 Introduced the 'meta_type_key' parameter. * @since 5.9.0 Added 'capability', 'capability__in', and 'capability__not_in' parameters. * - * @global wpdb $wpdb WordPress database abstraction object. - * @global int $blog_id + * @global wpdb $wpdb WordPress database abstraction object. + * @global WP_Roles $wp_roles WordPress role management object. * * @param string|array $query { * Optional. Array or string of Query parameters. @@ -256,7 +257,7 @@ public static function fill_query_vars( $args ) { * } */ public function prepare_query( $query = array() ) { - global $wpdb; + global $wpdb, $wp_roles; if ( empty( $this->query_vars ) || ! empty( $query ) ) { $this->query_limit = null; @@ -448,8 +449,6 @@ public function prepare_query( $query = array() ) { $available_roles = array(); if ( ! empty( $qv['capability'] ) || ! empty( $qv['capability__in'] ) || ! empty( $qv['capability__not_in'] ) ) { - global $wp_roles; - $wp_roles->for_site( $blog_id ); $available_roles = $wp_roles->roles; } diff --git a/src/wp-includes/class-wp-user-request.php b/src/wp-includes/class-wp-user-request.php index 7e445cfa63511..8c66dcdf8189e 100644 --- a/src/wp-includes/class-wp-user-request.php +++ b/src/wp-includes/class-wp-user-request.php @@ -6,6 +6,7 @@ * * @since 4.9.6 */ +#[AllowDynamicProperties] final class WP_User_Request { /** * Request ID. diff --git a/src/wp-includes/class-wp-user.php b/src/wp-includes/class-wp-user.php index 45878986f76e2..b190960009575 100644 --- a/src/wp-includes/class-wp-user.php +++ b/src/wp-includes/class-wp-user.php @@ -36,6 +36,7 @@ * @property string $syntax_highlighting * @property string $use_ssl */ +#[AllowDynamicProperties] class WP_User { /** * User data container. diff --git a/src/wp-includes/class-wp-walker.php b/src/wp-includes/class-wp-walker.php index d47d25261f0dc..f7f4715ed1250 100644 --- a/src/wp-includes/class-wp-walker.php +++ b/src/wp-includes/class-wp-walker.php @@ -11,6 +11,7 @@ * @package WordPress * @abstract */ +#[AllowDynamicProperties] class Walker { /** * What the class handles. diff --git a/src/wp-includes/class-wp-widget-factory.php b/src/wp-includes/class-wp-widget-factory.php index a7554846a22e6..ed719b9d4d7a1 100644 --- a/src/wp-includes/class-wp-widget-factory.php +++ b/src/wp-includes/class-wp-widget-factory.php @@ -13,6 +13,7 @@ * @since 2.8.0 * @since 4.4.0 Moved to its own file from wp-includes/widgets.php */ +#[AllowDynamicProperties] class WP_Widget_Factory { /** diff --git a/src/wp-includes/class-wp-widget.php b/src/wp-includes/class-wp-widget.php index 086e9e9ffbf40..79a1efe1bf93f 100644 --- a/src/wp-includes/class-wp-widget.php +++ b/src/wp-includes/class-wp-widget.php @@ -17,6 +17,7 @@ * @since 2.8.0 * @since 4.4.0 Moved to its own file from wp-includes/widgets.php */ +#[AllowDynamicProperties] class WP_Widget { /** diff --git a/src/wp-includes/class-wp-xmlrpc-server.php b/src/wp-includes/class-wp-xmlrpc-server.php index f48f4a01f51ba..6e3ee0a13a33f 100644 --- a/src/wp-includes/class-wp-xmlrpc-server.php +++ b/src/wp-includes/class-wp-xmlrpc-server.php @@ -20,6 +20,7 @@ * * @see IXR_Server */ +#[AllowDynamicProperties] class wp_xmlrpc_server extends IXR_Server { /** * Methods. diff --git a/src/wp-includes/class-wp.php b/src/wp-includes/class-wp.php index ca9399e4e54b5..8d6782054595d 100644 --- a/src/wp-includes/class-wp.php +++ b/src/wp-includes/class-wp.php @@ -5,6 +5,7 @@ * @package WordPress * @since 2.0.0 */ +#[AllowDynamicProperties] class WP { /** * Public query variables. diff --git a/src/wp-includes/class-wpdb.php b/src/wp-includes/class-wpdb.php index 81a43900f5b52..e81b9caf790c1 100644 --- a/src/wp-includes/class-wpdb.php +++ b/src/wp-includes/class-wpdb.php @@ -51,6 +51,7 @@ * * @since 0.71 */ +#[AllowDynamicProperties] class wpdb { /** diff --git a/src/wp-includes/class.wp-dependencies.php b/src/wp-includes/class.wp-dependencies.php index c527715a63af9..1deb9a41fbeaa 100644 --- a/src/wp-includes/class.wp-dependencies.php +++ b/src/wp-includes/class.wp-dependencies.php @@ -15,6 +15,7 @@ * * @see _WP_Dependency */ +#[AllowDynamicProperties] class WP_Dependencies { /** * An array of all registered dependencies keyed by handle. diff --git a/src/wp-includes/class.wp-scripts.php b/src/wp-includes/class.wp-scripts.php index 649f086d60970..f20964ead4f72 100644 --- a/src/wp-includes/class.wp-scripts.php +++ b/src/wp-includes/class.wp-scripts.php @@ -501,12 +501,17 @@ public function localize( $handle, $object_name, $l10n ) { ), '5.7.0' ); + + if ( false === $l10n ) { + // This should really not be needed, but is necessary for backward compatibility. + $l10n = array( $l10n ); + } } if ( is_string( $l10n ) ) { $l10n = html_entity_decode( $l10n, ENT_QUOTES, 'UTF-8' ); - } else { - foreach ( (array) $l10n as $key => $value ) { + } elseif ( is_array( $l10n ) ) { + foreach ( $l10n as $key => $value ) { if ( ! is_scalar( $value ) ) { continue; } diff --git a/src/wp-includes/comment-template.php b/src/wp-includes/comment-template.php index f4cf72c258fbd..6a27a67d929ab 100644 --- a/src/wp-includes/comment-template.php +++ b/src/wp-includes/comment-template.php @@ -1738,7 +1738,7 @@ function get_comment_reply_link( $args = array(), $comment = null, $post = null $data_attribute_string = ''; foreach ( $data_attributes as $name => $value ) { - $data_attribute_string .= " data-${name}=\"" . esc_attr( $value ) . '"'; + $data_attribute_string .= " data-{$name}=\"" . esc_attr( $value ) . '"'; } $data_attribute_string = trim( $data_attribute_string ); diff --git a/src/wp-includes/customize/class-wp-customize-partial.php b/src/wp-includes/customize/class-wp-customize-partial.php index f75ac4394590d..06502bec115e8 100644 --- a/src/wp-includes/customize/class-wp-customize-partial.php +++ b/src/wp-includes/customize/class-wp-customize-partial.php @@ -16,6 +16,7 @@ * * @since 4.5.0 */ +#[AllowDynamicProperties] class WP_Customize_Partial { /** diff --git a/src/wp-includes/customize/class-wp-customize-selective-refresh.php b/src/wp-includes/customize/class-wp-customize-selective-refresh.php index e5e3bcbba542d..6119e68944bc9 100644 --- a/src/wp-includes/customize/class-wp-customize-selective-refresh.php +++ b/src/wp-includes/customize/class-wp-customize-selective-refresh.php @@ -12,6 +12,7 @@ * * @since 4.5.0 */ +#[AllowDynamicProperties] final class WP_Customize_Selective_Refresh { /** diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index bf76a5d5e1f67..f85ac884a4957 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -575,6 +575,10 @@ add_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' ); add_action( 'wp_footer', 'wp_enqueue_global_styles', 1 ); +// Block supports, and other styles parsed and stored in the Style Engine. +add_action( 'wp_enqueue_scripts', 'wp_enqueue_stored_styles' ); +add_action( 'wp_footer', 'wp_enqueue_stored_styles', 1 ); + // SVG filters like duotone have to be loaded at the beginning of the body in both admin and the front-end. add_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' ); add_action( 'in_admin_header', 'wp_global_styles_render_svg_filters' ); diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 8841519b64240..0a3d0f30924dc 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -3654,7 +3654,7 @@ function post_permalink( $post = 0 ) { * @param string|bool $file_path Optional. File path to write request to. Default false. * @param int $red Optional. The number of Redirects followed, Upon 5 being hit, * returns false. Default 1. - * @return bool|string False on failure and string of headers if HEAD request. + * @return \Requests_Utility_CaseInsensitiveDictionary|false Headers on success, false on failure. */ function wp_get_http( $url, $file_path = false, $red = 1 ) { _deprecated_function( __FUNCTION__, '4.4.0', 'WP_Http' ); @@ -4442,3 +4442,17 @@ function _get_path_to_translation_from_lang_dir( $domain ) { return false; } + +/** + * Allows multiple block styles. + * + * @since 5.9.0 + * @deprecated 6.1.0 + * + * @param array $metadata Metadata for registering a block type. + * @return array Metadata for registering a block type. + */ + function _wp_multiple_block_styles( $metadata ) { + _deprecated_function( __FUNCTION__, '6.1.0' ); + return $metadata; +} diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 946853c361b73..74f421f862c99 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -978,7 +978,7 @@ function do_enclose( $content, $post ) { * * @param string $url URL to retrieve HTTP headers from. * @param bool $deprecated Not Used. - * @return string|false Headers on success, false on failure. + * @return \Requests_Utility_CaseInsensitiveDictionary|false Headers on success, false on failure. */ function wp_get_http_headers( $url, $deprecated = false ) { if ( ! empty( $deprecated ) ) { @@ -5261,7 +5261,7 @@ function wp_widgets_add_menu() { } $menu_name = __( 'Widgets' ); - if ( wp_is_block_theme() ) { + if ( wp_is_block_theme() || current_theme_supports( 'block-template-parts' ) ) { $submenu['themes.php'][] = array( $menu_name, 'edit_theme_options', 'widgets.php' ); } else { $submenu['themes.php'][7] = array( $menu_name, 'edit_theme_options', 'widgets.php' ); @@ -6033,7 +6033,7 @@ function wp_guess_url() { // The request is for the admin. if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) { - $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] ); + $path = preg_replace( '#/(wp-admin/?.*|wp-login\.php.*)#i', '', $_SERVER['REQUEST_URI'] ); // The request is for a file in ABSPATH. } elseif ( $script_filename_dir . '/' === $abspath_fix ) { diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php index 444a2dcddf1ae..f53934966e5ae 100644 --- a/src/wp-includes/general-template.php +++ b/src/wp-includes/general-template.php @@ -3106,7 +3106,12 @@ function feed_links( $args = array() ) { * @param bool $show Whether to display the posts feed link. Default true. */ if ( apply_filters( 'feed_links_show_posts_feed', true ) ) { - echo '\n"; + printf( + '' . "\n", + feed_content_type(), + esc_attr( sprintf( $args['feedtitle'], get_bloginfo( 'name' ), $args['separator'] ) ), + esc_url( get_feed_link() ) + ); } /** @@ -3117,7 +3122,12 @@ function feed_links( $args = array() ) { * @param bool $show Whether to display the comments feed link. Default true. */ if ( apply_filters( 'feed_links_show_comments_feed', true ) ) { - echo '\n"; + printf( + '' . "\n", + feed_content_type(), + esc_attr( sprintf( $args['comstitle'], get_bloginfo( 'name' ), $args['separator'] ) ), + esc_url( get_feed_link( 'comments_' . get_default_feed() ) ) + ); } } @@ -3157,8 +3167,29 @@ function feed_links_extra( $args = array() ) { /** This filter is documented in wp-includes/general-template.php */ $show_comments_feed = apply_filters( 'feed_links_show_comments_feed', true ); - if ( $show_comments_feed && ( comments_open() || pings_open() || $post->comment_count > 0 ) ) { - $title = sprintf( $args['singletitle'], get_bloginfo( 'name' ), $args['separator'], the_title_attribute( array( 'echo' => false ) ) ); + /** + * Filters whether to display the post comments feed link. + * + * This filter allows to enable or disable the feed link for a singular post + * in a way that is independent of {@see 'feed_links_show_comments_feed'} + * (which controls the global comments feed). The result of that filter + * is accepted as a parameter. + * + * @since 6.1.0 + * + * @param bool $show_comments_feed Whether to display the post comments feed link. Defaults to + * the {@see 'feed_links_show_comments_feed'} filter result. + */ + $show_post_comments_feed = apply_filters( 'feed_links_extra_show_post_comments_feed', $show_comments_feed ); + + if ( $show_post_comments_feed && ( comments_open() || pings_open() || $post->comment_count > 0 ) ) { + $title = sprintf( + $args['singletitle'], + get_bloginfo( 'name' ), + $args['separator'], + the_title_attribute( array( 'echo' => false ) ) + ); + $feed_link = get_post_comments_feed_link( $post->ID ); if ( $feed_link ) { @@ -3166,48 +3197,159 @@ function feed_links_extra( $args = array() ) { } } } elseif ( is_post_type_archive() ) { - $post_type = get_query_var( 'post_type' ); - if ( is_array( $post_type ) ) { - $post_type = reset( $post_type ); - } + /** + * Filters whether to display the post type archive feed link. + * + * @since 6.1.0 + * + * @param bool $show Whether to display the post type archive feed link. Default true. + */ + $show_post_type_archive_feed = apply_filters( 'feed_links_extra_show_post_type_archive_feed', true ); + + if ( $show_post_type_archive_feed ) { + $post_type = get_query_var( 'post_type' ); + + if ( is_array( $post_type ) ) { + $post_type = reset( $post_type ); + } + + $post_type_obj = get_post_type_object( $post_type ); - $post_type_obj = get_post_type_object( $post_type ); - $title = sprintf( $args['posttypetitle'], get_bloginfo( 'name' ), $args['separator'], $post_type_obj->labels->name ); - $href = get_post_type_archive_feed_link( $post_type_obj->name ); + $title = sprintf( + $args['posttypetitle'], + get_bloginfo( 'name' ), + $args['separator'], + $post_type_obj->labels->name + ); + + $href = get_post_type_archive_feed_link( $post_type_obj->name ); + } } elseif ( is_category() ) { - $term = get_queried_object(); + /** + * Filters whether to display the category feed link. + * + * @since 6.1.0 + * + * @param bool $show Whether to display the category feed link. Default true. + */ + $show_category_feed = apply_filters( 'feed_links_extra_show_category_feed', true ); - if ( $term ) { - $title = sprintf( $args['cattitle'], get_bloginfo( 'name' ), $args['separator'], $term->name ); - $href = get_category_feed_link( $term->term_id ); + if ( $show_category_feed ) { + $term = get_queried_object(); + + if ( $term ) { + $title = sprintf( + $args['cattitle'], + get_bloginfo( 'name' ), + $args['separator'], + $term->name + ); + + $href = get_category_feed_link( $term->term_id ); + } } } elseif ( is_tag() ) { - $term = get_queried_object(); + /** + * Filters whether to display the tag feed link. + * + * @since 6.1.0 + * + * @param bool $show Whether to display the tag feed link. Default true. + */ + $show_tag_feed = apply_filters( 'feed_links_extra_show_tag_feed', true ); - if ( $term ) { - $title = sprintf( $args['tagtitle'], get_bloginfo( 'name' ), $args['separator'], $term->name ); - $href = get_tag_feed_link( $term->term_id ); + if ( $show_tag_feed ) { + $term = get_queried_object(); + + if ( $term ) { + $title = sprintf( + $args['tagtitle'], + get_bloginfo( 'name' ), + $args['separator'], + $term->name + ); + + $href = get_tag_feed_link( $term->term_id ); + } } } elseif ( is_tax() ) { - $term = get_queried_object(); + /** + * Filters whether to display the custom taxonomy feed link. + * + * @since 6.1.0 + * + * @param bool $show Whether to display the custom taxonomy feed link. Default true. + */ + $show_tax_feed = apply_filters( 'feed_links_extra_show_tax_feed', true ); - if ( $term ) { - $tax = get_taxonomy( $term->taxonomy ); - $title = sprintf( $args['taxtitle'], get_bloginfo( 'name' ), $args['separator'], $term->name, $tax->labels->singular_name ); - $href = get_term_feed_link( $term->term_id, $term->taxonomy ); + if ( $show_tax_feed ) { + $term = get_queried_object(); + + if ( $term ) { + $tax = get_taxonomy( $term->taxonomy ); + + $title = sprintf( + $args['taxtitle'], + get_bloginfo( 'name' ), + $args['separator'], + $term->name, + $tax->labels->singular_name + ); + + $href = get_term_feed_link( $term->term_id, $term->taxonomy ); + } } } elseif ( is_author() ) { - $author_id = (int) get_query_var( 'author' ); + /** + * Filters whether to display the author feed link. + * + * @since 6.1.0 + * + * @param bool $show Whether to display the author feed link. Default true. + */ + $show_author_feed = apply_filters( 'feed_links_extra_show_author_feed', true ); + + if ( $show_author_feed ) { + $author_id = (int) get_query_var( 'author' ); + + $title = sprintf( + $args['authortitle'], + get_bloginfo( 'name' ), + $args['separator'], + get_the_author_meta( 'display_name', $author_id ) + ); - $title = sprintf( $args['authortitle'], get_bloginfo( 'name' ), $args['separator'], get_the_author_meta( 'display_name', $author_id ) ); - $href = get_author_feed_link( $author_id ); + $href = get_author_feed_link( $author_id ); + } } elseif ( is_search() ) { - $title = sprintf( $args['searchtitle'], get_bloginfo( 'name' ), $args['separator'], get_search_query( false ) ); - $href = get_search_feed_link(); + /** + * Filters whether to display the search results feed link. + * + * @since 6.1.0 + * + * @param bool $show Whether to display the search results feed link. Default true. + */ + $show_search_feed = apply_filters( 'feed_links_extra_show_search_feed', true ); + + if ( $show_search_feed ) { + $title = sprintf( + $args['searchtitle'], + get_bloginfo( 'name' ), + $args['separator'], + get_search_query( false ) + ); + + $href = get_search_feed_link(); + } } if ( isset( $title ) && isset( $href ) ) { - echo '' . "\n"; + printf( + '' . "\n", + feed_content_type(), + esc_attr( $title ), + esc_url( $href ) + ); } } @@ -3218,7 +3360,10 @@ function feed_links_extra( $args = array() ) { * @since 2.0.0 */ function rsd_link() { - echo '' . "\n"; + printf( + '' . "\n", + esc_url( site_url( 'xmlrpc.php?rsd', 'rpc' ) ) + ); } /** @@ -3228,7 +3373,10 @@ function rsd_link() { * @since 2.3.1 */ function wlwmanifest_link() { - echo ' ' . "\n"; + printf( + '' . "\n", + includes_url( 'wlwmanifest.xml' ) + ); } /** @@ -5024,9 +5172,16 @@ function __checked_selected_helper( $helper, $current, $echo, $type ) { // phpcs function wp_required_field_indicator() { /* translators: Character to identify required form fields. */ $glyph = __( '*' ); - $indicator = ''; + $indicator = '' . esc_html( $glyph ) . ''; - return $indicator; + /** + * Filters the markup for a visual indicator of required form fields. + * + * @since 6.1.0 + * + * @param string $indicator Markup for the indicator element. + */ + return apply_filters( 'wp_required_field_indicator', $indicator ); } /** @@ -5038,12 +5193,19 @@ function wp_required_field_indicator() { */ function wp_required_field_message() { $message = sprintf( - '', + '%s', /* translators: %s: Asterisk symbol (*). */ sprintf( __( 'Required fields are marked %s' ), wp_required_field_indicator() ) ); - return $message; + /** + * Filters the message to explain required form fields. + * + * @since 6.1.0 + * + * @param string $message Message text and glyph wrapped in a `span` tag. + */ + return apply_filters( 'wp_required_field_message', $message ); } /** diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index efc2edcaaa354..1187837ed651f 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -107,7 +107,7 @@ function wp_get_global_stylesheet( $types = array() ) { $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support(); if ( empty( $types ) && ! $supports_theme_json ) { - $types = array( 'variables', 'presets' ); + $types = array( 'variables', 'presets', 'base-layout-styles' ); } elseif ( empty( $types ) ) { $types = array( 'variables', 'styles', 'presets' ); } @@ -192,3 +192,45 @@ function wp_get_global_styles_svg_filters() { return $svgs; } + +/** + * Adds global style rules to the inline style for each block. + * + * @since 6.1.0 + */ +function wp_add_global_styles_for_blocks() { + $tree = WP_Theme_JSON_Resolver::get_merged_data(); + $block_nodes = $tree->get_styles_block_nodes(); + foreach ( $block_nodes as $metadata ) { + $block_css = $tree->get_styles_for_block( $metadata ); + + if ( isset( $metadata['name'] ) ) { + $block_name = str_replace( 'core/', '', $metadata['name'] ); + /* + * These block styles are added on block_render. + * This hooks inline CSS to them so that they are loaded conditionally + * based on whether or not the block is used on the page. + */ + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } + + // The likes of block element styles from theme.json do not have $metadata['name'] set. + if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) { + $result = array_values( + array_filter( + $metadata['path'], + function ( $item ) { + if ( strpos( $item, 'core/' ) !== false ) { + return true; + } + return false; + } + ) + ); + if ( isset( $result[0] ) ) { + $block_name = str_replace( 'core/', '', $result[0] ); + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } + } + } +} diff --git a/src/wp-includes/http.php b/src/wp-includes/http.php index 0ef297921db91..f77d9a69a7b86 100644 --- a/src/wp-includes/http.php +++ b/src/wp-includes/http.php @@ -205,7 +205,8 @@ function wp_remote_head( $url, $args = array() ) { * @see \Requests_Utility_CaseInsensitiveDictionary * * @param array|WP_Error $response HTTP response. - * @return array|\Requests_Utility_CaseInsensitiveDictionary The headers of the response. Empty array if incorrect parameter given. + * @return \Requests_Utility_CaseInsensitiveDictionary|array The headers of the response, or empty array + * if incorrect parameter given. */ function wp_remote_retrieve_headers( $response ) { if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) { @@ -245,7 +246,7 @@ function wp_remote_retrieve_header( $response, $header ) { * @since 2.7.0 * * @param array|WP_Error $response HTTP response. - * @return int|string The response code as an integer. Empty string on incorrect parameter given. + * @return int|string The response code as an integer. Empty string if incorrect parameter given. */ function wp_remote_retrieve_response_code( $response ) { if ( is_wp_error( $response ) || ! isset( $response['response'] ) || ! is_array( $response['response'] ) ) { @@ -263,7 +264,7 @@ function wp_remote_retrieve_response_code( $response ) { * @since 2.7.0 * * @param array|WP_Error $response HTTP response. - * @return string The response message. Empty string on incorrect parameter given. + * @return string The response message. Empty string if incorrect parameter given. */ function wp_remote_retrieve_response_message( $response ) { if ( is_wp_error( $response ) || ! isset( $response['response'] ) || ! is_array( $response['response'] ) ) { @@ -295,7 +296,8 @@ function wp_remote_retrieve_body( $response ) { * @since 4.4.0 * * @param array|WP_Error $response HTTP response. - * @return WP_Http_Cookie[] An array of `WP_Http_Cookie` objects from the response. Empty array if there are none, or the response is a WP_Error. + * @return WP_Http_Cookie[] An array of `WP_Http_Cookie` objects from the response. + * Empty array if there are none, or the response is a WP_Error. */ function wp_remote_retrieve_cookies( $response ) { if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) { @@ -312,7 +314,8 @@ function wp_remote_retrieve_cookies( $response ) { * * @param array|WP_Error $response HTTP response. * @param string $name The name of the cookie to retrieve. - * @return WP_Http_Cookie|string The `WP_Http_Cookie` object. Empty string if the cookie isn't present in the response. + * @return WP_Http_Cookie|string The `WP_Http_Cookie` object, or empty string + * if the cookie is not present in the response. */ function wp_remote_retrieve_cookie( $response, $name ) { $cookies = wp_remote_retrieve_cookies( $response ); @@ -337,7 +340,8 @@ function wp_remote_retrieve_cookie( $response, $name ) { * * @param array|WP_Error $response HTTP response. * @param string $name The name of the cookie to retrieve. - * @return string The value of the cookie. Empty string if the cookie isn't present in the response. + * @return string The value of the cookie, or empty string + * if the cookie is not present in the response. */ function wp_remote_retrieve_cookie_value( $response, $name ) { $cookie = wp_remote_retrieve_cookie( $response, $name ); diff --git a/src/wp-includes/kses.php b/src/wp-includes/kses.php index 2be0b5e14c3cf..7776de59d55d6 100644 --- a/src/wp-includes/kses.php +++ b/src/wp-includes/kses.php @@ -2229,7 +2229,7 @@ function kses_init() { * @since 5.7.1 Added support for `object-position`. * @since 5.8.0 Added support for `calc()` and `var()` values. * @since 6.1.0 Added support for `min()`, `max()`, `minmax()`, `clamp()`, - * and nested `var()` values. + * nested `var()` values, and assigning values to CSS variables. * Added support for `gap`, `column-gap`, `row-gap`, and `flex-wrap`. * Extended `margin-*` and `padding-*` support for logical properties. * @@ -2391,6 +2391,9 @@ function safecss_filter_attr( $css, $deprecated = '' ) { 'object-position', 'overflow', 'vertical-align', + + // Custom CSS properties. + '--*', ) ); @@ -2436,6 +2439,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { $found = false; $url_attr = false; $gradient_attr = false; + $is_custom_var = false; if ( strpos( $css_item, ':' ) === false ) { $found = true; @@ -2443,11 +2447,23 @@ function safecss_filter_attr( $css, $deprecated = '' ) { $parts = explode( ':', $css_item, 2 ); $css_selector = trim( $parts[0] ); + // Allow assigning values to CSS variables. + if ( in_array( '--*', $allowed_attr, true ) && preg_match( '/^--[a-zA-Z0-9-_]+$/', $css_selector ) ) { + $allowed_attr[] = $css_selector; + $is_custom_var = true; + } + if ( in_array( $css_selector, $allowed_attr, true ) ) { $found = true; $url_attr = in_array( $css_selector, $css_url_data_types, true ); $gradient_attr = in_array( $css_selector, $css_gradient_data_types, true ); } + + if ( $is_custom_var ) { + $css_value = trim( $parts[1] ); + $url_attr = str_starts_with( $css_value, 'url(' ); + $gradient_attr = str_contains( $css_value, '-gradient(' ); + } } if ( $found && $url_attr ) { diff --git a/src/wp-includes/link-template.php b/src/wp-includes/link-template.php index 17327426547d2..de9988be1f319 100644 --- a/src/wp-includes/link-template.php +++ b/src/wp-includes/link-template.php @@ -2870,6 +2870,22 @@ function get_the_posts_pagination( $args = array() ) { ) ); + /** + * Filters the arguments for posts pagination links. + * + * @since 6.1.0 + * + * @param array $args { + * Optional. Default pagination arguments, see paginate_links(). + * + * @type string $screen_reader_text Screen reader text for navigation element. + * Default 'Posts navigation'. + * @type string $aria_label ARIA label text for the nav element. Default 'Posts'. + * @type string $class Custom class for the nav element. Default 'pagination'. + * } + */ + $args = apply_filters( 'the_posts_pagination_args', $args ); + // Make sure we get a string back. Plain is the next best thing. if ( isset( $args['type'] ) && 'array' === $args['type'] ) { $args['type'] = 'plain'; diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index caf8d247f5f11..86775d893acef 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -7,7 +7,7 @@ */ /** - * Retrieve additional image sizes. + * Retrieves additional image sizes. * * @since 4.7.0 * @@ -26,7 +26,7 @@ function wp_get_additional_image_sizes() { } /** - * Scale down the default size of an image. + * Scales down the default size of an image. * * This is so that the image is a better fit for the editor and theme. * @@ -136,7 +136,7 @@ function image_constrain_size_for_editor( $width, $height, $size = 'medium', $co } /** - * Retrieve width and height attributes using given width and height values. + * Retrieves width and height attributes using given width and height values. * * Both attributes are required in the sense that both parameters must have a * value, but are optional in that if you set them to false or null, then they @@ -164,7 +164,7 @@ function image_hwstring( $width, $height ) { } /** - * Scale an image to fit a particular size (such as 'thumb' or 'medium'). + * Scales an image to fit a particular size (such as 'thumb' or 'medium'). * * The URL might be the original image, or it might be a resized version. This * function won't create a new resized copy, it will just return an already @@ -272,7 +272,7 @@ function image_downsize( $id, $size = 'medium' ) { } /** - * Register a new image size. + * Registers a new image size. * * @since 2.9.0 * @@ -299,7 +299,7 @@ function add_image_size( $name, $width = 0, $height = 0, $crop = false ) { } /** - * Check if an image size exists. + * Checks if an image size exists. * * @since 3.9.0 * @@ -312,7 +312,7 @@ function has_image_size( $name ) { } /** - * Remove a new image size. + * Removes a new image size. * * @since 3.9.0 * @@ -368,7 +368,7 @@ function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) { * @param string $align Part of the class name for aligning the image. * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of * width and height values in pixels (in that order). Default 'medium'. - * @return string HTML IMG element for given image attachment + * @return string HTML IMG element for given image attachment? */ function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) { @@ -993,7 +993,7 @@ function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon } /** - * Get an HTML img element representing an image attachment. + * Gets an HTML img element representing an image attachment. * * While `$size` will accept an array, it is better to register a size with * add_image_size() so that a cropped version is generated. It's much more @@ -1105,7 +1105,7 @@ function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = f } /** - * HTML img element representing an image attachment. + * Filters the HTML img element representing an image attachment. * * @since 5.6.0 * @@ -1121,7 +1121,7 @@ function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = f } /** - * Get the URL of an image attachment. + * Gets the URL of an image attachment. * * @since 4.4.0 * @@ -1138,7 +1138,7 @@ function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon } /** - * Get the attachment path relative to the upload directory. + * Gets the attachment path relative to the upload directory. * * @since 4.4.1 * @access private @@ -1163,7 +1163,7 @@ function _wp_get_attachment_relative_path( $file ) { } /** - * Get the image size as array from its meta data. + * Gets the image size as array from its meta data. * * Used for responsive images. * @@ -1247,7 +1247,7 @@ function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $imag */ function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) { /** - * Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data. + * Pre-filters the image meta to be able to fix inconsistencies in the stored data. * * @since 4.5.0 * @@ -2330,6 +2330,25 @@ function img_caption_shortcode( $attr, $content = '' ) { * WordPress images on a post. * * @since 2.5.0 + * @since 2.8.0 Added the `$attr` parameter to set the shortcode output. New attributes included + * such as `size`, `itemtag`, `icontag`, `captiontag`, and columns. Changed markup from + * `div` tags to `dl`, `dt` and `dd` tags. Support more than one gallery on the + * same page. + * @since 2.9.0 Added support for `include` and `exclude` to shortcode. + * @since 3.5.0 Use get_post() instead of global `$post`. Handle mapping of `ids` to `include` + * and `orderby`. + * @since 3.6.0 Added validation for tags used in gallery shortcode. Add orientation information to items. + * @since 3.7.0 Introduced the `link` attribute. + * @since 3.9.0 `html5` gallery support, accepting 'itemtag', 'icontag', and 'captiontag' attributes. + * @since 4.0.0 Removed use of `extract()`. + * @since 4.1.0 Added attribute to `wp_get_attachment_link()` to output `aria-describedby`. + * @since 4.2.0 Passed the shortcode instance ID to `post_gallery` and `post_playlist` filters. + * @since 4.6.0 Standardized filter docs to match documentation standards for PHP. + * @since 5.1.0 Code cleanup for WPCS 1.0.0 coding standards. + * @since 5.3.0 Saved progress of intermediate image creation after upload. + * @since 5.5.0 Ensured that galleries can be output as a list of links in feeds. + * @since 5.6.0 Replaced order-style PHP type conversion functions with typecasts. Fix logic for + * an array of image dimensions. * * @param array $attr { * Attributes of the gallery shortcode. @@ -2643,7 +2662,7 @@ function wp_underscore_playlist_templates() { } /** - * Outputs and enqueue default scripts and styles for playlists. + * Outputs and enqueues default scripts and styles for playlists. * * @since 3.9.0 * @@ -3219,6 +3238,7 @@ function wp_get_video_extensions() { * @type string $poster The 'poster' attribute for the `