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

On Locking and TemplateLocking #29864

Closed
Tracked by #29733
mtias opened this issue Mar 15, 2021 · 55 comments
Closed
Tracked by #29733

On Locking and TemplateLocking #29864

mtias opened this issue Mar 15, 2021 · 55 comments
Assignees
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Block Locking The API allowing for the ability to lock/unlock blocks [Feature] Blocks Overall functionality of blocks [Feature] List View Menu item in the top toolbar to select blocks from a list of links. Needs Design Feedback Needs general design feedback.

Comments

@mtias
Copy link
Member

mtias commented Mar 15, 2021

Background

The block editor has had template locking support since very early on. Template locking allowed to designate the original content templates (the ones you could use on custom post types) to prevent insertion or moving blocks. Inner blocks also has supported a templateLock attribute. This was extended in #26128 to be used directly in columns and group as attributes, not just as internal props of <InnerBlocks>.

Limitations

While powerful on its own, template locking has not offered too much granular control nor has the UI adapted to communicate different locking states.

With block themes, the necessity for locking down elements of the page is more pronounced. For example, it might be desirable that by default the "post-content" block of a single template is locked so that it cannot be removed. This extends to many other blocks and template parts in all sorts of ways.

Proposal

Let's establish a new block-level API representing lock status. This is in addition to templateLock. The lock attribute would allow control over what UI interactions are present.

Lock status needs to allow a few state options. A locked block could imply any or all of these:

  • Cannot be removed.
  • Cannot be moved.
  • Cannot be edited.
    • Worthwhile exploring (though complex) how specific attributes could be locked instead of the entire block. It might be better to keep this separate as a lockAttribute prop down the line.

While templateLock separately governs the inner blocks state (blocks cannot be added, etc).

This lock status can be toggled by the user. A user can choose to lock down a block so that they don't accidentally remove it, like on most design applications.

This could be represented in the UI as follows:

image

Note: block locking has nothing to do with capabilities for editing and it only governs interface controls.

If a block lock state is editable by the user, clicking on the "lock" icon should bring about a modal with the lock configuration. If only "remove" is locked, the movers and drag handle should remain and the lock indication should go somewhere else (in the ellipsis menu, for example.)

Lock status should be reflected in more places than just the Toolbar:

  • List View.
  • Block Inspector.

image

@mtias mtias added [Feature] Block API API that allows to express the block paradigm. [Feature] Blocks Overall functionality of blocks Needs Design Feedback Needs general design feedback. [Feature] List View Menu item in the top toolbar to select blocks from a list of links. labels Mar 15, 2021
@jameskoster
Copy link
Contributor

Making templates contextually un-removable and/or un-editable (attributes) will be crucial in establishing an intuitive experience as one moves between editing content / template 👍

Some more background on that (and rough concepts) can be found in #27848.

Cannot be moved.

This one feels especially tricky because the position of a block is always relative to those around it. Even if a block is position-locked to the top of the tree, it can still effectively be "moved" by re-positioning the blocks around it. Is this perhaps something that can only be applied to container blocks, and cascades down to all the innerblocks? IE everything is position-locked, or nothing is.

@mtias
Copy link
Member Author

mtias commented Mar 15, 2021

TemplateLocking already handles the disabling of moving for all children. I don't think it's much of an issue that you can move something by moving the things around it, that will always be the case. This is more about the peace of mind and reduced overhead of controls that you don't need.

@paaljoachim
Copy link
Contributor

paaljoachim commented Mar 30, 2021

I really like the iterations you made Matias!
Simple and straight forward.

I am wondering if it should contain a drop down of toggle options instead of a modal.
As one clicks the lock/unlock icon. A drop down is seen to where the administrator toggles various options on and off depending on what should be locked. Such as various levels of importance. Such as editing the block, moving, removing etc.

@nerrad
Copy link
Contributor

nerrad commented Jun 3, 2021

If a block lock state is editable by the user, clicking on the "lock" icon should bring about a modal with the lock configuration.

How would permissions governing editing block lock state be governed? It'd be nice if the API allowed for blocks to define the rules around that (either via user capability or programatically).

@senadir
Copy link
Contributor

senadir commented Jun 4, 2021

TemplateLocking already handles the disabling of moving for all children. I don't think it's much of an issue that you can move something by moving the things around it, that will always be the case. This is more about the peace of mind and reduced overhead of controls that you don't need.

One good case I see for disabling moving is that if you lock 2+ blocks, they're always relatively on the same position, in our example (Checkout block), we always need the contact information section to be before address section, or the address section to be before the shipping options, locking them would prevent people from switching and creating a broken UX but still allow them to insert stuff between.

@senadir
Copy link
Contributor

senadir commented Jun 4, 2021

@mtias I started working on this yesterday, I'm going to tackle this by parts instead of all at once in a single PR.

Currently, the API lives on the supports level, with this shape

supports: {
  lock: {
    remove: true | false | 'user',
    move: true | false | 'user',
    edit: true | false | 'user',
  }
}

The values, if not set, would inherit the parent templateLock attribute.

