diff --git a/.eslintrc.js b/.eslintrc.js index e997e7804beac4..177f3cf35b8ccf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -83,6 +83,72 @@ const restrictedImports = [ }, ]; +const restrictedSyntax = [ + // NOTE: We can't include the forward slash in our regex or + // we'll get a `SyntaxError` (Invalid regular expression: \ at end of pattern) + // here. That's why we use \\u002F in the regexes below. + { + selector: + 'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]', + message: 'Path access on WordPress dependencies is not allowed.', + }, + { + selector: + 'CallExpression[callee.name="deprecated"] Property[key.name="version"][value.value=/' + + majorMinorRegExp + + '/]', + message: + 'Deprecated functions must be removed before releasing this version.', + }, + { + selector: + 'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]', + message: + 'This method is deprecated. You should use the more explicit API methods available.', + }, + { + selector: + 'CallExpression[callee.object.name="page"][callee.property.name="waitForTimeout"]', + message: 'Prefer page.waitForSelector instead.', + }, + { + selector: 'JSXAttribute[name.name="id"][value.type="Literal"]', + message: + 'Do not use string literals for IDs; use withInstanceId instead.', + }, + { + // Discourage the usage of `Math.random()` as it's a code smell + // for UUID generation, for which we already have a higher-order + // component: `withInstanceId`. + selector: + 'CallExpression[callee.object.name="Math"][callee.property.name="random"]', + message: + 'Do not use Math.random() to generate unique IDs; use withInstanceId instead. (If you’re not generating unique IDs: ignore this message.)', + }, + { + selector: + 'CallExpression[callee.name="withDispatch"] > :function > BlockStatement > :not(VariableDeclaration,ReturnStatement)', + message: + 'withDispatch must return an object with consistent keys. Avoid performing logic in `mapDispatchToProps`.', + }, + { + selector: + 'LogicalExpression[operator="&&"][left.property.name="length"][right.type="JSXElement"]', + message: + 'Avoid truthy checks on length property rendering, as zero length is rendered verbatim.', + }, +]; + +/** `no-restricted-syntax` rules for components. */ +const restrictedSyntaxComponents = [ + { + selector: + 'JSXOpeningElement[name.name="Button"]:not(:has(JSXAttribute[name.name="__experimentalIsFocusable"])) JSXAttribute[name.name="disabled"]', + message: + '`disabled` used without the `__experimentalIsFocusable` prop. Disabling a control without maintaining focusability can cause accessibility issues, by hiding their presence from screen reader users, or preventing focus from returning to a trigger element. (Ignore this error if you truly mean to disable.)', + }, +]; + module.exports = { root: true, extends: [ @@ -147,63 +213,7 @@ module.exports = { disallowTypeAnnotations: false, }, ], - 'no-restricted-syntax': [ - 'error', - // NOTE: We can't include the forward slash in our regex or - // we'll get a `SyntaxError` (Invalid regular expression: \ at end of pattern) - // here. That's why we use \\u002F in the regexes below. - { - selector: - 'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]', - message: - 'Path access on WordPress dependencies is not allowed.', - }, - { - selector: - 'CallExpression[callee.name="deprecated"] Property[key.name="version"][value.value=/' + - majorMinorRegExp + - '/]', - message: - 'Deprecated functions must be removed before releasing this version.', - }, - { - selector: - 'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]', - message: - 'This method is deprecated. You should use the more explicit API methods available.', - }, - { - selector: - 'CallExpression[callee.object.name="page"][callee.property.name="waitForTimeout"]', - message: 'Prefer page.waitForSelector instead.', - }, - { - selector: 'JSXAttribute[name.name="id"][value.type="Literal"]', - message: - 'Do not use string literals for IDs; use withInstanceId instead.', - }, - { - // Discourage the usage of `Math.random()` as it's a code smell - // for UUID generation, for which we already have a higher-order - // component: `withInstanceId`. - selector: - 'CallExpression[callee.object.name="Math"][callee.property.name="random"]', - message: - 'Do not use Math.random() to generate unique IDs; use withInstanceId instead. (If you’re not generating unique IDs: ignore this message.)', - }, - { - selector: - 'CallExpression[callee.name="withDispatch"] > :function > BlockStatement > :not(VariableDeclaration,ReturnStatement)', - message: - 'withDispatch must return an object with consistent keys. Avoid performing logic in `mapDispatchToProps`.', - }, - { - selector: - 'LogicalExpression[operator="&&"][left.property.name="length"][right.type="JSXElement"]', - message: - 'Avoid truthy checks on length property rendering, as zero length is rendered verbatim.', - }, - ], + 'no-restricted-syntax': [ 'error', ...restrictedSyntax ], }, overrides: [ { @@ -262,12 +272,8 @@ module.exports = { rules: { 'no-restricted-syntax': [ 'error', - { - selector: - 'JSXOpeningElement[name.name="Button"]:not(:has(JSXAttribute[name.name="__experimentalIsFocusable"])) JSXAttribute[name.name="disabled"]', - message: - '`disabled` used without the `__experimentalIsFocusable` prop. Disabling a control without maintaining focusability can cause accessibility issues, by hiding their presence from screen reader users, or preventing focus from returning to a trigger element. (Ignore this error if you truly mean to disable.)', - }, + ...restrictedSyntax, + ...restrictedSyntaxComponents, ], }, }, @@ -390,6 +396,7 @@ module.exports = { rules: { 'no-restricted-syntax': [ 'error', + ...restrictedSyntax, { selector: ':matches(Literal[value=/--wp-admin-theme-/],TemplateElement[value.cooked=/--wp-admin-theme-/])', diff --git a/.github/workflows/php-changes-detection.yml b/.github/workflows/php-changes-detection.yml index 2642485bce1ce2..2eeaea561eb7ed 100644 --- a/.github/workflows/php-changes-detection.yml +++ b/.github/workflows/php-changes-detection.yml @@ -17,7 +17,7 @@ jobs: - name: Get changed PHP files id: changed-files-php - uses: tj-actions/changed-files@03334d095e2739fa9ac4034ec16f66d5d01e9eba # v44.5.1 + uses: tj-actions/changed-files@d6babd6899969df1a11d14c368283ea4436bca78 # v44.5.2 with: files: | lib/** diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 9640243e86629c..83228bd87b85ca 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -27,7 +27,7 @@ jobs: with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - - uses: ruby/setup-ruby@943103cae7d3f1bb1e4951d5fcc7928b40e4b742 # v1.177.1 + - uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0 with: # `.ruby-version` file location working-directory: packages/react-native-editor/ios diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index dd50ea68e0e5d5..570fd8477b5fed 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -185,7 +185,7 @@ jobs: # dependency versions are installed and cached. ## - name: Set up PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 + uses: shivammathur/setup-php@fc14643b0a99ee9db10a3c025a33d76544fa3761 # v2.30.5 with: php-version: '${{ matrix.php }}' ini-file: development @@ -286,7 +286,7 @@ jobs: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Set up PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 + uses: shivammathur/setup-php@fc14643b0a99ee9db10a3c025a33d76544fa3761 # v2.30.5 with: php-version: '7.4' coverage: none diff --git a/backport-changelog/6.6/6616.md b/backport-changelog/6.6/6616.md index 91261f78fb5c7a..bb35d6c74493cf 100644 --- a/backport-changelog/6.6/6616.md +++ b/backport-changelog/6.6/6616.md @@ -2,4 +2,6 @@ https://github.com/WordPress/wordpress-develop/pull/6616 * https://github.com/WordPress/gutenberg/pull/58409 * https://github.com/WordPress/gutenberg/pull/61328 -* https://github.com/WordPress/gutenberg/pull/61842 \ No newline at end of file +* https://github.com/WordPress/gutenberg/pull/61842 +* https://github.com/WordPress/gutenberg/pull/62199 +* https://github.com/WordPress/gutenberg/pull/62252 diff --git a/backport-changelog/6.6/6731.md b/backport-changelog/6.6/6731.md new file mode 100644 index 00000000000000..b8671873251659 --- /dev/null +++ b/backport-changelog/6.6/6731.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6731 + +* https://github.com/WordPress/gutenberg/pull/62299 diff --git a/backport-changelog/6.6/6737.md b/backport-changelog/6.6/6737.md new file mode 100644 index 00000000000000..84e2234ca4e79a --- /dev/null +++ b/backport-changelog/6.6/6737.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6737 + +* https://github.com/WordPress/gutenberg/pull/62305 diff --git a/backport-changelog/6.6/6744.md b/backport-changelog/6.6/6744.md new file mode 100644 index 00000000000000..032f5420cb7184 --- /dev/null +++ b/backport-changelog/6.6/6744.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6744 + +* https://github.com/WordPress/gutenberg/pull/62355 \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 006ca4a7c3e6b6..decdb88ea9a7a4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,6 @@ == Changelog == -= 18.5.0-rc.1 = - += 18.5.0 = ## Changelog @@ -111,6 +110,7 @@ - Lock binding editing with functions. ([61734](https://github.com/WordPress/gutenberg/pull/61734)) #### Block Variations +- Detect active variation correctly based on RichText attribute. ([62325](https://github.com/WordPress/gutenberg/pull/62325)) - Have `getActiveBlockVariation` return variation with highest specificity. ([62031](https://github.com/WordPress/gutenberg/pull/62031)) - Support dot notation in `isActive` string array. ([62088](https://github.com/WordPress/gutenberg/pull/62088)) @@ -137,6 +137,8 @@ ### Bug Fixes +- Editor: Only render the site logo once if there's a fill. ([62320](https://github.com/WordPress/gutenberg/pull/62320)) +- Interactivity API: Increase directive `wp-each-child` priority. ([62293](https://github.com/WordPress/gutenberg/pull/62293))w - Compose: Fix 'useFocusOnMount' cleanup callback. ([62053](https://github.com/WordPress/gutenberg/pull/62053)) - Do not auto save post status changes. ([62171](https://github.com/WordPress/gutenberg/pull/62171)) - Editor: Fix canvas padding in post editor. ([61893](https://github.com/WordPress/gutenberg/pull/61893)) @@ -167,6 +169,7 @@ - Post Actions: Hide the trash action for auto-drafts. ([61865](https://github.com/WordPress/gutenberg/pull/61865)) #### Block Editor +- Inserter: Update Openverse API URLs. ([62241](https://github.com/WordPress/gutenberg/pull/62241)) - Fix being unable to switch modes while inserter is open. ([61563](https://github.com/WordPress/gutenberg/pull/61563)) - Fix editor inserter tabs indicator. ([61973](https://github.com/WordPress/gutenberg/pull/61973)) - Fix positioning of close icons in panels to be consistent. ([61832](https://github.com/WordPress/gutenberg/pull/61832)) @@ -467,6 +470,8 @@ The following contributors merged PRs in this release: @aaronrobertshaw @abhi3315 @afercia @ajlende @akashdhawade2005 @akasunil @Aljullu @amitraj2203 @andrewserong @anton-vlasenko @anver @artemiomorales @carolinan @cbravobernal @colorful-tones @creativecoder @DaniGuardiola @DAreRodz @dbrian @draganescu @ellatrix @fabiankaegy @fullofcaffeine @gemkev @geriux @glendaviesnz @gziolo @jameskoster @jasmussen @jeryj @jorgefilipecosta @jsnajdr @kellenmace @kevin940726 @kt-12 @madhusudhand @Mamaduka @mattsherman @mcsf @michalczaplinski @mirka @narenin @nateinaction @ndiego @ntsekouras @oandregal @ockham @paolopiaggio @ramonjd @retrofox @richtabor @sanjucta @SantosGuillamot @scruffian @senadir @shail-mehta @sirreal @stokesman @t-hamano @talldan @taylorgorman @tellthemachines @tjcafferkey @twstokes @tyxla @vcanales @vipul0425 @westonruter @WunderBart @youknowriad + + = 18.4.1 = ## Changelog diff --git a/docs/how-to-guides/themes/global-settings-and-styles.md b/docs/how-to-guides/themes/global-settings-and-styles.md index a5c3e828a2d661..f71bd67bfaf2ec 100644 --- a/docs/how-to-guides/themes/global-settings-and-styles.md +++ b/docs/how-to-guides/themes/global-settings-and-styles.md @@ -310,20 +310,21 @@ There's one special setting property, `appearanceTools`, which is a boolean and To retain backward compatibility, the existing `add_theme_support` declarations that configure the block editor are retrofit in the proper categories for the top-level section. For example, if a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as setting `settings.color.custom` to `false`. If the `theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`. This is the complete list of equivalences: -| add_theme_support | theme.json setting | -| --------------------------- | --------------------------------------------------------- | -| `custom-line-height` | Set `typography.lineHeight` to `true`. | -| `custom-spacing` | Set `spacing.padding` to `true`. | -| `custom-units` | Provide the list of units via `spacing.units`. | -| `disable-custom-colors` | Set `color.custom` to `false`. | -| `disable-custom-font-sizes` | Set `typography.customFontSize` to `false`. | -| `disable-custom-gradients` | Set `color.customGradient` to `false`. | -| `editor-color-palette` | Provide the list of colors via `color.palette`. | -| `editor-font-sizes` | Provide the list of font size via `typography.fontSizes`. | -| `editor-gradient-presets` | Provide the list of gradients via `color.gradients`. | -| `appearance-tools` | Set `appearanceTools` to `true`. | -| `border` | Set `border: color, radius, style, width` to `true`. | -| `link-color ` | Set `color.link` to `true`. | +| add_theme_support | theme.json setting | +| --------------------------- | ------------------------------------------------------------- | +| `custom-line-height` | Set `typography.lineHeight` to `true`. | +| `custom-spacing` | Set `spacing.padding` to `true`. | +| `custom-units` | Provide the list of units via `spacing.units`. | +| `disable-custom-colors` | Set `color.custom` to `false`. | +| `disable-custom-font-sizes` | Set `typography.customFontSize` to `false`. | +| `disable-custom-gradients` | Set `color.customGradient` to `false`. | +| `editor-color-palette` | Provide the list of colors via `color.palette`. | +| `editor-font-sizes` | Provide the list of font size via `typography.fontSizes`. | +| `editor-gradient-presets` | Provide the list of gradients via `color.gradients`. | +| `editor-spacing-sizes` | Provide the list of spacing sizes via `spacing.spacingSizes`. | +| `appearance-tools` | Set `appearanceTools` to `true`. | +| `border` | Set `border: color, radius, style, width` to `true`. | +| `link-color ` | Set `color.link` to `true`. | #### Presets diff --git a/gutenberg.php b/gutenberg.php index aadebe998d7ab5..a8d9ebe7e981f0 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.4 * Requires PHP: 7.2 - * Version: 18.5.0-rc.1 + * Version: 18.5.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index ad4e2fe105b0c3..a1e79a56a683bf 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -734,14 +734,14 @@ public static function get_element_class_name( $element ) { * * @param array $theme_json A structure that follows the theme.json schema. * @param string $origin Optional. What source of data this object represents. - * One of 'default', 'theme', or 'custom'. Default 'theme'. + * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. */ public function __construct( $theme_json = array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA ), $origin = 'theme' ) { if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { $origin = 'theme'; } - $this->theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json ); + $this->theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json, $origin ); $registry = WP_Block_Type_Registry::get_instance(); $valid_block_names = array_keys( $registry->get_all_registered() ); $valid_element_names = array_keys( static::ELEMENTS ); @@ -3278,15 +3278,21 @@ protected static function filter_slugs( $node, $slugs ) { * Removes insecure data from theme.json. * * @since 5.9.0 - * @since 6.6.0 Added support for block style variation element styles. + * @since 6.6.0 Added support for block style variation element styles and $origin parameter. * * @param array $theme_json Structure to sanitize. + * @param string $origin Optional. What source of data this object represents. + * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. * @return array Sanitized structure. */ - public static function remove_insecure_properties( $theme_json ) { + public static function remove_insecure_properties( $theme_json, $origin = 'theme' ) { + if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { + $origin = 'theme'; + } + $sanitized = array(); - $theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json ); + $theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json, $origin ); $valid_block_names = array_keys( static::get_blocks_metadata() ); $valid_element_names = array_keys( static::ELEMENTS ); @@ -3559,53 +3565,32 @@ public static function get_from_editor_settings( $settings ) { // Deprecated theme supports. if ( isset( $settings['disableCustomColors'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['custom'] = ! $settings['disableCustomColors']; } if ( isset( $settings['disableCustomGradients'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['customGradient'] = ! $settings['disableCustomGradients']; } if ( isset( $settings['disableCustomFontSizes'] ) ) { - if ( ! isset( $theme_settings['settings']['typography'] ) ) { - $theme_settings['settings']['typography'] = array(); - } $theme_settings['settings']['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; } if ( isset( $settings['enableCustomLineHeight'] ) ) { - if ( ! isset( $theme_settings['settings']['typography'] ) ) { - $theme_settings['settings']['typography'] = array(); - } $theme_settings['settings']['typography']['lineHeight'] = $settings['enableCustomLineHeight']; } if ( isset( $settings['enableCustomUnits'] ) ) { - if ( ! isset( $theme_settings['settings']['spacing'] ) ) { - $theme_settings['settings']['spacing'] = array(); - } $theme_settings['settings']['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? array( 'px', 'em', 'rem', 'vh', 'vw', '%' ) : $settings['enableCustomUnits']; } if ( isset( $settings['colors'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['palette'] = $settings['colors']; } if ( isset( $settings['gradients'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['gradients'] = $settings['gradients']; } @@ -3617,19 +3602,17 @@ public static function get_from_editor_settings( $settings ) { $font_sizes[ $key ]['size'] = $font_size['size'] . 'px'; } } - if ( ! isset( $theme_settings['settings']['typography'] ) ) { - $theme_settings['settings']['typography'] = array(); - } $theme_settings['settings']['typography']['fontSizes'] = $font_sizes; } if ( isset( $settings['enableCustomSpacing'] ) ) { - if ( ! isset( $theme_settings['settings']['spacing'] ) ) { - $theme_settings['settings']['spacing'] = array(); - } $theme_settings['settings']['spacing']['padding'] = $settings['enableCustomSpacing']; } + if ( isset( $settings['spacingSizes'] ) ) { + $theme_settings['settings']['spacing']['spacingSizes'] = $settings['spacingSizes']; + } + return $theme_settings; } @@ -3794,12 +3777,10 @@ public function get_data() { /** * Sets the spacingSizes array based on the spacingScale values from theme.json. * - * No longer used since theme.json version 3 as the spacingSizes are now - * automatically generated during construction and merge instead of manually - * set in the resolver. - * * @since 6.1.0 - * @deprecated 6.6.0 + * @deprecated 6.6.0 No longer used as the spacingSizes are automatically + * generated in the constructor and merge methods instead + * of manually after instantiation. * * @return null|void */ @@ -3852,6 +3833,10 @@ public function set_spacing_sizes() { * @return array The merged set of spacing sizes. */ private static function merge_spacing_sizes( $base, $incoming ) { + // Preserve the order if there are no base (spacingScale) values. + if ( empty( $base ) ) { + return $incoming; + } $merged = array(); foreach ( $base as $item ) { $merged[ $item['slug'] ] = $item; @@ -3859,6 +3844,7 @@ private static function merge_spacing_sizes( $base, $incoming ) { foreach ( $incoming as $item ) { $merged[ $item['slug'] ] = $item; } + ksort( $merged, SORT_NUMERIC ); return array_values( $merged ); } diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 84f999e4e9d020..507876af4952a8 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -220,6 +220,7 @@ protected static function has_same_registered_blocks( $origin ) { * @since 5.8.0 * @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed. * @since 6.0.0 Added an `$options` parameter to allow the theme data to be returned without theme supports. + * @since 6.6.0 Add support for 'default-font-sizes' and 'default-spacing-sizes' theme supports. * * @param array $deprecated Deprecated. Not used. * @param array $options { @@ -291,35 +292,27 @@ public static function get_theme_data( $deprecated = array(), $options = array() * So we take theme supports, transform it to theme.json shape * and merge the static::$theme upon that. */ - $theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() ); + $theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( gutenberg_get_classic_theme_supports_block_editor_settings() ); if ( ! wp_theme_has_theme_json() ) { - if ( ! isset( $theme_support_data['settings']['color'] ) ) { - $theme_support_data['settings']['color'] = array(); - } - - $default_palette = false; - if ( current_theme_supports( 'default-color-palette' ) ) { - $default_palette = true; - } - if ( ! isset( $theme_support_data['settings']['color']['palette'] ) ) { - // If the theme does not have any palette, we still want to show the core one. - $default_palette = true; - } - $theme_support_data['settings']['color']['defaultPalette'] = $default_palette; - - $default_gradients = false; - if ( current_theme_supports( 'default-gradient-presets' ) ) { - $default_gradients = true; - } - if ( ! isset( $theme_support_data['settings']['color']['gradients'] ) ) { - // If the theme does not have any gradients, we still want to show the core ones. - $default_gradients = true; - } - $theme_support_data['settings']['color']['defaultGradients'] = $default_gradients; + /* + * Unlike block themes, classic themes without a theme.json disable + * default presets when custom preset theme support is added. This + * behavior can be overridden by using the corresponding default + * preset theme support. + */ + $theme_support_data['settings']['color']['defaultPalette'] = + ! isset( $theme_support_data['settings']['color']['palette'] ) || + current_theme_supports( 'default-color-palette' ); + $theme_support_data['settings']['color']['defaultGradients'] = + ! isset( $theme_support_data['settings']['color']['gradients'] ) || + current_theme_supports( 'default-gradient-presets' ); + $theme_support_data['settings']['typography']['defaultFontSizes'] = + ! isset( $theme_support_data['settings']['typography']['fontSizes'] ) || + current_theme_supports( 'default-font-sizes' ); + $theme_support_data['settings']['spacing']['defaultSpacingSizes'] = + ! isset( $theme_support_data['settings']['spacing']['spacingSizes'] ) || + current_theme_supports( 'default-spacing-sizes' ); - if ( ! isset( $theme_support_data['settings']['shadow'] ) ) { - $theme_support_data['settings']['shadow'] = array(); - } /* * Shadow presets are explicitly disabled for classic themes until a * decision is made for whether the default presets should match the @@ -541,18 +534,14 @@ public static function get_user_data() { isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) && $decoded_data['isGlobalStylesUserThemeJSON'] ) { + unset( $decoded_data['isGlobalStylesUserThemeJSON'] ); $config = $decoded_data; } } /** This filter is documented in wp-includes/class-wp-theme-json-resolver.php */ - $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'custom' ) ); - $config = $theme_json->get_data(); - - // Needs to be set for schema migrations of user data. - $config['isGlobalStylesUserThemeJSON'] = true; - - static::$user = new WP_Theme_JSON_Gutenberg( $config, 'custom' ); + $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'custom' ) ); + static::$user = $theme_json->get_theme_json(); return static::$user; } diff --git a/lib/class-wp-theme-json-schema-gutenberg.php b/lib/class-wp-theme-json-schema-gutenberg.php index 0def88f86a23a7..af0977ada1b307 100644 --- a/lib/class-wp-theme-json-schema-gutenberg.php +++ b/lib/class-wp-theme-json-schema-gutenberg.php @@ -40,11 +40,13 @@ class WP_Theme_JSON_Schema_Gutenberg { * @since 5.9.0 * @since 6.6.0 Migrate up to v3. * - * @param array $theme_json The structure to migrate. + * @param array $theme_json The structure to migrate. + * @param string $origin Optional. What source of data this object represents. + * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. * * @return array The structure in the last version. */ - public static function migrate( $theme_json ) { + public static function migrate( $theme_json, $origin = 'theme' ) { if ( ! isset( $theme_json['version'] ) ) { $theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -55,10 +57,9 @@ public static function migrate( $theme_json ) { switch ( $theme_json['version'] ) { case 1: $theme_json = self::migrate_v1_to_v2( $theme_json ); - // no break + // Deliberate fall through. Once migrated to v2, also migrate to v3. case 2: - $theme_json = self::migrate_v2_to_v3( $theme_json ); - // no break + $theme_json = self::migrate_v2_to_v3( $theme_json, $origin ); } return $theme_json; @@ -97,15 +98,19 @@ private static function migrate_v1_to_v2( $old ) { /** * Migrates from v2 to v3. * - * - Sets settings.typography.defaultFontSizes to false. + * - Sets settings.typography.defaultFontSizes to false if settings.typography.fontSizes are defined. + * - Sets settings.spacing.defaultSpacingSizes to false if settings.spacing.spacingSizes are defined. + * - Prevents settings.spacing.spacingSizes from merging with settings.spacing.spacingScale by + * unsetting spacingScale when spacingSizes are defined. * * @since 6.6.0 * - * @param array $old Data to migrate. - * + * @param array $old Data to migrate. + * @param string $origin What source of data this object represents. + * One of 'blocks', 'default', 'theme', or 'custom'. * @return array Data with defaultFontSizes set to false. */ - private static function migrate_v2_to_v3( $old ) { + private static function migrate_v2_to_v3( $old, $origin ) { // Copy everything. $new = $old; @@ -116,10 +121,7 @@ private static function migrate_v2_to_v3( $old ) { * Remaining changes do not need to be applied to the custom origin, * as they should take on the value of the theme origin. */ - if ( - isset( $new['isGlobalStylesUserThemeJSON'] ) && - true === $new['isGlobalStylesUserThemeJSON'] - ) { + if ( 'custom' === $origin ) { return $new; } @@ -132,12 +134,6 @@ private static function migrate_v2_to_v3( $old ) { * when the theme did not provide any. */ if ( isset( $old['settings']['typography']['fontSizes'] ) ) { - if ( ! isset( $new['settings'] ) ) { - $new['settings'] = array(); - } - if ( ! isset( $new['settings']['typography'] ) ) { - $new['settings']['typography'] = array(); - } $new['settings']['typography']['defaultFontSizes'] = false; } @@ -151,12 +147,6 @@ private static function migrate_v2_to_v3( $old ) { isset( $old['settings']['spacing']['spacingSizes'] ) || isset( $old['settings']['spacing']['spacingScale'] ) ) { - if ( ! isset( $new['settings'] ) ) { - $new['settings'] = array(); - } - if ( ! isset( $new['settings']['spacing'] ) ) { - $new['settings']['spacing'] = array(); - } $new['settings']['spacing']['defaultSpacingSizes'] = false; } diff --git a/lib/compat/wordpress-6.5/blocks.php b/lib/compat/wordpress-6.5/blocks.php index d3a8b3f5571813..5c5688e7cdf43e 100644 --- a/lib/compat/wordpress-6.5/blocks.php +++ b/lib/compat/wordpress-6.5/blocks.php @@ -65,27 +65,68 @@ function gutenberg_block_bindings_replace_html( $block_content, $block_name, str switch ( $block_type->attributes[ $attribute_name ]['source'] ) { case 'html': case 'rich-text': - // Hardcode the selectors and processing until the HTML API is able to read CSS selectors and replace inner HTML. - // TODO: Use the HTML API instead. - if ( 'core/paragraph' === $block_name && 'content' === $attribute_name ) { - $selector = 'p'; - } - if ( 'core/heading' === $block_name && 'content' === $attribute_name ) { - $selector = 'h[1-6]'; + $block_reader = new WP_HTML_Tag_Processor( $block_content ); + + // TODO: Support for CSS selectors whenever they are ready in the HTML API. + // In the meantime, support comma-separated selectors by exploding them into an array. + $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] ); + // Add a bookmark to the first tag to be able to iterate over the selectors. + $block_reader->next_tag(); + $block_reader->set_bookmark( 'iterate-selectors' ); + + // TODO: This shouldn't be needed when the `set_inner_html` function is ready. + // Store the parent tag and its attributes to be able to restore them later in the button. + // The button block has a wrapper while the paragraph and heading blocks don't. + if ( 'core/button' === $block_name ) { + $button_wrapper = $block_reader->get_tag(); + $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' ); + $button_wrapper_attrs = array(); + foreach ( $button_wrapper_attribute_names as $name ) { + $button_wrapper_attrs[ $name ] = $block_reader->get_attribute( $name ); + } } - if ( 'core/button' === $block_name && 'text' === $attribute_name ) { - // Check if it is a ); } diff --git a/packages/editor/src/components/save-publish-panels/style.scss b/packages/editor/src/components/save-publish-panels/style.scss index eefa32a8a9a1a6..74dcf113f0479b 100644 --- a/packages/editor/src/components/save-publish-panels/style.scss +++ b/packages/editor/src/components/save-publish-panels/style.scss @@ -26,11 +26,3 @@ bottom: 0; } } - -.edit-post-layout__toggle-sidebar-panel { - .interface-interface-skeleton__sidebar:focus &, - .interface-interface-skeleton__sidebar:focus-within & { - top: auto; - bottom: 0; - } -} diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index 58e15135e13ac9..48e43e7737fec8 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -6,21 +6,19 @@ import * as interfaceApis from '@wordpress/interface'; /** * Internal dependencies */ -import { ExperimentalEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import EditorContentSlotFill from './components/editor-interface/content-slot-fill'; import useBlockEditorSettings from './components/provider/use-block-editor-settings'; import BackButton from './components/header/back-button'; -import EditorInterface from './components/editor-interface'; import CreateTemplatePartModal from './components/create-template-part-modal'; +import Editor from './components/editor'; import PluginPostExcerpt from './components/post-excerpt/plugin'; import PreferencesModal from './components/preferences-modal'; import { usePostActions } from './components/post-actions/actions'; import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; import ViewMoreMenuGroup from './components/more-menu/view-more-menu-group'; import ResizableEditor from './components/resizable-editor'; -import Sidebar from './components/sidebar'; import { mergeBaseAndUserConfigs, GlobalStylesProvider, @@ -32,9 +30,8 @@ export const privateApis = {}; lock( privateApis, { CreateTemplatePartModal, BackButton, - ExperimentalEditorProvider, EntitiesSavedStatesExtensible, - EditorInterface, + Editor, EditorContentSlotFill, GlobalStylesProvider, mergeBaseAndUserConfigs, @@ -44,7 +41,6 @@ lock( privateApis, { ToolsMoreMenuGroup, ViewMoreMenuGroup, ResizableEditor, - Sidebar, // This is a temporary private API while we're updating the site editor to use EditorProvider. useBlockEditorSettings, diff --git a/packages/editor/src/private-apis.native.js b/packages/editor/src/private-apis.native.js index 7c302c9c87d3aa..5ba2d8e4406739 100644 --- a/packages/editor/src/private-apis.native.js +++ b/packages/editor/src/private-apis.native.js @@ -7,7 +7,6 @@ import * as interfaceApis from '@wordpress/interface'; * Internal dependencies */ import VisualEditor from './components/visual-editor'; -import { ExperimentalEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import useBlockEditorSettings from './components/provider/use-block-editor-settings'; @@ -22,7 +21,6 @@ const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis; export const privateApis = {}; lock( privateApis, { VisualEditor, - ExperimentalEditorProvider, EntitiesSavedStatesExtensible, PluginPostExcerpt, PreferencesModal, diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index bd8d03568e9d47..a4034a8a51c733 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -9,6 +9,7 @@ @import "./components/document-bar/style.scss"; @import "./components/document-outline/style.scss"; @import "./components/document-tools/style.scss"; +@import "./components/editor-interface/style.scss"; @import "./components/editor-notices/style.scss"; @import "./components/entities-saved-states/style.scss"; @import "./components/error-boundary/style.scss"; diff --git a/packages/env/README.md b/packages/env/README.md index fb9e9751d9c666..b82f59f734840c 100644 --- a/packages/env/README.md +++ b/packages/env/README.md @@ -480,7 +480,7 @@ You can customize the WordPress installation, plugins and themes that the develo `.wp-env.json` supports fields for options applicable to both the tests and development instances. | Field | Type | Default | Description | -| -------------- | -------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +|----------------|----------------|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| | `"core"` | `string\|null` | `null` | The WordPress installation to use. If `null` is specified, `wp-env` will use the latest production release of WordPress. | | `"phpVersion"` | `string\|null` | `null` | The PHP version to use. If `null` is specified, `wp-env` will use the default version used with production release of WordPress. | | `"plugins"` | `string[]` | `[]` | A list of plugins to install and activate in the environment. | @@ -489,6 +489,7 @@ You can customize the WordPress installation, plugins and themes that the develo | `"testsPort"` | `integer` | `8889` | The port number for the test site. You'll access the instance through the port: 'http://localhost:8889'. | | `"config"` | `Object` | See below. | Mapping of wp-config.php constants to their desired values. | | `"mappings"` | `Object` | `"{}"` | Mapping of WordPress directories to local directories to be mounted in the WordPress instance. | +| `"mysqlPort"` | `integer` | `null` (randomly assigned) | The MySQL port number to expose. The setting is only available in the `env.development` and `env.tests` objects. | _Note: the port number environment variables (`WP_ENV_PORT` and `WP_ENV_TESTS_PORT`) take precedent over the .wp-env.json values._ @@ -521,7 +522,8 @@ Additionally, the key `env` is available to override any of the above options on "config": { "KEY_1": false }, - "port": 3000 + "port": 3000, + "mysqlPort": 13306 } } } @@ -686,6 +688,8 @@ You can tell `wp-env` to use a custom port number so that your instance does not } ``` +These can also be set via the environment variables `WP_ENV_PORT`, `WP_ENV_TESTS_PORT`, `WP_ENV_MYSQL_PORT` and `WP_ENV_TESTS_MYSQL_PORT`. + ### Specific PHP Version You can tell `wp-env` to use a specific PHP version for compatibility and testing. This can also be set via the environment variable `WP_ENV_PHP_VERSION`. diff --git a/packages/env/lib/build-docker-compose-config.js b/packages/env/lib/build-docker-compose-config.js index 1794f7217ff946..d7a813e1afafb0 100644 --- a/packages/env/lib/build-docker-compose-config.js +++ b/packages/env/lib/build-docker-compose-config.js @@ -166,14 +166,20 @@ module.exports = function buildDockerComposeConfig( config ) { // Set the default ports based on the config values. const developmentPorts = `\${WP_ENV_PORT:-${ config.env.development.port }}:80`; + const developmentMysqlPorts = `\${WP_ENV_MYSQL_PORT:-${ + config.env.development.mysqlPort ?? '' + }}:3306`; const testsPorts = `\${WP_ENV_TESTS_PORT:-${ config.env.tests.port }}:80`; + const testsMysqlPorts = `\${WP_ENV_TESTS_MYSQL_PORT:-${ + config.env.tests.mysqlPort ?? '' + }}:3306`; return { version: '3.7', services: { mysql: { image: 'mariadb:lts', - ports: [ '3306' ], + ports: [ developmentMysqlPorts ], environment: { MYSQL_ROOT_HOST: '%', MYSQL_ROOT_PASSWORD: @@ -184,7 +190,7 @@ module.exports = function buildDockerComposeConfig( config ) { }, 'tests-mysql': { image: 'mariadb:lts', - ports: [ '3306' ], + ports: [ testsMysqlPorts ], environment: { MYSQL_ROOT_HOST: '%', MYSQL_ROOT_PASSWORD: diff --git a/packages/env/lib/config/get-config-from-environment-vars.js b/packages/env/lib/config/get-config-from-environment-vars.js index 8a4608b859b7f7..beaf721ea1c0c1 100644 --- a/packages/env/lib/config/get-config-from-environment-vars.js +++ b/packages/env/lib/config/get-config-from-environment-vars.js @@ -17,7 +17,9 @@ const { checkPort, checkVersion, checkString } = require( './validate-config' ); * * @typedef WPEnvironmentVariableConfig * @property {?number} port An override for the development environment's port. + * @property {?number} mysqlPort An override for the development environment's MySQL port. * @property {?number} testsPort An override for the testing environment's port. + * @property {?number} testsMysqlPort An override for the testing environment's MySQL port. * @property {?WPSource} coreSource An override for all environment's coreSource. * @property {?string} phpVersion An override for all environment's PHP version. * @property {?Object.} lifecycleScripts An override for various lifecycle scripts. @@ -33,7 +35,11 @@ const { checkPort, checkVersion, checkString } = require( './validate-config' ); module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) { const environmentConfig = { port: getPortFromEnvironmentVariable( 'WP_ENV_PORT' ), + mysqlPort: getPortFromEnvironmentVariable( 'WP_ENV_MYSQL_PORT' ), testsPort: getPortFromEnvironmentVariable( 'WP_ENV_TESTS_PORT' ), + testsMysqlPort: getPortFromEnvironmentVariable( + 'WP_ENV_TESTS_MYSQL_PORT' + ), lifecycleScripts: getLifecycleScriptOverrides(), }; diff --git a/packages/env/lib/config/parse-config.js b/packages/env/lib/config/parse-config.js index 5da05396ec468c..30125951b1ac89 100644 --- a/packages/env/lib/config/parse-config.js +++ b/packages/env/lib/config/parse-config.js @@ -50,6 +50,7 @@ const mergeConfigs = require( './merge-configs' ); * @property {WPSource[]} pluginSources Plugins to load in the environment. * @property {WPSource[]} themeSources Themes to load in the environment. * @property {number} port The port to use. + * @property {number} mysqlPort The port to use for MySQL. Random if empty. * @property {Object} config Mapping of wp-config.php constants to their desired values. * @property {Object.} mappings Mapping of WordPress directories to local directories which should be mounted. * @property {string|null} phpVersion Version of PHP to use in the environments, of the format 0.0. @@ -85,6 +86,7 @@ const DEFAULT_ENVIRONMENT_CONFIG = { themes: [], port: 8888, testsPort: 8889, + mysqlPort: null, mappings: {}, config: { FS_METHOD: 'direct', @@ -276,11 +278,19 @@ function getEnvironmentVarOverrides( cacheDirectoryPath ) { overrideConfig.env.development.port = overrides.port; } + if ( overrides.mysqlPort ) { + overrideConfig.env.development.mysqlPort = overrides.mysqlPort; + } + if ( overrides.testsPort ) { overrideConfig.testsPort = overrides.testsPort; overrideConfig.env.tests.port = overrides.testsPort; } + if ( overrides.testsMysqlPort ) { + overrideConfig.env.tests.mysqlPort = overrides.testsMysqlPort; + } + if ( overrides.coreSource ) { overrideConfig.coreSource = overrides.coreSource; overrideConfig.env.development.coreSource = overrides.coreSource; @@ -436,6 +446,10 @@ async function parseEnvironmentConfig( parsedConfig.port = config.port; } + if ( config.mysqlPort !== undefined ) { + parsedConfig.mysqlPort = config.mysqlPort; + } + if ( config.phpVersion !== undefined ) { // Support null as a valid input. if ( config.phpVersion !== null ) { diff --git a/packages/env/lib/config/test/__snapshots__/config-integration.js.snap b/packages/env/lib/config/test/__snapshots__/config-integration.js.snap index 53a2d652c740fd..6c3618f4724cb0 100644 --- a/packages/env/lib/config/test/__snapshots__/config-integration.js.snap +++ b/packages/env/lib/config/test/__snapshots__/config-integration.js.snap @@ -29,6 +29,7 @@ exports[`Config Integration should load local and override configuration files 1 "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": 23306, "phpVersion": null, "pluginSources": [], "port": 999, @@ -57,6 +58,7 @@ exports[`Config Integration should load local and override configuration files 1 "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": 23307, "phpVersion": null, "pluginSources": [], "port": 456, @@ -102,6 +104,7 @@ exports[`Config Integration should load local configuration file 1`] = ` "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": 13306, "phpVersion": null, "pluginSources": [], "port": 123, @@ -130,6 +133,7 @@ exports[`Config Integration should load local configuration file 1`] = ` "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": 23307, "phpVersion": null, "pluginSources": [], "port": 8889, @@ -175,6 +179,7 @@ exports[`Config Integration should use default configuration 1`] = ` "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": null, "phpVersion": null, "pluginSources": [], "port": 8888, @@ -203,6 +208,7 @@ exports[`Config Integration should use default configuration 1`] = ` "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": null, "phpVersion": null, "pluginSources": [], "port": 8889, @@ -248,6 +254,7 @@ exports[`Config Integration should use environment variables over local and over "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": 23306, "phpVersion": null, "pluginSources": [], "port": 12345, @@ -277,6 +284,7 @@ exports[`Config Integration should use environment variables over local and over "url": "https://github.com/WordPress/WordPress.git", }, "mappings": {}, + "mysqlPort": 23307, "phpVersion": null, "pluginSources": [], "port": 61234, diff --git a/packages/env/lib/config/test/config-integration.js b/packages/env/lib/config/test/config-integration.js index a6728f91200f11..8ab2897da7ff4f 100644 --- a/packages/env/lib/config/test/config-integration.js +++ b/packages/env/lib/config/test/config-integration.js @@ -48,7 +48,9 @@ describe( 'Config Integration', () => { afterEach( () => { delete process.env.WP_ENV_HOME; delete process.env.WP_ENV_PORT; + delete process.env.WP_ENV_MYSQL_PORT; delete process.env.WP_ENV_TESTS_PORT; + delete process.env.WP_ENV_TESTS_MYSQL_PORT; delete process.env.WP_ENV_LIFECYCLE_SCRIPT_AFTER_START; } ); @@ -61,6 +63,8 @@ describe( 'Config Integration', () => { expect( config.env.development.port ).toEqual( 8888 ); expect( config.env.tests.port ).toEqual( 8889 ); + expect( config.env.development.mysqlPort ).toEqual( null ); + expect( config.env.tests.mysqlPort ).toEqual( null ); expect( config ).toMatchSnapshot(); } ); @@ -75,6 +79,14 @@ describe( 'Config Integration', () => { afterClean: null, afterDestroy: null, }, + env: { + development: { + mysqlPort: 13306, + }, + tests: { + mysqlPort: 23307, + }, + }, } ); } @@ -85,6 +97,8 @@ describe( 'Config Integration', () => { expect( config.env.development.port ).toEqual( 123 ); expect( config.env.tests.port ).toEqual( 8889 ); + expect( config.env.development.mysqlPort ).toEqual( 13306 ); + expect( config.env.tests.mysqlPort ).toEqual( 23307 ); expect( config ).toMatchSnapshot(); } ); @@ -100,6 +114,11 @@ describe( 'Config Integration', () => { afterClean: null, afterDestroy: null, }, + env: { + tests: { + mysqlPort: 13306, + }, + }, } ); } @@ -111,6 +130,14 @@ describe( 'Config Integration', () => { afterClean: null, afterDestroy: 'test', }, + env: { + development: { + mysqlPort: 23306, + }, + tests: { + mysqlPort: 23307, + }, + }, } ); } @@ -121,12 +148,16 @@ describe( 'Config Integration', () => { expect( config.env.development.port ).toEqual( 999 ); expect( config.env.tests.port ).toEqual( 456 ); + expect( config.env.development.mysqlPort ).toEqual( 23306 ); + expect( config.env.tests.mysqlPort ).toEqual( 23307 ); expect( config ).toMatchSnapshot(); } ); it( 'should use environment variables over local and override configuration files', async () => { process.env.WP_ENV_PORT = 12345; + process.env.WP_ENV_MYSQL_PORT = 23306; process.env.WP_ENV_TESTS_PORT = 61234; + process.env.WP_ENV_TESTS_MYSQL_PORT = 23307; process.env.WP_ENV_LIFECYCLE_SCRIPT_AFTER_START = 'test'; readFile.mockImplementation( async ( fileName ) => { @@ -140,6 +171,11 @@ describe( 'Config Integration', () => { afterClean: null, afterDestroy: null, }, + env: { + tests: { + mysqlPort: 13306, + }, + }, } ); } @@ -156,6 +192,8 @@ describe( 'Config Integration', () => { expect( config.env.development.port ).toEqual( 12345 ); expect( config.env.tests.port ).toEqual( 61234 ); + expect( config.env.development.mysqlPort ).toEqual( 23306 ); + expect( config.env.tests.mysqlPort ).toEqual( 23307 ); expect( config.lifecycleScripts ).toHaveProperty( 'afterStart', 'test' diff --git a/packages/env/lib/config/test/parse-config.js b/packages/env/lib/config/test/parse-config.js index f2e9b923d7fdcd..c1b01df9d8d884 100644 --- a/packages/env/lib/config/test/parse-config.js +++ b/packages/env/lib/config/test/parse-config.js @@ -21,6 +21,7 @@ jest.mock( '../../wordpress', () => ( { const DEFAULT_CONFIG = { port: 8888, testsPort: 8889, + mysqlPort: null, phpVersion: null, coreSource: { type: 'git', diff --git a/packages/interactivity/src/directives.tsx b/packages/interactivity/src/directives.tsx index a4a320eda57f02..a013d442166897 100644 --- a/packages/interactivity/src/directives.tsx +++ b/packages/interactivity/src/directives.tsx @@ -632,5 +632,5 @@ export default () => { { priority: 20 } ); - directive( 'each-child', () => null ); + directive( 'each-child', () => null, { priority: 1 } ); }; diff --git a/packages/interface/src/components/interface-skeleton/style.scss b/packages/interface/src/components/interface-skeleton/style.scss index be8eced71dabad..776a177321d4be 100644 --- a/packages/interface/src/components/interface-skeleton/style.scss +++ b/packages/interface/src/components/interface-skeleton/style.scss @@ -114,13 +114,6 @@ html.interface-interface-skeleton__html-container { // On Mobile the header is fixed to keep HTML as scrollable. @include break-medium() { position: relative !important; - - // Set this z-index only when the sidebar is opened. When it's closed, the - // button to open the sidebar that is shown when navigating regions needs to - // be above the footer. See `editor-layout__toggle-sidebar-panel`. - .is-sidebar-opened & { - z-index: z-index(".interface-interface-skeleton__sidebar {greater than small}"); - } } } diff --git a/packages/list-reusable-blocks/src/index.js b/packages/list-reusable-blocks/src/index.js index 4440ba1c49f05a..f5cb411726963c 100644 --- a/packages/list-reusable-blocks/src/index.js +++ b/packages/list-reusable-blocks/src/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { createRoot } from '@wordpress/element'; +import { createRoot, StrictMode } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** @@ -44,6 +44,8 @@ document.addEventListener( 'DOMContentLoaded', () => { container.className = 'list-reusable-blocks__container'; button.parentNode.insertBefore( container, button ); createRoot( container ).render( - + + + ); } ); diff --git a/packages/media-utils/src/components/media-upload/index.js b/packages/media-utils/src/components/media-upload/index.js index 732a9bcabd79fc..91de011869ad38 100644 --- a/packages/media-utils/src/components/media-upload/index.js +++ b/packages/media-utils/src/components/media-upload/index.js @@ -400,6 +400,8 @@ class MediaUpload extends Component { if ( onClose ) { onClose(); } + + this.frame.detach(); } updateCollection() { diff --git a/packages/react-native-aztec/package.json b/packages/react-native-aztec/package.json index b3352cdbd3eb57..dd290b47c435de 100644 --- a/packages/react-native-aztec/package.json +++ b/packages/react-native-aztec/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-aztec", - "version": "1.119.0", + "version": "1.119.1", "description": "Aztec view for react-native.", "private": true, "author": "The WordPress Contributors", diff --git a/packages/react-native-bridge/package.json b/packages/react-native-bridge/package.json index 0d8998c650b8f1..3921901d8ac036 100644 --- a/packages/react-native-bridge/package.json +++ b/packages/react-native-bridge/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-bridge", - "version": "1.119.0", + "version": "1.119.1", "description": "Native bridge library used to integrate the block editor into a native App.", "private": true, "author": "The WordPress Contributors", diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index beb32d70e60725..e57e671931567d 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -13,6 +13,10 @@ For each user feature we should also add a importance categorization label to i - [*] Prevent deleting content when backspacing in the first Paragraph block [#62069] - [internal] Adds new bridge functionality for updating content [#61796] +## 1.119.1 +- [*] Image corrector - Check the path extension is a valid one [#62190] +- [*] Unsupported block - UI improvements [#62240] + ## 1.119.0 - [internal] Remove circular dependencies within the components package [#61102] - [internal] Upgrade target sdk version to Android API 34 [#61727] diff --git a/packages/react-native-editor/ios/Podfile.lock b/packages/react-native-editor/ios/Podfile.lock index 896262f752f0c9..86405ca4eacfc0 100644 --- a/packages/react-native-editor/ios/Podfile.lock +++ b/packages/react-native-editor/ios/Podfile.lock @@ -13,7 +13,7 @@ PODS: - ReactCommon/turbomodule/core (= 0.73.3) - fmt (6.2.1) - glog (0.3.5) - - Gutenberg (1.119.0): + - Gutenberg (1.119.1): - React-Core (= 0.73.3) - React-CoreModules (= 0.73.3) - React-RCTImage (= 0.73.3) @@ -1109,7 +1109,7 @@ PODS: - React-Core - RNSVG (14.0.0): - React-Core - - RNTAztecView (1.119.0): + - RNTAztecView (1.119.1): - React-Core - WordPress-Aztec-iOS (= 1.19.11) - SDWebImage (5.11.1): @@ -1343,7 +1343,7 @@ SPEC CHECKSUMS: FBReactNativeSpec: 73b3972e2bd20b3235ff2014f06a3d3af675ed29 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 - Gutenberg: 8f5a5b16c987c6532add8413cb3411f583f43b69 + Gutenberg: be04e16bda9f59460f938d9c3f1248778df0368f hermes-engine: 5420539d016f368cd27e008f65f777abd6098c56 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c @@ -1402,7 +1402,7 @@ SPEC CHECKSUMS: RNReanimated: 6936b41d8afb97175e7c0ab40425b53103f71046 RNScreens: 2b73f5eb2ac5d94fbd61fa4be0bfebd345716825 RNSVG: 255767813dac22db1ec2062c8b7e7b856d4e5ae6 - RNTAztecView: c0a124a24b01a96ceeac8c0dcdc461f2d06e13f2 + RNTAztecView: 268a6489f223c3a91afa2ba5ee7bef82df900c69 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 diff --git a/packages/react-native-editor/package.json b/packages/react-native-editor/package.json index 710202587b55a4..c131e7caf1f776 100644 --- a/packages/react-native-editor/package.json +++ b/packages/react-native-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-editor", - "version": "1.119.0", + "version": "1.119.1", "description": "Mobile WordPress gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 453760a6ba94bb..470929fd0628a2 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -6,7 +6,9 @@ ### Breaking Changes -- Use React's automatic runtime to transform JSX ([#61692](https://github.com/WordPress/gutenberg/pull/61692)). +**Note** If you're using @wordpress/scripts for building JS scripts to target WordPress 6.5 or earlier, you should not upgrade to this version and continue using @wordpress/scripts@27. + +- Use React's automatic runtime to transform JSX ([#61692](https://github.com/WordPress/gutenberg/pull/61692)). - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 549898b3c8773c..bcf0d238400a08 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -3161,7 +3161,7 @@ public function test_get_editor_settings_blank() { public function test_get_editor_settings_custom_units_can_be_disabled() { add_theme_support( 'custom-units', array() ); - $actual = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() ); + $actual = WP_Theme_JSON_Gutenberg::get_from_editor_settings( gutenberg_get_classic_theme_supports_block_editor_settings() ); remove_theme_support( 'custom-units' ); $expected = array( @@ -3174,7 +3174,7 @@ public function test_get_editor_settings_custom_units_can_be_disabled() { public function test_get_editor_settings_custom_units_can_be_enabled() { add_theme_support( 'custom-units' ); - $actual = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() ); + $actual = WP_Theme_JSON_Gutenberg::get_from_editor_settings( gutenberg_get_classic_theme_supports_block_editor_settings() ); remove_theme_support( 'custom-units' ); $expected = array( @@ -3187,7 +3187,7 @@ public function test_get_editor_settings_custom_units_can_be_enabled() { public function test_get_editor_settings_custom_units_can_be_filtered() { add_theme_support( 'custom-units', 'rem', 'em' ); - $actual = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() ); + $actual = WP_Theme_JSON_Gutenberg::get_from_editor_settings( gutenberg_get_classic_theme_supports_block_editor_settings() ); remove_theme_support( 'custom-units' ); $expected = array( diff --git a/schemas/json/block.json b/schemas/json/block.json index 92bcecf90b9b60..0c036a6e05ffe6 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -640,6 +640,11 @@ } } ] + }, + "splitting": { + "type": "boolean", + "description": "This property indicates whether the block can split when the Enter key is pressed or when blocks are pasted.", + "default": false } }, "additionalProperties": true diff --git a/test/e2e/specs/editor/plugins/custom-post-types.spec.js b/test/e2e/specs/editor/plugins/custom-post-types.spec.js index 36050415925c19..67372d46c61a70 100644 --- a/test/e2e/specs/editor/plugins/custom-post-types.spec.js +++ b/test/e2e/specs/editor/plugins/custom-post-types.spec.js @@ -59,6 +59,19 @@ test.describe( 'Test Custom Post Types', () => { await expect( parentPageLocator ).toHaveValue( parentPage ); } ); + test( 'should not be able to rename a post that lacks title support', async ( { + admin, + editor, + page, + } ) => { + await admin.createNewPost( { postType: 'hierar-no-title' } ); + await editor.openDocumentSettingsSidebar(); + await page.getByRole( 'button', { name: 'Actions' } ).click(); + await expect( + page.getByRole( 'menuitem', { name: 'Rename' } ) + ).toHaveCount( 0 ); + } ); + test( 'should create a cpt with a legacy block in its template without WSOD', async ( { admin, editor, diff --git a/test/e2e/specs/interactivity/directive-each.spec.ts b/test/e2e/specs/interactivity/directive-each.spec.ts index a9f09191685a3b..9dbd1e47a2ef1c 100644 --- a/test/e2e/specs/interactivity/directive-each.spec.ts +++ b/test/e2e/specs/interactivity/directive-each.spec.ts @@ -492,4 +492,17 @@ test.describe( 'data-wp-each', () => { await expect( avocado ).toHaveAttribute( 'data-tag', '0' ); await expect( banana ).toHaveAttribute( 'data-tag', '1' ); } ); + + test( 'directives inside elements with `wp-each-child` should not run', async ( { + page, + } ) => { + const element = page + .getByTestId( 'elements with directives' ) + .getByTestId( 'item' ); + const callbackRunCount = page + .getByTestId( 'elements with directives' ) + .getByTestId( 'callbackRunCount' ); + await expect( element ).toHaveText( 'beta' ); + await expect( callbackRunCount ).toHaveText( '1' ); + } ); } ); diff --git a/test/performance/config/performance-reporter.ts b/test/performance/config/performance-reporter.ts index 049a21fb333b18..6360b78636a2ac 100644 --- a/test/performance/config/performance-reporter.ts +++ b/test/performance/config/performance-reporter.ts @@ -212,6 +212,18 @@ class PerformanceReporter implements Reporter { console.table( printableResults ); } } + + printsToStdio() { + return true; + } + + onStdOut( chunk: string | Buffer ) { + process.stdout.write( chunk ); + } + + onStdErr( chunk: string | Buffer ) { + process.stderr.write( chunk ); + } } export default PerformanceReporter; diff --git a/test/performance/playwright.config.ts b/test/performance/playwright.config.ts index ed221b1dc7bfbe..fafca3a589122f 100644 --- a/test/performance/playwright.config.ts +++ b/test/performance/playwright.config.ts @@ -14,9 +14,7 @@ process.env.ASSETS_PATH = path.join( __dirname, 'assets' ); const config = defineConfig( { ...baseConfig, - reporter: process.env.CI - ? './config/performance-reporter.ts' - : [ [ 'list' ], [ './config/performance-reporter.ts' ] ], + reporter: [ [ 'list' ], [ './config/performance-reporter.ts' ] ], forbidOnly: !! process.env.CI, fullyParallel: false, retries: 0, diff --git a/test/performance/specs/site-editor.spec.js b/test/performance/specs/site-editor.spec.js index 4b31b24460dc3d..f0a55f9bbeeb39 100644 --- a/test/performance/specs/site-editor.spec.js +++ b/test/performance/specs/site-editor.spec.js @@ -295,47 +295,22 @@ test.describe( 'Site Editor Performance', () => { } ); await editor.openDocumentSettingsSidebar(); - /* - * https://github.com/WordPress/gutenberg/pull/55091 updated the HTML by - * removing the replace template button in sidebar-edit-mode/template-panel/replace-template-button.js - * with a "transform into" list. https://github.com/WordPress/gutenberg/pull/59259 made these tests - * compatible with the new UI, however, the performance tests compare previous versions of the UI. - * - * The following code is a workaround to test the performance of the new UI. - * `actionsButtonElement` is used to check if the old UI is present. - * If there is a Replace template button (old UI), click it, otherwise, click the "transform into" button. - * Once the performance tests are updated to compare compatible versions this code can be removed. - */ - // eslint-disable-next-line no-restricted-syntax - const isActionsButtonVisible = await page - .locator( - '.edit-site-template-card__actions button[aria-label="Actions"]' - ) - .isVisible(); - - if ( isActionsButtonVisible ) { - await page - .getByRole( 'button', { - name: 'Actions', - } ) - .click(); - } - // Wait for the browser to be idle before starting the monitoring. // eslint-disable-next-line no-restricted-syntax, playwright/no-wait-for-timeout await page.waitForTimeout( BROWSER_IDLE_WAIT ); const startTime = performance.now(); - if ( isActionsButtonVisible ) { - await page - .getByRole( 'menuitem', { name: 'Replace template' } ) - .click(); - } else { - await page - .getByRole( 'button', { name: 'Design' } ) - .click(); - } + await page + .getByRole( 'button', { name: 'Design' } ) + .or( + // Locator for backward compatibility with the old UI. + // The label was updated in https://github.com/WordPress/gutenberg/pull/62161. + page.getByRole( 'button', { + name: 'Transform into:', + } ) + ) + .click(); const patterns = [ 'Blogging home template',