Skip to content

Commit

Permalink
Fix DisableNonPageContentBlocks (#59297)
Browse files Browse the repository at this point in the history
* Fix DisableNonPageContentBlocks

- Updates DisableNonPageContentBlocks to only affect top level content.
  For example, a Featured Image within a Content block should remain as
  is.

- Refactors DisableNonPageContentBlocks to use a selector so that we can
  write unit tests for the logic.

* Use useSelect() approach instead of private selector

Co-authored-by: noisysocks <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: fabiankaegy <[email protected]>
Co-authored-by: andrewserong <[email protected]>
Co-authored-by: jsnajdr <[email protected]>
Co-authored-by: ramonjd <[email protected]>
Co-authored-by: kmanijak <[email protected]>
  • Loading branch information
8 people authored Feb 27, 2024
1 parent 33cd576 commit 1e22838
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 41 deletions.
5 changes: 0 additions & 5 deletions packages/editor/src/components/provider/constants.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,52 @@
* WordPress dependencies
*/
import { useSelect, useDispatch } from '@wordpress/data';
import {
useBlockEditingMode,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { useEffect } from '@wordpress/element';

/**
* Internal dependencies
*/
import { PAGE_CONTENT_BLOCK_TYPES } from './constants';
const PAGE_CONTENT_BLOCKS = [
'core/post-title',
'core/post-featured-image',
'core/post-content',
];

function useDisableNonPageContentBlocks() {
const contentIds = useSelect( ( select ) => {
const { getBlocksByName, getBlockParents, getBlockName } =
select( blockEditorStore );
return getBlocksByName( PAGE_CONTENT_BLOCKS ).filter( ( clientId ) =>
getBlockParents( clientId ).every( ( parentClientId ) => {
const parentBlockName = getBlockName( parentClientId );
return (
parentBlockName !== 'core/query' &&
! PAGE_CONTENT_BLOCKS.includes( parentBlockName )
);
} )
);
}, [] );

function DisableBlock( { clientId } ) {
const isDescendentOfQueryLoop = useSelect(
( select ) => {
const { getBlockParentsByBlockName } = select( blockEditorStore );
return (
getBlockParentsByBlockName( clientId, 'core/query' ).length !==
0
);
},
[ clientId ]
);
const mode = isDescendentOfQueryLoop ? undefined : 'contentOnly';
const { setBlockEditingMode, unsetBlockEditingMode } =
useDispatch( blockEditorStore );

useEffect( () => {
if ( mode ) {
setBlockEditingMode( clientId, mode );
return () => {
unsetBlockEditingMode( clientId );
};
setBlockEditingMode( '', 'disabled' ); // Disable editing at the root level.

for ( const contentId of contentIds ) {
setBlockEditingMode( contentId, 'contentOnly' ); // Re-enable each content block.
}
}, [ clientId, mode, setBlockEditingMode, unsetBlockEditingMode ] );
return () => {
unsetBlockEditingMode( '' );
for ( const contentId of contentIds ) {
unsetBlockEditingMode( contentId );
}
};
}, [ contentIds, setBlockEditingMode, unsetBlockEditingMode ] );
}

/**
* Component that when rendered, makes it so that the site editor allows only
* page content to be edited.
*/
export default function DisableNonPageContentBlocks() {
useBlockEditingMode( 'disabled' );
const clientIds = useSelect( ( select ) => {
return select( blockEditorStore ).getBlocksByName(
PAGE_CONTENT_BLOCK_TYPES
);
}, [] );

return clientIds.map( ( clientId ) => {
return <DisableBlock key={ clientId } clientId={ clientId } />;
} );
useDisableNonPageContentBlocks();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';

/**
* WordPress dependencies
*/
import { createRegistry, RegistryProvider } from '@wordpress/data';

/**
* Internal dependencies
*/
import DisableNonPageContentBlocks from '../disable-non-page-content-blocks';

describe( 'DisableNonPageContentBlocks', () => {
it( 'disables page content blocks', () => {
const testBlocks = {
0: 'core/template-part',
/**/ '00': 'core/site-title',
/**/ '01': 'core/navigation',
1: 'core/group',
/**/ 10: 'core/post-title',
/**/ 11: 'core/post-featured-image',
/**/ 12: 'core/post-content',
/**/ /**/ 120: 'core/paragraph',
/**/ /**/ 121: 'core/post-featured-image',
2: 'core/query',
/**/ 20: 'core/post-title',
/**/ 21: 'core/post-featured-image',
/**/ 22: 'core/post-content',
3: 'core/template-part',
/**/ 30: 'core/paragraph',
};

const setBlockEditingMode = jest.fn( () => ( {
type: 'SET_BLOCK_EDITING_MODE',
} ) );
const unsetBlockEditingMode = jest.fn( () => ( {
type: 'UNSET_BLOCK_EDITING_MODE',
} ) );

const registry = createRegistry( {
'core/block-editor': {
reducer: () => {},
selectors: {
getBlocksByName( state, blockNames ) {
return Object.keys( testBlocks ).filter( ( clientId ) =>
blockNames.includes( testBlocks[ clientId ] )
);
},
getBlockParents( state, clientId ) {
return clientId.slice( 0, -1 ).split( '' );
},
getBlockName( state, clientId ) {
return testBlocks[ clientId ];
},
},
actions: {
setBlockEditingMode,
unsetBlockEditingMode,
},
},
} );

const { unmount } = render(
<RegistryProvider value={ registry }>
<DisableNonPageContentBlocks />
</RegistryProvider>
);

expect( setBlockEditingMode.mock.calls ).toEqual( [
[ '', 'disabled' ], // root
[ '10', 'contentOnly' ], // post-title
[ '11', 'contentOnly' ], // post-featured-image
[ '12', 'contentOnly' ], // post-content
// NOT the post-featured-image nested within post-content
// NOT any of the content blocks within query
] );

unmount();

expect( unsetBlockEditingMode.mock.calls ).toEqual( [
[ '' ], // root
[ '10' ], // post-title
[ '11' ], // post-featured-image
[ '12' ], // post-content
] );
} );
} );

0 comments on commit 1e22838

Please sign in to comment.