One issue I'm not sure about is editing and how we intend to prevent this, it seems to be something on the block implementation side of things, not on block editor side. Moving and removing are done to the whole block at the data store level. Editing is done on parts of the block at the block level, best you can do is prevent setAttributes update from propagating or wrapping the whole block in a Disabled so users can't interact with it, but this would still leave settings accessible.
All what we can do here is indicate to the block that the user has chosen to lock this block and the block has to honor its value.

The second question is where should this live, should it be on the Block type level (like the above example) or the instance level (block level)?

I can see the see that having this on the block type level would be the equivalence of locked by system in your example, while locking on the block level would be locked by user type of thing.

@jameskoster
Copy link
Contributor

Sharing a couple of issues (with designs) here that may be relevant to the edit implementation.

In #31461 the contents of blocks like the Post Title should be locked when editing a template.

Similarly, in #32317 the contents of blocks like the Post Title should be locked when inside a Query block.

At a high level the edit-ability of the contents of these blocks boils down to whether the scope is local or not. If the source is outside of the immediate editing context then the block contents should be locked. I don't know if that can be built in to the API but I figured it was worth sharing.

@senadir
Copy link
Contributor

senadir commented Jun 4, 2021

This PR is an iteration of this issue
#32457

@jorgefilipecosta
Copy link
Member

One issue I'm not sure about is editing and how we intend to prevent this, it seems to be something on the block implementation side of things, not on block editor side.

If we could have edit locking as a general thing instead of a block-specific implementation it would have some advantages. For example, post-content may have multiple blocks inside and have an edit locking the edit locking should affect all the blocks inside even if they don't implement an edit lock. A general solution may be having the editor put an invisible overlay to make things unclickable and have something catch the focus so changing with the keyboard is also not an option.

@senadir
Copy link
Contributor

senadir commented Jun 9, 2021

A general solution may be having the editor put an invisible overlay to make things unclickable and have something catch the focus so changing with the keyboard is also not an option.

We use <Disabled> to prevent interactions but this still doesn't prevent settings from showing up in the sidebar, do you want to prevent both?

@jorgefilipecosta
Copy link
Member

We use to prevent interactions but this still doesn't prevent settings from showing up in the sidebar, do you want to prevent both?

I guess if we add a general API to the core the slot fills of the sidebar and toolbar would not render if the block is disabled.

But at the start, we may opt for a block-specific implementation as you referred using disabled and a condition to not render sidebar and toolbar. This solution is simple and also covers the child block case because with one can not select the child blocks.

@gaambo
Copy link
Contributor

gaambo commented Mar 15, 2022

L. by system: this means the block is locked but the user doesn't have permissions to change that state. These permissions could come from user roles & capabilities or by flags in theme.json (which could also be based on roles or capabilities).

For building custom themes this is very important. Right now we're using patterns with lock-attributes + templateLock-attributes to allow the editors to insert specific rows/sections which were designed in this specific way. So in this case, the lock-UI should not be visible. This could also be handled by a specific capability (probably to complicated). But I think there needs to be some way to lock use the block-locking in a programmatic way only and disable the lock-UI.
I'm wondering how granular this control should be. If there's a flag in theme.json it disables the lock-UI for alle blocks. Maybe have the lock attribute have another property allow_change or something? So each pattern/template which uses block-locking can define if it's a "system" lock or not.

@Mamaduka
Copy link
Member

Locked by System

The easiest way to implement this restriction is to use block editor settings. It will be enabled by default but will give developers the flexibility to toggle the feature as they see fit.

We can also support passing value from the theme.json.

Examples

add_filter(
	'block_editor_settings_all',
	static function( $settings, $context ) {
		// Allow for the Editor role and above.
		$settings['__experimentalAllowBlockLock'] = current_user_can( 'delete_others_posts' );

		// Disable for Pages.
		if ( $context->post && $context->post->post_type === 'page' ) {
			$settings['__experimentalAllowBlockLock'] = false;
		}
		
		// Only enable for specific user(s).
		$user = wp_get_current_user();
		$settings['__experimentalAllowBlockLock'] = $user->ID === 1;


		return $settings;
	},
	10,
	2
);

@senadir
Copy link
Contributor

senadir commented Mar 15, 2022

This implementation of locked by system seems to reflect the ability to access locking on all blocks. This doesn't offer any options at all, you can either lock/unlock all blocks or nothing.

Shouldn't system locking be a bit granular than this? on a block type level?

@Mamaduka
Copy link
Member

@senadir I think we can also include your original suggestion about block level settings.

Locking on a system level would be that locking is defined on the attribute level lock.move and there's maybe another attribute allowUserLocking or support.userLocking that would show/prevent locking behavior.

@mtias what do you think?

@fabiankaegy
Copy link
Member

@Mamaduka I like the idea with presenting the global setting that way. Especially the Idea to do it via the php filter because often times it really needs to be dependent on a user role or on a specific user id. Which is not something that would be possible in theme.json alone.

And yeah allowing this setting again on a per block basis in the block_editor_settings would also be quite interesting. That way you could open up some blocks but leave others locked. Which I can see being very useful.

