Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Product Gallery block: Restrict block to be available only on the Single Product template or the Product Gallery template part #11664

Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
dbda009
WIP: experimenting with strategy pattern for block registration
thealexandrelara Nov 7, 2023
2553387
Add TemplateChangeDetector to BlocksRegistrationManager
thealexandrelara Nov 9, 2023
ebe4625
Handle blocks registration
thealexandrelara Nov 9, 2023
e79e1b8
Fix issue causing blocks to be registered multiple times
thealexandrelara Nov 9, 2023
3bc09e0
Allow register/unregister blocks when on pages or posts
thealexandrelara Nov 10, 2023
450a292
Add BlockRegistrationStrategy logic
thealexandrelara Nov 13, 2023
17f1cb4
Merge branch 'trunk' into feat/11027-restrict-product-gallery-block-t…
thealexandrelara Nov 13, 2023
5eaa14e
Fix import error
thealexandrelara Nov 13, 2023
b322d69
Add doc comments for BlockRegistrationManager class
thealexandrelara Nov 13, 2023
fe4b161
Add doc comments to TemplateChangeDetector class
thealexandrelara Nov 13, 2023
29025b8
Fix eslint errors
thealexandrelara Nov 13, 2023
0b8b81d
Import domReady from @wordpress/dom-ready
thealexandrelara Nov 14, 2023
e8a88a7
Prevent error when using blockName for registerBlockType function
thealexandrelara Nov 14, 2023
4162dfb
Add e2e tests to check for block availability in different contexts
thealexandrelara Nov 14, 2023
4b00273
Add e2e tests to cover block availability on different contexts
thealexandrelara Nov 14, 2023
6c809cf
Fix JS error when trying to unregister the same block twice
Aljullu Nov 16, 2023
08eafcb
Rename method from 'blockShouldBeRegistered' to 'shouldBlockBeRegiste…
Aljullu Nov 16, 2023
904f946
Remove 'blocksWithRestriction' property from BlockRegistrationManager
Aljullu Nov 16, 2023
403830b
Merge branch 'trunk' into feat/11027-restrict-product-gallery-block-t…
roykho Nov 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* External dependencies
*/
import {
BlockConfiguration,
registerBlockType,
unregisterBlockType,
registerBlockVariation,
unregisterBlockVariation,
BlockVariation,
BlockAttributes,
} from '@wordpress/blocks';

export interface BlockRegistrationStrategy {
register(
blockName: string | Partial< BlockConfiguration >,
blockSettings: Partial< BlockConfiguration >
): boolean;
unregister( blockName: string, variationName?: string ): boolean;
}

export class BlockTypeStrategy implements BlockRegistrationStrategy {
register(
blockName: string,
blockSettings: Partial< BlockConfiguration >
): boolean {
return Boolean( registerBlockType( blockName, blockSettings ) );
Aljullu marked this conversation as resolved.
Show resolved Hide resolved
}

unregister( blockName: string ): boolean {
return Boolean( unregisterBlockType( blockName ) );
}
}

