Is it possible to allow only a specific variant inside an InnerBlock?
const innerBlockProps = useInnerBlocksProps( blockProps, {
allowedBlocks: [ 'woocommerce/product-collection' ],
} );
This works. But woocommerce/product-collection
has multiple variants, and I want the user to be able to only set a specific variant inside a custom block.
This is not working for me:
const innerBlockProps = useInnerBlocksProps( blockProps, {
allowedBlocks: [ 'woocommerce/product-collection/hand-picked' ], // specific variant.
} );
Anyone knows if this is possible?
Is it possible to allow only a specific variant inside an InnerBlock?
const innerBlockProps = useInnerBlocksProps( blockProps, {
allowedBlocks: [ 'woocommerce/product-collection' ],
} );
This works. But woocommerce/product-collection
has multiple variants, and I want the user to be able to only set a specific variant inside a custom block.
This is not working for me:
const innerBlockProps = useInnerBlocksProps( blockProps, {
allowedBlocks: [ 'woocommerce/product-collection/hand-picked' ], // specific variant.
} );
Anyone knows if this is possible?
Share Improve this question asked May 11 at 16:10 Siddharth ThevarilSiddharth Thevaril 6078 silver badges22 bronze badges 2- Probably not, the second code block you tried will not work as that would only work if they were separate blocks. Can you share why you need this? What you're trying to do is a dead end, with very kludgey workarounds that are brittle and easy to break, but that doesn't mean there aren't other solutions. Even if what you wanted is possible, it would be trivial to convert that block into another variant using the block UI to break your system, or even just drag and drop. – Tom J Nowell ♦ Commented May 11 at 16:44
- You cannot restrict InnerBlocks to only allow a specific block variant using the allowedBlocks property. Only base block names are supported. To enforce a specific variant, you must use a workaround such as creating a custom block wrapper or programmatically restricting attributes after insertion – Arizona Web Development Commented May 11 at 18:14
2 Answers
Reset to default 1First: It is impossible
allowedBlocks
only accepts block names as strings — not specific variations or object definitions.
Second: What’s the correct approach?
Use the base block name, then define the variation via className
or attributes in the template
.
How to find a variation's className? Insert the block (e.g., core/group) and select the desired variation.
Go to the sidebar → Advanced → copy the className
it uses.
Enter the className
in the code
<div {...blockProps}>
<InnerBlocks
allowedBlocks={['core/group']}
template={[
[
'core/group',
{ className: 'is-style-boxed-1' }
]
]}
/>
</div>
Example of application in your code.
const innerBlockProps = useInnerBlocksProps(blockProps, {
allowedBlocks: ['core/group'],
template: [['core/group', { className: 'is-style-boxed-1' }]],
});
Replace core/group
and is-style-boxed-1
with your desired block and variation class.
Not only className
, but other attributes like spacing, margin, padding, etc. can also be added. Since I don't know the content of woocommerce/product-collection
, I only show className
, and className
is also an attribute that defines the variation.
You cannot directly restrict InnerBlocks
to a specific block variant (e.g., woocommerce/product-collection/hand-picked
) using the allowedBlocks
property, as it only supports base block types (e.g., woocommerce/product-collection
). Variants are not treated as distinct blocks in the WordPress block editor's API.
Why It Doesn't Work
The allowedBlocks
property in useInnerBlocksProps
filters blocks by their registered block type, not by their variants. Block variants (like hand-picked
for woocommerce/product-collection
) are essentially predefined configurations of the same block type, sharing the same block name. Thus, specifying woocommerce/product-collection/hand-picked
in allowedBlocks
is invalid because it’s not a registered block type.
Possible Workarounds
Here are some approaches to achieve your goal of restricting users to a specific variant:
Custom Block Wrapper with Locked Variant
- Create a custom block that wraps the
woocommerce/product-collection
block. - Use the
template
property inuseInnerBlocksProps
to predefine the block with the desired variant. - Set
templateLock: 'all'
to prevent users from changing the block or its variant.
const innerBlockProps = useInnerBlocksProps(blockProps, { allowedBlocks: ['woocommerce/product-collection'], template: [ [ 'woocommerce/product-collection', { variation: 'hand-picked' }, // Set the specific variant ], ], templateLock: 'all', // Lock the template to prevent changes });
Pros: Ensures the block is inserted with the desired variant and prevents variant switching. Cons: Users cannot add or remove blocks within the
InnerBlocks
area.- Create a custom block that wraps the
Programmatic Variant Enforcement
- Allow the
woocommerce/product-collection
block inallowedBlocks
. - Use a client-side script or block validation to enforce the variant by checking the block’s attributes and resetting them to the desired variant if they don’t match.
Example:
import { useEffect } from '@wordpress/element'; import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; export default function Edit({ attributes, setAttributes, clientId }) { const blockProps = useBlockProps(); const innerBlockProps = useInnerBlocksProps(blockProps, { allowedBlocks: ['woocommerce/product-collection'], }); useEffect(() => { const blocks = wp.data.select('core/block-editor').getBlocks(clientId); blocks.forEach((block) => { if ( block.name === 'woocommerce/product-collection' && block.attributes.variation !== 'hand-picked' ) { wp.data .dispatch('core/block-editor') .updateBlockAttributes(block.clientId, { variation: 'hand-picked' }); } }); }, [clientId]); return <div {...innerBlockProps} />; }
Pros: Dynamically enforces the variant without locking the template. Cons: Brittle, as users can still switch variants via the UI, requiring constant monitoring. Also, it may cause unexpected behavior if the block’s attributes change frequently.
- Allow the
Custom Block with Hardcoded Variant
- Instead of using
InnerBlocks
, create a custom block that renders thewoocommerce/product-collection
block with thehand-picked
variant hardcoded in its attributes. - Use the
renderCallback
or client-side rendering to ensure only the desired variant is used.
Example:
import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType('my-custom/hand-picked-collection', { title: 'Hand-Picked Product Collection', category: 'woocommerce', edit: () => { const blockProps = useBlockProps(); return ( <div {...blockProps}> <InnerBlocks allowedBlocks={['woocommerce/product-collection']} template={[ ['woocommerce/product-collection', { variation: 'hand-picked' }], ]} templateLock="all" /> </div> ); }, save: () => <InnerBlocks.Content />, });
Pros: Full control over the block’s behavior and variant. Cons: Less flexible if you need to support multiple variants or dynamic configurations.
- Instead of using
Block Validation on Save
- Implement server-side or client-side block validation to reject the block if the variant doesn’t match
hand-picked
. - Use the
validateBlock
hook or a custom validation function.
Example (client-side validation):
import { addFilter } from '@wordpress/hooks'; addFilter( 'blocks.getBlockAttributes', 'my-custom/validate-product-collection', (attributes, blockType, { clientId }) => { if (blockType.name === 'woocommerce/product-collection') { if (attributes.variation !== 'hand-picked') { wp.data .dispatch('core/notices') .createErrorNotice('Only the hand-picked variant is allowed.'); return { ...attributes, variation: 'hand-picked' }; } } return attributes; } );
Pros: Provides feedback to users and enforces the variant. Cons: Complex to implement and may not prevent UI-based variant changes before validation.
- Implement server-side or client-side block validation to reject the block if the variant doesn’t match
Considerations
- Why It’s a Challenge: As noted in the comments, even if you restrict the variant, users can switch variants via the block editor’s UI (e.g., dropdowns, drag-and-drop). This makes client-side enforcement brittle.
- Alternative Solutions: If the goal is to simplify the user experience or ensure a specific configuration, consider:
- Using a predefined pattern or template instead of a custom block.
- Communicating with the WooCommerce team (if possible) to see if they can expose variants as distinct block types in the future.
- WooCommerce-Specific Notes: The
woocommerce/product-collection
block’s variants are managed via attributes (e.g.,variation: 'hand-picked'
). Check the block’s documentation or source code for supported attributes and ensure your solution aligns with WooCommerce’s updates.
Recommendation
The Custom Block Wrapper with Locked Variant (Option 1) is the most robust and user-friendly approach. It ensures the hand-picked
variant is used without requiring complex validation or monitoring. If you need more flexibility, combine it with Programmatic Variant Enforcement (Option 2) to handle edge cases.
If you share more details about your use case (e.g., why you need to restrict the variant, whether users need to add multiple blocks), I can refine the solution further. Would you like me to elaborate on any of these approaches or explore another angle?