[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Develop a custom Gutenberg block that Sell products and subscriptions.

[Assistant]
// File: projects/plugins/jetpack/extensions/blocks/payment-buttons/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/payment-buttons",
	"title": "Payment Buttons",
	"description": "Sell products and subscriptions.",
	"keywords": [
		"buy",
		"contribution",
		"commerce",
		"credit card",
		"debit card",
		"donate",
		"Donations",
		"earn",
		"monetize",
		"ecommerce",
		"gofundme",
		"memberships",
		"money",
		"paid",
		"patreon",
		"pay",
		"payments",
		"products",
		"purchase",
		"recurring",
		"sell",
		"shop",
		"stripe",
		"subscribe",
		"subscriptions",
		"sponsor",
		"square",
		"toast",
		"venmo"
	],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "monetize",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><path d='M20 4H4c-1.105 0-2 .895-2 2v12c0 1.105.895 2 2 2h16c1.105 0 2-.895 2-2V6c0-1.105-.895-2-2-2zm0 2v2H4V6h16zM4 18v-6h16v6H4zm2-4h7v2H6v-2zm9 0h3v2h-3v-2z'/></svg>",
	"supports": {
		"__experimentalExposeControlsToChildren": true,
		"align": [ "wide", "full" ],
		"spacing": {
			"blockGap": true,
			"margin": [ "vertical" ],
			"__experimentalDefaultControls": {
				"blockGap": true
			}
		},
		"layout": {
			"allowSwitching": false,
			"allowInheriting": false,
			"default": {
				"type": "flex"
			}
		},
		"typography": {
			"fontSize": true,
			"__experimentalFontFamily": true,
			"__experimentalTextTransform": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		}
	},
	"attributes": {}
}

