Open tomjn opened 3 years ago
While investigating this, I devised a superior workaround:
import { addFilter } from '@wordpress/hooks';
import { select, dispatch, subscribe } from '@wordpress/data';
// Erase the existence of any reusable blocks.
subscribe( () => {
const settings = select( 'core/block-editor' ).getSettings();
if ( settings.__experimentalReusableBlocks && settings.__experimentalReusableBlocks.length > 0 ) {
dispatch('core/block-editor').updateSettings( { __experimentalReusableBlocks: [] } );
}
});
/**
* Remove supported features from all blocks
*
* @param {*} settings
* @param {*} name
*/
function filterBlockSupports( settings, name ) {
// ensure there is a supports section
if ( undefined === settings.supports ) {
settings.supports = {}
}
settings.supports.reusable = false;
return settings;
}
addFilter( 'blocks.registerBlockType', 'tomjn/disable-reusability', filterBlockSupports );
It doesn't fully disable all reusable blocks UI but it hide it from the inserter, and prevents new reusable blocks being created via the block toolbar menu
Hey @tomjn Tom I assume this would have to do with user roles. I believe @Mamaduka George has worked on another aspect of this.
I believe @Mamaduka George has worked on another aspect of this.
Which aspects, I can't recall anything š
LOL..:) I was thinking locking programatically by user role, but as you just mentioned for me on a direct message on Slack that is different compared to in general disabling Reusable blocks.
For some sites reusable blocks just don't make sense, and are a major liability.
This isn't a case of controlling who can and can't use/create/modify reusable blocks, although that would be a useful thing to have documented, it's about disabling it completely for all users in all forms.
I assume we should be able to turn off features like Reusable blocks and Patterns in the preferences panels. @ntsekouras
no I mean in code, not a user preference, but a site design decision or business requirement, this issue was not created to address a preference.
I should be able to completely disable reusable blocks such that the existence of the feature and ability to use it are not possible. Not disabling it for a user, session, or role, but for an entire site, in code.
This can already be done for other features using the add_theme_support
and remove_theme_support
, it should be possible for reusable blocks.
One thing that seems to at least hide the UI is unregistering the core/block
block type. Haven't tested this thoroughly though.
Any updates/progress on this?
It would be great to have this feature in the core.
I just wanted to note here that the need to disable pattern creation came up again in this week's Developer Hours session on pattern overrides. The idea is that certain users (perhaps designers) would be able to create patterns on a site, but lower-tiered users would only be able to use patterns, not create them.
When a user has pattern creation disabled, the "Edit original" should also be disabled.
I personally don't think we need a user preference for this. It should be a filter that a developer can apply, much like the other Editor curation mechanisms. I would love to see this prioritized for 6.7 š
Also wanted to flag this comment in relation to #55911 from @MadtownLems.
I think allowing customizations to theme-provided Patterns has potential for some sites, but can imagine plenty of environments (such as ours) where we wouldn't want to allow it. Hopefully that's the kind of thing that could be disabled via code. š¤
Since this is a big issue for tightly curated sites I did dig into this some more.
My specific use case is hiding patterns in the inserter as well as preventing pattern creation. But I do want the user to be able to use Overrides in Synced Patterns that got inserted by the admin.
As @tomjn said wp_blocks
reuses the post capabilities. But that only happens in map_meta_cap()
.
So what mostly works is going in even earlier and manipulating the capabilities on the registration of the wp_blocks
post type like this:
add_filter('register_post_type_args', function($args, $post_type){
if($post_type !== 'wp_block'){
return $args;
}
$args['capabilities']['create_posts'] = 'manage_options';
// We need to keep the general `edit_post` capability
// because otherwise the pattern can't even be seen if it was inserted by another user.
// $args['capabilities']['edit_posts'] = 'manage_options';
$args['capabilities']['edit_published_posts'] = 'manage_options';
$args['capabilities']['delete_published_posts'] = 'manage_options';
$args['capabilities']['delete_posts'] = 'manage_options';
$args['capabilities']['edit_others_posts'] = 'manage_options';
$args['capabilities']['delete_others_posts'] = 'manage_options';
return $args;
}, 10, 2);
This hides all the inserter and creation UI but displays the Synced Pattern so the user can edit the overrides.
But I've hit another problem then: For some reason on initial render patterns then show:
Block has been deleted or is unavailable.
Only when you focus the block or interact in any other way with the editor it shows.
I think I've narrowed this down to the fact that there first is a request to the one single block (42 is the post id of the synced pattern wp_block
post):
http://example.com/wp-json/wp/v2/blocks/42?context=edit&_locale=user
This is denied since for singular posts edit_published_posts
and edit_others_posts
is considered which we have denied.
Only later there is a request that queries all blocks, where only edit_posts
is checked so the same block is included:
http://example.com/wp-json/wp/v2/blocks?context=edit&per_page=100&_locale=user
And as soon as that goes through everything renders properly. Now this is mostly working, but the initial showing of an error isn't great UX.
I've tried to narrow this down to the originating code. Maybe it has something to with those two differing retrievals of block data:
But this is just guessing since what is going on overall is over my head right now. :)
What I did find out though is that simply calling
wp.data.select('core').getEntityRecords('postType', 'wp_block')
triggers the fetching of all blocks. So doing this anywhere after the block editor seems to make things work.
I know this is a workaround and not a solution, but since it seems to work for now and I don't have time to dig even deeper I'll leave this here anyway for anyone else wanting to build on top of my investigation.
I think I've narrowed this down to the fact that there first is a request to the one single block (42 is the post id of the synced pattern wp_block post) I've tried to narrow this down to the originating code. Maybe it has something to with those two differing retrievals of block data:
The second bit of code is only to determine when the 'Edit original' button on the block toolbar is shown.
It's likely related to the first bit of code, or the code just after that (the call to useEntityBlockEditor
). Maybe try logging out the values returned by those functions (record
, hasResolved
, blocks
) as the editor loads and when you focus the block. It looks like the first two values determine when 'Block has been deleted or is unavailable.' is shown and the blocks
value is used to render the blocks.
I also wonder if you'd need to override the 'read' capability for the post type (it's set to edit_posts
by default).
@talldan Thanks for looking into it! I probably won't find time to further investigate this soon, that is why I left what I found so maybe someone else can pick that up.
Concerning the overriding of read
. I think that won't help. If I restrict that (or edit_posts
for that matter) any further you end up with always getting the "Block has been deleted or is unavailable." I think the problem is that the code only really considers the cases of read&write or neither, but not the split case of read but not write since that only became relevant with pattern overrides.
This is very interesting. There is an ongoing effort to add more capabilities targeting Block Bindings. It's a very similar challenge to what @kraftner covered in https://github.com/WordPress/gutenberg/issues/28895#issuecomment-2306685540. How to offer a way to disable Block Bindings UI in the editor for less privileged users:
The initial approach that landed in the Gutenberg plugin:
It disables the UI when the following check is false: current_user_can( 'manage_options' )
. However, it isn't the most flexible approach even when folks can filter the editor setting canUpdateBlockBindings
using block_editor_settings_all
hook.
For some sites reusable blocks just don't make sense, and are a major liability.
This isn't a case of controlling who can and can't use/create/modify reusable blocks, although that would be a useful thing to have documented, it's about disabling it completely for all users in all forms.
Related to this - is there a way to limit Reusable Blocks or Patterns to specific post types?
@jbrck You may be able to limit Synced Patterns (formerly reusable blocks) by unregistering the core/block
block.
What problem does this address?
I'm working on a site that has users signing up and creating posts, but they can create insert and update reusable blocks. This allows them to bypass moderation, and modify other users posts via these blocks, etc, etc, it's a major headache
I've been trying to exterminate this feature, but I cannot hide the UI components, I cannot filter them, I can't disable them, remove support, etc
I thought I could remove the caapability from their roles, and it is implied this can be done on the .org dev site, but the
wp_block
post type reuses the post capabilities so I cannot target non-admin users.I can find no official method for removing this feature, be it totally or conditionally.
The closest I have found so far is to use
wp.data.dispatch('core/block-editor').updateSettings( { __experimentalReusableBlocks: [] } )
to fool the block editor into thinking there are no reusable blocks at the moment, then deliberately crashing on the save post hook if it matcheswp_block
.What is your proposed solution?
Implement capabilities for reusable blocks, and hide UI/UX if the current user does not have the capability to create/view/edit reeusable block posts.