block editor - set allowedBlocks to a specific variant

admin2025-05-31  0

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
Add a comment  | 

2 Answers 2

Reset to default 1

First: 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:

  1. Custom Block Wrapper with Locked Variant

    • Create a custom block that wraps the woocommerce/product-collection block.
    • Use the template property in useInnerBlocksProps 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.

  2. Programmatic Variant Enforcement

    • Allow the woocommerce/product-collection block in allowedBlocks.
    • 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.

  3. Custom Block with Hardcoded Variant

    • Instead of using InnerBlocks, create a custom block that renders the woocommerce/product-collection block with the hand-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.

  4. 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.

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?

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1748631209a313657.html

最新回复(0)