Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patterns: ability to disable creation of patterns for certain roles/permissions #28895

Open
tomjn opened this issue Feb 9, 2021 · 18 comments
Open
Labels
[Feature] Extensibility The ability to extend blocks or the editing experience [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Type] Enhancement A suggestion for improvement.

Comments

@tomjn
Copy link
Contributor

tomjn commented Feb 9, 2021

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 matches wp_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.

@gziolo gziolo added the [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) label Feb 10, 2021
@tomjn
Copy link
Contributor Author

tomjn commented Feb 11, 2021

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

@mtias mtias added the [Feature] Extensibility The ability to extend blocks or the editing experience label Feb 11, 2021
@paaljoachim
Copy link
Contributor

Hey @tomjn Tom
I assume this would have to do with user roles.
I believe @Mamaduka George has worked on another aspect of this.

@Mamaduka
Copy link
Member

Mamaduka commented Apr 3, 2022

I believe @Mamaduka George has worked on another aspect of this.

Which aspects, I can't recall anything 😅

@paaljoachim
Copy link
Contributor

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.

@tomjn
Copy link
Contributor Author

tomjn commented Apr 3, 2022

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.

@paaljoachim
Copy link
Contributor

I assume we should be able to turn off features like Reusable blocks and Patterns in the preferences panels. @ntsekouras

@tomjn
Copy link
Contributor Author

tomjn commented Apr 3, 2022

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.

@kraftner
Copy link

One thing that seems to at least hide the UI is unregistering the core/block block type. Haven't tested this thoroughly though.

@jordesign jordesign added the [Type] Enhancement A suggestion for improvement. label Sep 8, 2023
@jordesign jordesign changed the title Ability to disable reusable blocks Patterns: ability to disable creation of patterns for certain roles/permissions Sep 8, 2023
@brown-a2
Copy link

Any updates/progress on this?

@dashkevych
Copy link

It would be great to have this feature in the core.

@ndiego
Copy link
Member

ndiego commented Jun 14, 2024

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.

image

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 🙏

@talldan
Copy link
Contributor

talldan commented Jun 19, 2024

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

@kraftner
Copy link

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:

const { record, hasResolved } = useEntityRecord(
'postType',
'wp_block',
ref
);

const canUserEdit = useSelect(
( select ) =>
!! select( coreStore ).canUser( 'update', {
kind: 'postType',
name: 'wp_block',
id: recordId,
} ),
[ recordId ]
);

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.

@talldan
Copy link
Contributor

talldan commented Aug 26, 2024

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

@kraftner
Copy link

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

@gziolo
Copy link
Member

gziolo commented Sep 9, 2024

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 #28895 (comment). 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.

@jbrck
Copy link

jbrck commented Oct 3, 2024

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?

@talldan
Copy link
Contributor

talldan commented Oct 8, 2024

@jbrck You may be able to limit Synced Patterns (formerly reusable blocks) by unregistering the core/block block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Extensibility The ability to extend blocks or the editing experience [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Type] Enhancement A suggestion for improvement.
Projects
Status: Needs discussion
Status: No status
Development

No branches or pull requests