diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index e9a0e0b85bdc7..becb96ca60b1c 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -144,6 +144,7 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
getSelectedBlockCount,
getBlockName,
__unstableGetContentLockingParent,
+ getTemplateLock,
} = select( blockEditorStore );
const _selectedBlockClientId = getSelectedBlockClientId();
@@ -157,9 +158,11 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
selectedBlockClientId: _selectedBlockClientId,
selectedBlockName: _selectedBlockName,
blockType: _blockType,
- topLevelLockedBlock: __unstableGetContentLockingParent(
- _selectedBlockClientId
- ),
+ topLevelLockedBlock:
+ __unstableGetContentLockingParent( _selectedBlockClientId ) ||
+ ( getTemplateLock( _selectedBlockClientId ) === 'contentOnly'
+ ? _selectedBlockClientId
+ : undefined ),
};
}, [] );
diff --git a/packages/block-editor/src/components/block-patterns-list/style.scss b/packages/block-editor/src/components/block-patterns-list/style.scss
index 8ae80f63ce1e3..3b5c2571be0fa 100644
--- a/packages/block-editor/src/components/block-patterns-list/style.scss
+++ b/packages/block-editor/src/components/block-patterns-list/style.scss
@@ -2,6 +2,11 @@
cursor: pointer;
margin-bottom: $grid-unit-30;
+ // The list item contains absolutely positioned visually hidden text,
+ // so make this container relative. This prevents the bug experienced in
+ // https://github.com/WordPress/gutenberg/issues/44842.
+ position: relative;
+
&.is-placeholder {
min-height: 100px;
}
diff --git a/packages/block-editor/src/components/button-block-appender/style.scss b/packages/block-editor/src/components/button-block-appender/style.scss
index 45358b9a0f050..b2af07e50a944 100644
--- a/packages/block-editor/src/components/button-block-appender/style.scss
+++ b/packages/block-editor/src/components/button-block-appender/style.scss
@@ -36,8 +36,9 @@
.block-list-appender:only-child {
.is-layout-constrained.block-editor-block-list__block:not(.is-selected) > &,
.is-layout-flow.block-editor-block-list__block:not(.is-selected) > &,
- .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > &,
- .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > & {
+ // Legacy groups have an inner container so need to be targeted separately
+ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > &,
+ .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > & {
pointer-events: none;
&::after {
diff --git a/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js b/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js
index 5eff89609f6d8..1b81069c44f3d 100644
--- a/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js
+++ b/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js
@@ -40,7 +40,7 @@ export default function useInnerBlockTemplateSync(
templateLock,
templateInsertUpdatesSelection
) {
- const { getSelectedBlocksInitialCaretPosition } =
+ const { getSelectedBlocksInitialCaretPosition, isBlockSelected } =
useSelect( blockEditorStore );
const { replaceInnerBlocks } = useDispatch( blockEditorStore );
const innerBlocks = useSelect(
@@ -86,7 +86,8 @@ export default function useInnerBlockTemplateSync(
nextBlocks,
currentInnerBlocks.length === 0 &&
templateInsertUpdatesSelection &&
- nextBlocks.length !== 0,
+ nextBlocks.length !== 0 &&
+ isBlockSelected( clientId ),
// This ensures the "initialPosition" doesn't change when applying the template
// If we're supposed to focus the block, we'll focus the first inner block
// otherwise, we won't apply any auto-focus.
diff --git a/packages/block-editor/src/components/spacing-sizes-control/spacing-input-control.js b/packages/block-editor/src/components/spacing-sizes-control/spacing-input-control.js
index cf9a663fe1fa1..4a08bb9b3348a 100644
--- a/packages/block-editor/src/components/spacing-sizes-control/spacing-input-control.js
+++ b/packages/block-editor/src/components/spacing-sizes-control/spacing-input-control.js
@@ -221,6 +221,7 @@ export default function SpacingInputControl( {
hideLabelFromVision={ true }
className="components-spacing-sizes-control__custom-value-input"
style={ { gridColumn: '1' } }
+ size={ '__unstable-large' }
/>
) }
>
diff --git a/packages/block-editor/src/components/spacing-sizes-control/style.scss b/packages/block-editor/src/components/spacing-sizes-control/style.scss
index 27b83a9ba5ca8..02731920c5e6f 100644
--- a/packages/block-editor/src/components/spacing-sizes-control/style.scss
+++ b/packages/block-editor/src/components/spacing-sizes-control/style.scss
@@ -2,7 +2,7 @@
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
- grid-template-rows: 25px auto;
+ grid-template-rows: 16px auto;
}
.component-spacing-sizes-control {
@@ -27,7 +27,7 @@
grid-column: 1 / 1;
justify-content: left;
height: $grid-unit-20;
- margin-top: $grid-unit-15;
+ margin-top: $grid-unit-20;
}
.components-spacing-sizes-control__side-label {
@@ -37,8 +37,9 @@
}
&.is-unlinked {
- .components-range-control.components-spacing-sizes-control__range-control {
- margin-top: $grid-unit-15;
+ .components-range-control.components-spacing-sizes-control__range-control,
+ .components-spacing-sizes-control__custom-value-input {
+ margin-top: $grid-unit-10;
}
}
@@ -60,12 +61,7 @@
grid-column: 2 / 2;
grid-row: 1 / 1;
justify-self: end;
- padding: 0;
- &.is-small.has-icon {
- padding: 0;
- min-width: $icon-size;
- height: $grid-unit-20;
- }
+ margin-top: -4px;
}
.component-spacing-sizes-control__linked-button ~ .components-spacing-sizes-control__custom-toggle-all {
@@ -75,33 +71,43 @@
.components-spacing-sizes-control__custom-toggle-single {
grid-column: 3 / 3;
justify-self: end;
- &.is-small.has-icon {
- padding: 0;
- min-width: $icon-size;
- height: $grid-unit-20;
- margin-top: $grid-unit-15;
- }
+ margin-top: $grid-unit-15;
}
.component-spacing-sizes-control__linked-button {
grid-column: 3 / 3;
grid-row: 1 / 1;
justify-self: end;
+ line-height: 0;
+ margin-top: -4px;
}
.components-spacing-sizes-control__custom-value-range {
grid-column: span 2;
- margin-left: $grid-unit-10;
- height: 30px;
+ margin-left: $grid-unit-20;
+ margin-top: 8px;
}
.components-spacing-sizes-control__custom-value-input {
width: 124px;
+ margin-top: 8px;
+ }
+
+ .components-range-control {
+ height: 40px;
+ /* Vertically center the RangeControl until it has true 40px height. */
+ display: flex;
+ align-items: center;
+
+ > .components-base-control__field {
+ /* Fixes RangeControl contents when the outer wrapper is flex */
+ flex: 1;
+ }
}
.components-spacing-sizes-control__range-control {
grid-column: span 3;
- height: 40px;
+ margin-top: 8px;
}
.components-range-control__mark {
@@ -125,5 +131,6 @@
.components-spacing-sizes-control__custom-select-control {
grid-column: span 3;
+ margin-top: $grid-unit-10;
}
}
diff --git a/packages/block-library/src/avatar/index.php b/packages/block-library/src/avatar/index.php
index 9e20d81b648ed..f6e3f6a7eeaf2 100644
--- a/packages/block-library/src/avatar/index.php
+++ b/packages/block-library/src/avatar/index.php
@@ -127,7 +127,7 @@ function render_block_core_avatar( $attributes, $content, $block ) {
$label = 'aria-label="' . sprintf( esc_attr__( '(%s website link, opens in a new tab)' ), $comment->comment_author ) . '"';
}
// translators: %1$s: Comment Author website link. %2$s: Link target. %3$s Aria label. %4$s Avatar image.
- $avatar_block = sprintf( '%4$s', $comment->comment_author_url, esc_attr( $attributes['linkTarget'] ), $label, $avatar_block );
+ $avatar_block = sprintf( '%4$s', esc_url( $comment->comment_author_url ), esc_attr( $attributes['linkTarget'] ), $label, $avatar_block );
}
return sprintf( '
%2s
', $wrapper_attributes, $avatar_block );
}
diff --git a/packages/block-library/src/list-item/hooks/use-outdent-list-item.js b/packages/block-library/src/list-item/hooks/use-outdent-list-item.js
index 93472f49dbba8..d4c034b06e813 100644
--- a/packages/block-library/src/list-item/hooks/use-outdent-list-item.js
+++ b/packages/block-library/src/list-item/hooks/use-outdent-list-item.js
@@ -20,12 +20,16 @@ export default function useOutdentListItem( clientId ) {
const registry = useRegistry();
const { canOutdent } = useSelect(
( innerSelect ) => {
- const { getBlockRootClientId } = innerSelect( blockEditorStore );
+ const { getBlockRootClientId, getBlockName } =
+ innerSelect( blockEditorStore );
const grandParentId = getBlockRootClientId(
getBlockRootClientId( clientId )
);
+ const grandParentName = getBlockName( grandParentId );
+ const isListItem = grandParentName === listItemName;
+
return {
- canOutdent: !! grandParentId,
+ canOutdent: isListItem,
};
},
[ clientId ]
diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php
index 33e1ebdbab56d..c3f6317eb2955 100644
--- a/packages/block-library/src/navigation/index.php
+++ b/packages/block-library/src/navigation/index.php
@@ -646,7 +646,7 @@ function render_block_core_navigation( $attributes, $content, $block ) {
$toggle_aria_label_close,
esc_attr( implode( ' ', $responsive_container_classes ) ),
esc_attr( implode( ' ', $open_button_classes ) ),
- safecss_filter_attr( $colors['overlay_inline_styles'] ),
+ esc_attr( safecss_filter_attr( $colors['overlay_inline_styles'] ) ),
__( 'Menu' ),
$toggle_button_content,
$toggle_close_button_content
diff --git a/packages/block-library/src/rss/index.php b/packages/block-library/src/rss/index.php
index 0edbc90490c31..e32155195af1d 100644
--- a/packages/block-library/src/rss/index.php
+++ b/packages/block-library/src/rss/index.php
@@ -20,7 +20,7 @@ function render_block_core_rss( $attributes ) {
$rss = fetch_feed( $attributes['feedURL'] );
if ( is_wp_error( $rss ) ) {
- return '' . __( 'RSS Error:' ) . ' ' . $rss->get_error_message() . '
';
+ return '' . __( 'RSS Error:' ) . ' ' . esc_html( $rss->get_error_message() ) . '
';
}
if ( ! $rss->get_item_quantity() ) {
@@ -48,8 +48,8 @@ function render_block_core_rss( $attributes ) {
if ( $date ) {
$date = sprintf(
' ',
- date_i18n( get_option( 'c' ), $date ),
- date_i18n( get_option( 'date_format' ), $date )
+ esc_attr( date_i18n( get_option( 'c' ), $date ) ),
+ esc_attr( date_i18n( get_option( 'date_format' ), $date ) )
);
}
}
diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php
index 61b2cf2b06b51..26b6a7585ccc7 100644
--- a/packages/block-library/src/search/index.php
+++ b/packages/block-library/src/search/index.php
@@ -367,12 +367,12 @@ function styles_for_block_core_search( $attributes ) {
// Add color styles.
$has_text_color = ! empty( $attributes['style']['color']['text'] );
if ( $has_text_color ) {
- $button_styles[] = sprintf( 'color: %s;', esc_attr( $attributes['style']['color']['text'] ) );
+ $button_styles[] = sprintf( 'color: %s;', $attributes['style']['color']['text'] );
}
$has_background_color = ! empty( $attributes['style']['color']['background'] );
if ( $has_background_color ) {
- $button_styles[] = sprintf( 'background-color: %s;', esc_attr( $attributes['style']['color']['background'] ) );
+ $button_styles[] = sprintf( 'background-color: %s;', $attributes['style']['color']['background'] );
}
$has_custom_gradient = ! empty( $attributes['style']['color']['gradient'] );
@@ -399,9 +399,9 @@ function styles_for_block_core_search( $attributes ) {
}
return array(
- 'input' => ! empty( $input_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $input_styles ) ) ) : '',
- 'button' => ! empty( $button_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $button_styles ) ) ) : '',
- 'wrapper' => ! empty( $wrapper_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $wrapper_styles ) ) ) : '',
+ 'input' => ! empty( $input_styles ) ? sprintf( ' style="%s"', esc_attr( safecss_filter_attr( implode( ' ', $input_styles ) ) ) ) : '',
+ 'button' => ! empty( $button_styles ) ? sprintf( ' style="%s"', esc_attr( safecss_filter_attr( implode( ' ', $button_styles ) ) ) ) : '',
+ 'wrapper' => ! empty( $wrapper_styles ) ? sprintf( ' style="%s"', esc_attr( safecss_filter_attr( implode( ' ', $wrapper_styles ) ) ) ) : '',
'label' => ! empty( $label_styles ) ? sprintf( ' style="%s"', esc_attr( safecss_filter_attr( implode( ' ', $label_styles ) ) ) ) : '',
);
}
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 31ad5b0457d7e..bf32aadd73ff5 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -5,6 +5,7 @@
### Bug Fix
- `FontSizePicker`: Ensure that fluid font size presets appear correctly in the UI controls ([#44791](https://github.com/WordPress/gutenberg/pull/44791))
+- `Navigator`: restore focus only once per location ([#44972](https://github.com/WordPress/gutenberg/pull/44972)).
- The `LinkedButton` to unlink sides in `BoxControl`, `BorderBoxControl` and `BorderRadiusControl` have changed from a rectangular primary button to an icon-only button, with a sentence case tooltip, and default-size icon for better legibility. The `Button` component has been fixed so when `isSmall` and `icon` props are set, and no text is present, the button shape is square rather than rectangular.
- `Popover`: fix limitShift logic by adding iframe offset correctly [#42950](https://github.com/WordPress/gutenberg/pull/42950)).
diff --git a/packages/components/src/font-size-picker/index.js b/packages/components/src/font-size-picker/index.js
index 1fb266bba02b2..47668eb2dca16 100644
--- a/packages/components/src/font-size-picker/index.js
+++ b/packages/components/src/font-size-picker/index.js
@@ -116,7 +116,7 @@ function FontSizePicker(
}
// Calculate the `hint` for toggle group control.
- let hint = selectedOption.name;
+ let hint = selectedOption?.name || selectedOption.slug;
if (
! fontSizesContainComplexValues &&
typeof selectedOption.size === 'string'
diff --git a/packages/components/src/navigator/navigator-provider/component.tsx b/packages/components/src/navigator/navigator-provider/component.tsx
index 634c6f8204b10..fc769f2f5736c 100644
--- a/packages/components/src/navigator/navigator-provider/component.tsx
+++ b/packages/components/src/navigator/navigator-provider/component.tsx
@@ -49,6 +49,7 @@ function NavigatorProvider(
...options,
path,
isBack: false,
+ hasRestoredFocus: false,
},
] );
},
@@ -62,6 +63,7 @@ function NavigatorProvider(
{
...locationHistory[ locationHistory.length - 2 ],
isBack: true,
+ hasRestoredFocus: false,
},
] );
}
diff --git a/packages/components/src/navigator/navigator-screen/component.tsx b/packages/components/src/navigator/navigator-screen/component.tsx
index 94b7bfee306e9..092b95b50d97f 100644
--- a/packages/components/src/navigator/navigator-screen/component.tsx
+++ b/packages/components/src/navigator/navigator-screen/component.tsx
@@ -79,7 +79,13 @@ function NavigatorScreen( props: Props, forwardedRef: ForwardedRef< any > ) {
// - if the current location is not the initial one (to avoid moving focus on page load)
// - when the screen becomes visible
// - if the wrapper ref has been assigned
- if ( isInitialLocation || ! isMatch || ! wrapperRef.current ) {
+ // - if focus hasn't already been restored for the current location
+ if (
+ isInitialLocation ||
+ ! isMatch ||
+ ! wrapperRef.current ||
+ location.hasRestoredFocus
+ ) {
return;
}
@@ -103,10 +109,12 @@ function NavigatorScreen( props: Props, forwardedRef: ForwardedRef< any > ) {
elementToFocus = firstTabbable ?? wrapperRef.current;
}
+ location.hasRestoredFocus = true;
elementToFocus.focus();
}, [
isInitialLocation,
isMatch,
+ location.hasRestoredFocus,
location.isBack,
previousLocation?.focusTargetSelector,
] );
diff --git a/packages/components/src/navigator/types.ts b/packages/components/src/navigator/types.ts
index edc80c356e18e..217b940892337 100644
--- a/packages/components/src/navigator/types.ts
+++ b/packages/components/src/navigator/types.ts
@@ -11,6 +11,7 @@ export type NavigatorLocation = NavigateOptions & {
isInitial?: boolean;
isBack?: boolean;
path?: string;
+ hasRestoredFocus?: boolean;
};
export type NavigatorContext = {
diff --git a/packages/env/lib/download-wp-phpunit.js b/packages/env/lib/download-wp-phpunit.js
index 923750d58b1d7..3900fd9495343 100644
--- a/packages/env/lib/download-wp-phpunit.js
+++ b/packages/env/lib/download-wp-phpunit.js
@@ -122,7 +122,7 @@ async function downloadTestSuite(
// Alpha, Beta, and RC versions are bleeding edge and should pull from trunk.
let ref;
const fetchRaw = [];
- if ( ! wpVersion || wpVersion.match( /-(?:alpha|beta|rc)/ ) ) {
+ if ( ! wpVersion || wpVersion.match( /-(?:alpha|beta|rc)/i ) ) {
ref = 'trunk';
fetchRaw.push( 'fetch', 'origin', ref, '--depth', '1' );
} else {
diff --git a/packages/widgets/src/blocks/legacy-widget/index.php b/packages/widgets/src/blocks/legacy-widget/index.php
index c3aa55fdfe241..94cfb9ba71ebf 100644
--- a/packages/widgets/src/blocks/legacy-widget/index.php
+++ b/packages/widgets/src/blocks/legacy-widget/index.php
@@ -34,7 +34,7 @@ function render_block_core_legacy_widget( $attributes ) {
if ( isset( $attributes['instance']['encoded'], $attributes['instance']['hash'] ) ) {
$serialized_instance = base64_decode( $attributes['instance']['encoded'] );
- if ( wp_hash( $serialized_instance ) !== $attributes['instance']['hash'] ) {
+ if ( ! hash_equals( wp_hash( $serialized_instance ), (string) $attributes['instance']['hash'] ) ) {
return '';
}
$instance = unserialize( $serialized_instance );
diff --git a/packages/widgets/src/blocks/widget-group/index.php b/packages/widgets/src/blocks/widget-group/index.php
index 6cf6442346a30..8c8584b296d57 100644
--- a/packages/widgets/src/blocks/widget-group/index.php
+++ b/packages/widgets/src/blocks/widget-group/index.php
@@ -28,7 +28,7 @@ function render_block_core_widget_group( $attributes, $content, $block ) {
$html = '';
if ( ! empty( $attributes['title'] ) ) {
- $html .= $before_title . $attributes['title'] . $after_title;
+ $html .= $before_title . esc_html( $attributes['title'] ) . $after_title;
}
$html .= '