// Strategy for BlockVariation
export class BlockVariationStrategy implements BlockRegistrationStrategy {
register(
blockName: string,
blockSettings: Partial< BlockConfiguration >
): boolean {
return Boolean(
registerBlockVariation(
blockName,
blockSettings as BlockVariation< BlockAttributes >
)
);
}

unregister( blockName: string, variationName: string ): boolean {
return Boolean( unregisterBlockVariation( blockName, variationName ) );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/**
* External dependencies
*/
import { unregisterBlockType } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import {
TemplateChangeDetector,
TemplateChangeDetectorObserver,
} from './template-change-detector';
import {
BlockRegistrationStrategy,
BlockTypeStrategy,
BlockVariationStrategy,
} from './block-registration-strategy';
import {
BLOCKS_WITH_RESTRICTION,
BlocksWithRestriction,
} from './blocks-with-restriction';

/**
* Manages the registration and unregistration of blocks based on template or page restrictions.
*
* This class implements the TemplateChangeDetectorObserver interface and is responsible for managing the registration and unregistration of blocks based on the restrictions defined in the BLOCKS_WITH_RESTRICTION constant.
*
* The class maintains a list of unregistered blocks and uses a block registration strategy to register and unregister blocks as needed. The strategy used depends on whether the block is a variation block or a regular block.
*
* The `run` method is the main entry point for the class. It is called with a TemplateChangeDetector object and registers and unregisters blocks based on the current template and whether the editor is in post or page mode.
*/
export class BlockRegistrationManager
implements TemplateChangeDetectorObserver
{
private blocksWithRestriction: BlocksWithRestriction;
private unregisteredBlocks: string[] = [];
private blockRegistrationStrategy: BlockRegistrationStrategy;

constructor() {
this.blocksWithRestriction = BLOCKS_WITH_RESTRICTION;
Aljullu marked this conversation as resolved.
Show resolved Hide resolved
this.blockRegistrationStrategy = new BlockTypeStrategy();
}

/**
* Determines whether a block should be registered based on the current template or page.
*
* This method checks whether a block with restrictions should be registered based on the current template ID and
* whether the editor is in post or page mode. It checks whether the current template ID starts with any of the
* allowed templates or template parts for the block, and whether the block is available in the post or page editor.
*
* @param {Object} params - The parameters for the method.
* @param {string} params.blockWithRestrictionName - The name of the block with restrictions.
* @param {string} params.currentTemplateId - The ID of the current template.
* @param {boolean} params.isPostOrPage - Whether the editor is in a post or page.
* @return {boolean} True if the block should be registered, false otherwise.
*/
private blockShouldBeRegistered( {
Aljullu marked this conversation as resolved.
Show resolved Hide resolved
blockWithRestrictionName,
currentTemplateId,
isPostOrPage,
}: {
blockWithRestrictionName: string;
currentTemplateId: string;
isPostOrPage: boolean;
} ) {
const {
allowedTemplates,
allowedTemplateParts,
availableInPostOrPageEditor,
} = this.blocksWithRestriction[ blockWithRestrictionName ];
const shouldBeAvailableOnTemplate = Object.keys(
allowedTemplates
).some( ( allowedTemplate ) =>
currentTemplateId.startsWith( allowedTemplate )
);
const shouldBeAvailableOnTemplatePart = Object.keys(
allowedTemplateParts
).some( ( allowedTemplate ) =>
currentTemplateId.startsWith( allowedTemplate )
);
const shouldBeAvailableOnPostOrPageEditor =
isPostOrPage && availableInPostOrPageEditor;

return (
shouldBeAvailableOnTemplate ||
shouldBeAvailableOnTemplatePart ||
shouldBeAvailableOnPostOrPageEditor
);
}

/**
* Unregisters blocks before entering a restricted area based on the current template or page/post.
*
* This method iterates over all blocks with restrictions and unregisters them if they should not be registered
* based on the current template ID and whether the editor is in a post or page. It uses a block registration
* strategy to unregister the blocks, which depends on whether the block is a variation block or a regular block.
*
* @param {Object} params - The parameters for the method.
* @param {string} params.currentTemplateId - The ID of the current template.
* @param {boolean} params.isPostOrPage - Whether the editor is in post or page mode.
*/
unregisterBlocksBeforeEnteringRestrictedArea( {
currentTemplateId,
isPostOrPage,
}: {
currentTemplateId: string;
isPostOrPage: boolean;
} ) {
for ( const blockWithRestrictionName of Object.keys(
BLOCKS_WITH_RESTRICTION
) ) {
if ( this.blocksWithRestriction[ blockWithRestrictionName ] ) {
if (
this.blockShouldBeRegistered( {
blockWithRestrictionName,
currentTemplateId,
isPostOrPage,
} )
) {
continue;
}
this.blockRegistrationStrategy = this.blocksWithRestriction[
blockWithRestrictionName
].isVariationBlock
? new BlockVariationStrategy()
: new BlockTypeStrategy();

this.blockRegistrationStrategy.unregister(
blockWithRestrictionName
);
unregisterBlockType( blockWithRestrictionName );
Aljullu marked this conversation as resolved.
Show resolved Hide resolved
this.unregisteredBlocks.push( blockWithRestrictionName );
}
}
}

/**
* Registers blocks after leaving a restricted area.
*
* This method iterates over all unregistered blocks and registers them if they are not restricted in the current context.
* It uses a block registration strategy to register the blocks, which depends on whether the block is a variation block or a regular block.
* If the block is successfully registered, it is removed from the list of unregistered blocks.
*/
registerBlocksAfterLeavingRestrictedArea() {
for ( const unregisteredBlockName of this.unregisteredBlocks ) {
const restrictedBlockData =
this.blocksWithRestriction[ unregisteredBlockName ];
this.blockRegistrationStrategy = this.blocksWithRestriction[
unregisteredBlockName
].isVariationBlock
? new BlockVariationStrategy()
: new BlockTypeStrategy();
const isBlockRegistered = this.blockRegistrationStrategy.register(
restrictedBlockData.blockMetadata,
restrictedBlockData.blockSettings
);
this.unregisteredBlocks = isBlockRegistered
? this.unregisteredBlocks.filter(
( blockName ) => blockName !== unregisteredBlockName
)
: this.unregisteredBlocks;
}
}

/**
* Runs the block registration manager.
*
* This method is the main entry point for the block registration manager. It is called with a TemplateChangeDetector object,
* and registers and unregisters blocks based on the current template and whether the editor is in a post or page.
*
* @param {TemplateChangeDetector} templateChangeDetector - The template change detector object.
*/
run( templateChangeDetector: TemplateChangeDetector ) {
this.registerBlocksAfterLeavingRestrictedArea();
this.unregisterBlocksBeforeEnteringRestrictedArea( {
currentTemplateId:
templateChangeDetector.getCurrentTemplateId() || '',
isPostOrPage: templateChangeDetector.getIsPostOrPage(),
} );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* External dependencies
*/
import { BlockConfiguration } from '@wordpress/blocks';
import { ProductGalleryBlockSettings } from '@woocommerce/blocks/product-gallery/settings';

/**
* Internal dependencies
*/
import productGalleryBlockMetadata from '../../../blocks/product-gallery/block.json';

export interface BlocksWithRestriction {
[ key: string ]: {
blockMetadata: Partial< BlockConfiguration >;
blockSettings: Partial< BlockConfiguration >;
allowedTemplates: {
[ key: string ]: boolean;
};
allowedTemplateParts: {
[ key: string ]: boolean;
};
availableInPostOrPageEditor: boolean;
isVariationBlock: boolean;
};
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error: `metadata` currently does not have a type definition in WordPress core
export const BLOCKS_WITH_RESTRICTION: BlocksWithRestriction = {
[ productGalleryBlockMetadata.name ]: {
blockMetadata: productGalleryBlockMetadata,
blockSettings: ProductGalleryBlockSettings,
allowedTemplates: {
'single-product': true,
},
allowedTemplateParts: {
'product-gallery': true,
},
availableInPostOrPageEditor: false,
isVariationBlock: false,
},
};
11 changes: 11 additions & 0 deletions assets/js/atomic/utils/blocks-registration-manager/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Internal dependencies
*/
import { BlockRegistrationManager } from './blocks-registration-manager';
import { TemplateChangeDetector } from './template-change-detector';

wp.domReady( () => {
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
const templateChangeDetector = new TemplateChangeDetector();
const blockRegistrationManager = new BlockRegistrationManager();
templateChangeDetector.add( blockRegistrationManager );
} );
Loading
Loading