[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 name of the author of the review. with these attributes: is link, link target, text align

[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/review-author-name/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "woocommerce/product-review-author-name",
	"title": "Review Author Name",
	"category": "woocommerce",
	"ancestor": [ "woocommerce/product-reviews" ],
	"description": "Displays the name of the author of the review.",
	"textdomain": "woocommerce",
	"attributes": {
		"isLink": {
			"type": "boolean",
			"default": true
		},
		"linkTarget": {
			"type": "string",
			"default": "_self"
		},
		"textAlign": {
			"type": "string"
		}
	},
	"usesContext": [ "commentId" ],
	"supports": {
		"html": false,
		"spacing": {
			"margin": true,
			"padding": true
		},
		"color": {
			"gradients": true,
			"link": true,
			"__experimentalDefaultControls": {
				"background": true,
				"text": 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
		},
		"__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-author-name/edit.tsx
/**
 * External dependencies
 */
import clsx from 'clsx';
import { __, _x } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import type { BlockEditProps } from '@wordpress/blocks';
import { store as coreStore } from '@wordpress/core-data';
import { PanelBody, ToggleControl } from '@wordpress/components';
import {
	// @ts-expect-error AlignmentControl is not exported from @wordpress/block-editor
	AlignmentControl,
	BlockControls,
	InspectorControls,
	useBlockProps,
} from '@wordpress/block-editor';

type Comment = {
	author_name?: string;
	author: number;
};

type User = {
	name?: string;
};

export default function Edit( {
	attributes: { isLink, linkTarget, textAlign },
	context: { commentId },
	setAttributes,
}: BlockEditProps< {
	isLink: boolean;
	linkTarget: string;
	textAlign: string;
} > & {
	context: { commentId: string };
} ) {
	const blockProps = useBlockProps( {
		className: clsx( {
			[ `has-text-align-${ textAlign }` ]: textAlign,
		} ),
	} );
	let displayName = useSelect(
		( select ) => {
			const { getEntityRecord } = select( coreStore );

			const comment = getEntityRecord(
				'root',
				'comment',
				commentId
			) as Comment | null;
			const authorName = comment?.author_name;

			if ( comment && ! authorName ) {
				const user = getEntityRecord(
					'root',
					'user',
					comment.author
				) as User | null;
				return user?.name ?? __( 'Anonymous', 'woocommerce' );
			}
			return authorName ?? '';
		},
		[ commentId ]
	);

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

	const displayAuthor = isLink ? (
		<a
			href="#review-author-pseudo-link"
			onClick={ ( event ) => event.preventDefault() }
		>
			{ displayName }
		</a>
	) : (
		displayName
	);
	return (
		<>
			<InspectorControls>
				<PanelBody title={ __( 'Settings', 'woocommerce' ) }>
					<ToggleControl
						__nextHasNoMarginBottom
						label={ __( 'Link to authors URL', 'woocommerce' ) }
						onChange={ () => setAttributes( { isLink: ! isLink } ) }
						checked={ isLink }
					/>
					{ isLink && (
						<ToggleControl
							__nextHasNoMarginBottom
							label={ __( 'Open in new tab', 'woocommerce' ) }
							onChange={ ( value ) =>
								setAttributes( {
									linkTarget: value ? '_blank' : '_self',
								} )
							}
							checked={ linkTarget === '_blank' }
						/>
					) }
				</PanelBody>
			</InspectorControls>
			<BlockControls>
				<AlignmentControl
					value={ textAlign }
					onChange={ ( newAlign: string | undefined ) => {
						if ( typeof newAlign === 'string' ) {
							setAttributes( { textAlign: newAlign } );
						}
					} }
				/>
			</BlockControls>
			<div { ...blockProps }>{ displayAuthor }</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 block for A group of headers and associated expandable content. that allows users to configure: icon position, autoclose, allowed blocks

[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/accordion/accordion-group/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "woocommerce/accordion-group",
	"title": "Accordion Group",
	"category": "woocommerce",
	"keywords": [ "WooCommerce" ],
	"description": "A group of headers and associated expandable content.",
	"example": {},
	"__experimental": true,
	"supports": {
		"html": false,
		"align": [ "wide", "full" ],
		"background": {
			"backgroundImage": true,
			"backgroundSize": true,
			"__experimentalDefaultControls": {
				"backgroundImage": true
			}
		},
		"color": {
			"background": true,
			"gradient": true
		},
		"__experimentalBorder": {
			"color": true,
			"radius": true,
			"style": true,
			"width": true,
			"__experimentalDefaultControls": {
				"color": true,
				"radius": true,
				"style": true,
				"width": true
			}
		},
		"spacing": {
			"padding": true,
			"margin": [ "top", "bottom" ],
			"blockGap": true
		},
		"shadow": true,
		"layout": true,
		"interactivity": true
	},
	"attributes": {
		"iconPosition": {
			"type": "string",
			"default": "right"
		},
		"autoclose": {
			"type": "boolean",
			"default": false
		},
		"allowedBlocks": {
			"type": "array"
		}
	},
	"allowedBlocks": [ "woocommerce/accordion-item" ],
	"textdomain": "woocommerce",
	"viewScriptModule": "woocommerce/accordion-group",
	"style": "file:../woocommerce/accordion-group-style.css"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/accordion/accordion-group/index.js
/**
 * External dependencies
 */
import { SVG, Path } from '@wordpress/components';
import { registerBlockType } from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import edit from './edit';
import save from './save';
import metadata from './block.json';

const icon = (
	<SVG
		width="24"
		height="24"
		viewBox="0 0 24 24"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<Path
			fillRule="evenodd"
			clipRule="evenodd"
			d="M19.5 9.25L9.5 9.25L9.5 7.75L19.5 7.75L19.5 9.25Z"
			fill="currentColor"
		/>
		<Path d="M4.5 6L8.5 8.5L4.5 11L4.5 6Z" fill="currentColor" />
		<Path
			fillRule="evenodd"
			clipRule="evenodd"
			d="M19.5 16.25L9.5 16.25L9.5 14.75L19.5 14.75L19.5 16.25Z"
			fill="currentColor"
		/>
		<Path d="M4.5 13L8.5 15.5L4.5 18L4.5 13Z" fill="currentColor" />
	</SVG>
);

const { name } = metadata;

export { metadata, name };

export const settings = {
	apiVersion: 3,
	icon,
	example: {},
	edit,
	save,
};

registerBlockType( metadata, settings );

// File: plugins/woocommerce/client/blocks/assets/js/blocks/accordion/accordion-group/save.js
/**
 * External dependencies
 */
import clsx from 'clsx';
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

export default function save( { attributes } ) {
	const { iconPosition } = attributes;
	const blockProps = useBlockProps.save();
	const className = clsx(
		{
			'icon-position-left': iconPosition === 'left',
		},
		blockProps.className
	);

	return (
		<div { ...useInnerBlocksProps.save( { ...blockProps, className } ) } />
	);
}


[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 text block with customizable answers link, answers link text, gravatars, and 8 more options

[Assistant]
// File: projects/plugins/jetpack/extensions/blocks/blogging-prompt/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/blogging-prompt",
	"title": "Writing Prompt",
	"description": "Answer a new and inspiring writing prompt each day.",
	"keywords": [ "writing", "blogging" ],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "text",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><path d='M14.3438 19.3438H9.65625C9.57031 19.3438 9.5 19.4141 9.5 19.5V20.125C9.5 20.4707 9.7793 20.75 10.125 20.75H13.875C14.2207 20.75 14.5 20.4707 14.5 20.125V19.5C14.5 19.4141 14.4297 19.3438 14.3438 19.3438ZM12 3.25C8.46289 3.25 5.59375 6.11914 5.59375 9.65625C5.59375 12.0273 6.88281 14.0977 8.79688 15.2051V17.4688C8.79688 17.8145 9.07617 18.0938 9.42188 18.0938H14.5781C14.9238 18.0938 15.2031 17.8145 15.2031 17.4688V15.2051C17.1172 14.0977 18.4062 12.0273 18.4062 9.65625C18.4062 6.11914 15.5371 3.25 12 3.25ZM14.498 13.9883L13.7969 14.3945V16.6875H10.2031V14.3945L9.50195 13.9883C7.96484 13.0996 7 11.4629 7 9.65625C7 6.89453 9.23828 4.65625 12 4.65625C14.7617 4.65625 17 6.89453 17 9.65625C17 11.4629 16.0352 13.0996 14.498 13.9883Z' stroke-width='0.1'/></svg>",
	"supports": {
		"align": false,
		"alignWide": false,
		"anchor": false,
		"className": true,
		"color": {
			"background": true,
			"gradients": true,
			"link": true,
			"text": true
		},
		"customClassName": true,
		"html": false,
		"inserter": true,
		"multiple": false,
		"reusable": true,
		"spacing": {
			"margin": [ "top", "bottom" ],
			"padding": true,
			"blockGap": false
		}
	},
	"attributes": {
		"answersLink": {
			"type": "string",
			"source": "attribute",
			"attribute": "href",
			"selector": ".jetpack-blogging-prompt__answers-link"
		},
		"answersLinkText": {
			"type": "string",
			"source": "html",
			"selector": ".jetpack-blogging-prompt__answers-link"
		},
		"gravatars": {
			"type": "array",
			"source": "query",
			"selector": ".jetpack-blogging-prompt__answers-gravatar",
			"query": {
				"url": {
					"type": "string",
					"source": "attribute",
					"attribute": "src"
				}
			},
			"default": []
		},
		"promptLabel": {
			"type": "string",
			"source": "html",
			"selector": ".jetpack-blogging-prompt__label"
		},
		"promptText": {
			"type": "string",
			"source": "html",
			"selector": ".jetpack-blogging-prompt__text"
		},
		"promptFetched": {
			"type": "boolean",
			"default": false
		},
		"promptId": {
			"type": "number"
		},
		"showResponses": {
			"type": "boolean",
			"default": true
		},
		"showLabel": {
			"type": "boolean",
			"default": true
		},
		"tagsAdded": {
			"type": "boolean",
			"default": false
		},
		"isBloganuary": {
			"type": "boolean",
			"default": false
		}
	},
	"styles": [
		{ "name": "block", "label": "Block", "isDefault": true },
		{ "name": "quote", "label": "Quote" }
	]
}

// File: projects/plugins/jetpack/extensions/blocks/blogging-prompt/edit.js
import apiFetch from '@wordpress/api-fetch';
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
import { Button, PanelBody, Spinner, ToggleControl, withNotices } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { __, _x, sprintf } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import clsx from 'clsx';
import './editor.scss';
import { languageToLocale } from '../../shared/locale';
import { usePromptTags } from './use-prompt-tags';

function BloggingPromptEdit( { attributes, noticeOperations, noticeUI, setAttributes } ) {
	// Use the ref to keep track of starting to fetch the prompt, so we don't make duplicate requests.
	const fetchingPromptRef = useRef( false );
	const {
		answersLink,
		answersLinkText,
		gravatars,
		// Use the attribute the track when we've finished fetching the prompt.
		promptFetched,
		promptId,
		promptLabel,
		promptText,
		showLabel,
		showResponses,
		tagsAdded,
		isBloganuary,
	} = attributes;
	const blockProps = useBlockProps( { className: 'jetpack-blogging-prompt' } );

	const setTagsAdded = state => setAttributes( { tagsAdded: state } );

	// Add the prompt tags to the post, if they haven't already been added.
	usePromptTags( promptId, tagsAdded, setTagsAdded );

	const siteLanguage = useSelect( select => {
		const { getEntityRecord, hasFinishedResolution } = select( 'core' );
		const language = getEntityRecord( 'root', 'site' )?.language || 'en_US';
		const hasFinishedResolving = hasFinishedResolution( 'getEntityRecord', [ 'root', 'site' ] );
		return hasFinishedResolving ? language : null;
	}, [] );

	// Fetch the prompt by id, if present, otherwise the get the prompt for today.
	useEffect( () => {
		// Only fetch the prompt one time when the block is inserted, after we know the site language.
		if ( ! siteLanguage || fetchingPromptRef.current || promptFetched ) {
			return;
		}

		const retryPrompt = () => {
			setAttributes( { promptFetched: false, promptId: null, tagsAdded: false } );
			fetchingPromptRef.current = false;
			noticeOperations.removeAllNotices();
		};

		const errorMessage = message => (
			<>
				{ sprintf(
					/* translators: %s is the error message. */
					__( 'Error while fetching prompt: %s', 'jetpack' ),
					message
				) }{ ' ' }
				<Button variant="link" onClick={ retryPrompt }>
					{ __( 'Retry', 'jetpack' ) }
				</Button>
			</>
		);

		const notFoundMessage = pId => (
			<>
				{ sprintf(
					/* translators: %d is the prompt id. */
					__( 'Prompt with id %d not found.', 'jetpack' ),
					pId
				) }{ ' ' }
				<Button variant="link" onClick={ retryPrompt }>
					{ __( 'Reset prompt', 'jetpack' ) }
				</Button>
			</>
		);

		let path = '/wpcom/v3/blogging-prompts';

		if ( promptId ) {
			path += '/' + encodeURIComponent( promptId );
		} else {
			const date = new Date();

			// Current month and day with leading zeros.
			const month = ( date.getMonth() + 1 ).toString().padStart( 2, '0' );
			const day = date.getDate().toString().padStart( 2, '0' );

			path += `?after=--${ month }-${ day }&order=desc`;
		}

		path = addQueryArgs( path, {
			_locale: siteLanguage,
			force_year: new Date()?.getFullYear(),
		} );
		fetchingPromptRef.current = true;
		apiFetch( { path } )
			.then( prompts => {
				const promptData = promptId ? prompts : prompts[ 0 ];
				const locale = languageToLocale( siteLanguage );

				setAttributes( {
					answersLink: promptData.answered_link + `?locale=${ locale }`,
					answersLinkText: promptData.answered_link_text,
					gravatars: promptData.answered_users_sample.map( ( { avatar } ) => ( { url: avatar } ) ),
					promptFetched: true,
					promptLabel: promptData.label,
					promptText: promptData.text,
					promptId: promptData.id,
					isBloganuary: !! promptData.bloganuary_id,
				} );
			} )
			.catch( error => {
				setAttributes( { promptFetched: true } );
				const message =
					error.code === 'rest_post_invalid_id' && promptId
						? notFoundMessage( promptId )
						: errorMessage( error.message );
				noticeOperations.removeAllNotices();
				noticeOperations.createErrorNotice( message );
			} );
	}, [
		fetchingPromptRef,
		noticeOperations,
		promptFetched,
		promptId,
		setAttributes,
		siteLanguage,
	] );

	const onShowLabelChange = newValue => {
		setAttributes( { showLabel: newValue } );
	};

	const onShowResponsesChange = newValue => {
		setAttributes( { showResponses: newValue } );
	};

	const renderControls = () => (
		<>
			<InspectorControls>
				<PanelBody title={ _x( 'Settings', 'title of block settings sidebar section', 'jetpack' ) }>
					<ToggleControl
						label={ __( 'Show prompt label', 'jetpack' ) }
						checked={ showLabel }
						onChange={ onShowLabelChange }
						__nextHasNoMarginBottom={ true }
					/>
					<ToggleControl
						label={ __( 'Show other responses', 'jetpack' ) }
						checked={ showResponses }
						onChange={ onShowResponsesChange }
						__nextHasNoMarginBottom={ true }
					/>
				</PanelBody>
			</InspectorControls>
		</>
	);
	const labelClassnames = clsx( [ 'jetpack-blogging-prompt__label' ], {
		'is-bloganuary-icon': isBloganuary,
	} );

	const renderPrompt = () => (
		<>
			{ showLabel &&
{ promptLabel }
 }

{ promptText }

			{ showResponses && promptId && (

					{ gravatars &&
						gravatars.slice( 0, 3 ).map( ( { url } ) => {
							return (
								url && (
									// eslint-disable-next-line jsx-a11y/alt-text

								)
							);
						} ) }

						{ answersLinkText }

			) }
		</>
	);

	return (

			{ noticeUI }
			{ renderControls() }

			{ ! promptFetched ? (

					<Spinner />

			) : (
				renderPrompt()
			) }

	);
}

export default withNotices( BloggingPromptEdit );

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

function BloggingPromptSave( { attributes } ) {
	const {
		answersLink,
		answersLinkText,
		gravatars,
		promptId,
		promptLabel,
		promptText,
		showLabel,
		showResponses,
		isBloganuary,
	} = attributes;

	const blockProps = useBlockProps.save( { className: 'jetpack-blogging-prompt' } );

	const labelClassnames = clsx( [ 'jetpack-blogging-prompt__label' ], {
		'is-bloganuary-icon': isBloganuary,
	} );

	return (

			{ showLabel &&
{ promptLabel }
 }

{ promptText }

			{ showResponses && promptId && (

					{ gravatars.map( ( { url } ) => {
						return (
							url && (
								// eslint-disable-next-line jsx-a11y/alt-text

							)
						);
					} ) }

						{ answersLinkText }

			) }

	);
}

export default BloggingPromptSave;


[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 lock

[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/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/block.json
{
	"name": "woocommerce/mini-cart-footer-block",
	"version": "1.0.0",
	"title": "Mini-Cart Footer",
	"description": "Block that displays the footer of the Mini-Cart block.",
	"category": "woocommerce",
	"supports": {
		"align": false,
		"html": false,
		"multiple": false,
		"reusable": false,
		"inserter": false,
		"lock": false,
		"interactivity": true
	},
	"attributes": {
		"lock": {
			"type": "object",
			"default": {
				"remove": true,
				"move": true
			}
		}
	},
	"parent": [ "woocommerce/filled-mini-cart-contents-block" ],
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/edit.tsx
/**
 * External dependencies
 */
import { __ } from '@wordpress/i18n';
import { TotalsItem } from '@woocommerce/blocks-components';
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
import {
	usePaymentMethods,
	useStoreCart,
} from '@woocommerce/base-context/hooks';
import PaymentMethodIcons from '@woocommerce/base-components/cart-checkout/payment-method-icons';
import { getIconsFromPaymentMethods } from '@woocommerce/base-utils';
import { getSetting } from '@woocommerce/settings';
import { PaymentEventsProvider } from '@woocommerce/base-context';

/**
 * Internal dependencies
 */
import { getTotalsItemDescription } from '../utils';
import './editor.scss';

const PaymentMethodIconsElement = (): JSX.Element => {
	const { paymentMethods } = usePaymentMethods();
	return (
		<PaymentMethodIcons
			icons={ getIconsFromPaymentMethods( paymentMethods ) }
		/>
	);
};

export const Edit = (): JSX.Element => {
	const blockProps = useBlockProps();
	const { cartTotals } = useStoreCart();
	const subTotal = getSetting( 'displayCartPricesIncludingTax', false )
		? parseInt( cartTotals.total_items, 10 ) +
		  parseInt( cartTotals.total_items_tax, 10 )
		: parseInt( cartTotals.total_items, 10 );

	const TEMPLATE = [
		[ 'woocommerce/mini-cart-cart-button-block', {} ],
		[ 'woocommerce/mini-cart-checkout-button-block', {} ],
	];

	return (

				<TotalsItem
					className="wc-block-mini-cart__footer-subtotal"
					currency={ getCurrencyFromPriceResponse( cartTotals ) }
					label={ __( 'Subtotal', 'woocommerce' ) }
					value={ subTotal }
					description={ getTotalsItemDescription() }
				/>

					<InnerBlocks template={ TEMPLATE } />

				<PaymentEventsProvider>
					<PaymentMethodIconsElement />
				</PaymentEventsProvider>

	);
};

export const Save = (): JSX.Element => {
	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] Craft a configurable media component that allows users to personalize display settings and upload various media assets.

[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/story/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/story",
	"title": "Story",
	"description": "Add an interactive story.",
	"keywords": [ "story", "image", "video", "gallery" ],
	"version": "12.5.0",
	"textdomain": "jetpack",
	"category": "media",
	"icon": "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'><g><path d='M17 5a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2h9z' /><path d='M13 4H5a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2z' /><path d='M7 16h8a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z' /></g></svg>",
	"supports": {
		"html": false
	},
	"attributes": {
		"settings": {
			"type": "object"
		},
		"mediaFiles": {
			"type": "array",
			"default": []
		}
	},
	"example": {
		"attributes": {
			"mediaFiles": [
				{
					"alt": "",
					"caption": "",
					"mime": "image/jpg",
					"type": "image",
					"id": 22,
					"url": "./storyExample1.png"
				}
			]
		}
	}
}

// File: projects/plugins/jetpack/extensions/blocks/story/edit.js
import { getBlockIconComponent } from '@automattic/jetpack-shared-extension-utils';
import { isBlobURL } from '@wordpress/blob';
import { MediaPlaceholder, useBlockProps } from '@wordpress/block-editor';
import { withNotices } from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import metadata from './block.json';
import Controls from './controls';
import StoryPlayer from './player';

import './editor.scss';

const ALLOWED_MEDIA_TYPES = [ 'image', 'video' ];
const ALLOWED_MEDIA_PROPS = [
	'alt',
	'title',
	'id',
	'link',
	'type',
	'mime',
	'caption',
	'width',
	'height',
];
const icon = getBlockIconComponent( metadata );

export const pickRelevantMediaFiles = media => {
	const mediaProps = Object.fromEntries(
		Object.entries( media ).filter( ( [ k ] ) => ALLOWED_MEDIA_PROPS.includes( k ) )
	);
	mediaProps.url =
		media?.media_details?.original?.url ||
		media?.media_details?.videopress?.original ||
		media?.media_details?.sizes?.large?.source_url ||
		media?.sizes?.large?.url ||
		media.url;
	mediaProps.type = media.media_type || media.type;
	mediaProps.mime = media.mime_type || media.mime;
	mediaProps.title = mediaProps.title?.rendered || mediaProps.title;
	mediaProps.width = mediaProps.width || media.media_details?.width;
	mediaProps.height = mediaProps.height || media.media_details?.height;
	return mediaProps;
};

export default withNotices( function StoryEdit( {
	attributes,
	isSelected,
	noticeOperations,
	noticeUI,
	setAttributes,
} ) {
	const { mediaFiles } = attributes;
	const { lockPostSaving, unlockPostSaving } = useDispatch( 'core/editor' );
	const blockProps = useBlockProps();
	const lockName = 'storyBlockLock';

	const onSelectMedia = newMediaFiles => {
		const allMedia = newMediaFiles
			.map( newMedia => {
				// MediaPlaceholder passes only the media ids as value to MediaUpload, so we're only getting those back
				if ( ! isNaN( newMedia ) ) {
					const existingMedia = mediaFiles.find( mediaFile => mediaFile.id === newMedia );
					return existingMedia || { id: newMedia };
				}
				return newMedia;
			} )
			.map( pickRelevantMediaFiles );
		const uploadedMedias = allMedia.filter( media => ! isBlobURL( media.url ) );
		// prevent saving blob urls in mediaFiles block attribute
		if ( allMedia.length !== uploadedMedias.length ) {
			lockPostSaving( lockName );
		} else {
			unlockPostSaving( lockName );
		}
		setAttributes( {
			mediaFiles: allMedia,
		} );
	};

	const controls = (
		<Controls
			allowedMediaTypes={ ALLOWED_MEDIA_TYPES }
			attributes={ attributes }
			onSelectMedia={ onSelectMedia }
		/>
	);

	const hasImages = !! mediaFiles.length;

	const mediaPlaceholder = (
		<MediaPlaceholder
			addToGallery={ hasImages }
			isAppender={ hasImages }
			className={ blockProps.className }
			disableMediaButtons={ hasImages && ! isSelected }
			icon={ ! hasImages && icon }
			labels={ {
				title: ! hasImages && __( 'Story', 'jetpack' ),
				instructions:
					! hasImages &&
					__(
						'Drag images and videos, upload new ones, or select files from your library.',
						'jetpack'
					),
			} }
			onSelect={ onSelectMedia }
			accept={ ALLOWED_MEDIA_TYPES.map( type => type + '/*' ).join( ',' ) }
			allowedTypes={ ALLOWED_MEDIA_TYPES }
			multiple="add"
			value={ mediaFiles }
			notices={ hasImages ? undefined : noticeUI }
			onError={ noticeOperations.createErrorNotice }
		/>
	);

	let content;

	if ( ! hasImages ) {
		content = (
			<>
				{ controls }
				{ mediaPlaceholder }
			</>
		);
	} else {
		content = (
			<>
				{ controls }
				{ noticeUI }
				<StoryPlayer
					slides={ mediaFiles }
					disabled={ ! isSelected }
					showSlideCount={ isSelected }
					shadowDOM={ {
						enabled: false,
					} }
					playInFullscreen={ false }
					tapToPlayPause={ false }
					playOnNextSlide={ false }
				/>
				{ isSelected && mediaPlaceholder }
			</>
		);
	}

	return (
		<div
			{ ...blockProps }
			className={ clsx( 'wp-block-jetpack-story', 'wp-story', blockProps.className ) }
		>
			{ content }
		</div>
	);
} );

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

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

	return <div { ...blockProps } className={ clsx( 'wp-story', blockProps.className ) }></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] Build an adaptable block featuring configurable URL settings to enable seamless monetization strategies within your WordPress site.

[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/tock/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "jetpack/tock",
	"title": "Tock",
	"description": "Reserve a table at your restaurant with Tock.",
	"keywords": [ "booking", "reservation", "restaurant" ],
	"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='M10 15.619C6.84915 15.619 4.28572 13.0542 4.28572 9.90176C4.28572 7.24269 6.10957 5.00183 8.57143 4.36551V0C3.72557 0.693782 0 4.86162 0 9.90176C0 15.4274 4.47715 19.9069 10 19.9069C12.2461 19.9069 14.3193 19.1658 15.9887 17.9148L12.9003 14.825C12.0494 15.3287 11.0581 15.619 10 15.619 M15.7135 9.90176C15.7135 10.9604 15.4233 11.9522 14.9199 12.8035L18.0082 15.8935C19.2585 14.2232 19.9992 12.149 19.9992 9.90176C19.9992 4.86162 16.2736 0.693782 11.4277 0V4.36551C13.8896 5.00183 15.7135 7.24269 15.7135 9.90176'/></svg>",
	"supports": {
		"align": true,
		"html": false,
		"multiple": false
	},
	"attributes": {
		"url": {
			"type": "string"
		}
	},
	"example": {
		"attributes": {
			"url": "roister"
		},
		"viewportWidth": 250
	}
}

// File: projects/plugins/jetpack/extensions/blocks/tock/edit.js
import { useBlockProps, BlockControls } from '@wordpress/block-editor';
import {
	SandBox,
	TextControl,
	ToolbarGroup,
	ToolbarButton,
	Button,
	BaseControl,
	Dropdown,
} from '@wordpress/components';
import {
	createInterpolateElement,
	useCallback,
	useEffect,
	useState,
	useRef,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { keyboardReturn } from '@wordpress/icons';
import { ENTER, ESCAPE } from '@wordpress/keycodes';

import './editor.scss';

const UrlDropdown = ( { tockUrl, setEditedUrl, setUrl, cancel } ) => {
	const firstRender = useRef( true );
	const committedChanges = useRef( false );
	const handleSubmitOrCancel = ( event, onClose ) => {
		const { keyCode } = event;

		if (
			keyCode === ENTER &&
			'' !== tockUrl // Disallow submitting empty values.
		) {
			event.preventDefault();
			commitChanges( onClose );
		}

		if ( keyCode === ESCAPE ) {
			event.preventDefault();
			cancel();
			onClose();
		}
	};

	const commitChanges = close => {
		setUrl();
		committedChanges.current = true;
		close();
	};

	return (
		<ToolbarGroup>
			<Dropdown
				popoverProps={ {
					variant: 'toolbar',
				} }
				onClose={ () =>
					committedChanges.current ? ( committedChanges.current = false ) : cancel()
				}
				placement="bottom-start"
				renderToggle={ ( { isOpen, onToggle } ) => {
					if ( firstRender.current && ! isOpen && ! tockUrl ) {
						firstRender.current = false;
						onToggle();
					}

					return (
						<ToolbarButton
							className="components-toolbar__control"
							label={ __( 'Edit Tock business name', 'jetpack' ) }
							onClick={ () => {
								onToggle();
								isOpen && cancel();
							} }
						>
							{ __( 'Edit', 'jetpack' ) }
						</ToolbarButton>
					);
				} }
				renderContent={ ( { onClose } ) => (
					<BaseControl
						className="jetpack-tock-url-settings"
						help={ createInterpolateElement(
							__(
								'The Tock business can be found in the URL of your public Tock page. For example: www.exploretock.com/myname',
								'jetpack'
							),
							{
								b: ,
							}
						) }
						__nextHasNoMarginBottom={ true }
					>

							<TextControl
								placeholder={ __( 'Add Tock business name', 'jetpack' ) }
								onChange={ setEditedUrl }
								value={ tockUrl }
								onKeyDownCapture={ event => handleSubmitOrCancel( event, onClose ) }
								className="jetpack-tock-url-input"
								__nextHasNoMarginBottom={ true }
								__next40pxDefaultSize={ true }
							/>

								<Button
									type="submit"
									label={ __( 'Submit', 'jetpack' ) }
									icon={ keyboardReturn }
									className="jetpack-tock-url-input-submit"
									onClick={ () => commitChanges( onClose ) }
								/>

					</BaseControl>
				) }
			/>
		</ToolbarGroup>
	);
};

const TockPreview = ( { url, popoverAnchor } ) => {
	const html = `

	`;

	return (

			{
				// Related to this bug (https://github.com/WordPress/gutenberg/issues/16831), the
				// `SandBox` component won't rerun the scripts correctly when the injected `html` prop changes.
				// To work around that, we change the key of the component to force a new one render
			 }
			<SandBox html={ html } key={ `tock-${ url }` } />
			{ /* Use an overlay to prevent interactivity with the preview, since the preview does not always resize correctly. */ }

	);
};

export default function TockBlockEdit( { attributes, setAttributes, isSelected } ) {
	const tockUrl = attributes.url ?? '';
	const [ editedUrl, setEditedUrl ] = useState( tockUrl );

	const setUrl = () => {
		const newUrl = editedUrl.replace( /.*exploretock.com\//, '' );
		setEditedUrl( newUrl );
		setAttributes( { url: newUrl } );
	};

	const cancel = useCallback( () => {
		setEditedUrl( tockUrl );
	}, [ tockUrl ] );

	useEffect( () => {
		if ( ! isSelected ) {
			cancel();
		}
	}, [ isSelected, cancel ] );

	return (

			<BlockControls>
				<UrlDropdown
					tockUrl={ editedUrl }
					setEditedUrl={ setEditedUrl }
					setUrl={ setUrl }
					cancel={ cancel }
				/>
			</BlockControls>
			<TockPreview url={ tockUrl } />

	);
}


[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 Enable customers to filter the product grid by selecting one or more attributes, such as color. with these attributes: class name, attribute id, show counts, and 6 more options

[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/attribute-filter/block.json
{
	"name": "woocommerce/attribute-filter",
	"title": "Filter by Attribute Controls",
	"description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.",
	"category": "woocommerce",
	"keywords": [ "WooCommerce" ],
	"supports": {
		"html": false,
		"color": {
			"text": true,
			"background": false
		},
		"inserter": false,
		"lock": false,
		"interactivity": false
	},
	"attributes": {
		"className": {
			"type": "string",
			"default": ""
		},
		"attributeId": {
			"type": "number",
			"default": 0
		},
		"showCounts": {
			"type": "boolean",
			"default": false
		},
		"queryType": {
			"type": "string",
			"default": "or"
		},
		"headingLevel": {
			"type": "number",
			"default": 3
		},
		"displayStyle": {
			"type": "string",
			"default": "list"
		},
		"showFilterButton": {
			"type": "boolean",
			"default": false
		},
		"selectType": {
			"type": "string",
			"default": "multiple"
		},
		"isPreview": {
			"type": "boolean",
			"default": false
		}
	},
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/attribute-filter/edit.tsx
/**
 * External dependencies
 */
import { sort } from 'fast-sort';
import { __, sprintf, _n, _x } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import {
	InspectorControls,
	BlockControls,
	useBlockProps,
} from '@wordpress/block-editor';
import { Icon, category, external } from '@wordpress/icons';
import { SearchListControl } from '@woocommerce/editor-components/search-list-control';
import { getAdminLink, getSetting } from '@woocommerce/settings';
import BlockTitle from '@woocommerce/editor-components/block-title';
import clsx from 'clsx';
import { SearchListItem } from '@woocommerce/editor-components/search-list-control/types';
import { AttributeSetting } from '@woocommerce/types';
import {
	Placeholder,
	Disabled,
	PanelBody,
	ToggleControl,
	Button,
	ToolbarGroup,
	Notice,
	withSpokenMessages,
	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
	__experimentalToggleGroupControl as ToggleGroupControl,
	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
	__experimentalToggleGroupControlOption as ToggleGroupControlOption,
} from '@wordpress/components';

/**
 * Internal dependencies
 */
import Block from './block';
import './editor.scss';
import type { EditProps, GetNotice } from './types';
import { UpgradeNotice } from '../filter-wrapper/upgrade';

const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );

const noticeContent = {
	noAttributes: __(
		'Please select an attribute to use this filter!',
		'woocommerce'
	),
	noProducts: __(
		'There are no products with the selected attributes.',
		'woocommerce'
	),
};

const getNotice: GetNotice = ( type ) => {
	const content = noticeContent[ type ];
	return content ? (
		<Notice status="warning" isDismissible={ false }>

{ content }

		</Notice>
	) : null;
};

const Edit = ( {
	attributes,
	setAttributes,
	debouncedSpeak,
	clientId,
}: EditProps ) => {
	const {
		attributeId,
		displayStyle,
		heading,
		headingLevel,
		isPreview,
		queryType,
		showCounts,
		showFilterButton,
		selectType,
	} = attributes;

	const [ isEditing, setIsEditing ] = useState(
		! attributeId && ! isPreview
	);

	const blockProps = useBlockProps();

	const getBlockControls = () => {
		return (
			<BlockControls>
				<ToolbarGroup
					controls={ [
						{
							icon: 'edit',
							title: __( 'Edit', 'woocommerce' ),
							onClick: () => setIsEditing( ! isEditing ),
							isActive: isEditing,
						},
					] }
				/>
			</BlockControls>
		);
	};

	const onChange = ( selected: SearchListItem[] ) => {
		if ( ! selected || ! selected.length ) {
			return;
		}

		const selectedId = selected[ 0 ].id;
		const productAttribute = ATTRIBUTES.find(
			( attribute ) => attribute.attribute_id === selectedId.toString()
		);

		if ( ! productAttribute || attributeId === selectedId ) {
			return;
		}

		setAttributes( {
			attributeId: selectedId as number,
		} );
	};

	const renderAttributeControl = ( {
		isCompact,
	}: {
		isCompact: boolean;
	} ) => {
		const messages = {
			clear: __( 'Clear selected attribute', 'woocommerce' ),
			list: __( 'Product Attributes', 'woocommerce' ),
			noItems: __(
				"Your store doesn't have any product attributes.",
				'woocommerce'
			),
			search: __( 'Search for a product attribute:', 'woocommerce' ),
			selected: ( n: number ) =>
				sprintf(
					/* translators: %d is the number of attributes selected. */
					_n(
						'%d attribute selected',
						'%d attributes selected',
						n,
						'woocommerce'
					),
					n
				),
			updated: __(
				'Product attribute search results updated.',
				'woocommerce'
			),
		};

		const list = sort(
			ATTRIBUTES.map( ( item ) => {
				return {
					id: parseInt( item.attribute_id, 10 ),
					name: item.attribute_label,
				};
			} )
		).asc( 'name' );

		return (
			<SearchListControl
				className="woocommerce-product-attributes"
				list={ list }
				selected={ list.filter( ( { id } ) => id === attributeId ) }
				onChange={ onChange }
				messages={ messages }
				isSingle
				isCompact={ isCompact }
			/>
		);
	};

	const getInspectorControls = () => {
		return (
			<InspectorControls key="inspector">
				<PanelBody>
					<UpgradeNotice clientId={ clientId } />
				</PanelBody>
				<PanelBody title={ __( 'Display Settings', 'woocommerce' ) }>
					<ToggleControl
						label={ __( 'Display product count', 'woocommerce' ) }
						checked={ showCounts }
						onChange={ () =>
							setAttributes( {
								showCounts: ! showCounts,
							} )
						}
					/>
					<ToggleGroupControl
						label={ __(
							'Allow selecting multiple options?',
							'woocommerce'
						) }
						isBlock
						value={ selectType || 'multiple' }
						onChange={ ( value: string ) =>
							setAttributes( {
								selectType: value,
							} )
						}
						className="wc-block-attribute-filter__multiple-toggle"
					>
						<ToggleGroupControlOption
							value="multiple"
							label={ _x(
								'Multiple',
								'Number of filters',
								'woocommerce'
							) }
						/>
						<ToggleGroupControlOption
							value="single"
							label={ _x(
								'Single',
								'Number of filters',
								'woocommerce'
							) }
						/>
					</ToggleGroupControl>
					{ selectType === 'multiple' && (
						<ToggleGroupControl
							label={ __( 'Filter Conditions', 'woocommerce' ) }
							isBlock
							help={
								queryType === 'and'
									? __(
											'Choose to return filter results for all of the attributes selected.',
											'woocommerce'
									  )
									: __(
											'Choose to return filter results for any of the attributes selected.',
											'woocommerce'
									  )
							}
							value={ queryType }
							onChange={ ( value: string ) =>
								setAttributes( {
									queryType: value,
								} )
							}
							className="wc-block-attribute-filter__conditions-toggle"
						>
							<ToggleGroupControlOption
								value="or"
								label={ __( 'Any', 'woocommerce' ) }
							/>
							<ToggleGroupControlOption
								value="and"
								label={ __( 'All', 'woocommerce' ) }
							/>
						</ToggleGroupControl>
					) }
					<ToggleGroupControl
						label={ __( 'Display Style', 'woocommerce' ) }
						isBlock
						value={ displayStyle }
						onChange={ ( value: string ) =>
							setAttributes( {
								displayStyle: value,
							} )
						}
						className="wc-block-attribute-filter__display-toggle"
					>
						<ToggleGroupControlOption
							value="list"
							label={ __( 'List', 'woocommerce' ) }
						/>
						<ToggleGroupControlOption
							value="dropdown"
							label={ __( 'Dropdown', 'woocommerce' ) }
						/>
					</ToggleGroupControl>
					<ToggleControl
						label={ __(
							"Show 'Apply filters' button",
							'woocommerce'
						) }
						help={ __(
							'Products will update when the button is clicked.',
							'woocommerce'
						) }
						checked={ showFilterButton }
						onChange={ ( value ) =>
							setAttributes( {
								showFilterButton: value,
							} )
						}
					/>
				</PanelBody>
				<PanelBody
					title={ __( 'Content Settings', 'woocommerce' ) }
					initialOpen={ false }
				>
					{ renderAttributeControl( { isCompact: true } ) }
				</PanelBody>
			</InspectorControls>
		);
	};

	const noAttributesPlaceholder = () => (
		<Placeholder
			className="wc-block-attribute-filter"
			icon={ <Icon icon={ category } /> }
			label={ __( 'Filter by Attribute', 'woocommerce' ) }
			instructions={ __(
				'Display a list of filters based on the selected attributes.',
				'woocommerce'
			) }
		>

				{ __(
					"Attributes are needed for filtering your products. You haven't created any attributes yet.",
					'woocommerce'
				) }

			<Button
				className="wc-block-attribute-filter__add-attribute-button"
				variant="secondary"
				href={ getAdminLink(
					'edit.php?post_type=product&page=product_attributes'
				) }
				target="_top"
			>
				{ __( 'Add new attribute', 'woocommerce' ) + ' ' }
				<Icon icon={ external } />
			</Button>
			<Button
				className="wc-block-attribute-filter__read_more_button"
				variant="tertiary"
				href="https://woocommerce.com/document/managing-product-taxonomies/"
				target="_blank"
			>
				{ __( 'Learn more', 'woocommerce' ) }
			</Button>
		</Placeholder>
	);

	const onDone = () => {
		setIsEditing( false );
		debouncedSpeak(
			__(
				'Now displaying a preview of the Filter Products by Attribute block.',
				'woocommerce'
			)
		);
	};

	const renderEditMode = () => {
		return (
			<Placeholder
				className="wc-block-attribute-filter"
				icon={ <Icon icon={ category } /> }
				label={ __( 'Filter by Attribute', 'woocommerce' ) }
			>

					{ __(
						'Display a list of filters based on the selected attributes.',
						'woocommerce'
					) }

					{ renderAttributeControl( { isCompact: false } ) }
					<Button variant="primary" onClick={ onDone }>
						{ __( 'Done', 'woocommerce' ) }
					</Button>

			</Placeholder>
		);
	};

	return Object.keys( ATTRIBUTES ).length === 0 ? (
		noAttributesPlaceholder()
	) : (

			{ getBlockControls() }
			{ getInspectorControls() }
			{ isEditing ? (
				renderEditMode()
			) : (

					{ heading && (
						<BlockTitle
							className="wc-block-attribute-filter__title"
							headingLevel={ headingLevel }
							heading={ heading }
							onChange={ ( value: string ) =>
								setAttributes( { heading: value } )
							}
						/>
					) }
					<Disabled>
						<Block
							attributes={ attributes }
							isEditor={ true }
							getNotice={ getNotice }
						/>
					</Disabled>

			) }

	);
};

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 WordPress block enabling dynamic login/logout link display with configurable form presentation and current-page redirection options.

[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/loginout/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/loginout",
	"title": "Login/out",
	"category": "theme",
	"description": "Show login & logout links.",
	"keywords": [ "login", "logout", "form" ],
	"textdomain": "default",
	"attributes": {
		"displayLoginAsForm": {
			"type": "boolean",
			"default": false
		},
		"redirectToCurrent": {
			"type": "boolean",
			"default": true
		}
	},
	"example": {
		"viewportWidth": 350
	},
	"supports": {
		"className": true,
		"color": {
			"background": true,
			"text": false,
			"gradients": true,
			"link": true
		},
		"spacing": {
			"margin": true,
			"padding": true,
			"__experimentalDefaultControls": {
				"margin": false,
				"padding": false
			}
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true
		},
		"interactivity": {
			"clientNavigation": true
		}
	},
	"style": "wp-block-loginout"
}

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

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

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] Implement a Gutenberg block for Contains the block elements used to render a product.

[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-template/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "woocommerce/product-template",
	"title": "Product Template",
	"category": "woocommerce",
	"description": "Contains the block elements used to render a product.",
	"keywords": [ "WooCommerce" ],
	"textdomain": "woocommerce",
	"usesContext": [
		"queryId",
		"query",
		"queryContext",
		"displayLayout",
		"templateSlug",
		"postId",
		"queryContextIncludes",
		"collection",
		"__privateProductCollectionPreviewState"
	],
	"supports": {
		"interactivity": true,
		"inserter": false,
		"reusable": false,
		"html": false,
		"align": [ "wide", "full" ],
		"anchor": true,
		"color": {
			"gradients": true,
			"link": true,
			"__experimentalDefaultControls": {
				"background": true,
				"text": true
			}
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"layout": {
			"allowEditing": false,
			"allowSwitching": false,
			"allowInheriting": false,
			"allowSizingOnChildren": false,
			"allowVerticalAlignment": false
		},
		"email": true
	},
	"editorStyle": "file:../woocommerce/product-template-editor.css",
	"style": "file:../woocommerce/product-template-style.css"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-template/edit.tsx
/* eslint-disable @wordpress/no-unsafe-wp-apis */
/* eslint-disable @typescript-eslint/naming-convention */
/**
 * External dependencies
 */
import clsx from 'clsx';
import { memo, useMemo, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import {
	BlockContextProvider,
	__experimentalUseBlockPreview as useBlockPreview,
	useBlockProps,
	useInnerBlocksProps,
	store as blockEditorStore,
} from '@wordpress/block-editor';
import { Spinner } from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
import { ProductCollectionAttributes } from '@woocommerce/blocks/product-collection/types';
import { getSettingWithCoercion } from '@woocommerce/settings';
import { isNumber, ProductResponseItem } from '@woocommerce/types';
import { ProductDataContextProvider } from '@woocommerce/shared-context';
import { withProduct } from '@woocommerce/block-hocs';
import type { BlockEditProps, BlockInstance } from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import {
	useGetLocation,
	useProductCollectionQueryContext,
	parseTemplateSlug,
} from './utils';
import { getDefaultStockStatuses } from '../product-collection/constants';

const DEFAULT_QUERY_CONTEXT_ATTRIBUTES = [ 'collection' ];

const ProductTemplateInnerBlocks = () => {
	const innerBlocksProps = useInnerBlocksProps(
		{ className: 'wc-block-product' },
		{ __unstableDisableLayoutClassNames: true }
	);
	return <li { ...innerBlocksProps } />;
};

type ProductTemplateBlockPreviewProps = {
	blocks: object[];
	blockContextId: string;
	isHidden: boolean;
	setActiveBlockContextId: ( blockContextId: string ) => void;
};

const ProductTemplateBlockPreview = ( {
	blocks,
	blockContextId,
	isHidden,
	setActiveBlockContextId,
}: ProductTemplateBlockPreviewProps ) => {
	const blockPreviewProps = useBlockPreview( {
		blocks,
		props: {
			className: 'wc-block-product',
		},
	} );

	const handleOnClick = () => {
		setActiveBlockContextId( blockContextId );
	};

	const style = {
		display: isHidden ? 'none' : undefined,
	};

	return (
		<li
			{ ...blockPreviewProps }
			tabIndex={ 0 }
			// eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
			role="button"
			onClick={ handleOnClick }
			onKeyPress={ handleOnClick }
			style={ style }
		/>
	);
};

const MemoizedProductTemplateBlockPreview = memo( ProductTemplateBlockPreview );

type ProductContentProps = {
	attributes: { productId: string };
	displayTemplate: boolean;
	blocks: BlockInstance[];
	blockContext: {
		postType: string;
		postId: string;
	};
	setActiveBlockContextId: ( id: string ) => void;
};

const ProductContent = ( {
	displayTemplate,
	blocks,
	blockContext,
	setActiveBlockContextId,
}: ProductContentProps ) => {
	return (
		<BlockContextProvider
			key={ blockContext.postId }
			value={ blockContext }
		>
			{ displayTemplate ? <ProductTemplateInnerBlocks /> : null }
			<MemoizedProductTemplateBlockPreview
				blocks={ blocks }
				blockContextId={ blockContext.postId }
				setActiveBlockContextId={ setActiveBlockContextId }
				isHidden={ displayTemplate }
			/>
		</BlockContextProvider>
	);
};

// This version of the component is used only when Product Collection is within Single Product block.
// But because it's causing performance issues in editor, it's extracted to a separate component
// and will be removed once all inner blocks are migrated from withProduct to useProduct HOC.
const ProductContentWithProduct = withProduct(
	( {
		isLoading,
		product,
		displayTemplate,
		blocks,
		blockContext,
		setActiveBlockContextId,
	}: ProductContentProps & {
		isLoading: boolean;
		product: ProductResponseItem;
	} ) => {
		return (
			<BlockContextProvider
				key={ blockContext.postId }
				value={ blockContext }
			>
				<ProductDataContextProvider
					product={ product }
					isLoading={ isLoading }
				>
					{ displayTemplate ? <ProductTemplateInnerBlocks /> : null }
					<MemoizedProductTemplateBlockPreview
						blocks={ blocks }
						blockContextId={ blockContext.postId }
						setActiveBlockContextId={ setActiveBlockContextId }
						isHidden={ displayTemplate }
					/>
				</ProductDataContextProvider>
			</BlockContextProvider>
		);
	}
);

const getOrderPropertiesForDefaultQuery = ( defaultSetting: string ) => {
	switch ( defaultSetting ) {
		case 'title':
			return {
				orderby: 'title',
				order: 'asc',
			};
		case 'price':
			return {
				orderby: 'price',
				order: 'asc',
			};
		case 'price-desc':
			return {
				orderby: 'price',
				order: 'desc',
			};
		case 'popularity':
			return {
				orderby: 'popularity',
				order: 'desc',
			};
		case 'rating':
			return {
				orderby: 'rating',
				order: 'desc',
			};
		case 'date':
			return {
				orderby: 'date',
				order: 'desc',
			};
	}

	return {
		orderby: 'menu_order',
		order: 'asc',
	};
};

const ProductTemplateEdit = (
	props: BlockEditProps< {
		clientId: string;
	} > & {
		context: ProductCollectionAttributes;
		__unstableLayoutClassNames: string;
	}
) => {
	const {
		clientId,
		context: {
			query: {
				perPage,
				offset = 0,
				order,
				orderBy,
				search,
				exclude,
				inherit,
				taxQuery,
				pages,
				...restQueryArgs
			},
			queryContext = [ { page: 1 } ],
			templateSlug,
			displayLayout: { type: layoutType, columns, shrinkColumns } = {
				type: 'flex',
				columns: 3,
				shrinkColumns: false,
			},
			queryContextIncludes = [],
			__privateProductCollectionPreviewState,
		},
		__unstableLayoutClassNames,
	} = props;
	const location = useGetLocation( props.context, props.clientId );

	const [ { page } ] = queryContext;
	const [ activeBlockContextId, setActiveBlockContextId ] =
		useState< string >();
	const postType = 'product';
	const loopShopPerPage = getSettingWithCoercion(
		'loopShopPerPage',
		12,
		isNumber
	);

	// Add default query context attributes to queryContextIncludes
	const queryContextIncludesWithDefaults = [
		...new Set(
			queryContextIncludes.concat( DEFAULT_QUERY_CONTEXT_ATTRIBUTES )
		),
	];

	const productCollectionQueryContext = useProductCollectionQueryContext( {
		clientId,
		queryContextIncludes: queryContextIncludesWithDefaults,
	} );

	const { products, isInSingleProductBlock, blocks } = useSelect(
		( select ) => {
			const { getEntityRecords, getEditedEntityRecord, getTaxonomies } =
				select( coreStore );
			const { getBlocks, getBlockParentsByBlockName } =
				select( blockEditorStore );
			const taxonomies = getTaxonomies( {
				type: postType,
				per_page: -1,
				context: 'view',
			} );
			const query: Record< string, unknown > = {
				postType,
				offset: perPage ? perPage * ( page - 1 ) + offset : 0,
				order,
				orderby: orderBy,
			};
			// There is no need to build the taxQuery if we inherit.
			if ( taxQuery && ! inherit ) {
				// We have to build the tax query for the REST API and use as
				// keys the taxonomies `rest_base` with the `term ids` as values.
				const builtTaxQuery = Object.entries( taxQuery ).reduce(
					( accumulator, [ taxonomySlug, terms ] ) => {
						const taxonomy = taxonomies?.find(
							( { slug } ) => slug === taxonomySlug
						);
						if ( taxonomy?.rest_base ) {
							accumulator[ taxonomy?.rest_base ] = terms;
						}
						return accumulator;
					},
					{}
				);
				if ( !! Object.keys( builtTaxQuery ).length ) {
					Object.assign( query, builtTaxQuery );
				}
			}
			if ( perPage ) {
				query.per_page = perPage;
			}
			if ( search ) {
				query.search = search;
			}
			if ( exclude?.length ) {
				query.exclude = exclude;
			}
			// If `inherit` is truthy, adjust conditionally the query to create a better preview.
			if ( inherit ) {
				const { taxonomy, slug } = parseTemplateSlug( templateSlug );

				if ( taxonomy && slug ) {
					const taxonomyRecord = getEntityRecords(
						'taxonomy',
						taxonomy,
						{
							context: 'view',
							per_page: 1,
							_fields: [ 'id' ],
							slug,
						}
					);

					if ( taxonomyRecord ) {
						const taxonomyId = taxonomyRecord[ 0 ]?.id;
						if ( taxonomy === 'category' ) {
							query.categories = taxonomyId;
						} else {
							// If taxonomy is not `category`, we expect either `product_cat` or `product_tag`
							query[ taxonomy ] = taxonomyId;
						}
					}
				}
				query.per_page = loopShopPerPage;

				const settings = getEditedEntityRecord(
					'root',
					'site',
					undefined
				) as unknown as Record< string, string >;

				const orderProperties = getOrderPropertiesForDefaultQuery(
					settings.woocommerce_default_catalog_orderby
				);
				query.orderby = orderProperties.orderby;
				query.order = orderProperties.order;
			}
			return {
				products: getEntityRecords( 'postType', postType, {
					...query,
					...restQueryArgs,
					productCollectionLocation: location,
					productCollectionQueryContext,
					previewState: __privateProductCollectionPreviewState,
					/**
					 * Use value of "Out of stock visibility" setting to determine
					 * which stock statuses to include if inherit query
					 * from template is true.
					 */
					...( inherit && {
						woocommerceStockStatus: getDefaultStockStatuses(),
					} ),
				} ),
				isInSingleProductBlock:
					getBlockParentsByBlockName( clientId, [
						'woocommerce/single-product',
					] ).length > 0,
				blocks: getBlocks( clientId ),
			};
		},
		[
			perPage,
			page,
			offset,
			order,
			orderBy,
			clientId,
			search,
			postType,
			exclude,
			inherit,
			templateSlug,
			taxQuery,
			restQueryArgs,
			location,
			productCollectionQueryContext,
			loopShopPerPage,
			__privateProductCollectionPreviewState,
		]
	);
	const blockContexts = useMemo(
		() =>
			products?.map( ( product ) => ( {
				postType: product.type,
				postId: product.id,
			} ) ),
		[ products ]
	);

	const hasLayoutFlex = layoutType === 'flex' && columns > 1;
	let customClassName = '';

	// We don't want to apply layout styles if there's no products.
	if ( products && products.length && hasLayoutFlex ) {
		const dynamicGrid = `wc-block-product-template__responsive columns-${ columns }`;
		const staticGrid = `is-flex-container columns-${ columns }`;

		customClassName = shrinkColumns ? dynamicGrid : staticGrid;
	}

	const blockProps = useBlockProps( {
		className: clsx(
			__unstableLayoutClassNames,
			'wc-block-product-template',
			customClassName,
			{ [ `is-product-collection-layout-${ layoutType }` ]: layoutType }
		),
	} );

	if ( ! products ) {
		return (
			<p { ...blockProps }>
				<Spinner className="wc-block-product-template__spinner" />
			</p>
		);
	}

	if ( ! products.length ) {
		return (
			<p { ...blockProps }>
				{ ' ' }
				{ __(
					'No products to display. Try adjusting the filters in the block settings panel.',
					'woocommerce'
				) }
			</p>
		);
	}

	const ProductContentComponent = isInSingleProductBlock
		? ProductContentWithProduct
		: ProductContent;

	// To avoid flicker when switching active block contexts, a preview is rendered
	// for each block context, but the preview for the active block context is hidden.
	// This ensures that when it is displayed again, the cached rendering of the
	// block preview is used, instead of having to re-render the preview from scratch.
	return (
		<ul { ...blockProps }>
			{ blockContexts &&
				blockContexts.map( ( blockContext ) => {
					const displayTemplate =
						blockContext.postId ===
						( activeBlockContextId || blockContexts[ 0 ]?.postId );

					return (
						// eslint-disable-next-line @typescript-eslint/ban-ts-comment
						// @ts-ignore isLoading and product props are missing as they're coming from untyped withProduct HOC.
						<ProductContentComponent
							key={ blockContext.postId }
							attributes={ {
								productId: blockContext.postId,
							} }
							blocks={ blocks }
							displayTemplate={ displayTemplate }
							blockContext={ blockContext }
							setActiveBlockContextId={ setActiveBlockContextId }
						/>
					);
				} ) }
		</ul>
	);
};

export default ProductTemplateEdit;

// File: plugins/woocommerce/client/blocks/assets/js/blocks/product-template/save.tsx
/**
 * External 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] Craft a custom Gutenberg block enabling video embedding directly from WordPress media or new uploads, incorporating autoplay, caption, controls, and additional configurable settings.

[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/video/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/video",
	"title": "Video",
	"category": "media",
	"description": "Embed a video from your media library or upload a new one.",
	"keywords": [ "movie" ],
	"textdomain": "default",
	"attributes": {
		"autoplay": {
			"type": "boolean",
			"source": "attribute",
			"selector": "video",
			"attribute": "autoplay"
		},
		"caption": {
			"type": "rich-text",
			"source": "rich-text",
			"selector": "figcaption",
			"role": "content"
		},
		"controls": {
			"type": "boolean",
			"source": "attribute",
			"selector": "video",
			"attribute": "controls",
			"default": true
		},
		"id": {
			"type": "number",
			"role": "content"
		},
		"loop": {
			"type": "boolean",
			"source": "attribute",
			"selector": "video",
			"attribute": "loop"
		},
		"muted": {
			"type": "boolean",
			"source": "attribute",
			"selector": "video",
			"attribute": "muted"
		},
		"poster": {
			"type": "string",
			"source": "attribute",
			"selector": "video",
			"attribute": "poster"
		},
		"preload": {
			"type": "string",
			"source": "attribute",
			"selector": "video",
			"attribute": "preload",
			"default": "metadata"
		},
		"blob": {
			"type": "string",
			"role": "local"
		},
		"src": {
			"type": "string",
			"source": "attribute",
			"selector": "video",
			"attribute": "src",
			"role": "content"
		},
		"playsInline": {
			"type": "boolean",
			"source": "attribute",
			"selector": "video",
			"attribute": "playsinline"
		},
		"tracks": {
			"role": "content",
			"type": "array",
			"items": {
				"type": "object"
			},
			"default": []
		}
	},
	"supports": {
		"anchor": true,
		"align": true,
		"spacing": {
			"margin": true,
			"padding": true,
			"__experimentalDefaultControls": {
				"margin": false,
				"padding": false
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	},
	"editorStyle": "wp-block-video-editor",
	"style": "wp-block-video"
}

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

/**
 * Internal dependencies
 */
import initBlock from '../utils/init-block';
import deprecated from './deprecated';
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: {
			src: 'https://upload.wikimedia.org/wikipedia/commons/c/ca/Wood_thrush_in_Central_Park_switch_sides_%2816510%29.webm',
			// translators: Caption accompanying a video of the wood thrush singing, which serves as an example for the Video block.
			caption: __( 'Wood thrush singing in Central Park, NYC.' ),
		},
	},
	transforms,
	deprecated,
	edit,
	save,
};

if ( window.__experimentalContentOnlyInspectorFields ) {
	settings[ fieldsKey ] = [
		{
			id: 'video',
			label: __( 'Video' ),
			type: 'media',
			mapping: {
				id: 'id',
				url: 'src',
				caption: 'caption',
				poster: 'poster',
			},
			args: {
				allowedTypes: [ 'video' ],
				multiple: false,
			},
		},
		{
			id: 'caption',
			label: __( 'Caption' ),
			type: 'richtext',
		},
	];
	settings[ formKey ] = {
		fields: [ 'video' ],
	};
}

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

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

/**
 * Internal dependencies
 */
import Tracks from './tracks';

export default function save( { attributes } ) {
	const {
		autoplay,
		caption,
		controls,
		loop,
		muted,
		poster,
		preload,
		src,
		playsInline,
		tracks,
	} = attributes;
	return (
		<figure { ...useBlockProps.save() }>
			{ src && (
				<video
					autoPlay={ autoplay }
					controls={ controls }
					loop={ loop }
					muted={ muted }
					poster={ poster }
					preload={ preload !== 'metadata' ? preload : undefined }
					src={ src }
					playsInline={ playsInline }
				>
					<Tracks tracks={ tracks } />
				</video>
			) }
			{ ! RichText.isEmpty( caption ) && (
				<RichText.Content
					className={ __experimentalGetElementClassName( 'caption' ) }
					tagName="figcaption"
					value={ caption }
				/>
			) }
		</figure>
	);
}


[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 Gutenberg block representing the cart subtotal, featuring configurable class name and lock settings to enhance block functionality.

[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/checkout/inner-blocks/checkout-order-summary-subtotal/block.json
{
	"name": "woocommerce/checkout-order-summary-subtotal-block",
	"version": "1.0.0",
	"title": "Subtotal",
	"description": "Shows the cart subtotal row.",
	"category": "woocommerce",
	"supports": {
		"align": false,
		"html": false,
		"multiple": false,
		"reusable": false,
		"lock": false
	},
	"attributes": {
		"className": {
			"type": "string",
			"default": ""
		},
		"lock": {
			"type": "object",
			"default": {
				"remove": true,
				"move": true
			}
		}
	},
	"parent": [
		"woocommerce/checkout-order-summary-totals-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-subtotal/edit.tsx
/**
 * External dependencies
 */
import { useBlockProps } from '@wordpress/block-editor';

/**
 * 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 }>
			<Block className={ className } />
		</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] Build a Gutenberg block that Block that displays the shopping button when the Mini-Cart is empty. with these attributes: lock, start shopping button 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/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json
{
	"name": "woocommerce/mini-cart-shopping-button-block",
	"version": "1.0.0",
	"title": "Mini-Cart Shopping Button",
	"description": "Block that displays the shopping button when the Mini-Cart is empty.",
	"category": "woocommerce",
	"supports": {
		"align": false,
		"html": false,
		"multiple": false,
		"reusable": false,
		"inserter": true,
		"color": {
			"text": true,
			"background": true
		},
		"interactivity": {
			"clientNavigation": true
		}
	},
	"attributes": {
		"lock": {
			"type": "object",
			"default": {
				"remove": false,
				"move": false
			}
		},
		"startShoppingButtonLabel": {
			"type": "string",
			"default": ""
		}
	},
	"styles": [
		{
			"name": "fill",
			"label": "Fill",
			"isDefault": true
		},
		{
			"name": "outline",
			"label": "Outline"
		}
	],
	"parent": [ "woocommerce/empty-mini-cart-contents-block" ],
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/edit.tsx
/**
 * External dependencies
 */
import {
	useBlockProps,
	__experimentalUseColorProps as useColorProps,
} from '@wordpress/block-editor';
import EditableButton from '@woocommerce/editor-components/editable-button';

/**
 * Internal dependencies
 */
import { defaultStartShoppingButtonLabel } from './constants';
import { getVariant } from '../utils';

export const Edit = ( {
	attributes,
	setAttributes,
}: {
	attributes: {
		startShoppingButtonLabel: string;
	};
	setAttributes: ( attributes: Record< string, unknown > ) => void;
} ): JSX.Element => {
	const blockProps = useBlockProps( {
		className: 'wp-block-button aligncenter',
	} );
	const colorProps = useColorProps( attributes );
	const { startShoppingButtonLabel } = attributes;

	return (
		<div { ...blockProps }>
			<EditableButton
				className={ `wc-block-mini-cart__shopping-button ${
					colorProps.className || ''
				}` }
				value={ startShoppingButtonLabel }
				placeholder={ defaultStartShoppingButtonLabel }
				onChange={ ( content ) => {
					setAttributes( {
						startShoppingButtonLabel: content,
					} );
				} }
				variant={ getVariant( blockProps.className, 'contained' ) }
				style={ colorProps.style }
			/>
		</div>
	);
};

export const Save = (): JSX.Element => {
	return <div { ...useBlockProps.save() }></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] Build a dynamic WordPress block empowering users to filter and showcase taxonomy terms using configurable search criteria and visual customization options for term and tag selection.

[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/terms-query/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/terms-query",
	"title": "Terms Query",
	"category": "theme",
	"description": "An advanced block that allows displaying taxonomy terms based on different query parameters and visual configurations.",
	"keywords": [ "terms", "taxonomy", "categories", "tags", "list" ],
	"textdomain": "default",
	"attributes": {
		"termQuery": {
			"type": "object",
			"default": {
				"perPage": 10,
				"taxonomy": "category",
				"order": "asc",
				"orderBy": "name",
				"include": [],
				"hideEmpty": true,
				"showNested": false,
				"inherit": false
			}
		},
		"tagName": {
			"type": "string",
			"default": "div"
		}
	},
	"usesContext": [ "templateSlug" ],
	"providesContext": {
		"termQuery": "termQuery"
	},
	"supports": {
		"align": [ "wide", "full" ],
		"html": false,
		"layout": true,
		"interactivity": true
	}
}

// File: packages/block-library/src/terms-query/index.js
/**
 * WordPress dependencies
 */
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';
import variations from './variations';

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

export const settings = {
	icon,
	edit,
	save,
	example: {},
	variations,
};

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

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

export default function save( { attributes: { tagName: Tag = 'div' } } ) {
	const blockProps = useBlockProps.save();
	const innerBlocksProps = useInnerBlocksProps.save( blockProps );
	return <Tag { ...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 a list of your most recent posts. that allows users to configure: categories, selected author, posts to show, and 15 more options

[Assistant]
// File: packages/block-library/src/latest-posts/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/latest-posts",
	"title": "Latest Posts",
	"category": "widgets",
	"description": "Display a list of your most recent posts.",
	"keywords": [ "recent posts" ],
	"textdomain": "default",
	"attributes": {
		"categories": {
			"type": "array",
			"items": {
				"type": "object"
			}
		},
		"selectedAuthor": {
			"type": "number"
		},
		"postsToShow": {
			"type": "number",
			"default": 5
		},
		"displayPostContent": {
			"type": "boolean",
			"default": false
		},
		"displayPostContentRadio": {
			"type": "string",
			"default": "excerpt"
		},
		"excerptLength": {
			"type": "number",
			"default": 55
		},
		"displayAuthor": {
			"type": "boolean",
			"default": false
		},
		"displayPostDate": {
			"type": "boolean",
			"default": false
		},
		"postLayout": {
			"type": "string",
			"default": "list"
		},
		"columns": {
			"type": "number",
			"default": 3
		},
		"order": {
			"type": "string",
			"default": "desc"
		},
		"orderBy": {
			"type": "string",
			"default": "date"
		},
		"displayFeaturedImage": {
			"type": "boolean",
			"default": false
		},
		"featuredImageAlign": {
			"type": "string",
			"enum": [ "left", "center", "right" ]
		},
		"featuredImageSizeSlug": {
			"type": "string",
			"default": "thumbnail"
		},
		"featuredImageSizeWidth": {
			"type": "number",
			"default": null
		},
		"featuredImageSizeHeight": {
			"type": "number",
			"default": null
		},
		"addLinkToFeaturedImage": {
			"type": "boolean",
			"default": false
		}
	},
	"supports": {
		"align": true,
		"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
			}
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true,
			"__experimentalDefaultControls": {
				"radius": true,
				"color": true,
				"width": true,
				"style": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	},
	"editorStyle": "wp-block-latest-posts-editor",
	"style": "wp-block-latest-posts"
}

// File: packages/block-library/src/latest-posts/index.js
/**
 * WordPress dependencies
 */
import { postList as icon } from '@wordpress/icons';

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

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

export const settings = {
	icon,
	example: {},
	edit,
	deprecated,
};

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 enabling vertical spacing between content sections, with customizable height and width parameters for flexible layout control.

[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/spacer/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/spacer",
	"title": "Spacer",
	"category": "design",
	"description": "Add white space between blocks and customize its height.",
	"textdomain": "default",
	"attributes": {
		"height": {
			"type": "string",
			"default": "100px"
		},
		"width": {
			"type": "string"
		}
	},
	"usesContext": [ "orientation" ],
	"supports": {
		"anchor": true,
		"spacing": {
			"margin": [ "top", "bottom" ],
			"__experimentalDefaultControls": {
				"margin": true
			}
		},
		"interactivity": {
			"clientNavigation": true
		}
	},
	"editorStyle": "wp-block-spacer-editor",
	"style": "wp-block-spacer"
}

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

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

const { name } = metadata;

export { metadata, name };

export const settings = {
	icon,
	transforms,
	edit,
	save,
	deprecated,
};

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

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

export default function save( { attributes } ) {
	const { height, width, style } = attributes;
	const { layout: { selfStretch } = {} } = style || {};
	// If selfStretch is set to 'fill' or 'fit', don't set default height.
	const finalHeight =
		selfStretch === 'fill' || selfStretch === 'fit' ? undefined : height;
	return (
		<div
			{ ...useBlockProps.save( {
				style: {
					height: getSpacingPresetCssVar( finalHeight ),
					width: getSpacingPresetCssVar( width ),
				},
				'aria-hidden': 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 A collection of blocks that allow visitors to get around your site. with these attributes: ref, text color, custom text color, and 16 more options

[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/navigation/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/navigation",
	"title": "Navigation",
	"category": "theme",
	"allowedBlocks": [
		"core/navigation-link",
		"core/search",
		"core/social-links",
		"core/page-list",
		"core/spacer",
		"core/home-link",
		"core/site-title",
		"core/site-logo",
		"core/navigation-submenu",
		"core/loginout",
		"core/buttons"
	],
	"description": "A collection of blocks that allow visitors to get around your site.",
	"keywords": [ "menu", "navigation", "links" ],
	"textdomain": "default",
	"attributes": {
		"ref": {
			"type": "number"
		},
		"textColor": {
			"type": "string"
		},
		"customTextColor": {
			"type": "string"
		},
		"rgbTextColor": {
			"type": "string"
		},
		"backgroundColor": {
			"type": "string"
		},
		"customBackgroundColor": {
			"type": "string"
		},
		"rgbBackgroundColor": {
			"type": "string"
		},
		"showSubmenuIcon": {
			"type": "boolean",
			"default": true
		},
		"openSubmenusOnClick": {
			"type": "boolean",
			"default": false
		},
		"overlayMenu": {
			"type": "string",
			"default": "mobile"
		},
		"icon": {
			"type": "string",
			"default": "handle"
		},
		"hasIcon": {
			"type": "boolean",
			"default": true
		},
		"__unstableLocation": {
			"type": "string"
		},
		"overlayBackgroundColor": {
			"type": "string"
		},
		"customOverlayBackgroundColor": {
			"type": "string"
		},
		"overlayTextColor": {
			"type": "string"
		},
		"customOverlayTextColor": {
			"type": "string"
		},
		"maxNestingLevel": {
			"type": "number",
			"default": 5
		},
		"templateLock": {
			"type": [ "string", "boolean" ],
			"enum": [ "all", "insert", "contentOnly", false ]
		}
	},
	"providesContext": {
		"textColor": "textColor",
		"customTextColor": "customTextColor",
		"backgroundColor": "backgroundColor",
		"customBackgroundColor": "customBackgroundColor",
		"overlayTextColor": "overlayTextColor",
		"customOverlayTextColor": "customOverlayTextColor",
		"overlayBackgroundColor": "overlayBackgroundColor",
		"customOverlayBackgroundColor": "customOverlayBackgroundColor",
		"fontSize": "fontSize",
		"customFontSize": "customFontSize",
		"showSubmenuIcon": "showSubmenuIcon",
		"openSubmenusOnClick": "openSubmenusOnClick",
		"style": "style",
		"maxNestingLevel": "maxNestingLevel"
	},
	"supports": {
		"align": [ "wide", "full" ],
		"ariaLabel": true,
		"contentRole": true,
		"html": false,
		"inserter": true,
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontStyle": true,
			"__experimentalFontWeight": true,
			"__experimentalTextTransform": true,
			"__experimentalFontFamily": true,
			"__experimentalLetterSpacing": true,
			"__experimentalTextDecoration": true,
			"__experimentalSkipSerialization": [ "textDecoration" ],
			"__experimentalDefaultControls": {
				"fontSize": true
			}
		},
		"spacing": {
			"blockGap": true,
			"units": [ "px", "em", "rem", "vh", "vw" ],
			"__experimentalDefaultControls": {
				"blockGap": true
			}
		},
		"layout": {
			"allowSwitching": false,
			"allowInheriting": false,
			"allowVerticalAlignment": false,
			"allowSizingOnChildren": true,
			"default": {
				"type": "flex"
			}
		},
		"interactivity": true,
		"renaming": false
	},
	"editorStyle": "wp-block-navigation-editor",
	"style": "wp-block-navigation"
}

// File: packages/block-library/src/navigation/index.js
/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { navigation as icon } from '@wordpress/icons';
import { select } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { decodeEntities } from '@wordpress/html-entities';

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

const { name } = metadata;

export { metadata, name };

export const settings = {
	icon,
	example: {
		attributes: {
			overlayMenu: 'never',
		},
		innerBlocks: [
			{
				name: 'core/navigation-link',
				attributes: {
					// translators: 'Home' as in a website's home page.
					label: __( 'Home' ),
					url: 'https://make.wordpress.org/',
				},
			},
			{
				name: 'core/navigation-link',
				attributes: {
					// translators: 'About' as in a website's about page.
					label: __( 'About' ),
					url: 'https://make.wordpress.org/',
				},
			},
			{
				name: 'core/navigation-link',
				attributes: {
					// translators: 'Contact' as in a website's contact page.
					label: __( 'Contact' ),
					url: 'https://make.wordpress.org/',
				},
			},
		],
	},
	edit,
	save,
	__experimentalLabel: ( { ref } ) => {
		if ( ! ref ) {
			return;
		}

		const navigation = select( coreStore ).getEditedEntityRecord(
			'postType',
			'wp_navigation',
			ref
		);

		if ( ! navigation?.title ) {
			return;
		}

		return decodeEntities( navigation.title );
	},
	deprecated,
};

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

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

export default function save( { attributes } ) {
	if ( attributes.ref ) {
		// Avoid rendering inner blocks when a ref is defined.
		// When this id is defined the inner blocks are loaded from the
		// `wp_navigation` entity rather than the hard-coded block html.
		return;
	}
	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] Create a woocommerce-product-elements block with customizable product id, is descendent of query loop, text align, and 2 more options

[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-counter/block.json
{
	"name": "woocommerce/product-rating-counter",
	"title": "Product Rating Counter",
	"description": "Display the review count 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
		},
		"inserter": false,
		"color": {
			"text": false,
			"background": false,
			"link": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"typography": {
			"fontSize": true,
			"__experimentalSkipSerialization": true
		},
		"__experimentalSelector": ".wc-block-components-product-rating-counter"
	},
	"usesContext": [ "query", "queryId", "postId" ],
	"keywords": [ "WooCommerce" ],
	"ancestor": [ "woocommerce/single-product" ],
	"textdomain": "woocommerce",
	"apiVersion": 3,
	"$schema": "https://schemas.wp.org/trunk/block.json"
}

// File: plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/rating-counter/edit.tsx
/**
 * External dependencies
 */
import {
	AlignmentToolbar,
	BlockControls,
	useBlockProps,
} from '@wordpress/block-editor';
import type { BlockEditProps } from '@wordpress/blocks';
import { useEffect } from '@wordpress/element';
import { ProductQueryContext as Context } from '@woocommerce/blocks/product-query/types';

/**
 * Internal dependencies
 */
import Block from './block';
import { BlockAttributes } from './types';
import { useIsDescendentOfSingleProductBlock } from '../shared/use-is-descendent-of-single-product-block';
import { useIsDescendentOfSingleProductTemplate } from '../shared/use-is-descendent-of-single-product-template';

const Edit = (
	props: BlockEditProps< BlockAttributes > & { context: Context }
): JSX.Element => {
	const { attributes, setAttributes, context } = props;
	const blockProps = useBlockProps( {
		className: 'wp-block-woocommerce-product-rating-counter',
	} );
	const blockAttrs = {
		...attributes,
		...context,
		shouldDisplayMockedReviewsWhenProductHasNoReviews: true,
	};
	const isDescendentOfQueryLoop = Number.isFinite( context.queryId );
	const { isDescendentOfSingleProductBlock } =
		useIsDescendentOfSingleProductBlock( {
			blockClientId: blockProps?.id,
		} );
	let { isDescendentOfSingleProductTemplate } =
		useIsDescendentOfSingleProductTemplate();

	if ( isDescendentOfQueryLoop || isDescendentOfSingleProductBlock ) {
		isDescendentOfSingleProductTemplate = false;
	}

	useEffect( () => {
		setAttributes( {
			isDescendentOfQueryLoop,
			isDescendentOfSingleProductBlock,
			isDescendentOfSingleProductTemplate,
		} );
	}, [
		setAttributes,
		isDescendentOfQueryLoop,
		isDescendentOfSingleProductBlock,
		isDescendentOfSingleProductTemplate,
	] );

	return (
		<>
			<BlockControls>
				<AlignmentToolbar
					value={ attributes.textAlign }
					onChange={ ( newAlign ) => {
						setAttributes( { textAlign: newAlign || '' } );
					} }
				/>
			</BlockControls>
			<div { ...blockProps }>
				<Block { ...blockAttrs } />
			</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] Create a widgets block with customizable columns, block layout, feed u r l, and 7 more options

[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/rss/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "core/rss",
	"title": "RSS",
	"category": "widgets",
	"description": "Display entries from any RSS or Atom feed.",
	"keywords": [ "atom", "feed" ],
	"textdomain": "default",
	"attributes": {
		"columns": {
			"type": "number",
			"default": 2
		},
		"blockLayout": {
			"type": "string",
			"default": "list"
		},
		"feedURL": {
			"type": "string",
			"default": "",
			"role": "content"
		},
		"itemsToShow": {
			"type": "number",
			"default": 5
		},
		"displayExcerpt": {
			"type": "boolean",
			"default": false
		},
		"displayAuthor": {
			"type": "boolean",
			"default": false
		},
		"displayDate": {
			"type": "boolean",
			"default": false
		},
		"excerptLength": {
			"type": "number",
			"default": 55
		},
		"openInNewTab": {
			"type": "boolean",
			"default": false
		},
		"rel": {
			"type": "string"
		}
	},
	"supports": {
		"align": true,
		"html": false,
		"interactivity": {
			"clientNavigation": true
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true
		},
		"spacing": {
			"margin": true,
			"padding": true,
			"__experimentalDefaultControls": {
				"padding": false,
				"margin": false
			}
		},
		"color": {
			"background": true,
			"text": true,
			"gradients": true,
			"link": true
		}
	},
	"editorStyle": "wp-block-rss-editor",
	"style": "wp-block-rss"
}

// File: packages/block-library/src/rss/index.js
/**
 * WordPress dependencies
 */
import { rss 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,
	example: {
		attributes: {
			feedURL: 'https://wordpress.org',
		},
	},
	edit,
};

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