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

Fix: Restrict block insert, move, and replace attending to allowedBlocks, locking, and child blocks #14003

Conversation

jorgefilipecosta
Copy link
Member

@jorgefilipecosta jorgefilipecosta commented Feb 21, 2019

Supersedes: https://github.com/WordPress/gutenberg/pull/7301/files
Uses the select control implemented in #13924.
This PR changes the action creators to be a generator and have all the required validations before yielding the action.

Fixes: #14568;
Fixes: #10186;
Fixes: #13099;

Missing the update to the unit tests.

How has this been tested?

Test block: gist.github.com/jorgefilipecosta/b7194daac3ce26827522694fb4252c1c#file-testallowedblocksmiddleware-js

I pasted the test block referred in the browser console.
I added the Product block.
I verified I cannot move using drag & drop the Buy button out of the Product block. (child block restriction.
I verified I cannot move using drag & drop a paragraph created outside of the Product block inside the product block. (allowed blocks restriction).
I verified that if I press enter in the buy button or image inside the product block, a paragraph is not created (allowed blocks restriction).
I added two galleries outside the product block, multi-selected them, and copied them ( ctrl + c ), I pasted them inside the list block inside the Product block and I verified they were not added (allowed blocks restriction).

I verified that when we have a template lock and we press enter on the title we now do not insert unallowed blocks.
Template lock code:

add_filter( 'allowed_block_types', function( $allowed_block_types, $post ) {
	if ( $post->post_type === 'post' ) {
	    return $allowed_block_types;
	}
	return [ 'core/image', 'core/button' ];
}, 10, 2 );

I verified that if we disable the paragraph, e.g., with a filter or inside the test block, pressing enter on the title or in placeholders does not add paragraph blocks. Pressing the sibling inserter also does not insert the paragraph (PR #7226).
Code to disable paragraph:

function myplugin_register_book_lock_post_type() {
    $args = array(
        'public' => true,
	  	'template_lock' => 'all',
        'label'  => 'Books Lock',
        'show_in_rest' => true,
        'template' => array(
            array( 'core/image', array(
            ) ),
            array( 'core/heading', array(
                'placeholder' => 'Add Author...',
            ) ),
            array( 'core/paragraph', array(
                'placeholder' => 'Add Description...',
            ) ),
        ),
    );
    register_post_type( 'book_lock', $args );
}
add_action( 'init', 'myplugin_register_book_lock_post_type' );

I added two image blocks, multi-selected them, copied them and tried to paste them on the list inside the test block. I checked the image blocks were not added inside the test block.

All these actions are possible in master.

Todo: If we accept this approach, end 2 end tests will be created before the merge that replicate this manual tests.

@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from 98a3794 to 16bd0e7 Compare February 26, 2019 22:19
@jorgefilipecosta jorgefilipecosta marked this pull request as ready for review February 26, 2019 22:20
@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from 16bd0e7 to 7cd4cac Compare February 27, 2019 09:03
@jorgefilipecosta jorgefilipecosta added the [Feature] Inserter The main way to insert blocks using the + button in the editing interface label Feb 27, 2019
@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from 7cd4cac to fd4a3b1 Compare February 27, 2019 12:07
@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch 3 times, most recently from eff4d12 to 73cb181 Compare March 4, 2019 13:36
@jorgefilipecosta jorgefilipecosta requested a review from a team March 5, 2019 09:14
@gziolo gziolo added this to the 5.3 (Gutenberg) milestone Mar 11, 2019
@youknowriad youknowriad removed this from the 5.3 (Gutenberg) milestone Mar 18, 2019
@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from 73cb181 to e113599 Compare March 18, 2019 18:19
first( clientIds )
);
// Replace is valid if the new blocks can be inserted in the root block
// or if we had a block of the same type in the position of the block being replaced.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or if we had a block of the same type in the position of the block being replaced.

Is there an occasion of this you had in mind that led you to implement this exception? It's not clear to me for what reason we'd want it, and it adds some complexity to the implementation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @aduth,
Initially, I followed your suggestion, but on a second thought, I think the condition has some benefits for the merging of blocks.
In the following gist we see a sample block with InnerBlocks:
https://gist.github.com/jorgefilipecosta/6d8c1620b46d916d8a16a23e730a2ab6

If we have this condition the user can merge paragraphs by pressing backspace or delete. Without this condition, merge is not possible. But the same result is possible to achieve by removing a paragraph and appending its content to the content of another paragraph -- So I think merging should be possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the following gist we see a sample block with InnerBlocks:
https://gist.github.com/jorgefilipecosta/6d8c1620b46d916d8a16a23e730a2ab6

This seems like an invalid use of InnerBlocks, by the fact the template contains blocks not valid per allowedBlocks. At the very least, we shouldn't optimize to anticipate this use-case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @aduth there are InnerBlocks scenarios where I expect this situation to happen.
For example, I just want to allow a maximum of 3 headings inside my InnerBlocks area. The way to implement this restriction would be remove heading from the allowed blocks if we already have 3 headings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I agree even this last scenario I referred is not normal and maybe something we should not optimize for.
I thought replacements would be needed to paste a block in the same position as an existing block. Paste HTML heading in a heading block, but that's not the case. I will reflect a little bit to make sure I'm not missing anything but I find don't any "normal" case I will simplify the logic.

@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from e113599 to 0f15475 Compare March 19, 2019 10:22
@jorgefilipecosta jorgefilipecosta added the [Status] In Progress Tracking issues with work in progress label Mar 19, 2019
@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from 0f15475 to f30c84a Compare March 19, 2019 17:39
@jorgefilipecosta
Copy link
Member Author

This PR was updated after the PR's it depended on were merged and is ready for a new look.

@jorgefilipecosta jorgefilipecosta removed the [Status] In Progress Tracking issues with work in progress label Mar 19, 2019
@aduth
Copy link
Member

aduth commented Mar 27, 2019

Noting some overlap between this and #14594 , cc @nerrad (specifically ensureDefaultBlock refactor).

@@ -201,16 +220,41 @@ export function toggleSelection( isSelectionEnabled = true ) {
*
* @param {(string|string[])} clientIds Block client ID(s) to replace.
* @param {(Object|Object[])} blocks Replacement block(s).
*
* @return {Object} Action object.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yields is available as a valid substitute in JSDoc.

http://usejsdoc.org/tags-yields.html

first( clientIds )
);
// Replace is valid if the new blocks can be inserted in the root block
// or if we had a block of the same type in the position of the block being replaced.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the following gist we see a sample block with InnerBlocks:
https://gist.github.com/jorgefilipecosta/6d8c1620b46d916d8a16a23e730a2ab6

This seems like an invalid use of InnerBlocks, by the fact the template contains blocks not valid per allowedBlocks. At the very least, we shouldn't optimize to anticipate this use-case.


// If moving to other parent block, the move is possible if we can insert a block of the same type inside the new parent block.
if ( canInsertBlock ) {
return action;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we yield, not return? Unclear to me what behavior is expected from redux-routine for the return.

packages/block-editor/src/store/actions.js Show resolved Hide resolved
blocks = castArray( blocks );
const allowedBlocks = [];
for ( const block of blocks ) {
if ( block ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there falsey entries in blocks ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it is never falsey, I updated the code to remove this check.

@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from f30c84a to cb87da3 Compare March 28, 2019 13:12
@jorgefilipecosta
Copy link
Member Author

Hi @aduth thank you for the review, I updated the code to follow your suggestions.

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions, but functionally this works well in my testing.

Your "fixes" syntax from the original comment will not auto-close all the related issues. It would need to be separate individual "Fixes" one-per-line.

type: 'MOVE_BLOCK_TO_POSITION',
fromRootClientId,
toRootClientId,
clientId,
index,
};
// If moving inside the same root block the move is always possible.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too seems contrary in the same sense as #14003 (comment) , and it could produce simpler code to avoid specialized conditions. I could see an argument being made that this helps as an optimized majority case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @aduth although this could be seen as optimization as the majority of cases will return here, this is also required.
The case this covers is locking=insert, in that case, we can not insert blocks but we can move the blocks, canInsertBlockType will return false but the move is in fact possible. Without this condition when locking = insert we would not be able to move the blocks as expected.

fromRootClientId
);

// If locking is equal to all on the original clientId (fromRootClientId),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locking is checked in canInsertBlockType, considered later in the function. Do we need to duplicate the check here as well, or could this condition be removed and it work just as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we need this condition -- If the user is moving the block from a parent with locking=all to a block without locking, canInsertBlockType will return true, but the move is not possible.

* in actions which may result in no blocks remaining in the editor (removal,
* replacement, etc).
*/
function* ensureDefaultBlock() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given #14754 and the possibility we may want to try to find a different way to "ensure" the default block, I think it's wise to not expose this as an exported action (i.e. as-is).

@jorgefilipecosta jorgefilipecosta force-pushed the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch from cb87da3 to 1252d77 Compare April 3, 2019 13:31
@jorgefilipecosta
Copy link
Member Author

Thank you for the reviews, if there is anything I missed feel free to comment and I will iterate on this.

@jorgefilipecosta jorgefilipecosta merged commit 2205f00 into master Apr 3, 2019
@jorgefilipecosta jorgefilipecosta deleted the fix/correctly-restrict-block-insert-move-and-replace-attending-to-allowed-blocks-locking-and-child-blocks branch April 3, 2019 14:44
@youknowriad youknowriad added the [Type] Bug An existing feature does not function as intended label Apr 12, 2019
@youknowriad youknowriad added this to the 5.5 (Gutenberg) milestone Apr 12, 2019
aduth pushed a commit that referenced this pull request Apr 16, 2019
…cks, locking, and child blocks (#14003)

Supersedes: https://github.com/WordPress/gutenberg/pull/7301/files
Uses the select control implemented in #13924.
This PR changes the action creators to be a generator and have all the required validations before yielding the action.

Fixes: #14568;
Fixes: #10186;
Fixes: #13099;

Missing the update to the unit tests.

## How has this been tested?
Test block: [gist.github.com/jorgefilipecosta/b7194daac3ce26827522694fb4252c1c#file-testallowedblocksmiddleware-js](https://gist.github.com/jorgefilipecosta/b7194daac3ce26827522694fb4252c1c#file-testallowedblocksmiddleware-js)

I pasted the test block referred in the browser console.
I added the Product block.
I verified I cannot move using drag & drop the Buy button out of the Product block. (child block restriction.
I verified I cannot move using drag & drop a paragraph created outside of the Product block inside the product block. (allowed blocks restriction).
I verified that if I press enter in the buy button or image inside the product block, a paragraph is not created (allowed blocks restriction).
I added two galleries outside the product block, multi-selected them, and copied them ( ctrl + c ), I pasted them inside the list block inside the Product block and I verified they were not added (allowed blocks restriction).

I verified that when we have a template lock and we press enter on the title we now do not insert unallowed blocks.
Template lock code:

```
add_filter( 'allowed_block_types', function( $allowed_block_types, $post ) {
	if ( $post->post_type === 'post' ) {
	    return $allowed_block_types;
	}
	return [ 'core/image', 'core/button' ];
}, 10, 2 );
```
I verified that if we disable the paragraph, e.g., with a filter or inside the test block, pressing enter on the title or in placeholders does not add paragraph blocks. Pressing the sibling inserter also does not insert the paragraph (PR #7226).
Code to disable paragraph:

```
function myplugin_register_book_lock_post_type() {
    $args = array(
        'public' => true,
	  	'template_lock' => 'all',
        'label'  => 'Books Lock',
        'show_in_rest' => true,
        'template' => array(
            array( 'core/image', array(
            ) ),
            array( 'core/heading', array(
                'placeholder' => 'Add Author...',
            ) ),
            array( 'core/paragraph', array(
                'placeholder' => 'Add Description...',
            ) ),
        ),
    );
    register_post_type( 'book_lock', $args );
}
add_action( 'init', 'myplugin_register_book_lock_post_type' );
```
I added two image blocks, multi-selected them, copied them and tried to paste them on the list inside the test block. I checked the image blocks were not added inside the test block.

All these actions are possible in master.

Todo: If we accept this approach, end 2 end tests will be created before the merge that replicate this manual tests.
aduth pushed a commit that referenced this pull request Apr 16, 2019
…cks, locking, and child blocks (#14003)

Supersedes: https://github.com/WordPress/gutenberg/pull/7301/files
Uses the select control implemented in #13924.
This PR changes the action creators to be a generator and have all the required validations before yielding the action.

Fixes: #14568;
Fixes: #10186;
Fixes: #13099;

Missing the update to the unit tests.

## How has this been tested?
Test block: [gist.github.com/jorgefilipecosta/b7194daac3ce26827522694fb4252c1c#file-testallowedblocksmiddleware-js](https://gist.github.com/jorgefilipecosta/b7194daac3ce26827522694fb4252c1c#file-testallowedblocksmiddleware-js)

I pasted the test block referred in the browser console.
I added the Product block.
I verified I cannot move using drag & drop the Buy button out of the Product block. (child block restriction.
I verified I cannot move using drag & drop a paragraph created outside of the Product block inside the product block. (allowed blocks restriction).
I verified that if I press enter in the buy button or image inside the product block, a paragraph is not created (allowed blocks restriction).
I added two galleries outside the product block, multi-selected them, and copied them ( ctrl + c ), I pasted them inside the list block inside the Product block and I verified they were not added (allowed blocks restriction).

I verified that when we have a template lock and we press enter on the title we now do not insert unallowed blocks.
Template lock code:

```
add_filter( 'allowed_block_types', function( $allowed_block_types, $post ) {
	if ( $post->post_type === 'post' ) {
	    return $allowed_block_types;
	}
	return [ 'core/image', 'core/button' ];
}, 10, 2 );
```
I verified that if we disable the paragraph, e.g., with a filter or inside the test block, pressing enter on the title or in placeholders does not add paragraph blocks. Pressing the sibling inserter also does not insert the paragraph (PR #7226).
Code to disable paragraph:

```
function myplugin_register_book_lock_post_type() {
    $args = array(
        'public' => true,
	  	'template_lock' => 'all',
        'label'  => 'Books Lock',
        'show_in_rest' => true,
        'template' => array(
            array( 'core/image', array(
            ) ),
            array( 'core/heading', array(
                'placeholder' => 'Add Author...',
            ) ),
            array( 'core/paragraph', array(
                'placeholder' => 'Add Description...',
            ) ),
        ),
    );
    register_post_type( 'book_lock', $args );
}
add_action( 'init', 'myplugin_register_book_lock_post_type' );
```
I added two image blocks, multi-selected them, copied them and tried to paste them on the list inside the test block. I checked the image blocks were not added inside the test block.

All these actions are possible in master.

Todo: If we accept this approach, end 2 end tests will be created before the merge that replicate this manual tests.
This was referenced Apr 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Inserter The main way to insert blocks using the + button in the editing interface [Type] Bug An existing feature does not function as intended
Projects
None yet
4 participants