// File: projects/plugins/jetpack/extensions/blocks/payment-buttons/edit.js
import { BlockControls, useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import ConnectBanner from '../../shared/components/connect-banner';
import StripeConnectToolbarButton from '../../shared/components/stripe-connect-toolbar-button';
import { StripeNudge } from '../../shared/components/stripe-nudge';
import useIsUserConnected from '../../shared/use-is-user-connected';
import { store as membershipProductsStore } from '../../store/membership-products';

const ALLOWED_BLOCKS = [ 'jetpack/recurring-payments' ];

function PaymentButtonsEdit( { clientId, attributes } ) {
	const { layout, fontSize } = attributes;
	const { connectUrl, isApiConnected } = useSelect( select => {
		const { getConnectUrl, isApiStateConnected } = select( membershipProductsStore );
		return {
			connectUrl: getConnectUrl(),
			isApiConnected: isApiStateConnected(),
		};
	} );
	const isUserConnected = useIsUserConnected();

	const paymentButtonBlocks = useSelect(
		select =>
			select( 'core/block-editor' )
				.getBlock( clientId )
				.innerBlocks.filter( block => block.name === 'jetpack/recurring-payments' ),
		[ clientId ]
	);

	useEffect( () => {
		addFilter(
			'jetpack.recurringPayments.editorSettings',
			'jetpack/payment-buttons-hide-nudges-from-inner-blocks',
			( editorSettings, paymentButtonClientId ) => {
				if (
					paymentButtonBlocks.some(
						paymentButtonBlock => paymentButtonBlock.clientId === paymentButtonClientId
					)
				) {
					return {
						...editorSettings,
						/*
						 * This block already displays Stripe and plan upgrades nudges, so we hide the ones
						 * displayed in the inner blocks.
						 */
						showStripeNudge: false,
						showUpgradeNudge: false,
					};
				}
				return editorSettings;
			}
		);
	}, [ paymentButtonBlocks ] );

	const showStripeConnectAction = ! isApiConnected && !! connectUrl;

	const blockProps = useBlockProps( {
		className: clsx( {
			'has-custom-font-size': !! fontSize || attributes?.style?.typography?.fontSize,
		} ),
	} );
	const innerBlocksProps = useInnerBlocksProps( blockProps, {
		allowedBlocks: ALLOWED_BLOCKS,
		orientation: 'horizontal',
		template: [ [ 'jetpack/recurring-payments' ] ],
		templateInsertUpdatesSelection: true,
		layout,
	} );

	// The ID needs to be just on the outermost wrapper - the toolbar and wpcom upgrade nudge
	// will then be positioned in relation to this.
	delete innerBlocksProps.id;
	delete innerBlocksProps[ 'data-block' ];

	if ( ! isUserConnected ) {
		return (
			<div { ...blockProps }>
				<ConnectBanner
					block="Payment Buttons"
					explanation={ __(
						'Connect your WordPress.com account to enable payment buttons on your site.',
						'jetpack'
					) }
				/>
			</div>
		);
	}

	return (
		<div { ...blockProps }>
			{ showStripeConnectAction && (
				<BlockControls group="block">
					<StripeConnectToolbarButton
						blockName="jetpack/payment-buttons"
						connectUrl={ connectUrl }
					/>
				</BlockControls>
			) }
			{ showStripeConnectAction && <StripeNudge blockName="payment-buttons" /> }
			<div { ...innerBlocksProps } />
		</div>
	);
}

export default PaymentButtonsEdit;

// File: projects/plugins/jetpack/extensions/blocks/payment-buttons/save.js
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import clsx from 'clsx';

export default function save( { attributes } ) {
	const className = clsx( {
		'has-custom-font-size': !! attributes?.fontSize || attributes?.style?.typography?.fontSize,
	} );
	const blockProps = useBlockProps.save( { className: className } );
	const innerBlocksProps = useInnerBlocksProps.save( blockProps );
	return <div { ...innerBlocksProps } />;
}


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Develop a block for Display code snippets that respect your spacing and tabs. that allows users to configure: content

[Assistant]
// File: packages/block-library/src/code/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/code",
	"title": "Code",
	"category": "text",
	"description": "Display code snippets that respect your spacing and tabs.",
	"textdomain": "default",
	"attributes": {
		"content": {
			"type": "rich-text",
			"source": "rich-text",
			"selector": "code",
			"__unstablePreserveWhiteSpace": true,
			"role": "content"
		}
	},
	"supports": {
		"align": [ "wide" ],
		"anchor": true,
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"spacing": {
			"margin": [ "top", "bottom" ],
			"padding": true,
			"__experimentalDefaultControls": {
				"margin": false,
				"padding": false
			}
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true,
			"__experimentalDefaultControls": {
				"width": true,
				"color": true
			}
		},
		"color": {
			"text": true,
			"background": true,
			"gradients": true,
			"__experimentalDefaultControls": {
				"background": true,
				"text": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	},
	"style": "wp-block-code"
}

// File: packages/block-library/src/code/index.js
/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { code as icon } from '@wordpress/icons';
import { privateApis as blocksPrivateApis } from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import initBlock from '../utils/init-block';
import edit from './edit';
import metadata from './block.json';
import save from './save';
import transforms from './transforms';
import { unlock } from '../lock-unlock';

const { fieldsKey, formKey } = unlock( blocksPrivateApis );

const { name } = metadata;

export { metadata, name };

export const settings = {
	icon,
	example: {
		attributes: {
			/* eslint-disable @wordpress/i18n-no-collapsible-whitespace */
			// translators: Preserve \n markers for line breaks
			content: __(
				'// A “block” is the abstract term used\n// to describe units of markup that\n// when composed together, form the\n// content or layout of a page.\nregisterBlockType( name, settings );'
			),
			/* eslint-enable @wordpress/i18n-no-collapsible-whitespace */
		},
	},
	merge( attributes, attributesToMerge ) {
		return {
			content: attributes.content + '\n\n' + attributesToMerge.content,
		};
	},
	transforms,
	edit,
	save,
};

if ( window.__experimentalContentOnlyInspectorFields ) {
	settings[ fieldsKey ] = [
		{
			id: 'content',
			label: __( 'Code' ),
			type: 'richtext',
		},
	];
	settings[ formKey ] = {
		fields: [ 'content' ],
	};
}

export const init = () => initBlock( { name, metadata, settings } );

// File: packages/block-library/src/code/save.js
/**
 * WordPress dependencies
 */
import { RichText, useBlockProps } from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import { escape } from './utils';

export default function save( { attributes } ) {
	return (
		<pre { ...useBlockProps.save() }>
			<RichText.Content
				tagName="code"
				// To do: `escape` encodes characters in shortcodes and URLs to
				// prevent embedding in PHP. Ideally checks for the code block,
				// or pre/code tags, should be made on the PHP side?
				value={ escape(
					typeof attributes.content === 'string'
						? attributes.content
						: attributes.content.toHTMLString( {
								preserveWhiteSpace: true,
						  } )
				) }
			/>
		</pre>
	);
}


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a WooCommerce-focused block that provides intuitive page display settings, empowering users to customize their content presentation within the WordPress editor.

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: plugins/woocommerce/client/blocks/assets/js/blocks/page-content-wrapper/block.json
{
	"name": "woocommerce/page-content-wrapper",
	"title": "WooCommerce Page",
	"description": "Displays WooCommerce page content.",
	"category": "woocommerce",
	"keywords": [ "WooCommerce" ],
	"textdomain": "woocommerce",
	"supports": {
		"html": false,
		"multiple": false,
		"inserter": false
	},
	"attributes": {
		"page": {
			"type": "string",
			"default": ""
		}
	},
	"providesContext": {
		"postId": "postId",
		"postType": "postType"
	},
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/page-content-wrapper/index.tsx
/**
 * External dependencies
 */
import {
	registerBlockType,
	InnerBlockTemplate,
	BlockAttributes,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import { page } from '@wordpress/icons';
import { CHECKOUT_PAGE_ID, CART_PAGE_ID } from '@woocommerce/block-settings';
import { useEffect } from '@wordpress/element';

/**
 * Internal dependencies
 */
import metadata from './block.json';
import './editor.scss';

const Edit = ( {
	attributes,
	setAttributes,
}: {
	attributes: BlockAttributes;
	setAttributes: ( attrs: BlockAttributes ) => void;
} ) => {
	const TEMPLATE: InnerBlockTemplate[] = [
		[ 'core/post-title', { align: 'wide', level: 1 } ],
		[ 'core/post-content', { align: 'wide' } ],
	];

	const blockProps = useBlockProps( {
		className: 'wp-block-woocommerce-page-content-wrapper',
	} );

	useEffect( () => {
		if ( ! attributes.postId && attributes.page ) {
			let postId = 0;

			if ( attributes.page === 'checkout' ) {
				postId = CHECKOUT_PAGE_ID;
			}

			if ( attributes.page === 'cart' ) {
				postId = CART_PAGE_ID;
			}

			if ( postId ) {
				setAttributes( { postId, postType: 'page' } );
			}
		}
	}, [ attributes, setAttributes ] );

	return (
		<div { ...blockProps }>
			<InnerBlocks template={ TEMPLATE } />
		</div>
	);
};

registerBlockType( metadata, {
	icon: {
		src: page,
	},
	edit: Edit,
	save: () => <InnerBlocks.Content />,
	variations: [
		{
			name: 'checkout-page',
			title: __( 'Checkout Page', 'woocommerce' ),
			attributes: {
				page: 'checkout',
			},
			isActive: ( blockAttributes, variationAttributes ) =>
				blockAttributes.page === variationAttributes.page,
		},
		{
			name: 'cart-page',
			title: __( 'Cart Page', 'woocommerce' ),
			attributes: {
				page: 'cart',
			},
			isActive: ( blockAttributes, variationAttributes ) =>
				blockAttributes.page === variationAttributes.page,
		},
	],
} );


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a WordPress block that enables view frequency-based visibility controls, allowing customization of visibility criteria and threshold limits for page access.

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: projects/plugins/jetpack/extensions/blocks/repeat-visitor/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/repeat-visitor",
	"title": "Repeat Visitor",
	"description": "Control block visibility based on how often a visitor has viewed the page.",
	"keywords": [ "return", "visitors", "visibility" ],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "widgets",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><path d='M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z'/></svg>",
	"supports": {
		"align": [ "wide", "full" ],
		"html": false
	},
	"attributes": {
		"criteria": {
			"type": "string",
			"default": "after-visits"
		},
		"threshold": {
			"type": "number",
			"default": 3
		}
	},
	"example": {
		"attributes": {
			"criteria": "after-visits",
			"threshold": 3
		},
		"innerBlocks": [
			{
				"name": "core/paragraph",
				"attributes": "This block will only appear to a visitor who visited the page three or more times."
			}
		]
	}
}

// File: projects/plugins/jetpack/extensions/blocks/repeat-visitor/constants.js
export const CRITERIA_AFTER = 'after-visits';
export const CRITERIA_BEFORE = 'before-visits';
export const DEFAULT_THRESHOLD = 3;
export const COOKIE_NAME = 'jp-visit-counter';
export const MAX_COOKIE_AGE = 6 * 30 * 24 * 60 * 60; // 6 months


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a WordPress block designed to showcase product ratings, enabling customization of product identification, query loop relationship, text alignment, and two additional configurable parameters.

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/rating/block.json
{
	"name": "woocommerce/product-rating",
	"icon": "info",
	"title": "Product Rating",
	"description": "Display the average rating of a product.",
	"category": "woocommerce-product-elements",
	"attributes": {
		"productId": {
			"type": "number",
			"default": 0
		},
		"isDescendentOfQueryLoop": {
			"type": "boolean",
			"default": false
		},
		"textAlign": {
			"type": "string",
			"default": ""
		},
		"isDescendentOfSingleProductBlock": {
			"type": "boolean",
			"default": false
		},
		"isDescendentOfSingleProductTemplate": {
			"type": "boolean",
			"default": false
		}
	},
	"supports": {
		"interactivity": {
			"clientNavigation": true
		},
		"color": {
			"text": true,
			"background": false,
			"link": false,
			"__experimentalSkipSerialization": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"typography": {
			"fontSize": true,
			"__experimentalSkipSerialization": true
		},
		"__experimentalSelector": ".wc-block-components-product-rating"
	},
	"ancestor": [
		"woocommerce/all-products",
		"woocommerce/single-product",
		"woocommerce/product-template",
		"core/post-template"
	],
	"usesContext": [ "query", "queryId", "postId" ],
	"keywords": [ "WooCommerce" ],
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/rating/index.ts
/**
 * External dependencies
 */
import type { BlockConfiguration } from '@wordpress/blocks';
import { registerProductBlockType } from '@woocommerce/atomic-utils';

/**
 * Internal dependencies
 */
import save from '../save';
import edit from './edit';
import { BLOCK_ICON as icon } from './constants';
import metadata from './block.json';

const blockConfig: BlockConfiguration = {
	...metadata,
	icon: { src: icon },
	edit,
	save,
};

registerProductBlockType( blockConfig, {
	isAvailableOnPostEditor: true,
} );


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Build a Gutenberg block that Display additional checkout fields from the 'contact' and 'order' locations. with these attributes: heading

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: plugins/woocommerce/client/blocks/assets/js/blocks/order-confirmation/additional-fields-wrapper/block.json
{
	"name": "woocommerce/order-confirmation-additional-fields-wrapper",
	"version": "1.0.0",
	"title": "Additional Fields",
	"description": "Display additional checkout fields from the 'contact' and 'order' locations.",
	"category": "woocommerce",
	"keywords": [
		"WooCommerce"
	],
	"attributes": {
		"heading": {
			"type": "string"
		}
	},
	"supports": {
		"multiple": false,
		"align": [
			"wide",
			"full"
		],
		"html": false,
		"spacing": {
			"padding": true,
			"margin": true,
			"__experimentalDefaultControls": {
				"margin": false,
				"padding": false
			}
		}
	},
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/order-confirmation/additional-fields-wrapper/edit.tsx
/**
 * External dependencies
 */
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import {
	ORDER_FORM_FIELDS,
	CONTACT_FORM_FIELDS,
} from '@woocommerce/block-settings';

/**
 * Internal dependencies
 */
import './style.scss';

const Edit = ( {
	attributes,
	setAttributes,
}: {
	attributes: {
		heading: string;
	};
	setAttributes: ( attributes: Record< string, unknown > ) => void;
} ) => {
	const blockProps = useBlockProps( {
		className: 'wc-block-order-confirmation-additional-fields-wrapper',
	} );

	const additionalFields = {
		...ORDER_FORM_FIELDS,
		...CONTACT_FORM_FIELDS,
	};

	if ( Object.entries( additionalFields ).length === 0 ) {
		return null;
	}

	return (
		<div { ...blockProps }>
			<InnerBlocks
				allowedBlocks={ [ 'core/heading' ] }
				template={ [
					[
						'core/heading',
						{
							level: 2,
							style: { typography: { fontSize: '24px' } },
							content: attributes.heading || '',
							onChangeContent: ( value: string ) =>
								setAttributes( { heading: value } ),
						},
					],
					[
						'woocommerce/order-confirmation-additional-fields',
						{
							lock: {
								remove: true,
							},
						},
					],
				] }
			/>
		</div>
	);
};

export default Edit;


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Develop a block for Displays the next posts page link. that allows users to configure: label

[Assistant]
// File: packages/block-library/src/query-pagination-next/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/query-pagination-next",
	"title": "Next Page",
	"category": "theme",
	"parent": [ "core/query-pagination" ],
	"description": "Displays the next posts page link.",
	"textdomain": "default",
	"attributes": {
		"label": {
			"type": "string"
		}
	},
	"usesContext": [
		"queryId",
		"query",
		"paginationArrow",
		"showLabel",
		"enhancedPagination"
	],
	"supports": {
		"reusable": false,
		"html": false,
		"color": {
			"gradients": true,
			"text": false,
			"__experimentalDefaultControls": {
				"background": true
			}
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	}
}

// File: packages/block-library/src/query-pagination-next/index.js
/**
 * WordPress dependencies
 */
import { queryPaginationNext as icon } from '@wordpress/icons';

/**
 * Internal dependencies
 */
import initBlock from '../utils/init-block';
import metadata from './block.json';
import edit from './edit';

const { name } = metadata;
export { metadata, name };

export const settings = {
	icon,
	edit,
};

export const init = () => initBlock( { name, metadata, settings } );


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Develop a Gutenberg block designed to render the principal product image with comprehensive attribute options, including toggles for link display, sale badge presentation, alignment, and several supplementary configuration choices.

[Assistant]
// File: plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/image/block.json
{
	"name": "woocommerce/product-image",
	"title": "Product Image",
	"description": "Display the main product image.",
	"category": "woocommerce-product-elements",
	"attributes": {
		"showProductLink": { "type": "boolean", "default": true },
		"showSaleBadge": { "type": "boolean", "default": true },
		"saleBadgeAlign": { "type": "string", "default": "right" },
		"imageSizing": { "type": "string", "default": "single" },
		"productId": { "type": "number", "default": 0 },
		"isDescendentOfQueryLoop": { "type": "boolean", "default": false },
		"isDescendentOfSingleProductBlock": {
			"type": "boolean",
			"default": false
		},
		"width": { "type": "string" },
		"height": { "type": "string" },
		"scale": { "type": "string", "default": "cover" },
		"aspectRatio": { "type": "string" }
	},
	"supports": {
		"interactivity": {
			"clientNavigation": true
		},
		"html": false,
		"__experimentalBorder": {
			"radius": true,
			"__experimentalSkipSerialization": true
		},
		"typography": {
			"fontSize": true,
			"__experimentalSkipSerialization": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"dimensions": {
			"aspectRatio": true,
			"__experimentalSkipSerialization": true
		},
		"email": true,
		"__experimentalSelector": ".wc-block-components-product-image"
	},
	"ancestor": [
		"woocommerce/all-products",
		"woocommerce/single-product",
		"woocommerce/product-template",
		"core/post-template"
	],
	"usesContext": [ "imageId", "postId", "query", "queryId" ],
	"keywords": [ "WooCommerce" ],
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/image/edit.tsx
/**
 * External dependencies
 */
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import {
	InspectorControls,
	useBlockProps,
	useInnerBlocksProps,
	store as blockEditorStore,
} from '@wordpress/block-editor';
import {
	createInterpolateElement,
	useEffect,
	useRef,
} from '@wordpress/element';
import { getAdminLink, getSettingWithCoercion } from '@woocommerce/settings';
import { useProduct } from '@woocommerce/entities';
import { isBoolean } from '@woocommerce/types';
import type { BlockEditProps } from '@wordpress/blocks';
import { ProductQueryContext as Context } from '@woocommerce/blocks/product-query/types';
import {
	PanelBody,
	ToggleControl,
	// eslint-disable-next-line @typescript-eslint/ban-ts-comment
	// @ts-ignore - Ignoring because `__experimentalToggleGroupControl` is not yet in the type definitions.
	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
	__experimentalToggleGroupControl as ToggleGroupControl,
	// eslint-disable-next-line @typescript-eslint/ban-ts-comment
	// @ts-ignore - Ignoring because `__experimentalToggleGroupControl` is not yet in the type definitions.
	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
	__experimentalToggleGroupControlOption as ToggleGroupControlOption,
} from '@wordpress/components';

/**
 * Internal dependencies
 */
import Block from './block';
import { useIsDescendentOfSingleProductBlock } from '../shared/use-is-descendent-of-single-product-block';
import { BlockAttributes, ImageSizing } from './types';
import { ImageSizeSettings } from './image-size-settings';

const TEMPLATE = [
	[
		'woocommerce/product-sale-badge',
		{
			align: 'right',
		},
	],
];

const Edit = ( {
	attributes,
	setAttributes,
	context,
	clientId,
}: BlockEditProps< BlockAttributes > & { context: Context } ): JSX.Element => {
	const { showProductLink, imageSizing, width, height, scale } = attributes;

	const ref = useRef< HTMLDivElement >( null );

	const blockProps = useBlockProps();
	const { wasBlockJustInserted, isInProductGallery } = useSelect(
		( select ) => {
			return {
				wasBlockJustInserted:
					// eslint-disable-next-line @typescript-eslint/ban-ts-comment
					// @ts-expect-error method exists but not typed
					select( blockEditorStore ).wasBlockJustInserted( clientId ),
				isInProductGallery:
					// eslint-disable-next-line @typescript-eslint/ban-ts-comment
					// @ts-expect-error method exists but not typed
					select( blockEditorStore ).getBlockParentsByBlockName(
						clientId,
						'woocommerce/product-gallery'
					).length > 0,
			};
		},
		[ clientId ]
	);

	const isDescendentOfQueryLoop = Number.isFinite( context.queryId );
	const { isDescendentOfSingleProductBlock } =
		useIsDescendentOfSingleProductBlock( {
			blockClientId: blockProps?.id,
		} );

	useEffect( () => {
		if ( isDescendentOfQueryLoop || isDescendentOfSingleProductBlock ) {
			setAttributes( {
				isDescendentOfQueryLoop,
				isDescendentOfSingleProductBlock,
				showSaleBadge: false,
			} );
		} else {
			setAttributes( {
				isDescendentOfQueryLoop,
				isDescendentOfSingleProductBlock,
			} );
		}
	}, [
		isDescendentOfQueryLoop,
		isDescendentOfSingleProductBlock,
		setAttributes,
	] );

	const showAllControls =
		isDescendentOfQueryLoop || isDescendentOfSingleProductBlock;

	const innerBlockProps = useInnerBlocksProps(
		{
			className: 'wc-block-components-product-image__inner-container',
		},
		{
			dropZoneElement: ref.current,
			template: wasBlockJustInserted ? TEMPLATE : undefined,
		}
	);

	const isBlockTheme = getSettingWithCoercion(
		'isBlockTheme',
		false,
		isBoolean
	);

	const { product, isResolving } = useProduct( context.postId );

	return (

			{ /* Don't show controls in product gallery as we rely on
			core supports API (aspect ratio setting) */ }
			{ showAllControls && ! isInProductGallery && (
				<InspectorControls>
					<ImageSizeSettings
						scale={ scale }
						width={ width }
						height={ height }
						setAttributes={ setAttributes }
					/>
					<PanelBody title={ __( 'Content', 'woocommerce' ) }>
						<ToggleControl
							label={ __(
								'Link to Product Page',
								'woocommerce'
							) }
							help={ __(
								'Links the image to the single product listing.',
								'woocommerce'
							) }
							checked={ showProductLink }
							onChange={ () =>
								setAttributes( {
									showProductLink: ! showProductLink,
								} )
							}
						/>
						<ToggleGroupControl
							label={ __( 'Resolution', 'woocommerce' ) }
							isBlock
							help={
								! isBlockTheme
									? createInterpolateElement(
											__(
												'Product image cropping can be modified in the Customizer.',
												'woocommerce'
											),
											{
												a: (
													// eslint-disable-next-line jsx-a11y/anchor-has-content

												),
											}
									  )
									: null
							}
							value={ imageSizing }
							onChange={ ( value: ImageSizing ) =>
								setAttributes( { imageSizing: value } )
							}
						>
							<ToggleGroupControlOption
								value={ ImageSizing.SINGLE }
								label={ __( 'Full Size', 'woocommerce' ) }
							/>
							<ToggleGroupControlOption
								value={ ImageSizing.THUMBNAIL }
								label={ __( 'Thumbnail', 'woocommerce' ) }
							/>
						</ToggleGroupControl>
					</PanelBody>
				</InspectorControls>
			) }
			<Block
				{ ...{ ...attributes, ...context } }
				isAdmin={ true }
				product={ product }
				isResolving={ isResolving }
			>
				{ showAllControls &&
 }
			</Block>

	);
};

export default Edit;


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Construct a WooCommerce block that supports a configurable CSS class identifier and implements locking functionality.

[Assistant]
// File: plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-coupon-form/block.json
{
	"name": "woocommerce/checkout-order-summary-coupon-form-block",
	"version": "1.0.0",
	"title": "Coupon Form",
	"description": "Shows the apply coupon form.",
	"category": "woocommerce",
	"supports": {
		"align": false,
		"html": false,
		"multiple": false,
		"reusable": false
	},
	"attributes": {
		"className": {
			"type": "string",
			"default": ""
		},
		"lock": {
			"type": "object",
			"default": {
				"remove": false,
				"move": false
			}
		}
	},
	"parent": [
		"woocommerce/checkout-order-summary-block"
	],
	"textdomain": "woocommerce",
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-coupon-form/edit.tsx
/**
 * External dependencies
 */
import { useBlockProps } from '@wordpress/block-editor';
import Noninteractive from '@woocommerce/base-components/noninteractive';

/**
 * Internal dependencies
 */
import Block from './block';

export const Edit = ( {
	attributes,
}: {
	attributes: {
		className: string;
	};
	setAttributes: ( attributes: Record< string, unknown > ) => void;
} ): JSX.Element => {
	const { className } = attributes;
	const blockProps = useBlockProps();
	return (
		<div { ...blockProps }>
			<Noninteractive>
				<Block className={ className } />
			</Noninteractive>
		</div>
	);
};

export const Save = (): JSX.Element => {
	return <div { ...useBlockProps.save() } />;
};


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Design a custom Gutenberg block that serves as a fallback display for scenarios where no search or query results are available.

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: packages/block-library/src/query-no-results/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/query-no-results",
	"title": "No Results",
	"category": "theme",
	"description": "Contains the block elements used to render content when no query results are found.",
	"ancestor": [ "core/query" ],
	"textdomain": "default",
	"usesContext": [ "queryId", "query" ],
	"supports": {
		"align": true,
		"reusable": false,
		"html": false,
		"color": {
			"gradients": true,
			"link": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	}
}

// File: packages/block-library/src/query-no-results/index.js
/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { loop as icon } from '@wordpress/icons';

/**
 * Internal dependencies
 */
import initBlock from '../utils/init-block';
import metadata from './block.json';
import edit from './edit';
import save from './save';

const { name } = metadata;
export { metadata, name };

export const settings = {
	icon,
	edit,
	save,
	example: {
		innerBlocks: [
			{
				name: 'core/paragraph',
				attributes: {
					content: __( 'No posts were found.' ),
				},
			},
		],
	},
};

export const init = () => initBlock( { name, metadata, settings } );

// File: packages/block-library/src/query-no-results/save.js
/**
 * WordPress dependencies
 */
import { InnerBlocks } from '@wordpress/block-editor';

export default function save() {
	return <InnerBlocks.Content />;
}


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Build a WordPress block to Block: a8c/starscape

[Assistant]
// File: blocks/starscape/src/index.js
/**
 * WordPress dependencies
 */
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import StarsIcon from './icon';
import attributes from './attributes';
import edit from './edit';
import save from './save';
import deprecated from './deprecated';

export function registerBlock() {
	registerBlockType( 'a8c/starscape', {
		apiVersion: 3,
		title: __( 'Starscape', 'starscape' ),
		description: __( 'Create content with stars in motion.', 'starscape' ),
		icon: <StarsIcon />,
		category: 'widgets',
		supports: {
			className: true,
			align: [ 'wide', 'full' ],
			color: {
				heading: true,
				text: true,
				link: true,
				background: false,
				gradients: false,
			},
			html: false,
			layout: {
				allowJustification: false,
			},
			spacing: {
				padding: true,
				margin: [ 'top', 'bottom' ],
				blockGap: true,
				__experimentalDefaultControls: {
					padding: true,
					blockGap: true,
				},
			},
		},
		attributes,
		edit,
		save,
		deprecated,
	} );
}

// File: blocks/starscape/src/save.js
/**
 * WordPress dependencies
 */
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import Starscape from './starscape';
import { genStars, genAnimations } from './utils';

function StarscapeSave( { attributes } ) {
	const {
		background,
		color,
		intensity,
		density,
		speed,
		minHeight,
		areaWidth,
		areaHeight,
		tagName,
	} = attributes;

	const starStyles = genStars( { color, density, areaWidth, areaHeight } );
	const animationStyles = genAnimations( { speed } );

	const blockProps = useBlockProps.save( {
		style: { background, minHeight, overflow: 'hidden' },
	} );

	const innerBlocksProps = useInnerBlocksProps.save( {
		className: 'wp-block-a8c-starscape__inner',
	} );

	return (
		<Starscape
			as={ tagName }
			starStyles={ starStyles }
			animationStyles={ animationStyles }
			intensity={ intensity }
			{ ...blockProps }
		>
			<div { ...innerBlocksProps } />
		</Starscape>
	);
}

export default StarscapeSave;


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Build a Gutenberg block that Displays the previous product review's page link. with these attributes: label

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-reviews/inner-blocks/reviews-pagination-previous/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "woocommerce/product-reviews-pagination-previous",
	"title": "Reviews Previous Page",
	"category": "woocommerce",
	"ancestor": [ "woocommerce/product-reviews-pagination" ],
	"description": "Displays the previous product review's page link.",
	"textdomain": "woocommerce",
	"attributes": {
		"label": {
			"type": "string"
		}
	},
	"usesContext": [ "postId", "reviews/paginationArrow" ],
	"supports": {
		"reusable": false,
		"html": false,
		"color": {
			"gradients": true,
			"text": false,
			"__experimentalDefaultControls": {
				"background": true
			}
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	}
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-reviews/inner-blocks/reviews-pagination-previous/edit.tsx
/**
 * External dependencies
 */
import { __ } from '@wordpress/i18n';
import { useBlockProps, PlainText } from '@wordpress/block-editor';
import { BlockEditProps } from '@wordpress/blocks';

const arrowMap = {
	none: '',
	arrow: '←',
	chevron: '«',
};

type Props = BlockEditProps< { label: string } > & {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	context: { 'reviews/paginationArrow': string };
};

export default function Edit( {
	attributes: { label },
	setAttributes,
	context: { 'reviews/paginationArrow': paginationArrow },
}: Props ) {
	const displayArrow = arrowMap[ paginationArrow as keyof typeof arrowMap ];
	return (
		<a
			href="#reviews-pagination-previous-pseudo-link"
			onClick={ ( event ) => event.preventDefault() }
			{ ...useBlockProps() }
		>
			{ displayArrow && (
				<span
					className={ `wp-block-woocommerce-product-reviews-pagination-previous-arrow is-arrow-${ paginationArrow }` }
				>
					{ displayArrow }
				</span>
			) }
			<PlainText
				__experimentalVersion={ 2 }
				tagName="span"
				aria-label={ __( 'Older reviews page link', 'woocommerce' ) }
				placeholder={ __( 'Older Reviews', 'woocommerce' ) }
				value={ label }
				onChange={ ( newLabel ) =>
					setAttributes( { label: newLabel } )
				}
			/>
		</a>
	);
}


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a woocommerce block with customizable align, class name

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: plugins/woocommerce/client/blocks/assets/js/blocks/order-confirmation/status/block.json
{
	"name": "woocommerce/order-confirmation-status",
	"version": "1.0.0",
	"title": "Order Status",
	"description": "Display a \"thank you\" message, or a sentence regarding the current order status.",
	"category": "woocommerce",
	"keywords": [
		"WooCommerce"
	],
	"supports": {
		"multiple": false,
		"align": [
			"wide",
			"full"
		],
		"html": false,
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalTextDecoration": true,
			"__experimentalFontStyle": true,
			"__experimentalFontWeight": true,
			"__experimentalLetterSpacing": true,
			"__experimentalTextTransform": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"color": {
			"background": true,
			"text": true,
			"gradients": true,
			"__experimentalDefaultControls": {
				"background": true,
				"text": true
			}
		},
		"spacing": {
			"padding": true,
			"margin": true,
			"__experimentalDefaultControls": {
				"margin": false,
				"padding": false
			}
		}
	},
	"attributes": {
		"align": {
			"type": "string",
			"default": "wide"
		},
		"className": {
			"type": "string",
			"default": ""
		}
	},
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/order-confirmation/status/edit.tsx
/**
 * External dependencies
 */
import { useBlockProps } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import './style.scss';

const Edit = (): JSX.Element => {
	const blockProps = useBlockProps( {
		className: 'wc-block-order-confirmation-status',
	} );

	return (

{ __( 'Order received', 'woocommerce' ) }

				{ __(
					'Thank you. Your order has been received.',
					'woocommerce'
				) }

	);
};

export default Edit;


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a woocommerce block with customizable taxonomy, show counts, display style, and 3 more options

[Assistant]
// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/taxonomy-filter/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"name": "woocommerce/product-filter-taxonomy",
	"title": "Taxonomy Filter",
	"description": "Enable customers to filter the product collection by selecting one or more taxonomy terms, such as categories, brands, or tags.",
	"category": "woocommerce",
	"keywords": [ "WooCommerce" ],
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"ancestor": [ "woocommerce/product-filters" ],
	"supports": {
		"interactivity": true,
		"color": {
			"text": true,
			"background": false,
			"__experimentalDefaultControls": {
				"text": false
			}
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontWeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": false
			}
		},
		"spacing": {
			"margin": true,
			"padding": true,
			"blockGap": true,
			"__experimentalDefaultControls": {
				"margin": false,
				"padding": false,
				"blockGap": false
			}
		},
		"__experimentalBorder": {
			"color": true,
			"radius": true,
			"style": true,
			"width": true,
			"__experimentalDefaultControls": {
				"color": false,
				"radius": false,
				"style": false,
				"width": false
			}
		}
	},
	"usesContext": [ "query", "filterParams" ],
	"attributes": {
		"taxonomy": {
			"type": "string",
			"default": "product_cat"
		},
		"showCounts": {
			"type": "boolean",
			"default": false
		},
		"displayStyle": {
			"type": "string",
			"default": "woocommerce/product-filter-checkbox-list"
		},
		"isPreview": {
			"type": "boolean",
			"default": false
		},
		"sortOrder": {
			"type": "string",
			"default": "count-desc"
		},
		"hideEmpty": {
			"type": "boolean",
			"default": true
		}
	},
	"example": {
		"attributes": {
			"isPreview": true
		}
	}
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/taxonomy-filter/edit.tsx
/**
 * External dependencies
 */
import {
	useBlockProps,
	useInnerBlocksProps,
	BlockContextProvider,
} from '@wordpress/block-editor';
import { withSpokenMessages } from '@wordpress/components';
import { useEffect, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { useCollectionData } from '@woocommerce/base-context/hooks';
import { objectHasProp } from '@woocommerce/types';

/**
 * Internal dependencies
 */
import { TaxonomyFilterInspectorControls } from './inspector';
import { termOptionsPreview } from './constants';
import { EditProps } from './types';
import { getAllowedBlocks } from '../../utils/get-allowed-blocks';
import { EXCLUDED_BLOCKS } from '../../constants';
import type { FilterOptionItem } from '../../types';
import { InitialDisabled } from '../../components/initial-disabled';
import { Notice } from '../../components/notice';
import { getTaxonomyLabel } from './utils';
import { sortFilterOptions } from '../../utils/sort-filter-options';

// Create hierarchical structure: parents followed by their children
function createHierarchicalList(
	terms: FilterOptionItem[],
	sortOrder: string
) {
	const children = new Map();

	// First: categorize terms
	terms.forEach( ( term ) => {
		if ( ! children.has( term.parent ) ) {
			children.set( term.parent, [] );
		}
		children.get( term.parent ).push( term );
	} );

	// Next: sort them
	children.keys().forEach( ( key ) => {
		children.set(
			key,
			sortFilterOptions( children.get( key ), sortOrder )
		);
	} );

	// Last: build hierarchical list
	const result: FilterOptionItem[] = [];
	function addTermsRecursively(
		termList: FilterOptionItem[],
		depth = 0,
		visited = new Set< number >()
	) {
		if ( depth > 10 ) {
			return;
		}
		termList.forEach( ( term ) => {
			if ( ! term.id || visited.has( term.id ) ) {
				return;
			}
			visited.add( term.id );
			result.push( { ...term, depth } );
			const termChildren = children.get( term.id ) || [];
			if ( termChildren.length > 0 ) {
				addTermsRecursively( termChildren, depth + 1, visited );
			}
		} );
	}

	addTermsRecursively( children.get( 0 ) );
	return result;
}

const Edit = ( props: EditProps ) => {
	const { attributes: blockAttributes } = props;

	const {
		taxonomy,
		isPreview,
		displayStyle,
		showCounts,
		sortOrder,
		hideEmpty,
	} = blockAttributes;

	const [ termOptions, setTermOptions ] = useState< FilterOptionItem[] >(
		isPreview
			? sortFilterOptions( [ ...termOptionsPreview ], sortOrder )
			: []
	);
	const [ isOptionsLoading, setIsOptionsLoading ] = useState< boolean >(
		! isPreview
	);

	// Fetch taxonomy terms using WordPress core data
	const { taxonomyTerms, isTermsLoading } = useSelect(
		( select ) => {
			if ( isPreview || ! taxonomy ) {
				return { taxonomyTerms: [], isTermsLoading: false };
			}

			const { getEntityRecords, hasFinishedResolution } =
				select( coreStore );

			const selectArgs = {
				per_page: 15,
				hide_empty: hideEmpty,
				orderby: 'name',
				order: 'asc',
			};
			return {
				taxonomyTerms:
					getEntityRecords( 'taxonomy', taxonomy, selectArgs ) || [],
				isTermsLoading: ! hasFinishedResolution( 'getEntityRecords', [
					'taxonomy',
					taxonomy,
					selectArgs,
				] ),
			};
		},
		[ taxonomy, hideEmpty, isPreview ]
	);

	// Fetch taxonomy counts using the updated useCollectionData hook
	const { data: filteredCounts, isLoading: isFilterCountsLoading } =
		useCollectionData( {
			queryTaxonomy: isPreview ? undefined : taxonomy,
			queryState: {},
			isEditor: true,
		} );

	useEffect( () => {
		if ( isPreview ) {
			// In preview mode, use the preview data directly
			setTermOptions(
				sortFilterOptions( [ ...termOptionsPreview ], sortOrder )
			);
			setIsOptionsLoading( false );
			return;
		}

		if ( isTermsLoading || isFilterCountsLoading ) {
			setIsOptionsLoading( true );
			return;
		}

		if ( ! taxonomyTerms.length ) {
			setTermOptions( [] );
			setIsOptionsLoading( false );
			return;
		}

		// Get taxonomy counts from the API response
		const taxonomyCounts =
			objectHasProp( filteredCounts, 'taxonomy_counts' ) &&
			Array.isArray( filteredCounts.taxonomy_counts )
				? filteredCounts.taxonomy_counts
				: [];

		// Process the terms
		const processedTerms = taxonomyTerms.reduce(
			( acc: FilterOptionItem[], term ) => {
				const count =
					taxonomyCounts.find( ( item ) => item.term === term.id )
						?.count || 0;

				// If hideEmpty is true and count is 0, exclude this term
				if ( hideEmpty && count === 0 ) {
					return acc;
				}

				acc.push( {
					label: term.name,
					value: term.slug,
					selected: false,
					count,
					id: term.id,
					parent: term.parent || 0,
				} );

				return acc;
			},
			[]
		);

		// Create hierarchical structure then apply sorting
		const hierarchicalTerms = createHierarchicalList(
			processedTerms,
			sortOrder
		);
		setTermOptions( hierarchicalTerms );
		setIsOptionsLoading( false );
	}, [
		taxonomy,
		taxonomyTerms,
		filteredCounts,
		sortOrder,
		hideEmpty,
		isPreview,
		isTermsLoading,
		isFilterCountsLoading,
	] );

	const { children, ...innerBlocksProps } = useInnerBlocksProps(
		useBlockProps(),
		{
			allowedBlocks: getAllowedBlocks( EXCLUDED_BLOCKS ),
			template: [
				[
					'core/heading',
					{
						level: 3,
						content: getTaxonomyLabel( taxonomy ),
						style: {
							spacing: {
								margin: {
									bottom: '0.625rem',
									top: '0',
								},
							},
						},
					},
				],
				[ displayStyle ],
			],
		}
	);

	const isLoading = isPreview
		? false
		: isTermsLoading || isFilterCountsLoading || isOptionsLoading;

	if ( ! taxonomy )
		return (

				<TaxonomyFilterInspectorControls { ...props } />
				<Notice>

						{ __(
							'Please select a taxonomy to use this filter!',
							'woocommerce'
						) }

				</Notice>

		);

	if ( ! isLoading && ! isPreview && taxonomyTerms.length === 0 )
		return (

				<TaxonomyFilterInspectorControls { ...props } />
				<Notice>

						{ sprintf(
							// translators: %s: Taxonomy label.
							__(
								'There are no products associated with %s.',
								'woocommerce'
							),
							getTaxonomyLabel( taxonomy )
						) }

				</Notice>

		);

	return (

			<TaxonomyFilterInspectorControls { ...props } />
			<InitialDisabled>
				<BlockContextProvider
					value={ {
						filterData: {
							items:
								termOptions.length === 0 && isPreview
									? termOptionsPreview
									: termOptions,
							isLoading,
							showCounts,
						},
					} }
				>
					{ children }
				</BlockContextProvider>
			</InitialDisabled>

	);
};

export default withSpokenMessages( Edit );


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a grow block with customizable email placeholder, consent text, interests, and 6 more options

[Assistant]
// File: projects/plugins/jetpack/extensions/blocks/mailchimp/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/mailchimp",
	"title": "Mailchimp",
	"description": "Allow readers to join a Mailchimp audience.",
	"keywords": [ "email", "subscription", "newsletter" ],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "grow",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><path d='m16.88,11.25c.17-.02.34-.02.49,0,.09-.2.1-.55.02-.93-.12-.57-.28-.91-.61-.86-.33.05-.34.46-.22,1.03.07.32.19.59.32.76'/><path d='m14.03,11.7c.24.1.38.17.44.11.04-.04.03-.11-.03-.2-.12-.19-.36-.38-.61-.49-.52-.22-1.14-.15-1.62.19-.16.12-.31.28-.29.37,0,.03.03.06.09.06.13.01.59-.22,1.11-.25.37-.02.68.09.92.2'/><path d='m13.56,11.97c-.31.05-.48.15-.59.25-.09.08-.15.17-.15.23,0,.03.01.05.02.06.01.01.03.02.05.02.07,0,.23-.06.23-.06.43-.15.71-.13.99-.1.16.02.23.03.26-.03.01-.02.02-.05,0-.1-.07-.12-.38-.32-.81-.26'/><path d='m15.92,12.97c.21.1.44.06.52-.09s-.03-.36-.24-.46c-.21-.1-.44-.06-.52.09-.08.15.03.36.24.46'/><path d='m17.26,11.79c-.17,0-.31.18-.32.42s.13.42.3.43.31-.18.32-.42c0-.23-.13-.42-.3-.43'/><path d='m5.83,16c-.04-.05-.11-.04-.18-.02-.05.01-.1.02-.16.02-.13,0-.23-.06-.29-.15-.08-.12-.07-.3.01-.5l.04-.09c.14-.31.36-.82.11-1.31-.19-.37-.51-.6-.89-.64-.36-.05-.74.09-.98.35-.38.42-.44.98-.36,1.18.03.07.07.09.1.1.06,0,.16-.04.22-.2l.02-.05c.03-.08.08-.24.16-.37.1-.15.25-.26.43-.29.18-.04.37,0,.52.1.26.17.37.5.25.8-.06.16-.15.46-.13.72.04.51.35.71.63.73.27.01.46-.14.51-.25.03-.07,0-.11-.01-.12'/><path d='m8.42,6.69c.89-1.03,1.98-1.92,2.96-2.42.03-.02.07.02.05.05-.08.14-.23.44-.28.67,0,.04.03.06.06.04.61-.42,1.67-.86,2.6-.92.04,0,.06.05.03.07-.14.11-.3.26-.41.41-.02.03,0,.06.03.06.65,0,1.57.23,2.17.57.04.02.01.1-.03.09-.91-.21-2.4-.37-3.94.01-1.38.34-2.43.86-3.2,1.41-.04.03-.09-.02-.05-.06h0Zm4.43,9.95h0s0,0,0,0h0Zm3.67.43s.04-.04.04-.07c0-.04-.04-.06-.07-.06,0,0-1.9.28-3.69-.38.2-.63.71-.41,1.5-.34,1.41.08,2.68-.12,3.62-.39.81-.23,1.88-.69,2.71-1.35.28.61.38,1.29.38,1.29,0,0,.22-.04.4.07.17.11.3.32.21.89-.17,1.05-.62,1.91-1.38,2.7-.46.49-1.02.92-1.65,1.24-.34.18-.7.33-1.08.46-2.84.93-5.75-.09-6.69-2.28-.07-.16-.14-.34-.19-.52-.4-1.44-.06-3.17,1-4.27h0c.07-.07.13-.15.13-.25,0-.09-.05-.18-.1-.24-.37-.54-1.66-1.45-1.4-3.23.19-1.27,1.3-2.17,2.34-2.12l.26.02c.45.03.84.08,1.21.1.62.03,1.18-.06,1.84-.61.22-.19.4-.35.7-.4.03,0,.11-.03.27-.03.16,0,.31.05.45.14.53.35.6,1.21.63,1.83.02.36.06,1.22.07,1.47.03.57.18.65.48.75.17.06.33.1.56.16.7.2,1.12.4,1.38.65.16.16.23.33.25.49.08.6-.47,1.35-1.93,2.03-1.59.74-3.53.93-4.87.78l-.47-.05c-1.07-.14-1.68,1.24-1.04,2.18.41.61,1.54,1.01,2.67,1.01,2.58,0,4.57-1.1,5.31-2.06l.06-.08c.04-.05,0-.08-.04-.05-.6.41-3.28,2.05-6.15,1.56,0,0-.35-.06-.67-.18-.25-.1-.78-.34-.85-.88,2.31.72,3.77.04,3.77.04h0ZM3.8,11.57c-.8.16-1.51.61-1.95,1.24-.26-.22-.74-.63-.83-.8-.69-1.31.76-3.87,1.77-5.32C5.3,3.13,9.21.43,11.02.92c.29.08,1.27,1.21,1.27,1.21,0,0-1.81,1.01-3.49,2.41-2.26,1.74-3.97,4.28-5,7.03h0Zm1.35,6.03c-.12.02-.25.03-.37.03-1.21-.03-2.52-1.12-2.65-2.42-.14-1.43.59-2.53,1.88-2.79.15-.03.34-.05.54-.04.72.04,1.79.6,2.04,2.17.22,1.4-.13,2.82-1.44,3.04h0Zm16.4-2.53s-.08-.28-.17-.58c-.09-.3-.19-.51-.19-.51.37-.56.38-1.06.33-1.34-.05-.35-.2-.65-.49-.96-.29-.31-.89-.62-1.74-.86l-.44-.12s-.02-1.04-.04-1.48c-.01-.32-.04-.82-.2-1.31-.18-.66-.5-1.24-.9-1.61,1.1-1.14,1.79-2.4,1.79-3.48,0-2.08-2.56-2.71-5.7-1.4l-.67.28s-1.2-1.18-1.22-1.2C8.33-2.63-2.89,9.84.7,12.86l.78.66c-.2.53-.28,1.13-.22,1.78.08.83.51,1.63,1.21,2.25.66.59,1.53.96,2.37.96,1.4,3.21,4.58,5.19,8.32,5.3,4.01.12,7.37-1.76,8.78-5.14.09-.24.48-1.31.48-2.25s-.54-1.34-.88-1.34'/></svg>",
	"supports": {
		"align": [ "wide", "full" ],
		"color": {
			"gradients": true
		},
		"spacing": {
			"padding": true,
			"margin": true
		}
	},
	"attributes": {
		"emailPlaceholder": {
			"type": "string"
		},
		"consentText": {
			"type": "string"
		},
		"interests": {
			"type": "array",
			"default": []
		},
		"processingLabel": {
			"type": "string"
		},
		"signupFieldTag": {
			"type": "string"
		},
		"signupFieldValue": {
			"type": "string"
		},
		"successLabel": {
			"type": "string"
		},
		"errorLabel": {
			"type": "string"
		},
		"preview": {
			"type": "boolean",
			"default": false
		}
	},
	"example": {
		"attributes": {
			"preview": true
		},
		"innerBlocks": [
			{
				"name": "jetpack/button",
				"attributes": {
					"element": "button",
					"text": "Join my Mailchimp audience",
					"uniqueId": "mailchimp-widget-id"
				}
			}
		]
	}
}

// File: projects/plugins/jetpack/extensions/blocks/mailchimp/edit.js
import {
	isCurrentUserConnected,
	getBlockIconComponent,
} from '@automattic/jetpack-shared-extension-utils';
import apiFetch from '@wordpress/api-fetch';
import { useBlockProps } from '@wordpress/block-editor';
import { withNotices } from '@wordpress/components';
import { useCallback, useEffect, useState } from '@wordpress/element';
import { addQueryArgs } from '@wordpress/url';
import metadata from './block.json';
import Body from './body';
import { API_STATE_CONNECTED, API_STATE_NOTCONNECTED, API_STATE_LOADING } from './constants';
import { MailChimpInspectorControls } from './controls';
import Loader from './loader';
import { UserConnectedPlaceholder, UserNotConnectedPlaceholder } from './placeholders';

const icon = getBlockIconComponent( metadata );

export const MailchimpSubscribeEdit = ( {
	attributes,
	setAttributes,
	notices,
	noticeUI,
	noticeOperations,
} ) => {
	const blockProps = useBlockProps();

	const [ audition, setAudition ] = useState( null );
	const [ connected, setConnected ] = useState( API_STATE_LOADING );
	const [ connectURL, setConnectURL ] = useState( null );
	const [ currentUserConnected, setCurrentUserconnected ] = useState( null );

	const apiCall = useCallback( () => {
		const isUserConnected = isCurrentUserConnected();

		if ( isUserConnected ) {
			apiFetch( { path: '/wpcom/v2/mailchimp', method: 'GET' } ).then(
				( { connect_url: url, code } ) => {
					setConnectURL( url );
					setConnected( code === 'connected' ? API_STATE_CONNECTED : API_STATE_NOTCONNECTED );
					setCurrentUserconnected( isUserConnected );
				},
				( { message } ) => {
					setConnectURL( null );
					setConnected( API_STATE_NOTCONNECTED );
					setCurrentUserconnected( isUserConnected );

					noticeOperations.removeAllNotices();
					noticeOperations.createErrorNotice( message );
				}
			);
		} else {
			apiFetch( {
				path: addQueryArgs( '/jetpack/v4/connection/url', {
					from: 'jetpack-block-editor',
					redirect: window.location.href,
				} ),
			} ).then( url => {
				setConnectURL( url );
				setConnected( API_STATE_NOTCONNECTED );
				setCurrentUserconnected( isUserConnected );
			} );
		}
	}, [ setConnectURL, setConnected, setCurrentUserconnected, noticeOperations ] );

	useEffect( () => {
		apiCall();
	}, [ apiCall ] );

	let content;

	if ( attributes.preview ) {
		content = (
			<Body attributes={ attributes } setAttributes={ setAttributes } audition={ audition } />
		);
	} else if ( connected === API_STATE_LOADING ) {
		content = <Loader icon={ icon } notices={ notices } />;
	} else if ( connected === API_STATE_NOTCONNECTED ) {
		if ( currentUserConnected ) {
			content = (
				<UserConnectedPlaceholder
					icon={ icon }
					notices={ notices }
					connectURL={ connectURL }
					apiCall={ apiCall }
				/>
			);
		} else {
			content = (
				<UserNotConnectedPlaceholder icon={ icon } notices={ notices } connectURL={ connectURL } />
			);
		}
	} else if ( connected === API_STATE_CONNECTED ) {
		content = (
			<>
				<MailChimpInspectorControls
					connectURL={ connectURL }
					attributes={ attributes }
					setAttributes={ setAttributes }
					setAudition={ setAudition }
				/>
				<Body attributes={ attributes } setAttributes={ setAttributes } audition={ audition } />
			</>
		);
	}

	return (
		<div { ...blockProps }>
			{ noticeUI }
			{ content }
		</div>
	);
};

export default withNotices( MailchimpSubscribeEdit );

// File: projects/plugins/jetpack/extensions/blocks/mailchimp/save.js
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';

export default () => {
	const blockProps = useBlockProps.save();

	return (
		<div { ...blockProps }>
			<InnerBlocks.Content />
		</div>
	);
};


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Craft a Gutenberg block for blog post newsletter subscription, incorporating customizable features like placeholder text, subscriber count display, social follower integration, and 26 additional configuration options.

[Assistant]
// File: projects/plugins/jetpack/extensions/blocks/subscriptions/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/subscriptions",
	"title": "Subscribe",
	"description": "Subscribe to this blog's posts as a newsletter.",
	"keywords": [ "newsletter", "email", "follow" ],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "grow",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><path d='m19.02,5H4.98c-1.09,0-1.98.89-1.98,1.98v10.04c0,1.09.89,1.98,1.98,1.98h14.04c1.09,0,1.98-.89,1.98-1.98V6.98c0-1.09-.89-1.98-1.98-1.98Zm.48,11.92c0,.32-.26.58-.58.58H5.08c-.32,0-.58-.26-.58-.58V7.08c0-.32.26-.58.58-.58h13.84c.32,0,.58.26.58.58v9.84Z'/><path d='m4.38,17.69l5.71-4.79s.96,1,1.91.99,1.91-.99,1.91-.99l5.59,4.79v-2.03l-4.41-3.73,4.41-3.72v-1.91l-7.14,5.76c-.24.19-.59.19-.83,0l-7.14-5.88v1.98l4.3,3.67-4.3,3.78v2.08Z'/></svg>",
	"supports": {
		"spacing": {
			"margin": true,
			"padding": true
		},
		"align": [ "wide", "full" ]
	},
	"styles": [
		{
			"name": "split",
			"label": "Split",
			"isDefault": true
		},
		{
			"name": "compact",
			"label": "Compact"
		},
		{
			"name": "button",
			"label": "Button only"
		}
	],
	"attributes": {
		"subscribePlaceholder": {
			"type": "string"
		},
		"showSubscribersTotal": {
			"type": "boolean",
			"default": false
		},
		"includeSocialFollowers": {
			"type": "boolean"
		},
		"buttonOnNewLine": {
			"type": "boolean",
			"default": false
		},
		"buttonWidth": {
			"type": "string"
		},
		"submitButtonText": {
			"type": "string"
		},
		"emailFieldBackgroundColor": {
			"type": "string"
		},
		"customEmailFieldBackgroundColor": {
			"type": "string"
		},
		"emailFieldGradient": {
			"type": "string"
		},
		"customEmailFieldGradient": {
			"type": "string"
		},
		"buttonBackgroundColor": {
			"type": "string"
		},
		"customButtonBackgroundColor": {
			"type": "string"
		},
		"buttonGradient": {
			"type": "string"
		},
		"customButtonGradient": {
			"type": "string"
		},
		"textColor": {
			"type": "string"
		},
		"customTextColor": {
			"type": "string"
		},
		"fontSize": {
			"type": "string"
		},
		"customFontSize": {
			"type": "string"
		},
		"borderRadius": {
			"type": "number"
		},
		"borderWeight": {
			"type": "number"
		},
		"borderColor": {
			"type": "string"
		},
		"customBorderColor": {
			"type": "string"
		},
		"padding": {
			"type": "number"
		},
		"spacing": {
			"type": "number"
		},
		"successMessage": {
			"type": "string",
			"default": "Success! An email was just sent to confirm your subscription. Please find the email now and click 'Confirm' to start subscribing."
		},
		"appSource": {
			"type": "string"
		},
		"className": {
			"type": "string"
		},
		"preselectNewsletterCategories": {
			"type": "boolean",
			"default": false
		},
		"selectedNewsletterCategoryIds": {
			"type": "array",
			"default": []
		}
	},
	"example": {}
}

// File: projects/plugins/jetpack/extensions/blocks/subscriptions/edit.js
import { ThemeProvider } from '@automattic/jetpack-components';
import { formatNumberCompact } from '@automattic/number-formatters';
import {
	BlockControls,
	InspectorControls,
	RichText,
	withColors,
	withFontSizes,
	useBlockProps,
	__experimentalUseGradient as useGradient, // eslint-disable-line @wordpress/no-unsafe-wp-apis
} from '@wordpress/block-editor';
import {
	TextControl,
	withFallbackStyles,
	ToolbarGroup,
	ToolbarButton,
} from '@wordpress/components';
import { compose, usePrevious } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { _n, sprintf, _x, __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { isEqual } from 'lodash';
import { getActiveStyleName } from '../../shared/block-styles';
import { getValidatedAttributes } from '../../shared/get-validated-attributes';
import { getPaidPlanLink } from '../../shared/memberships/utils';
import './view.scss';
import './editor.scss';
import { store as membershipProductsStore } from '../../store/membership-products';
import metadata from './block.json';
import {
	DEFAULT_BORDER_RADIUS_VALUE,
	DEFAULT_BORDER_WEIGHT_VALUE,
	DEFAULT_PADDING_VALUE,
	DEFAULT_SPACING_VALUE,
	DEFAULT_FONTSIZE_VALUE,
	DEFAULT_SUBSCRIBE_PLACEHOLDER,
	DEFAULT_SUBMIT_BUTTON_LABEL,
	DEFAULT_SUCCESS_MESSAGE,
} from './constants';
import SubscriptionControls from './controls';

const { getComputedStyle } = window;
const isGradientAvailable = !! useGradient;
const useGradientIfAvailable = isGradientAvailable ? useGradient : () => ( {} );

const applyFallbackStyles = withFallbackStyles( ( node, ownProps ) => {
	const { buttonBackgroundColor, textColor } = ownProps;
	const buttonBackgroundColorValue = buttonBackgroundColor && buttonBackgroundColor.color;
	const textColorValue = textColor && textColor.color;

	const buttonNode = node.querySelector( '.wp-block-jetpack-subscriptions__button' );

	return {
		fallbackButtonBackgroundColor:
			buttonBackgroundColorValue || ! node
				? undefined
				: buttonNode && getComputedStyle( buttonNode ).backgroundColor,
		fallbackTextColor:
			textColorValue || ! node ? undefined : buttonNode && getComputedStyle( buttonNode ).color,
	};
} );

export function SubscriptionEdit( props ) {
	const {
		attributes,
		setAttributes,
		emailFieldBackgroundColor,
		buttonBackgroundColor,
		setButtonBackgroundColor,
		fallbackButtonBackgroundColor,
		textColor,
		fallbackTextColor,
		setTextColor,
		borderColor,
		setBorderColor,
		fontSize,
	} = props;
	const hasTierPlans = useSelect(
		select => !! select( 'jetpack/membership-products' )?.getNewsletterTierProducts()?.length,
		[]
	);
	const blockProps = useBlockProps();
	const validatedAttributes = getValidatedAttributes( metadata.attributes, attributes );
	if ( ! isEqual( validatedAttributes, attributes ) ) {
		setAttributes( validatedAttributes );
	}

	const {
		borderRadius,
		borderWeight,
		buttonWidth,
		className,
		includeSocialFollowers,
		padding,
		preselectNewsletterCategories,
		selectedNewsletterCategoryIds,
		spacing,
		submitButtonText = DEFAULT_SUBMIT_BUTTON_LABEL,
		subscribePlaceholder = DEFAULT_SUBSCRIBE_PLACEHOLDER,
		showSubscribersTotal,
		buttonOnNewLine,
		successMessage = DEFAULT_SUCCESS_MESSAGE,
	} = validatedAttributes;

	const activeStyleName = getActiveStyleName( metadata.styles, className );

	const { subscriberCount, subscriberCountString } = useSelect( select => {
		const { totalSubscribers, socialFollowers } =
			select( membershipProductsStore ).getSubscriberCounts();
		let count = totalSubscribers;
		if ( includeSocialFollowers ) {
			count += socialFollowers;
		}

		return {
			subscriberCount: count,
			subscriberCountString: sprintf(
				/* translators: %s: the number of subscribers. */
				_n( 'Join %s other subscriber', 'Join %s other subscribers', count, 'jetpack' ),
				formatNumberCompact( count, { numberFormatOptions: { maximumFractionDigits: 1 } } )
			),
		};
	} );

	const { availableNewsletterCategories, areNewsletterCategoriesEnabled } = useSelect( select => {
		const store = select( membershipProductsStore );

		return {
			availableNewsletterCategories: store.getNewsletterCategories(),
			areNewsletterCategoriesEnabled: store.getNewsletterCategoriesEnabled(),
		};
	} );

	const emailFieldGradient = useGradientIfAvailable( {
		gradientAttribute: 'emailFieldGradient',
		customGradientAttribute: 'customEmailFieldGradient',
	} );
	const buttonGradient = useGradientIfAvailable( {
		gradientAttribute: 'buttonGradient',
		customGradientAttribute: 'customButtonGradient',
	} );

	const sharedClasses = {
		'no-border-radius': borderRadius === 0,
		[ fontSize.class ]: fontSize.class,
		'has-text-color': textColor.color,
		[ textColor.class ]: textColor.class,
	};

	const emailFieldClasses = {
		...sharedClasses,
		'has-background': emailFieldBackgroundColor.color || emailFieldGradient.gradientValue,
		[ emailFieldBackgroundColor.class ]:
			! emailFieldGradient.gradientValue && emailFieldBackgroundColor.class,
		[ emailFieldGradient.gradientClass ]: emailFieldGradient.gradientClass,
	};

	const buttonClasses = {
		...sharedClasses,
		'has-background': buttonBackgroundColor.color || buttonGradient.gradientValue,
		[ buttonBackgroundColor.class ]: ! buttonGradient.gradientValue && buttonBackgroundColor.class,
		[ buttonGradient.gradientClass ]: buttonGradient.gradientClass,
	};

	const getPaddingStyleValue = paddingValue => {
		const value = paddingValue ? paddingValue : DEFAULT_PADDING_VALUE;

		return (
			value +
			'px ' +
			Math.round( value * 1.5 ) +
			'px ' +
			value +
			'px ' +
			Math.round( value * 1.5 ) +
			'px'
		);
	};

	const getSpacingStyleValue = spacingValue => {
		return spacingValue ? spacingValue : DEFAULT_SPACING_VALUE;
	};

	const sharedStyles = {
		color: textColor.color,
		borderColor: borderColor.color,
		borderRadius: borderRadius ? borderRadius + 'px' : DEFAULT_BORDER_RADIUS_VALUE + 'px',
		borderWidth: borderWeight ? borderWeight + 'px' : DEFAULT_BORDER_WEIGHT_VALUE + 'px',
		fontSize: fontSize.size ? fontSize.size : DEFAULT_FONTSIZE_VALUE,
		padding: getPaddingStyleValue( padding ),
	};

	const cssVars = {
		'--subscribe-block-border-radius': borderRadius
			? borderRadius + 'px'
			: DEFAULT_BORDER_RADIUS_VALUE + 'px',
	};

	const emailFieldStyles = {
		...sharedStyles,
		...( ! emailFieldBackgroundColor.color && emailFieldGradient.gradientValue
			? { background: emailFieldGradient.gradientValue }
			: { backgroundColor: emailFieldBackgroundColor.color } ),
	};

	const buttonStyles = {
		...sharedStyles,
		...( ! buttonBackgroundColor.color && buttonGradient.gradientValue
			? { background: buttonGradient.gradientValue }
			: { backgroundColor: buttonBackgroundColor.color } ),
		width: buttonWidth?.length ? buttonWidth : 'auto',
	};

	if ( activeStyleName !== 'button' ) {
		if ( buttonOnNewLine ) {
			buttonStyles.marginTop = getSpacingStyleValue( spacing ) + 'px';
		} else {
			buttonStyles.marginLeft = getSpacingStyleValue( spacing ) + 'px';
		}
	}

	const previousButtonBackgroundColor = usePrevious( buttonBackgroundColor );

	useEffect( () => {
		if (
			previousButtonBackgroundColor?.color !== borderColor?.color ||
			borderColor?.color === buttonBackgroundColor?.color
		) {
			return;
		}
		setBorderColor( buttonBackgroundColor.color );
	}, [ buttonBackgroundColor, previousButtonBackgroundColor, borderColor, setBorderColor ] );

	return (

			<InspectorControls>
				<SubscriptionControls
					areNewsletterCategoriesEnabled={ areNewsletterCategoriesEnabled }
					availableNewsletterCategories={ availableNewsletterCategories }
					buttonBackgroundColor={ buttonBackgroundColor }
					borderColor={ borderColor }
					buttonGradient={ buttonGradient }
					borderRadius={ borderRadius }
					borderWeight={ borderWeight }
					buttonOnNewLine={ buttonOnNewLine }
					emailFieldBackgroundColor={ emailFieldBackgroundColor }
					fallbackButtonBackgroundColor={ fallbackButtonBackgroundColor }
					fallbackTextColor={ fallbackTextColor }
					fontSize={ fontSize }
					includeSocialFollowers={ includeSocialFollowers }
					isGradientAvailable={ isGradientAvailable }
					padding={ padding }
					preselectNewsletterCategories={ preselectNewsletterCategories }
					setAttributes={ setAttributes }
					setBorderColor={ setBorderColor }
					setButtonBackgroundColor={ setButtonBackgroundColor }
					setTextColor={ setTextColor }
					showSubscribersTotal={ showSubscribersTotal }
					spacing={ spacing }
					subscriberCount={ subscriberCount }
					textColor={ textColor }
					buttonWidth={ buttonWidth }
					selectedNewsletterCategoryIds={ selectedNewsletterCategoryIds }
					subscribePlaceholder={ subscribePlaceholder }
					submitButtonText={ submitButtonText }
					successMessage={ successMessage }
				/>
			</InspectorControls>
			<BlockControls>
				<ToolbarGroup>
					<ToolbarButton href={ getPaidPlanLink( hasTierPlans ) } target="_blank">
						{ hasTierPlans
							? _x( 'Manage plans', 'unused context to distinguish translations', 'jetpack' )
							: __( 'Set up a paid plan', 'jetpack' ) }
					</ToolbarButton>
				</ToolbarGroup>
			</BlockControls>

							{ activeStyleName !== 'button' && (
								<TextControl
									__nextHasNoMarginBottom={ true }
									__next40pxDefaultSize
									placeholder={ subscribePlaceholder }
									disabled={ true }
									className={ clsx(
										emailFieldClasses,
										'wp-block-jetpack-subscriptions__textfield'
									) }
									style={ emailFieldStyles }
								/>
							) }
							<RichText
								className={ clsx(
									buttonClasses,
									'wp-block-jetpack-subscriptions__button',
									'wp-block-button__link'
								) }
								onChange={ value => setAttributes( { submitButtonText: value } ) }
								style={ buttonStyles }
								value={ submitButtonText }
								withoutInteractiveFormatting
								allowedFormats={ [ 'core/bold', 'core/italic', 'core/strikethrough' ] }
							/>

				{ showSubscribersTotal && (

{ subscriberCountString }

				) }

	);
}

const withThemeProvider = WrappedComponent => props => (
	<ThemeProvider>
		<WrappedComponent { ...props } />
	</ThemeProvider>
);

export default compose( [
	withColors(
		{ emailFieldBackgroundColor: 'backgroundColor' },
		{ buttonBackgroundColor: 'backgroundColor' },
		{ textColor: 'color' },
		'borderColor'
	),
	withFontSizes( 'fontSize' ),
	applyFallbackStyles,
	withThemeProvider,
] )( SubscriptionEdit );


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Build a Gutenberg block that Displays the date on which the review was posted. with these attributes: format, is link

[Assistant]
// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-reviews/inner-blocks/review-date/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "woocommerce/product-review-date",
	"title": "Review Date",
	"category": "woocommerce",
	"ancestor": [ "woocommerce/product-reviews" ],
	"description": "Displays the date on which the review was posted.",
	"textdomain": "woocommerce",
	"attributes": {
		"format": {
			"type": "string"
		},
		"isLink": {
			"type": "boolean",
			"default": true
		}
	},
	"usesContext": [ "commentId" ],
	"supports": {
		"html": false,
		"color": {
			"gradients": true,
			"link": true,
			"__experimentalDefaultControls": {
				"background": true,
				"text": true,
				"link": true
			}
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true,
			"__experimentalDefaultControls": {
				"radius": true,
				"color": true,
				"width": true,
				"style": true
			}
		}
	}
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-reviews/inner-blocks/review-date/edit.tsx
/**
 * External dependencies
 */
import { useEntityProp } from '@wordpress/core-data';
import type { BlockEditProps } from '@wordpress/blocks';
import {
	dateI18n,
	humanTimeDiff,
	getSettings as getDateSettings,
} from '@wordpress/date';
import { PanelBody, ToggleControl } from '@wordpress/components';
import { __, _x } from '@wordpress/i18n';
import {
	InspectorControls,
	useBlockProps,
	// @ts-expect-error - Experimental component
	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
	__experimentalDateFormatPicker as DateFormatPicker,
} from '@wordpress/block-editor';

export default function Edit( {
	attributes: { format, isLink },
	context: { commentId },
	setAttributes,
}: BlockEditProps< {
	format: string;
	isLink: boolean;
} > & {
	context: { commentId: number };
} ) {
	const blockProps = useBlockProps();

	// eslint-disable-next-line @typescript-eslint/ban-ts-comment
	// @ts-expect-error - the type of useEntityProp is not correct
	let [ date ] = useEntityProp( 'root', 'comment', 'date', commentId );
	const [ siteFormat = getDateSettings().formats.date ] = useEntityProp(
		'root',
		'site',
		'date_format'
	);

	if ( ! commentId || ! date ) {
		date = _x( 'Review Date', 'block title', 'woocommerce' );
	}

	let reviewDate =
		date instanceof Date ? (
			<time dateTime={ dateI18n( 'c', date, true ) }>
				{ format === 'human-diff'
					? humanTimeDiff( date, new Date() )
					: dateI18n( format || siteFormat, date, true ) }
			</time>
		) : (
			<time>{ date }</time>
		);

	if ( isLink ) {
		reviewDate = (
			<a
				href="#review-date-pseudo-link"
				onClick={ ( event ) => event.preventDefault() }
			>
				{ reviewDate }
			</a>
		);
	}

	return (
		<>
			<InspectorControls>
				<PanelBody title={ __( 'Settings', 'woocommerce' ) }>
					<DateFormatPicker
						format={ format }
						defaultFormat={ siteFormat }
						onChange={ ( nextFormat: string ) =>
							setAttributes( { format: nextFormat } )
						}
					/>
					<ToggleControl
						__nextHasNoMarginBottom
						label={ __( 'Link to review', 'woocommerce' ) }
						onChange={ () => setAttributes( { isLink: ! isLink } ) }
						checked={ isLink }
					/>
				</PanelBody>
			</InspectorControls>
			<div { ...blockProps }>{ reviewDate }</div>
		</>
	);
}


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Develop a Gutenberg block utilizing AI technology to convert voice input directly into a publishable post, incorporating a content attribute for seamless text generation.

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: projects/plugins/jetpack/extensions/blocks/voice-to-content/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/voice-to-content",
	"title": "Voice to content",
	"description": "Transform your spoken words into a post ready to publish with AI.",
	"keywords": [ "AI", "GPT", "AL", "Magic", "help", "assistant" ],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "media",
	"icon": "<svg viewBox='0 0 20 20' width='20' height='20' xmlns='http://www.w3.org/2000/svg'><path d='M12 9V3c0-1.1-.89-2-2-2-1.12 0-2 .94-2 2v6c0 1.1.9 2 2 2 1.13 0 2-.94 2-2zm4 0c0 2.97-2.16 5.43-5 5.91V17h2c.56 0 1 .45 1 1s-.44 1-1 1H7c-.55 0-1-.45-1-1s.45-1 1-1h2v-2.09C6.17 14.43 4 11.97 4 9c0-.55.45-1 1-1 .56 0 1 .45 1 1 0 2.21 1.8 4 4 4 2.21 0 4-1.79 4-4 0-.55.45-1 1-1 .56 0 1 .45 1 1z'/></svg>",
	"supports": {
		"html": false,
		"multiple": true,
		"reusable": false
	},
	"attributes": {
		"content": {
			"type": "string"
		}
	}
}

// File: projects/plugins/jetpack/extensions/blocks/voice-to-content/edit.tsx
import {
	useMediaRecording,
	useAudioValidation,
	TRANSCRIPTION_POST_PROCESSING_ACTION_SIMPLE_DRAFT,
} from '@automattic/jetpack-ai-client';
import { ThemeProvider } from '@automattic/jetpack-components';
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { type BlockInstance } from '@wordpress/blocks';
import { Button, Modal, Icon } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback, useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { external } from '@wordpress/icons';
import ActionButtons from './components/action-buttons';
import AudioStatusPanel from './components/audio-status-panel';
import useTranscriptionCreator from './hooks/use-transcription-creator';
import useTranscriptionInserter from './hooks/use-transcription-inserter';
import type {
	RecordingState,
	TranscriptionState,
	ValidatedAudioInformation,
} from '@automattic/jetpack-ai-client';

/**
 * Helper to determine the state of the transcription.
 *
 * @param {boolean}        isCreatingTranscription - The transcription creation state
 * @param {boolean}        isValidatingAudio       - The audio validation state
 * @param {RecordingState} recordingState          - The recording state
 * @return {TranscriptionState} - The transcription state
 */
const transcriptionStateHelper = (
	isCreatingTranscription: boolean,
	isValidatingAudio: boolean,
	recordingState: RecordingState
): TranscriptionState => {
	if ( isValidatingAudio ) {
		return 'validating';
	}

	if ( isCreatingTranscription ) {
		return 'processing';
	}

	return recordingState;
};

export default function VoiceToContentEdit( { clientId } ) {
	const [ audio, setAudio ] = useState< Blob >( null );

	const { removeBlock } = useDispatch( blockEditorStore );
	// TODO: The second `deps` argument shouldn't be needed, but it's added to make the type checker happy.
	// This can be removed when the core data types are updated to fix the issue.
	const { getBlocks } = useSelect( blockEditorStore, [] ) as {
		getBlocks: () => BlockInstance[];
	};

	const destroyBlock = useCallback( () => {
		// Remove the block from the editor
		setTimeout( () => {
			removeBlock( clientId );
		}, 100 );
	}, [ removeBlock, clientId ] );

	// Track the usage of the feature
	const { tracks } = useAnalytics();

	const { isValidatingAudio, validateAudio } = useAudioValidation();

	const { upsertTranscription } = useTranscriptionInserter();
	const { isCreatingTranscription, createTranscription, cancelTranscription } =
		useTranscriptionCreator( {
			onReady: ( content: string ) => {
				// When transcription is ready, insert it into the editor
				upsertTranscription( content );

				// Then check if there is a single empty paragraph block before the transcription and remove it
				// This is to ensure the P2 title is correct as it's based on the first block
				const blocks = getBlocks();
				// One block is the voice-to-content block itself, so we check the first two blocks
				for ( let i = 0; i < 2; i++ ) {
					if ( blocks[ i ].name === 'core/paragraph' && blocks[ i ].attributes?.content === '' ) {
						removeBlock( String( blocks[ i ].clientId ) );
					}
				}

				handleClose();
			},
			onUpdate: ( content: string ) => {
				// When transcription is updated, insert it into the editor
				upsertTranscription( content );
			},
			onError: ( error: string ) => {
				// When transcription fails, show an error message
				onError( error );
			},
		} );

	const handleClose = () => {
		cancelTranscription();
		destroyBlock();
	};

	const { state, controls, error, onError, duration, analyser } = useMediaRecording( {
		onDone: lastBlob => {
			// When recording is done, set the audio to be transcribed
			onAudioHandler( lastBlob );
		},
	} );

	const onAudioHandler = useCallback(
		( audioFile: Blob ) => {
			if ( audioFile ) {
				setAudio( audioFile );
			}
		},
		[ setAudio ]
	);

	/**
	 * When the audio changes, create the transcription. In the future,
	 * we can trigger this action (and others) from a button in the UI.
	 */
	useEffect( () => {
		if ( audio ) {
			validateAudio(
				audio,
				( audioInfo: ValidatedAudioInformation ) => {
					// Track the transcription event
					tracks.recordEvent( 'jetpack_ai_voice_to_content_transcription_started', {
						post_processing_action: TRANSCRIPTION_POST_PROCESSING_ACTION_SIMPLE_DRAFT,
						type: audioInfo.isFile ? 'upload' : 'record',
						audio_duration: audioInfo.duration,
						audio_file_size: audioInfo.size,
					} );

					createTranscription( audio, TRANSCRIPTION_POST_PROCESSING_ACTION_SIMPLE_DRAFT );
				},
				onError
			);
		}
	}, [ audio, tracks, validateAudio, createTranscription, onError ] );

	// Destructure controls
	const {
		start: controlStart,
		pause: controlPause,
		resume: controlResume,
		stop: controlStop,
		reset: controlReset,
	} = controls;

	const onUploadHandler = useCallback(
		event => {
			if ( event.currentTarget.files.length > 0 ) {
				const file = event.currentTarget.files[ 0 ];
				onAudioHandler( file );
			}
		},
		[ onAudioHandler ]
	);

	const onCancelHandler = useCallback( () => {
		cancelTranscription();
		controlReset();
	}, [ cancelTranscription, controlReset ] );

	const onRecordHandler = useCallback( () => {
		controlStart( 1000 ); // Stream audio on 1 second intervals
	}, [ controlStart ] );

	const onPauseHandler = useCallback( () => {
		controlPause();
	}, [ controlPause ] );

	const onResumeHandler = useCallback( () => {
		controlResume();
	}, [ controlResume ] );

	const onDoneHandler = useCallback( () => {
		controlStop();
	}, [ controlStop ] );

	// To avoid a wrong TS warning
	const iconProps = { className: 'icon' };

	const transcriptionState = transcriptionStateHelper(
		isCreatingTranscription,
		isValidatingAudio,
		state
	);

	return (
		<Modal
			onRequestClose={ handleClose }
			title={ __( 'Jetpack AI Voice to content', 'jetpack' ) }
			className="jetpack-ai-voice-to-content__modal"
			shouldCloseOnEsc={ false }
			shouldCloseOnClickOutside={ false }
		>
			<ThemeProvider>

							{ __(
								'Transform your spoken words into a post ready to publish with AI.',
								'jetpack'
							) }

							<AudioStatusPanel
								state={ transcriptionState }
								error={ error }
								duration={ duration }
								analyser={ analyser }
							/>

						<ActionButtons
							state={ transcriptionState }
							onUpload={ onUploadHandler }
							onCancel={ onCancelHandler }
							onRecord={ onRecordHandler }
							onPause={ onPauseHandler }
							onResume={ onResumeHandler }
							onDone={ onDoneHandler }
						/>

						<Button
							variant="link"
							className="jetpack-ai-voice-to-content__feedback-button"
							href="https://a8c.slack.com/archives/C054LN8RNVA" // Jetpack AI Slack channel
							target="_blank"
						>
							{ __( 'Provide feedback', 'jetpack' ) }
							<Icon icon={ external } { ...iconProps } />
						</Button>

			</ThemeProvider>
		</Modal>
	);
}


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Create a widgets block with customizable ingredients, steps

[Assistant]
<|thinking|>
To create this {type}, I need to:
- Create the block.json configuration file
- Register the block type
- Define block attributes and their types
- Implement the Edit component for the editor
- Implement the Save component for frontend rendering
- Add necessary controls in the inspector panel
- Style the block for both editor and frontend
<|im_end|>

// File: projects/plugins/jetpack/extensions/blocks/recipe/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/recipe",
	"title": "Recipe (Beta)",
	"description": "Add images, ingredients and cooking steps to display an easy to read recipe.",
	"keywords": [],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "widgets",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><path d='M21,5c-1.11-0.35-2.33-0.5-3.5-0.5c-1.95,0-4.05,0.4-5.5,1.5c-1.45-1.1-3.55-1.5-5.5-1.5S2.45,4.9,1,6v14.65 c0,0.25,0.25,0.5,0.5,0.5c0.1,0,0.15-0.05,0.25-0.05C3.1,20.45,5.05,20,6.5,20c1.95,0,4.05,0.4,5.5,1.5c1.35-0.85,3.8-1.5,5.5-1.5 c1.65,0,3.35,0.3,4.75,1.05c0.1,0.05,0.15,0.05,0.25,0.05c0.25,0,0.5-0.25,0.5-0.5V6C22.4,5.55,21.75,5.25,21,5z M21,18.5 c-1.1-0.35-2.3-0.5-3.5-0.5c-1.7,0-4.15,0.65-5.5,1.5V8c1.35-0.85,3.8-1.5,5.5-1.5c1.2,0,2.4,0.15,3.5,0.5V18.5z' /><path d='M17.5,10.5c0.88,0,1.73,0.09,2.5,0.26V9.24C19.21,9.09,18.36,9,17.5,9c-1.7,0-3.24,0.29-4.5,0.83v1.66 C14.13,10.85,15.7,10.5,17.5,10.5z' /><path d='M13,12.49v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26V11.9c-0.79-0.15-1.64-0.24-2.5-0.24 C15.8,11.66,14.26,11.96,13,12.49z' /><path d='M17.5,14.33c-1.7,0-3.24,0.29-4.5,0.83v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26v-1.52 C19.21,14.41,18.36,14.33,17.5,14.33z' /></svg>",
	"supports": {
		"align": [ "full", "wide" ],
		"alignWide": true,
		"anchor": false,
		"customClassName": true,
		"className": true,
		"html": false,
		"multiple": true,
		"reusable": true
	},
	"attributes": {
		"ingredients": {
			"type": "array",
			"default": []
		},
		"steps": {
			"type": "array",
			"default": []
		}
	}
}

// File: projects/plugins/jetpack/extensions/blocks/recipe/edit.js
/**
 * External dependencies
 */
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';

function RecipeEdit( { className } ) {
	const RECIPE_TEMPLATE = [
		[ 'jetpack/recipe-hero' ],
		[
			'core/heading',
			{
				level: 2,
				placeholder: __( 'Recipe Title', 'jetpack' ),
				className: 'wp-block-jetpack-recipe-title',
			},
		],
		[
			'core/separator',
			{
				color: '--wp--custom--color--foreground',
				className: 'is-style-wide',
				style: 'wide',
			},
		],
		[
			'core/paragraph',
			{
				placeholder: __( 'Recipe Description', 'jetpack' ),
				className: 'wp-block-jetpack-recipe-description',
			},
		],
		[ 'jetpack/recipe-details', {} ],
		[
			'core/columns',
			{},
			[
				[
					'core/column',
					{
						width: '33.33%',
					},
					[
						[
							'core/heading',
							{
								level: 3,
								// translators: Ingredients heading for a recipe block.
								content: __( 'Ingredients', 'jetpack' ),
							},
						],
						[ 'jetpack/recipe-ingredients-list' ],
					],
				],
				[
					'core/column',
					{
						width: '66.66%',
					},
					[
						[
							'core/heading',
							{
								level: 3,
								// translators: Instructions heading for a recipe block.
								content: __( 'Instructions', 'jetpack' ),
							},
						],
						[ 'jetpack/recipe-steps' ],
					],
				],
			],
		],
	];

	return (
		<>
			<div { ...useBlockProps( { className } ) }>
				<InnerBlocks template={ RECIPE_TEMPLATE } />
			</div>
		</>
	);
}

export default RecipeEdit;

// File: projects/plugins/jetpack/extensions/blocks/recipe/save.js
/**
 * External dependencies
 */
import { InnerBlocks } from '@wordpress/block-editor';

const RecipeSave = ( { className } ) => {
	return (
		<div className={ className }>
			<InnerBlocks.Content />
		</div>
	);
};

export default RecipeSave;


[System]
You are an expert WordPress developer specializing in creating high-quality plugins and Gutenberg blocks.
You write clean, well-documented code following WordPress coding standards and best practices.
Your code is secure, performant, and maintainable.

[User] Build a Gutenberg block that Summarize your post with a list of headings. Add HTML anchors to Heading blocks to link them here. with these attributes: headings, only include current page, max level, ordered

[Assistant]
// File: packages/block-library/src/table-of-contents/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"__experimental": true,
	"name": "core/table-of-contents",
	"title": "Table of Contents",
	"category": "design",
	"description": "Summarize your post with a list of headings. Add HTML anchors to Heading blocks to link them here.",
	"keywords": [ "document outline", "summary" ],
	"textdomain": "default",
	"attributes": {
		"headings": {
			"type": "array",
			"items": {
				"type": "object"
			},
			"default": []
		},
		"onlyIncludeCurrentPage": {
			"type": "boolean",
			"default": false
		},
		"maxLevel": {
			"type": "number"
		},
		"ordered": {
			"type": "boolean",
			"default": true
		}
	},
	"supports": {
		"ariaLabel": true,
		"html": false,
		"color": {
			"text": true,
			"background": true,
			"gradients": true,
			"link": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true,
			"__experimentalDefaultControls": {
				"radius": true,
				"color": true,
				"width": true,
				"style": true
			}
		}
	},
	"style": "wp-block-table-of-contents"
}

// File: packages/block-library/src/table-of-contents/index.js
/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { tableOfContents as icon } from '@wordpress/icons';

/**
 * Internal dependencies
 */
import initBlock from '../utils/init-block';
import metadata from './block.json';
import edit from './edit';
import save from './save';

const { name } = metadata;

export { metadata, name };

export const settings = {
	icon,
	edit,
	save,
	example: {
		innerBlocks: [
			{
				name: 'core/heading',
				attributes: {
					level: 2,
					content: __( 'Heading' ),
				},
			},
			{
				name: 'core/heading',
				attributes: {
					level: 3,
					content: __( 'Subheading' ),
				},
			},
			{
				name: 'core/heading',
				attributes: {
					level: 2,
					content: __( 'Heading' ),
				},
			},
			{
				name: 'core/heading',
				attributes: {
					level: 3,
					content: __( 'Subheading' ),
				},
			},
		],
		attributes: {
			headings: [
				{
					content: __( 'Heading' ),
					level: 2,
				},
				{
					content: __( 'Subheading' ),
					level: 3,
				},
				{
					content: __( 'Heading' ),
					level: 2,
				},
				{
					content: __( 'Subheading' ),
					level: 3,
				},
			],
		},
	},
};

export const init = () => initBlock( { name, metadata, settings } );

// File: packages/block-library/src/table-of-contents/save.js
/**
 * WordPress dependencies
 */
import { useBlockProps } from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import TableOfContentsList from './list';
import { linearToNestedHeadingList } from './utils';

export default function save( {
	attributes: { headings = [], ordered = true },
} ) {
	if ( headings.length === 0 ) {
		return null;
	}
	const ListTag = ordered ? 'ol' : 'ul';
	return (
		<nav { ...useBlockProps.save() }>
			<ListTag>
				<TableOfContentsList
					nestedHeadingList={ linearToNestedHeadingList( headings ) }
					ordered={ ordered }
				/>
			</ListTag>
		</nav>
	);
}