Commit b88541ea46d for woocommerce

commit b88541ea46db044deb2ef4af0df1404c0878b247
Author: Karol Manijak <20098064+kmanijak@users.noreply.github.com>
Date:   Tue Oct 6 20:46:42 2026 +0200

    Make Featured Category customisable (#69016)

    * Add Core design supports to Featured blocks

    * Add changelogs for Featured block design supports

    * Simplify Featured block design support rendering

    * Simplify Featured block changelog entries

    * Restore default padding inside featured blocks

    * Prevent default gaps in existing featured blocks

    * Restore wide and full alignment options for featured blocks

    * Remove heading color support from featured blocks

    * Fix duplicated styles on featured block backgrounds

    * Fix title color inheritance in featured blocks

    * Fix block refs in featured item placeholders

    * Fix category description spacing in the editor

    * Restore top spacing in featured blocks

    * Remove redundant featured block wrapper class

    * Simplify featured block layout class removal

    * Simplify typography supports for featured blocks

    * Update featured block tests for supported typography

    * Remove unused featured block style configuration

    * Remove redundant featured block registration settings

    * Remove redundant featured block anchor output

    * Prefer Core minimum height over saved featured block height

    * Fix full-width featured block sizing

    * Preserve featured block spacing with custom vertical alignment (#69372)

diff --git a/docs/block-development/reference/block-references.md b/docs/block-development/reference/block-references.md
index 669d7fb4bfa..204fb548ac6 100644
--- a/docs/block-development/reference/block-references.md
+++ b/docs/block-development/reference/block-references.md
@@ -707,8 +707,8 @@ Visually highlight a product category and encourage prompt action.

 - **Name:** woocommerce/featured-category
 - **Category:** woocommerce
-- **Supports:** align (full, wide), ariaLabel, color (background, text), filter (duotone), interactivity (clientNavigation), spacing (padding), ~~html~~
-- **Attributes:** alt, categoryId, contentAlign, dimRatio, focalPoint, hasParallax, imageFit, isRepeated, linkText, mediaId, mediaSrc, minHeight, overlayColor, overlayGradient, previewCategory
+- **Supports:** align (full, wide), allowedBlocks, anchor, ariaLabel, color (background, gradients, link, text, ~~enableContrastChecker~~), dimensions (aspectRatio, minHeight), filter (duotone), interactivity (clientNavigation), shadow, spacing (blockGap, margin, padding), typography (), ~~html~~
+- **Attributes:** alt, anchor, categoryId, contentAlign, dimRatio, focalPoint, hasParallax, imageFit, isRepeated, linkText, mediaId, mediaSrc, minHeight, overlayColor, overlayGradient, previewCategory, verticalAlignment

 ## Featured Product - woocommerce/featured-product

@@ -716,8 +716,8 @@ Highlight a product or variation.

 - **Name:** woocommerce/featured-product
 - **Category:** woocommerce
-- **Supports:** align (full, wide), ariaLabel, color (background, text), filter (duotone), interactivity (clientNavigation), multiple, spacing (padding), ~~html~~
-- **Attributes:** alt, contentAlign, dimRatio, focalPoint, hasParallax, imageFit, isRepeated, linkText, mediaId, mediaSrc, minHeight, overlayColor, overlayGradient, previewProduct, productId
+- **Supports:** align (full, wide), allowedBlocks, anchor, ariaLabel, color (background, gradients, link, text, ~~enableContrastChecker~~), dimensions (aspectRatio, minHeight), filter (duotone), interactivity (clientNavigation), multiple, shadow, spacing (blockGap, margin, padding), typography (), ~~html~~
+- **Attributes:** alt, anchor, contentAlign, dimRatio, focalPoint, hasParallax, imageFit, isRepeated, linkText, mediaId, mediaSrc, minHeight, overlayColor, overlayGradient, previewProduct, productId, verticalAlignment

 ## Filter Block - woocommerce/filter-wrapper

diff --git a/plugins/woocommerce/changelog/add-featured-block-design-supports b/plugins/woocommerce/changelog/add-featured-block-design-supports
new file mode 100644
index 00000000000..e7c5fe2c8be
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-featured-block-design-supports
@@ -0,0 +1,4 @@
+Significance: minor
+Type: enhancement
+
+Support richer styling in Featured Product and Featured Category blocks.
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/category-description/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/category-description/edit.tsx
index 425753d6ecc..138ea5127a5 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/category-description/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/category-description/edit.tsx
@@ -82,23 +82,28 @@ export default function Edit( { attributes, setAttributes, context }: Props ) {
 	} );

 	let descriptionElement = (
-		<p { ...blockProps }>{ __( 'Category description', 'woocommerce' ) }</p>
+		<div { ...blockProps }>
+			<p>{ __( 'Category description', 'woocommerce' ) }</p>
+		</div>
 	);

 	if ( termId || isPreviewMode ) {
 		descriptionElement = userCanEdit ? (
-			<PlainText
-				tagName="p"
-				placeholder={ __( 'No description', 'woocommerce' ) as string }
-				value={ displayRawDescription }
-				onChange={ ( v: string ) =>
-					( setDescription as ( v: string ) => void )( v )
-				}
-				__experimentalVersion={ 2 }
-				{ ...blockProps }
-			/>
+			<div { ...blockProps }>
+				<PlainText
+					tagName="p"
+					placeholder={
+						__( 'No description', 'woocommerce' ) as string
+					}
+					value={ displayRawDescription }
+					onChange={ ( v: string ) =>
+						( setDescription as ( v: string ) => void )( v )
+					}
+					__experimentalVersion={ 2 }
+				/>
+			</div>
 		) : (
-			<p
+			<div
 				{ ...blockProps }
 				dangerouslySetInnerHTML={ {
 					__html: displayFullDescription,
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/block-controls.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/block-controls.tsx
index d3067594d29..5fcf7d42b84 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/block-controls.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/block-controls.tsx
@@ -4,6 +4,7 @@
 import { __ } from '@wordpress/i18n';
 import {
 	AlignmentToolbar,
+	BlockVerticalAlignmentToolbar,
 	BlockControls as BlockControlsWrapper,
 	MediaReplaceFlow,
 } from '@wordpress/block-editor';
@@ -49,6 +50,7 @@ type WithBlockControlsProps< T extends EditorBlock< T > > =

 type BlockControlRequiredAttributes = {
 	contentAlign: BlockAlignment;
+	verticalAlignment?: 'top' | 'center' | 'bottom' | undefined;
 	mediaId: number;
 	mediaSrc: string;
 };
@@ -58,6 +60,7 @@ interface BlockControlsProps {
 	backgroundImageId: number;
 	backgroundImageSrc: string;
 	contentAlign: BlockAlignment;
+	verticalAlignment?: 'top' | 'center' | 'bottom' | undefined;
 	cropLabel: string;
 	editLabel: string;
 	editMode: boolean;
@@ -78,6 +81,7 @@ export const BlockControls = ( {
 	backgroundImageId,
 	backgroundImageSrc,
 	contentAlign,
+	verticalAlignment,
 	cropLabel,
 	editLabel,
 	editMode,
@@ -89,6 +93,12 @@ export const BlockControls = ( {
 }: BlockControlsProps ) => {
 	return (
 		<BlockControlsWrapper>
+			<BlockVerticalAlignmentToolbar
+				value={ verticalAlignment || 'center' }
+				onChange={ ( nextAlignment ) =>
+					setAttributes( { verticalAlignment: nextAlignment } )
+				}
+			/>
 			<AlignmentToolbar
 				value={ contentAlign }
 				onChange={ ( nextAlign: BlockAlignment ) => {
@@ -148,7 +158,8 @@ export const withBlockControls =
 		const [ isEditingImage, setIsEditingImage ] = props.useEditingImage;
 		const [ editMode, setEditMode ] = props.useEditMode;
 		const { attributes, category, name, product, setAttributes } = props;
-		const { contentAlign, mediaId, mediaSrc } = attributes;
+		const { contentAlign, verticalAlignment, mediaId, mediaSrc } =
+			attributes;
 		const item = category || product;

 		const { backgroundImageId, backgroundImageSrc } = useBackgroundImage( {
@@ -165,6 +176,7 @@ export const withBlockControls =
 					backgroundImageId={ backgroundImageId }
 					backgroundImageSrc={ backgroundImageSrc }
 					contentAlign={ contentAlign }
+					verticalAlignment={ verticalAlignment }
 					cropLabel={ cropLabel }
 					editLabel={ editLabel }
 					editMode={ editMode }
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/edit.tsx
index 7c95a49bc00..526543bb1e6 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/edit.tsx
@@ -2,20 +2,12 @@
  * External dependencies
  */
 import { useBlockProps } from '@wordpress/block-editor';
-import type { FunctionComponent } from 'react';
+import type { FunctionComponent, JSX } from 'react';

 export function Edit< T >( Block: FunctionComponent< T > ) {
 	return function WithBlock( props: T ): JSX.Element {
 		const blockProps = useBlockProps();

-		// The useBlockProps function returns the style with the `color`.
-		// We need to remove it to avoid the block to be styled with the color.
-		const { color, ...styles } = blockProps.style;
-
-		return (
-			<div { ...blockProps } style={ styles }>
-				<Block { ...props } />
-			</div>
-		);
+		return <Block { ...props } blockProps={ blockProps } />;
 	};
 }
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/block.json
index dc8ce2b1b5a..31363278d6f 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/block.json
@@ -12,7 +12,10 @@
 		"ariaLabel": true,
 		"color": {
 			"background": true,
-			"text": true
+			"text": true,
+			"gradients": true,
+			"link": true,
+			"enableContrastChecker": false
 		},
 		"html": false,
 		"filter": {
@@ -20,24 +23,42 @@
 		},
 		"spacing": {
 			"padding": true,
+			"margin": [ "top", "bottom" ],
+			"blockGap": true,
 			"__experimentalDefaultControls": {
-				"padding": true
-			},
-			"__experimentalSkipSerialization": true
+				"padding": true,
+				"blockGap": true
+			}
 		},
 		"__experimentalBorder": {
 			"color": true,
 			"radius": true,
+			"style": true,
 			"width": true,
 			"__experimentalDefaultControls": {
 				"color": true,
 				"radius": true,
+				"style": true,
 				"width": true
-			},
-			"__experimentalSkipSerialization": true
-		}
+			}
+		},
+		"anchor": true,
+		"shadow": true,
+		"typography": {
+			"__experimentalTextTransform": true,
+			"__experimentalTextDecoration": true
+		},
+		"dimensions": {
+			"aspectRatio": true,
+			"minHeight": true
+		},
+		"allowedBlocks": true
 	},
 	"attributes": {
+		"verticalAlignment": {
+			"type": "string",
+			"enum": [ "top", "center", "bottom" ]
+		},
 		"alt": {
 			"type": "string",
 			"default": ""
@@ -78,8 +99,7 @@
 			"default": ""
 		},
 		"minHeight": {
-			"type": "number",
-			"default": 500
+			"type": "number"
 		},
 		"linkText": {
 			"default": "Shop now",
@@ -98,6 +118,9 @@
 		"previewCategory": {
 			"type": "object",
 			"default": null
+		},
+		"anchor": {
+			"type": "string"
 		}
 	},
 	"selectors": {
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/style.scss b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/style.scss
index a6688dfa188..ea6ddb98e72 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/style.scss
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-category/style.scss
@@ -1,6 +1,6 @@
 @import "../style";

-.wp-block-woocommerce-featured-category {
+:where(.wp-block-woocommerce-featured-category) {
 	@extend %wp-block-featured-item;
 }

diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/block.json
index 535560cff4e..1fe753ad365 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/block.json
@@ -16,29 +16,50 @@
 		},
 		"color": {
 			"background": true,
-			"text": true
+			"text": true,
+			"gradients": true,
+			"link": true,
+			"enableContrastChecker": false
 		},
 		"spacing": {
 			"padding": true,
+			"margin": [ "top", "bottom" ],
+			"blockGap": true,
 			"__experimentalDefaultControls": {
-				"padding": true
-			},
-			"__experimentalSkipSerialization": true
+				"padding": true,
+				"blockGap": true
+			}
 		},
 		"__experimentalBorder": {
 			"color": true,
 			"radius": true,
+			"style": true,
 			"width": true,
 			"__experimentalDefaultControls": {
 				"color": true,
 				"radius": true,
+				"style": true,
 				"width": true
-			},
-			"__experimentalSkipSerialization": true
+			}
+		},
+		"multiple": true,
+		"anchor": true,
+		"shadow": true,
+		"typography": {
+			"__experimentalTextTransform": true,
+			"__experimentalTextDecoration": true
 		},
-		"multiple": true
+		"dimensions": {
+			"aspectRatio": true,
+			"minHeight": true
+		},
+		"allowedBlocks": true
 	},
 	"attributes": {
+		"verticalAlignment": {
+			"type": "string",
+			"enum": [ "top", "center", "bottom" ]
+		},
 		"alt": {
 			"type": "string",
 			"default": ""
@@ -79,8 +100,7 @@
 			"default": ""
 		},
 		"minHeight": {
-			"type": "number",
-			"default": 500
+			"type": "number"
 		},
 		"linkText": {
 			"type": "string",
@@ -99,6 +119,9 @@
 		"previewProduct": {
 			"type": "object",
 			"default": null
+		},
+		"anchor": {
+			"type": "string"
 		}
 	},
 	"selectors": {
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/style.scss b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/style.scss
index 5e2a726dba7..294c02704d9 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/style.scss
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/featured-product/style.scss
@@ -1,6 +1,6 @@
 @import "../style";

-.wp-block-woocommerce-featured-product {
+:where(.wp-block-woocommerce-featured-product) {
 	@extend %wp-block-featured-item;
 	background-color: transparent;
 }
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/register.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/register.tsx
index 7e03e6dfc3b..e9fcac7b902 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/register.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/register.tsx
@@ -1,6 +1,3 @@
-// Disabling because of `__experimental` property names.
-/* eslint-disable @typescript-eslint/naming-convention */
-
 /**
  * External dependencies
  */
@@ -15,78 +12,12 @@ import type { BlockConfiguration } from '@wordpress/blocks';
  */
 import { Edit } from './edit';

-type CSSDirections = 'top' | 'right' | 'bottom' | 'left';
-
-interface ExtendedBlockSupports {
-	supports: {
-		color?: {
-			background: string;
-			gradients: boolean;
-			link: boolean;
-			text: string;
-		};
-		spacing?: {
-			margin: boolean | CSSDirections[];
-			padding: boolean | CSSDirections[];
-			__experimentalDefaultControls?: {
-				margin?: boolean;
-				padding?: boolean;
-			};
-			__experimentalSkipSerialization?: boolean;
-		};
-		__experimentalBorder?: {
-			color: boolean;
-			radius: boolean;
-			width: boolean;
-			__experimentalSkipSerialization?: boolean;
-		};
-	};
-}
-
 export function register(
 	Block: FunctionComponent,
 	example: { attributes: Record< string, unknown > },
-	metadata: BlockConfiguration & ExtendedBlockSupports,
+	metadata: BlockConfiguration,
 	settings: Partial< BlockConfiguration >
 ): void {
-	const DEFAULT_SETTINGS = {
-		attributes: {
-			...metadata.attributes,
-			/**
-			 * A minimum height for the block.
-			 *
-			 * Note: if padding is increased, this way the inner content will never
-			 * overflow, but instead will resize the container.
-			 *
-			 * It was decided to change this to make this block more in line with
-			 * the “Cover” block.
-			 */
-			minHeight: {
-				type: 'number',
-				default: getSetting( 'defaultHeight', 500 ),
-			},
-		},
-		supports: {
-			...metadata.supports,
-			color: {
-				background: metadata.supports?.color?.background,
-				text: metadata.supports?.color?.text,
-			},
-			spacing: {
-				padding: metadata.supports?.spacing?.padding,
-
-				__experimentalDefaultControls: {
-					padding:
-						metadata.supports?.spacing
-							?.__experimentalDefaultControls,
-				},
-				__experimentalSkipSerialization:
-					metadata.supports?.spacing?.__experimentalSkipSerialization,
-			},
-			__experimentalBorder: metadata?.supports?.__experimentalBorder,
-		},
-	};
-
 	const DEFAULT_EXAMPLE = {
 		attributes: {
 			alt: '',
@@ -102,7 +33,6 @@ export function register(
 	};

 	registerBlockType( metadata, {
-		...DEFAULT_SETTINGS,
 		example: {
 			...DEFAULT_EXAMPLE,
 			...example,
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/style.scss b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/style.scss
index a77412b6538..1a55efcc561 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/style.scss
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/style.scss
@@ -55,18 +55,23 @@
 	@include with-background-dim();
 	@include with-content-selection();

-	align-content: center;
-	align-items: center;
+	align-content: normal;
+	align-items: stretch;
 	background-position: center center;
 	background-size: cover;
-	display: flex;
-	flex-wrap: wrap;
+	display: grid;
+	grid-template-columns: minmax(0, 1fr);
 	justify-content: center;
 	margin: 0 auto;
+	min-height: var(--wc-featured-item-min-height, 500px);
 	overflow: hidden;
 	position: relative;
 	width: 100%;

+	&.alignfull {
+		width: auto;
+	}
+
 	&.has-left-content {
 		justify-content: flex-start;

@@ -113,7 +118,6 @@
 	}

 	&__description,
-	&__inner-blocks,
 	&__link,
 	&__price,
 	&__title,
@@ -145,6 +149,24 @@
 		}
 	}

+	&__inner-blocks {
+		box-sizing: border-box;
+		color: inherit;
+		width: 100%;
+		padding: 0 48px 16px;
+		z-index: 1;
+
+		&.has-custom-gap {
+			display: flex;
+			flex-direction: column;
+			gap: var(--wc-featured-item-block-gap);
+
+			> * {
+				margin-block: 0;
+			}
+		}
+	}
+
 	&__description {
 		color: inherit;

@@ -154,8 +176,7 @@
 	}

 	&__inner-blocks {
-		.wp-block-post-title,
-		.wp-block-woocommerce-category-title {
+		:where(.wp-block-post-title, .wp-block-woocommerce-category-title) {
 			&,
 			a {
 				color: inherit;
@@ -164,7 +185,6 @@
 	}

 	& &__title {
-		color: inherit;
 		margin-top: 0;

 		div {
@@ -185,7 +205,15 @@
 		justify-content: center;
 		overflow: hidden;
 		width: 100%;
-		height: 100%;
+		height: auto;
+	}
+
+	&.is-vertically-aligned-top > &__wrapper {
+		align-content: flex-start;
+	}
+
+	&.is-vertically-aligned-bottom > &__wrapper {
+		align-content: flex-end;
 	}

 	.wp-block-button.aligncenter {
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-edit-mode.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-edit-mode.tsx
index f712b3ba628..fb84f126d1c 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-edit-mode.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-edit-mode.tsx
@@ -1,6 +1,7 @@
 /**
  * External dependencies
  */
+import type { useBlockProps } from '@wordpress/block-editor';
 import { __ } from '@wordpress/i18n';
 import { usePreviewMode } from '@woocommerce/base-hooks';
 import type { ComponentType } from 'react';
@@ -43,6 +44,7 @@ type EditModeRequiredAttributes = {
 };

 interface EditModeRequiredProps< T > {
+	blockProps: ReturnType< typeof useBlockProps >;
 	attributes: EditModeRequiredAttributes & EditorBlock< T >[ 'attributes' ];
 	clientId: string;
 	effectiveCategoryId?: number;
@@ -138,74 +140,80 @@ export const withEditMode =

 		if ( editMode && canEditItem ) {
 			return (
-				<Placeholder
-					icon={ <Icon icon={ icon } /> }
-					label={ label }
-					className={ className }
-				>
-					<HStack alignment="center">
-						{ isDeleted ? (
-							<Icon
-								icon={ info }
-								className="wc-blocks-featured-items__orange-info-icon"
-							/>
-						) : (
-							<Icon icon={ info } />
-						) }
-						<Text>
-							{ isDeleted
-								? getInvalidItemDescription( name )
-								: description }
-						</Text>
-					</HStack>
-					<div className={ `${ className }__selection` }>
-						{ name === BLOCK_NAMES.featuredCategory && (
-							<ProductCategoryControl
-								selected={
-									selectedOptions?.categoryId
-										? [ selectedOptions.categoryId ]
-										: []
-								}
-								onChange={ (
-									value: ProductCategoryResponseItem[] = []
-								) => {
-									const id = value[ 0 ] ? value[ 0 ].id : 0;
-									setSelectedOptions( {
-										categoryId: id,
-										mediaId: 0,
-										mediaSrc: '',
-									} );
-									triggerUrlUpdate();
-								} }
-								isSingle
-							/>
-						) }
-						{ name === BLOCK_NAMES.featuredProduct && (
-							<ProductControl
-								selected={
-									selectedOptions?.productId
-										? [ selectedOptions.productId ]
-										: []
-								}
-								showVariations
-								onChange={ (
-									value: ProductResponseItem[] = []
-								) => {
-									const id = value[ 0 ] ? value[ 0 ].id : 0;
-									setSelectedOptions( {
-										productId: id,
-										mediaId: 0,
-										mediaSrc: '',
-									} );
-									triggerUrlUpdate();
-								} }
-							/>
-						) }
-						<Button variant="primary" onClick={ onDone }>
-							{ __( 'Done', 'woocommerce' ) }
-						</Button>
-					</div>
-				</Placeholder>
+				<div { ...props.blockProps }>
+					<Placeholder
+						icon={ <Icon icon={ icon } /> }
+						label={ label }
+						className={ className }
+					>
+						<HStack alignment="center">
+							{ isDeleted ? (
+								<Icon
+									icon={ info }
+									className="wc-blocks-featured-items__orange-info-icon"
+								/>
+							) : (
+								<Icon icon={ info } />
+							) }
+							<Text>
+								{ isDeleted
+									? getInvalidItemDescription( name )
+									: description }
+							</Text>
+						</HStack>
+						<div className={ `${ className }__selection` }>
+							{ name === BLOCK_NAMES.featuredCategory && (
+								<ProductCategoryControl
+									selected={
+										selectedOptions?.categoryId
+											? [ selectedOptions.categoryId ]
+											: []
+									}
+									onChange={ (
+										value: ProductCategoryResponseItem[] = []
+									) => {
+										const id = value[ 0 ]
+											? value[ 0 ].id
+											: 0;
+										setSelectedOptions( {
+											categoryId: id,
+											mediaId: 0,
+											mediaSrc: '',
+										} );
+										triggerUrlUpdate();
+									} }
+									isSingle
+								/>
+							) }
+							{ name === BLOCK_NAMES.featuredProduct && (
+								<ProductControl
+									selected={
+										selectedOptions?.productId
+											? [ selectedOptions.productId ]
+											: []
+									}
+									showVariations
+									onChange={ (
+										value: ProductResponseItem[] = []
+									) => {
+										const id = value[ 0 ]
+											? value[ 0 ].id
+											: 0;
+										setSelectedOptions( {
+											productId: id,
+											mediaId: 0,
+											mediaSrc: '',
+										} );
+										triggerUrlUpdate();
+									} }
+								/>
+							) }
+							<Button variant="primary" onClick={ onDone }>
+								{ __( 'Done', 'woocommerce' ) }
+							</Button>
+						</div>
+					</Placeholder>
+				</div>
 			);
 		}

diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-featured-item.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-featured-item.tsx
index 8bee87aebd1..1bde796d976 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-featured-item.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/with-featured-item.tsx
@@ -3,11 +3,18 @@
  */
 import type { BlockAlignment } from '@wordpress/blocks';
 import { __ } from '@wordpress/i18n';
-import type { ComponentType, Dispatch, SetStateAction } from 'react';
+import type {
+	ComponentType,
+	Dispatch,
+	SetStateAction,
+	CSSProperties,
+} from 'react';
+import { getSetting } from '@woocommerce/settings';
 import { ProductResponseItem } from '@woocommerce/types';
 import { Icon, Placeholder, Spinner } from '@wordpress/components';
 import { ProductDataContextProvider } from '@woocommerce/shared-context';
 import clsx from 'clsx';
+import { useMergeRefs } from '@wordpress/compose';
 import {
 	useCallback,
 	useState,
@@ -16,8 +23,12 @@ import {
 	useMemo,
 } from '@wordpress/element';
 import { WP_REST_API_Category } from 'wp-types';
-import { useStyleProps } from '@woocommerce/base-hooks';
-import { InnerBlocks, BlockContextProvider } from '@wordpress/block-editor';
+import {
+	BlockContextProvider,
+	getSpacingPresetCssVar,
+	useInnerBlocksProps,
+	useBlockProps,
+} from '@wordpress/block-editor';

 /**
  * Internal dependencies
@@ -43,6 +54,7 @@ interface WithFeaturedItemConfig extends GenericBlockUIConfig {

 export interface FeaturedItemRequiredAttributes {
 	contentAlign: BlockAlignment;
+	verticalAlignment?: 'top' | 'center' | 'bottom' | undefined;
 	dimRatio: number;
 	focalPoint: { x: number; y: number };
 	hasParallax: boolean;
@@ -57,7 +69,12 @@ export interface FeaturedItemRequiredAttributes {
 	showDesc: boolean;
 	showPrice: boolean;
 	backgroundColor: string | undefined;
-	style: { color: { background: string } };
+	style: {
+		color: { background: string };
+		dimensions?: { aspectRatio?: string; minHeight?: string };
+		spacing?: { blockGap?: string | { top?: string; left?: string } };
+	};
+	allowedBlocks?: string[];
 	backgroundColorVisibilityStatus: {
 		isBackgroundVisible: boolean;
 		message?: string | null;
@@ -78,6 +95,7 @@ interface FeaturedProductRequiredAttributes
 }

 interface FeaturedItemRequiredProps< T > {
+	blockProps: ReturnType< typeof useBlockProps >;
 	attributes: (
 		| FeaturedCategoryRequiredAttributes
 		| FeaturedProductRequiredAttributes
@@ -112,6 +130,40 @@ type FeaturedItemProps< T extends EditorBlock< T > > =
 	| ( T & FeaturedCategoryProps< T > )
 	| ( T & FeaturedProductProps< T > );

+function FeaturedItemInnerBlocks( {
+	className,
+	template,
+	attributes,
+}: {
+	className: string;
+	template: NonNullable<
+		Parameters< typeof useInnerBlocksProps >[ 1 ]
+	>[ 'template' ];
+	attributes: FeaturedItemRequiredAttributes;
+} ) {
+	const spacing = attributes.style?.spacing?.blockGap;
+	const blockGap = typeof spacing === 'object' ? spacing?.top : spacing;
+	const hasBlockGap =
+		blockGap !== undefined && blockGap !== null && blockGap !== '';
+	const innerProps = useInnerBlocksProps(
+		{
+			className: clsx( className, { 'has-custom-gap': hasBlockGap } ),
+			style: {
+				'--wc-featured-item-block-gap': hasBlockGap
+					? getSpacingPresetCssVar( String( blockGap ) )
+					: undefined,
+			} as CSSProperties,
+		},
+		{
+			template,
+			templateLock: false,
+			allowedBlocks: attributes.allowedBlocks,
+			orientation: 'vertical',
+		}
+	);
+	return <div { ...innerProps } />;
+}
+
 export const withFeaturedItem =
 	( {
 		emptyMessage,
@@ -148,6 +200,10 @@ export const withFeaturedItem =
 			blockName: name,
 		} );
 		const featuredProductParentRef = useRef( null );
+		const containerRef = useMergeRefs( [
+			props.blockProps.ref,
+			featuredProductParentRef,
+		] );
 		const [ parentContainerDimension, setParentContainerDimension ] =
 			useState< BgImageDimensions >( { height: 0, width: 0 } );

@@ -242,12 +298,11 @@ export const withFeaturedItem =
 							product={ product }
 							isLoading={ isLoading }
 						>
-							<div className={ `${ className }__inner-blocks` }>
-								<InnerBlocks
-									template={ innerBlocksTemplate }
-									templateLock={ false }
-								/>
-							</div>
+							<FeaturedItemInnerBlocks
+								className={ `${ className }__inner-blocks` }
+								template={ innerBlocksTemplate }
+								attributes={ attributes }
+							/>
 						</ProductDataContextProvider>
 					</BlockContextProvider>
 				);
@@ -264,31 +319,30 @@ export const withFeaturedItem =
 						taxonomy: 'product_cat',
 					} }
 				>
-					<div className={ `${ className }__inner-blocks` }>
-						<InnerBlocks
-							template={ FEATURED_CATEGORY_DEFAULT_TEMPLATE(
-								category,
-								! attributes.categoryId
-							) }
-							templateLock={ false }
-						/>
-					</div>
+					<FeaturedItemInnerBlocks
+						className={ `${ className }__inner-blocks` }
+						template={ FEATURED_CATEGORY_DEFAULT_TEMPLATE(
+							category,
+							! attributes.categoryId
+						) }
+						attributes={ attributes }
+					/>
 				</BlockContextProvider>
 			);
 		};

 		const renderNoItem = () => (
-			<Placeholder
-				className={ className }
-				icon={ <Icon icon={ icon } /> }
-				label={ label }
-			>
-				{ isLoading ? <Spinner /> : renderNoItemContent() }
-			</Placeholder>
+			<div { ...props.blockProps }>
+				<Placeholder
+					className={ className }
+					icon={ <Icon icon={ icon } /> }
+					label={ label }
+				>
+					{ isLoading ? <Spinner /> : renderNoItemContent() }
+				</Placeholder>
+			</div>
 		);

-		const styleProps = useStyleProps( attributes );
-
 		const renderItem = () => {
 			const {
 				contentAlign,
@@ -299,7 +353,6 @@ export const withFeaturedItem =
 				overlayColor,
 				overlayGradient,
 				style,
-				textColor,
 			} = attributes;

 			const containerClass = clsx(
@@ -316,18 +369,20 @@ export const withFeaturedItem =
 				},
 				dimRatioToClass( dimRatio ),
 				contentAlign !== 'center' && `has-${ contentAlign }-content`,
-				styleProps.className
+				props.blockProps.className,
+				attributes.verticalAlignment &&
+					`is-vertically-aligned-${ attributes.verticalAlignment }`
 			);

-			const containerStyle: React.CSSProperties = {
-				borderRadius: style?.border?.radius,
-				color: textColor
-					? `var(--wp--preset--color--${ textColor })`
-					: style?.color?.text,
-				boxSizing: 'border-box',
-				minHeight,
-				...styleProps.style,
-			};
+			const hasAspectRatio = !! style?.dimensions?.aspectRatio;
+			const containerStyle = {
+				'--wc-featured-item-min-height': `${ getSetting(
+					'defaultHeight',
+					500
+				) }px`,
+				minHeight: hasAspectRatio ? undefined : minHeight,
+				...props.blockProps.style,
+			} as CSSProperties;

 			const isImgElement = ! isRepeated && ! hasParallax;

@@ -346,17 +401,26 @@ export const withFeaturedItem =

 			return (
 				<>
-					<ConstrainedResizable
-						enable={ { bottom: true } }
-						onResize={ onResize }
-						showHandle={ isSelected }
-						style={ { minHeight } }
-					/>
 					<div
+						{ ...props.blockProps }
 						className={ containerClass }
-						ref={ featuredProductParentRef }
+						ref={ containerRef }
 						style={ containerStyle }
 					>
+						<ConstrainedResizable
+							enable={ { bottom: true } }
+							onResize={ onResize }
+							showHandle={
+								isSelected &&
+								! hasAspectRatio &&
+								! style?.dimensions?.minHeight
+							}
+							style={ {
+								minHeight: hasAspectRatio
+									? undefined
+									: minHeight,
+							} }
+						/>
 						<div className={ `${ className }__wrapper` }>
 							<div
 								className="background-dim__overlay"
@@ -402,13 +466,15 @@ export const withFeaturedItem =

 		if ( isEditingImage ) {
 			return (
-				<Component
-					{ ...props }
-					backgroundImageSize={ backgroundImageSize }
-					backgroundColorVisibilityStatus={
-						backgroundColorVisibilityStatus
-					}
-				/>
+				<div { ...props.blockProps }>
+					<Component
+						{ ...props }
+						backgroundImageSize={ backgroundImageSize }
+						backgroundColorVisibilityStatus={
+							backgroundColorVisibilityStatus
+						}
+					/>
+				</div>
 			);
 		}

diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/FeaturedItem.php b/plugins/woocommerce/src/Blocks/BlockTypes/FeaturedItem.php
index 24b693ddafb..3115d0161cc 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/FeaturedItem.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/FeaturedItem.php
@@ -2,8 +2,6 @@

 namespace Automattic\WooCommerce\Blocks\BlockTypes;

-use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
-
 /**
  * FeaturedItem class.
  */
@@ -24,22 +22,6 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 		'align' => 'none',
 	);

-	/**
-	 * Global style enabled for this block.
-	 *
-	 * @var array
-	 */
-	protected $global_style_wrapper = array(
-		'background_color',
-		'border_color',
-		'border_radius',
-		'border_width',
-		'font_size',
-		'padding',
-		'text_color',
-		'extra_classes',
-	);
-
 	/**
 	 * Initialize the block.
 	 */
@@ -250,7 +232,14 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 		$styles  = $this->get_styles( $attributes );
 		$classes = $this->get_classes( $attributes );

-		$output  = sprintf( '<div class="%1$s wp-block-woocommerce-%2$s" style="%3$s">', esc_attr( trim( $classes ) ), $this->block_name, esc_attr( $styles ) );
+		$wrapper_attributes = get_block_wrapper_attributes(
+			array(
+				'class' => $classes,
+				'style' => $styles,
+			)
+		);
+
+		$output  = '<div ' . $wrapper_attributes . '>';
 		$output .= sprintf( '<div class="wc-block-%s__wrapper">', $this->block_name );
 		$output .= $this->render_overlay( $attributes );

@@ -273,7 +262,17 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 		$output .= $this->render_attributes( $item, $attributes );

 		if ( ! empty( $content ) ) {
-			$output .= sprintf( '<div class="wc-block-%s__inner-blocks">%s</div>', $this->block_name, $content );
+			$block_gap  = $attributes['style']['spacing']['blockGap'] ?? null;
+			$block_gap  = is_array( $block_gap ) ? ( $block_gap['top'] ?? null ) : $block_gap;
+			$gap_styles = wp_style_engine_get_styles( array( 'spacing' => array( 'margin' => array( 'top' => null !== $block_gap ? (string) $block_gap : null ) ) ) );
+			$gap        = $gap_styles['declarations']['margin-top'] ?? null;
+			$output    .= sprintf(
+				'<div class="wc-block-%1$s__inner-blocks%2$s"%3$s>%4$s</div>',
+				$this->block_name,
+				null !== $gap ? ' has-custom-gap' : '',
+				null !== $gap ? ' style="' . esc_attr( '--wc-featured-item-block-gap:' . $gap ) . '"' : '',
+				$content
+			);
 		}

 		$output .= '</div>';
@@ -366,9 +365,6 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 			);
 		}

-		$global_style_style = StyleAttributesUtils::get_styles_by_attributes( $attributes, $this->global_style_wrapper );
-		$style             .= $global_style_style;
-
 		return $style;
 	}

@@ -434,29 +430,24 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 	}

 	/**
-	 * Get the styles for the wrapper element (background image, color).
+	 * Get Featured-specific height styles for the block wrapper.
 	 *
 	 * @param array $attributes Block attributes. Default empty array.
 	 * @return string
 	 */
 	public function get_styles( $attributes ) {
-		$style = '';
+		$style = sprintf( '--wc-featured-item-min-height:%dpx;', wc_get_theme_support( 'featured_block::default_height', 500 ) );

-		$min_height = $attributes['minHeight'] ?? wc_get_theme_support( 'featured_block::default_height', 500 );
-
-		if ( isset( $attributes['minHeight'] ) ) {
-			$style .= sprintf( 'min-height:%dpx;', intval( $min_height ) );
+		if ( isset( $attributes['minHeight'] ) && ! isset( $attributes['style']['dimensions']['minHeight'] ) ) {
+			$style .= sprintf( 'min-height:%dpx;', intval( $attributes['minHeight'] ) );
 		}

-		$global_style_style = StyleAttributesUtils::get_styles_by_attributes( $attributes, $this->global_style_wrapper );
-		$style             .= $global_style_style;
-
 		return $style;
 	}


 	/**
-	 * Get class names for the block container.
+	 * Get Featured-specific class names for the block container.
 	 *
 	 * @param array $attributes Block attributes. Default empty array.
 	 * @return string
@@ -464,10 +455,6 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 	public function get_classes( $attributes ) {
 		$classes = array( 'wc-block-' . $this->block_name );

-		if ( isset( $attributes['align'] ) ) {
-			$classes[] = "align{$attributes['align']}";
-		}
-
 		if ( isset( $attributes['dimRatio'] ) && ( 0 !== $attributes['dimRatio'] ) ) {
 			$classes[] = 'has-background-dim';

@@ -480,9 +467,9 @@ abstract class FeaturedItem extends AbstractDynamicBlock {
 			$classes[] = "has-{$attributes['contentAlign']}-content";
 		}

-		$global_style_classes = StyleAttributesUtils::get_classes_by_attributes( $attributes, $this->global_style_wrapper );
-
-		$classes[] = $global_style_classes;
+		if ( in_array( $attributes['verticalAlignment'] ?? '', array( 'top', 'center', 'bottom' ), true ) ) {
+			$classes[] = 'is-vertically-aligned-' . $attributes['verticalAlignment'];
+		}

 		return implode( ' ', $classes );
 	}
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/FeaturedItemSupportsTest.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/FeaturedItemSupportsTest.php
new file mode 100644
index 00000000000..d5a80f218bb
--- /dev/null
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/FeaturedItemSupportsTest.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * Featured item block support rendering tests.
+ *
+ * @package WooCommerce\Tests\Blocks
+ */
+
+declare( strict_types = 1 );
+
+namespace Automattic\WooCommerce\Tests\Blocks\BlockTypes;
+
+use WC_Helper_Product;
+use WC_Unit_Test_Case;
+use WP_HTML_Tag_Processor;
+
+/**
+ * Tests the shared Featured Category and Featured Product support renderer.
+ */
+class FeaturedItemSupportsTest extends WC_Unit_Test_Case {
+	/**
+	 * @testdox Design supports and vertical alignment render without changing the inner flow layout.
+	 *
+	 * @testWith ["category", "top"]
+	 *           ["category", "center"]
+	 *           ["category", "bottom"]
+	 *           ["product", "top"]
+	 *           ["product", "center"]
+	 *           ["product", "bottom"]
+	 * @param string $kind Featured item kind.
+	 * @param string $alignment Vertical content alignment.
+	 */
+	public function test_support_styles_and_layout_target( string $kind, string $alignment ): void {
+		$attributes                      = $this->get_item_attributes( $kind );
+		$attributes['anchor']            = 'featured-anchor';
+		$attributes['verticalAlignment'] = $alignment;
+		$attributes['style']             = array(
+			'color'      => array( 'text' => '#123456' ),
+			'border'     => array(
+				'style' => 'dashed',
+				'width' => '3px',
+			),
+			'typography' => array(
+				'textTransform'  => 'uppercase',
+				'textDecoration' => 'underline',
+			),
+			'dimensions' => array( 'aspectRatio' => '16/9' ),
+			'shadow'     => '2px 3px 4px #000000',
+			'spacing'    => array(
+				'margin'   => array( 'top' => '20px' ),
+				'blockGap' => '12px',
+			),
+		);
+		$html                            = $this->render_item( $kind, $attributes );
+		$tags                            = new WP_HTML_Tag_Processor( $html );
+		$this->assertTrue( $tags->next_tag() );
+		$this->assertSame( 'featured-anchor', $tags->get_attribute( 'id' ) );
+		$this->assertFalse( $tags->has_class( 'is-layout-flex' ) );
+		$this->assertTrue( $tags->has_class( 'is-vertically-aligned-' . $alignment ) );
+		foreach ( array( 'color:#123456', 'border-style:dashed', 'text-transform:uppercase', 'text-decoration:underline', 'aspect-ratio:16/9', 'min-height:unset', 'box-shadow:2px 3px 4px #000000', 'margin-top:20px' ) as $style ) {
+			$this->assertStringContainsString( $style, $tags->get_attribute( 'style' ) );
+		}
+		$this->assertStringNotContainsString( 'gap:', $tags->get_attribute( 'style' ) );
+		$this->assertTrue( $tags->next_tag( array( 'class_name' => 'wc-block-featured-' . $kind . '__inner-blocks' ) ) );
+		$this->assertFalse( $tags->has_class( 'is-layout-flex' ) );
+		$this->assertTrue( $tags->has_class( 'has-custom-gap' ) );
+		$this->assertStringContainsString( '--wc-featured-item-block-gap:12px', $tags->get_attribute( 'style' ) );
+	}
+
+	/**
+	 * @testdox Explicit zero spacing is distinguished from untouched inner-block margins.
+	 *
+	 * @testWith [null, false]
+	 *           ["0", true]
+	 *           [0, true]
+	 * @param mixed $gap Saved block spacing.
+	 * @param bool  $has_custom_gap Whether explicit spacing should be rendered.
+	 */
+	public function test_explicit_zero_spacing( $gap, bool $has_custom_gap ): void {
+		$attributes                                 = $this->get_item_attributes( 'category' );
+		$attributes['style']['spacing']['blockGap'] = $gap;
+		$tags                                       = new WP_HTML_Tag_Processor( $this->render_item( 'category', $attributes ) );
+		$this->assertTrue( $tags->next_tag( array( 'class_name' => 'wc-block-featured-category__inner-blocks' ) ) );
+		$this->assertSame( $has_custom_gap, $tags->has_class( 'has-custom-gap' ) );
+		$this->assertSame( $has_custom_gap ? '--wc-featured-item-block-gap:0' : null, $tags->get_attribute( 'style' ) );
+	}
+
+	/**
+	 * @testdox Core renders preset styles and wrapper classes for modern and legacy Featured blocks.
+	 *
+	 * @testWith ["category", false]
+	 *           ["category", true]
+	 *           ["product", false]
+	 *           ["product", true]
+	 * @param string $kind Featured item kind.
+	 * @param bool   $legacy Whether to render legacy markup.
+	 */
+	public function test_core_renders_presets( string $kind, bool $legacy ): void {
+		$attributes = array_merge(
+			$this->get_item_attributes( $kind ),
+			array(
+				'textColor'       => 'vivid-red',
+				'backgroundColor' => 'black',
+				'gradient'        => 'vivid-cyan-blue-to-vivid-purple',
+				'borderColor'     => 'white',
+				'align'           => 'wide',
+				'className'       => 'custom-featured',
+			)
+		);
+		if ( $legacy ) {
+			$attributes['editMode'] = false;
+		}
+		$tags = new WP_HTML_Tag_Processor( $this->render_item( $kind, $attributes ) );
+		$this->assertTrue( $tags->next_tag() );
+		foreach ( array( 'has-vivid-red-color', 'has-black-background-color', 'has-vivid-cyan-blue-to-vivid-purple-gradient-background', 'has-white-border-color', 'alignwide', 'custom-featured' ) as $class ) {
+			$this->assertTrue( $tags->has_class( $class ), $class . ' should be rendered by Core block supports.' );
+		}
+	}
+
+	/**
+	 * @testdox Existing posts keep their height and do not acquire flow spacing.
+	 *
+	 * @testWith ["category"]
+	 *           ["product"]
+	 * @param string $kind Featured item kind.
+	 */
+	public function test_legacy_rendering_keeps_content_and_height( string $kind ): void {
+		$attributes              = $this->get_item_attributes( $kind );
+		$attributes['editMode']  = false;
+		$attributes['minHeight'] = 620;
+		$attributes['showDesc']  = true;
+		$html                    = $this->render_item( $kind, $attributes );
+		$this->assertStringContainsString( 'min-height:620px', $html );
+		$this->assertStringContainsString( 'wc-block-featured-' . $kind . '__title', $html );
+		$this->assertStringNotContainsString( 'is-layout-flow', $html );
+		$this->assertStringNotContainsString( 'is-layout-flex', $html );
+		$this->assertStringContainsString( 'Saved content', $html );
+	}
+
+	/**
+	 * @testdox Terms Query context continues to supply the category and inner-block title.
+	 */
+	public function test_inherited_category_with_supports(): void {
+		$attributes = $this->get_item_attributes( 'category' );
+		$block      = new \WP_Block(
+			parse_blocks( '<!-- wp:woocommerce/featured-category {"style":{"dimensions":{"aspectRatio":"1"}}} --><!-- wp:woocommerce/category-title /--><!-- /wp:woocommerce/featured-category -->' )[0],
+			array(
+				'termId'       => $attributes['categoryId'],
+				'termTaxonomy' => 'product_cat',
+			)
+		);
+		$html       = $block->render();
+		$this->assertStringContainsString( 'Featured category', $html );
+		$this->assertStringContainsString( 'aspect-ratio:1', $html );
+	}
+
+	/**
+	 * Create the selected entity without an image.
+	 *
+	 * @param string $kind Featured item kind.
+	 * @return array
+	 */
+	private function get_item_attributes( string $kind ): array {
+		$id = 'category' === $kind
+			? $this->factory->term->create(
+				array(
+					'taxonomy' => 'product_cat',
+					'name'     => 'Featured category',
+				)
+			)
+			: WC_Helper_Product::create_simple_product()->get_id();
+		return array( $kind . 'Id' => $id );
+	}
+
+	/**
+	 * Render saved markup through all Core block support filters.
+	 *
+	 * @param string $kind Featured item kind.
+	 * @param array  $attributes Block attributes.
+	 * @return string
+	 */
+	private function render_item( string $kind, array $attributes ): string {
+		return do_blocks( '<!-- wp:woocommerce/featured-' . $kind . ' ' . wp_json_encode( $attributes ) . ' --><!-- wp:paragraph --><p>Saved content</p><!-- /wp:paragraph --><!-- /wp:woocommerce/featured-' . $kind . ' -->' );
+	}
+}