@Mamaduka
Copy link
Member

And yeah allowing this setting again on a per block basis in the block_editor_settings would also be quite interesting. That way you could open up some blocks but leave others locked. Which I can see being very useful.

Using block supports for this makes more sense to me. Blocks can define if locking UI should be available for them like @senadir suggested.

@Mamaduka
Copy link
Member

I create a new PR for system lock settings - #39566.

@Mamaduka
Copy link
Member

@critterverse, I plan to continue work started in #32710 and add edit locking support for Reusable Blocks.

Should blocks have any other indicators that editing is disabled besides the lock icon? I'm asking this because when UI is disabled, it might be confusing why the user can't edit block.

@critterverse
Copy link
Contributor

I plan to continue work started in #32710 and add edit locking support for Reusable Blocks.

Nice! For user locking, we could include the “restrict editing” option in the modal for Reusable blocks:

Locking

Once locked, are we thinking it would work like #32710 (comment) where you can’t select the inner blocks?

It seems like the clickthrough overlay could be really helpful here. Just a thought but I wonder if it could work slightly differently when editing is locked. For example, rather than an overlay effect on hover and the first click "unlocking" access to the inner contents, maybe the hover overlay (with no clickthrough) could remain even after selecting the Reusable block.

@Mamaduka
Copy link
Member

That's an interesting idea. So I will start with that, and let's see how it works in practice.

@critterverse
Copy link
Contributor

@Mamaduka It could be nice to start minimal and see if the clickthrough or anything else is needed from there!

@Mamaduka
Copy link
Member

Mamaduka commented Apr 3, 2022

Hi, folks

I started working on the edit Locking ability for the Reusable Blocks. You can follow the progress in this PR - #39950.

Cc @syedbalkhi

@carolinan carolinan added the [Feature] Block Locking The API allowing for the ability to lock/unlock blocks label Apr 19, 2022
@Mamaduka
Copy link
Member

Mamaduka commented Apr 20, 2022

A summary based on the Block edit locking discussion from the #core-editor Slack channel (needs login):

  • The general feeling is that the feature should be available for all blocks, not restricted to Reusable.
  • We need a generic method to disable editing. For example, the content overlay treatment might not work for every block.
  • The disabled content must be equally accessible as any other content on the page.

With this in mind, and considering issues we're facing with content overlay, I want to propose removing Reusable block edit locking from WP 6.0 release. Continue the feature development in the plugin and ship it with the next release.

@adamziel
Copy link
Contributor

@Mamaduka I agree, let's punt block editing locking to the next release. Would you please prepare a PR for that?

@Mamaduka
Copy link
Member

@mtias, can we close this issue?

@mtias mtias closed this as completed Oct 5, 2022
@MadtownLems
Copy link

I'd like to help make a case for the ability prevent editing of any block, whether reusable or not.

We run networks of sites for educators who aren't "web designers", but still have Site Administrator levels of access on their sites. We'd love for the ability to easily lock a section of their page content so they can't break it - even accidentally!

Another potential use of this is MultiSite where only Network Administrators have access to unfiltered_html. If we could lock block CONTENT, we'd be able to do things like easily put iframes or custom scripts onto a page via Custom HTML block, then lock it. This could allow the Site Administrator the ability to manage all the content AROUND our Custom HTML block without breaking it when they save the page (and scripts/iframes get stripped).

@mtias
Copy link
Member Author

mtias commented Jun 2, 2023

@MadtownLems that should be possible already for any container block. Isn't that the case for you or is the use case a bit different?

@MadtownLems
Copy link

Was this functionality added in 6.2? If so, I haven't had a chance to test yet. My comment was from 6.1

@mtias
Copy link
Member Author

mtias commented Jun 2, 2023

Locking on any block has been there for a while, but maybe I misunderstood the question — did you mean for locking to also prevent content editing here?

image

@MadtownLems
Copy link

did you mean for locking to also prevent content editing here?

Yes, exactly. To clarify the use case:
MultiSite, where only Network Administrators can do things like use iframes. If a Network Administrator puts an iframe on a page, and then a normal Site Administrator edits it, the iframe will get stripped out.

We'd love to be able to have Network Administrators add things like a Custom HTML block to a page (that includes an iframe, script, etc) - then Lock the content. In an ideal world, a Site Administrator wouldn't be able to unlock it (that part is easy enough), but would still be able to make edits to the rest of the page without worrying about the locked content being modified or stripped away in any way.

@mtias
Copy link
Member Author

mtias commented Jun 2, 2023

Got it, I think a full content lock would be a nice and easy addition to the API. Would you mind opening a new issue describing your use case?

@Zilero232
Copy link

How can I block a custom block so that it cannot be added to the group?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Block Locking The API allowing for the ability to lock/unlock blocks [Feature] Blocks Overall functionality of blocks [Feature] List View Menu item in the top toolbar to select blocks from a list of links. Needs Design Feedback Needs general design feedback.
Projects
None yet
Development

No branches or pull requests