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

Edit Site: Add convert to template part flow. #20445

Merged
merged 10 commits into from
Oct 23, 2020

Conversation

epiqueras
Copy link
Contributor

Description

This PR makes it possible to select and convert blocks to a template part in the site editor, similar to how it works for the group and reusable blocks.

It also fixes the breakage that G2 introduced to the block toolbar within the site editor.

How has this been tested?

It was verified that selecting blocks in the site editor, clicking on the block toolbar's settings dropdown, and selecting the option to make a template part, creates a template part with the chosen blocks after inserting the new template part's name and theme.

Screenshots

gif

Types of Changes

New Feature: The site editor now has a button in the block toolbar's settings dropdown for converting a selection of blocks into a template part.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@github-actions
Copy link

github-actions bot commented Feb 25, 2020

Size Change: +253 B (0%)

Total Size: 1.2 MB

Filename Size Change
build/block-library/index.js 145 kB +76 B (0%)
build/edit-site/index.js 22.2 kB +177 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.54 kB 0 B
build/api-fetch/index.js 3.35 kB 0 B
build/autop/index.js 2.72 kB 0 B
build/blob/index.js 667 B 0 B
build/block-directory/index.js 8.59 kB 0 B
build/block-directory/style-rtl.css 943 B 0 B
build/block-directory/style.css 942 B 0 B
build/block-editor/index.js 130 kB 0 B
build/block-editor/style-rtl.css 11 kB 0 B
build/block-editor/style.css 11 kB 0 B
build/block-library/editor-rtl.css 8.93 kB 0 B
build/block-library/editor.css 8.93 kB 0 B
build/block-library/style-rtl.css 7.75 kB 0 B
build/block-library/style.css 7.75 kB 0 B
build/block-library/theme-rtl.css 741 B 0 B
build/block-library/theme.css 741 B 0 B
build/block-serialization-default-parser/index.js 1.77 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 47.6 kB 0 B
build/components/index.js 171 kB 0 B
build/components/style-rtl.css 15.4 kB 0 B
build/components/style.css 15.4 kB 0 B
build/compose/index.js 9.63 kB 0 B
build/core-data/index.js 12.1 kB 0 B
build/data-controls/index.js 684 B 0 B
build/data/index.js 8.63 kB 0 B
build/date/index.js 31.9 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 569 B 0 B
build/dom/index.js 4.43 kB 0 B
build/edit-navigation/index.js 10.8 kB 0 B
build/edit-navigation/style-rtl.css 881 B 0 B
build/edit-navigation/style.css 885 B 0 B
build/edit-post/index.js 306 kB 0 B
build/edit-post/style-rtl.css 6.37 kB 0 B
build/edit-post/style.css 6.35 kB 0 B
build/edit-site/style-rtl.css 3.79 kB 0 B
build/edit-site/style.css 3.79 kB 0 B
build/edit-widgets/index.js 26.6 kB 0 B
build/edit-widgets/style-rtl.css 3.09 kB 0 B
build/edit-widgets/style.css 3.09 kB 0 B
build/editor/editor-styles-rtl.css 480 B 0 B
build/editor/editor-styles.css 482 B 0 B
build/editor/index.js 42.6 kB 0 B
build/editor/style-rtl.css 3.85 kB 0 B
build/editor/style.css 3.84 kB 0 B
build/element/index.js 4.45 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.49 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 1.74 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.54 kB 0 B
build/is-shallow-equal/index.js 709 B 0 B
build/keyboard-shortcuts/index.js 2.39 kB 0 B
build/keycodes/index.js 1.85 kB 0 B
build/list-reusable-blocks/index.js 3.02 kB 0 B
build/list-reusable-blocks/style-rtl.css 476 B 0 B
build/list-reusable-blocks/style.css 476 B 0 B
build/media-utils/index.js 5.12 kB 0 B
build/notices/index.js 1.69 kB 0 B
build/nux/index.js 3.27 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.45 kB 0 B
build/primitives/index.js 1.35 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/reusable-blocks/index.js 3.06 kB 0 B
build/rich-text/index.js 13 kB 0 B
build/server-side-render/index.js 2.61 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.24 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.75 kB 0 B
build/warning/index.js 1.13 kB 0 B
build/wordcount/index.js 1.23 kB 0 B

compressed-size-action

@mtias
Copy link
Member

mtias commented Feb 25, 2020

This is great. It starts to tie in experiences that were laid back with reusable blocks. I expect this to be a very common way to build a theme or template — start by designing with blocks, then group the pieces that make sense for different template parts.

@mtias mtias added the Needs Design Feedback Needs general design feedback. label Feb 25, 2020
Copy link
Member

@noahtallen noahtallen left a comment

Choose a reason for hiding this comment

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

just some thoughts and questions. It also needs rebased and tested locally again, but I'm sure you already know that ;)

@@ -14,7 +14,8 @@ export default function TemplatePartInnerBlocks() {
);
return (
<InnerBlocks
__experimentalBlocks={ blocks }
// Allow initial blocks from a block transform to load, if any.
__experimentalBlocks={ blocks.length === 0 ? undefined : blocks }
Copy link
Member

Choose a reason for hiding this comment

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

this should be value={ } now :) I'm also not sure if it's still needed with the latest block sync changes

@@ -730,6 +730,7 @@ _Parameters_

- _blocks_ `(Array|Object)`: Blocks array or block object.
- _name_ `string`: Block name.
- _isGroupingBlock_ `boolean`: Set to true to bypass default grouping block selection.
Copy link
Member

Choose a reason for hiding this comment

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

What does this do? Is bock transform normally wrapped by a group block or something?

import { switchToBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

export default function TemplatePartConverter() {
Copy link
Member

Choose a reason for hiding this comment

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

Should this live in the block-editor package? It seems like it would fit well there, since it's basically part of the block menu. (maybe we could then provide a mechanism to turn it off for the post editor?)

Copy link
Contributor

Choose a reason for hiding this comment

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

I would assume that if we want this in both editors (site and post) when FSE is enabled, that this would be better in block-editor as well. However, if it doesn't belong in the post editor I would think this is a fitting location for it? (asked about this below)

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the idea is to keep it edit-site only (for now at least). Id say edit-site package makes sense, and we can move it over to block-editor if things change and we want this in the post editor as well.

@MichaelArestad
Copy link
Contributor

I dig this. We can change the text from "template part" to whatever we decide to call them. I know I'm leaning toward "Section".

@mtias
Copy link
Member

mtias commented Jun 24, 2020

@MichaelArestad would we still call it "section" if it's something like just a navigation menu, or a list of social icons?

@MichaelArestad
Copy link
Contributor

@MichaelArestad would we still call it "section" if it's something like just a navigation menu, or a list of social icons?

Good question. I think section still works in those scenarios.

@Addison-Stavlo
Copy link
Contributor

Addison-Stavlo commented Jun 25, 2020

This convert-to flow seems like it will be super-smooth when combined with some of the other creation changes being developed in #23295!

Once these flows combine, will we be able to 'undo' the conversion if necessary (and also deleting the auto-draft created for the 'Untitled Section' in that undo) ?


@matias mentioned:

would we still call it "section" if it's something like just a navigation menu, or a list of social icons?

It sounds like we have pretty much settled on the term 'Section' ? If thats what we have decided to move forward with then I don't expect to change anyones mind, but I do have some fair concerns regarding this name:

  1. 'Section' and 'Group' are synonymous. So much so that searching for 'Section' in the block inserter brings the 'Group' block up as the first result. If there is already a subset of users that think of the 'Group' block as a section, this will be overly confusing. By the names and previous convention, a user could rightfully expect the Section block and Group block to behave very similarly.

  2. When we get around to adding semantic tag support for template parts, <section> would be one of those options. If we are calling this block a "Section", then the Section block would have the option to have a 'section' tag (as well as 'header', 'footer', etc.), creating a false implication that the 'section' tag would be the preferred tag for the Section block. This seems like another unfortunate confusion.

  3. 'Section' conveys zero meaning towards the behavioral properties and reusability of the saved entity. While the term 'Template Part' may be on the 'too technical' side of the spectrum, 'Section' seems to be on the exact opposite, 'too vague' side. If a user comes across a 'too technical' term that they do not understand, they are generally prompted to search for its meaning. However, when a user comes across a 'too vague' term, they could often assume they understand the meaning and consequently mis-use the block and get themselves in a bit of a mess. For this reason, 'too technical' seems preferable to 'too vague'.

  4. A complete disconnection between terms used in theme development and site editing. Calling it 'Thing A' in one place and 'Stuff B' in another is asking for more confusion points.

For these reasons I feel that renaming this 'Section' in the editor will cause a handful of different confusion points down the road and be looked back upon as an unfortunate naming convention.

@MichaelArestad
Copy link
Contributor

For these reasons I feel that renaming this 'Section' in the editor will cause a handful of different confusion points down the road and be looked back upon as an unfortunate naming convention.

These are all good points. What do you propose?

@Addison-Stavlo
Copy link
Contributor

These are all good points. What do you propose?

TLDR: To not rename it.

Consider a standard user who we are concerned with exposing the term 'Template Part' to:

  • Going into the site editor will load a Template from their theme.
  • That Template will already have 'Template Parts' in place.
  • If the user doesn't like these Template Parts, they can click on them and edit them. Or use an interface from the toolbar to select a different one.
  • At no point in this process has the user ever had to understand, know, or really be exposed to the term 'Template Part'.

If a user needs to find the "Template Part" block, it will be to add it to a Template. In this case the term 'Template Part' makes sense. If a user is editing Templates in this manner they are now leaning towards the side of theme development, in which case they should be exposed to the proper term that Themes use. (This assumes we wouldn't use the template part block in the post editor, but I believe this was suggested by both yourself and @mtias in the past? As noted we do have "Reusable Blocks" for that).

I personally don't think 'Template Part' really needs to be renamed. It seems like it would cause more confusion than clarity. I really have tried to think of a "good alternative" for the sake of the discussions but I don't feel that there really is any good alternative where the pros outweigh the cons. If it really needs to be renamed, something other than 'Section' would cut out a couple of the confusion points (but not all of them).

@MichaelArestad
Copy link
Contributor

@Addison-Stavlo I'm sold on going back to Template Parts. You make excellent points with benefits that outweigh the reasons I wanted to rename it in the first place. Should I create an issue or would you be interested in changing it back?

@Addison-Stavlo
Copy link
Contributor

Should I create an issue or would you be interested in changing it back?

Go ahead and create an Issue, I'm stuck on other priorities/duties until the end of next week. It should be a fairly quick task, but if its still around by then I can get to it.

Comment on lines 45 to 56
useEffect( () => {
if ( innerBlocks.length ) {
onCreate();
}
}, [] );
if ( innerBlocks.length ) {
return <Spinner />;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the placeholder has updated a lot since this PR was originally made, I had to make some changes for this transform to work properly. Here, we pass down the innerBlocks to the placeholder and immediately create the entity if they exist. The idea is that this block will never render the placeholder when innerBlocks are present, unless we are in the conversion flow.

Copy link
Contributor

@Addison-Stavlo Addison-Stavlo left a comment

Choose a reason for hiding this comment

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

This PR should be in a working state again:

convert-to-template-part

I am noticing this PR adds the ability to convert to template part in 2 separate areas of the toolbar, the new button as well as the standard block-transform tool.

In transform menu:
Screen Shot 2020-10-20 at 5 08 45 PM

New button:
Screen Shot 2020-10-20 at 5 15 52 PM

@shaunandrews @jameskoster @MichaelArestad - Are we fine with keeping it in the transform tool and getting rid of the separate button/component? Or do we want to somehow hide it from the transform tool and only allow it to happen from this new button area? (The transform tool seems to appear auto-magically once the transform is defined, which the separate button still relies on for functionality. So I am not certain the best way to hide it if we don't approve of it in the standard transform location). 🤔

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

We're talking about moving the convert template part flow business logic and the placeholder onCreate callback into its parent.

You asked a number of great questions in this discussion. To frame my reasoning, I'll start by describing why I thought it could be beneficial to move innerBlocks to the parent.

What does this do for us? The placeholder isn't dependent on innerBlocks, it either receives them or it doesn't. If it does, the context of creation is already clear as the content for the new template part is already selected and defined.

In this context, when I was using the word dependency, I was trying to say that innerBlocks is an argument that is passed to the Template Part Placeholder. Information about innerBlocks is necessary for the Placeholder to behave properly (knowing when to call onCreate, render a spinner, etc.).

I was thinking that if we moved innerBlocks into its parent, we could also, as a result, separate concerns, keep the responsibilities of the Placeholder narrowly defined, and move all business logic into the parent. The Placeholder would just be responsible for UI concerns and invoking onCreate when its button is clicked.

We already see a lot of business logic being consolidated in template-part/edit. For example, it already decides when to render the placeholder vs. the name panel + dropdown vs. inner blocks vs. a spinner.

I favored having onCreate in the parent for these reasons. It could be used in the convert flow if the logic were moved into template-part/edit, and it could also be passed through to the Placeholder easily as a callback, which would allow us to remove innerBlocks entirely from the Placeholder.

Hopefully that makes, sense, but let me know if it doesn't. Earlier I mentioned exploring whether or not some of these approaches were even worthwhile to implement.

+1 from me whenever we resolve these last few questions. I'll check this thread first thing tomorrow!

@Addison-Stavlo
Copy link
Contributor

Re: Creating the entity in the converter component vs. template part block:

if we save a new template part entity record immediately when clicking the "Make template part" button, I thought we could track loading state with a resolution selector like hasFinishedResolution or isResolving selector, allowing us to provide user feedback during the delay.

Right, we could use state to track this information, however it would require extra complexity and reworking how the template part block works to enable this in a meaningful way that still allows the standard select/create flows to work and appear when expected vs. the 'loading spinner' that is used to represent waiting a creation that was triggered elsewhere.

While reusable blocks is our closest equivalent to model this flow after, there are enough differences in the overall functionalities that we shouldn't expect the underlying code for this flow to look the same. The block controlling reusable blocks has no concept of creation/selection, while the template part block does. Since it does, I think it makes much more sense to keep using this functionality to create the entity after block conversion than to define a new separate creation system elsewhere and work to add extra logic to determine whether the template part block was initiated via a conversion awaiting entity creation elsewhere vs. being added from the inserter. The block shouldn't care about how it was put on the page, it should just initialize and make its determinations in how to function without needing that extra information.

The state of this PR back in February did this sort of flow as well. It converted block(s) to innerBlocks of a template part block that represented no entity, the template part block mounted and found no corresponding saved entity and therefore loaded the placeholder, the placeholder was then used to give the slug/theme names in an input and click 'create', and creation was done through the placeholder using the innerBlocks that were present. I think this still makes sense today, the only difference here is that the placeholder no longer asks for slug/theme inputs in creating a new template part as it was updated to create all new custom template parts as 'Untitled Template Part'. Since that creation flow was simplified, this PR has been updated to trigger that same creation from that same place when it is necessary.


Re: Moving onCreate/innerBlocks out of the placeholder:

I was thinking that if we moved innerBlocks into its parent, we could also, as a result, separate concerns,

I feel the concerns are separated in this way. When the template part block cannot find an entity, the placeholder is rendered and handles what needs to happen for the creation of that entity. Moving some of that creation to one place and leaving the rest of it in another seems like over-separation. That is, we are splitting the same concern up into multiple places instead of having it consolidated into one.

We already see a lot of business logic being consolidated in template-part/edit. For example, it already decides when to render the placeholder vs. the name panel + dropdown vs. inner blocks vs. a spinner.

Right, basically I see the current state of that edit file as:

  • If no corresponding entity -> render placeholder that handles creation
  • If an entity is resolved -> toolbar controls + inner blocks
  • if unresolvable file -> some error spinner

Agreed, there is a lot of business logic there. But I don't see that as a reason to clutter it with more logic if it's not necessary. If the template part block mounts with a corresponding entity it has no need of having an onCreate function defined, so to me it makes sense to not define this until we get to the component that handles creation. If we wanted to separate the creation with existing inner blocks from the select/create flow in the placeholder, that would become something like:

  • first move all creation logic here instead of the placeholder
  • If no corresponding entity + innerBlocks present -> trigger a creation
  • If no corresponding entity -> render placeholder that also handles creation in other cases
  • If an entity is resolved -> toolbar controls + inner blocks
  • if unresolvable file -> some error spinner

We could do that, but to me it seems more cluttered and less clearly defined.

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

it would require extra complexity and reworking how the template part block works to enable this in a meaningful way that still allows the standard select/create flows to work and appear when expected vs. the 'loading spinner' that is used to represent waiting a creation that was triggered elsewhere.

Gotcha 👍 That's the sense I got from previous comments, but I wanted to confirm to make sure that I wasn't misunderstanding. Thanks!

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

The block controlling reusable blocks has no concept of creation/selection, while the template part block does. Since it does, I think it makes much more sense to keep using this functionality to create the entity after block conversion than to define a new separate creation system elsewhere and work to add extra logic to determine whether the template part block was initiated via a conversion awaiting entity creation elsewhere vs. being added from the inserter. The block shouldn't care about how it was put on the page, it should just initialize and make its determinations in how to function without needing that extra information.

The point about a block not caring about how it was put on a page is very interesting. I didn't realize that's a typical expectation. I think I'm tracking. Correct me if I'm wrong, but you're saying that the block should act as its own self-contained unit, and when we say make its determinations of how to function, that includes triggering template part creation.

@Addison-Stavlo
Copy link
Contributor

Addison-Stavlo commented Oct 23, 2020

I didn't realize that's a typical expectation. I think I'm tracking. Correct me if I'm wrong, but you're saying that the block should act as its own self-contained unit, and when we say make its determinations of how to function, that includes triggering template part creation.

I think it is preferable, if the block is set up to handle these determinations I don't see a reason to complicate it by having its functionality dependent on more information about how it was added to the editor.

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

The state of this PR back in February did this sort of flow as well.

I think this still makes sense today, the only difference here is that the placeholder no longer asks for slug/theme inputs in creating a new template part as it was updated to create all new custom template parts as 'Untitled Template Part'.

I see. Enrique created this a while ago, had a certain intention when structuring the PR the way he did, was also handling the convert flow in the placeholder, and was, in fact, requiring even more information than it is now (slug + theme inputs).

@Addison-Stavlo
Copy link
Contributor

Yeah, thats how I see it.

was also handling the convert flow in the placeholder

To be clear, the 'convert flow' is and has been happening outside of the block. It is what replaces the blocks with the template part block in the first place. By that point the blocks are technically converted, but the template part block and its corresponding inner blocks that now exist don't correspond to any entity, and that entity creation is still handled by the placeholder.

@Addison-Stavlo
Copy link
Contributor

Addison-Stavlo commented Oct 23, 2020

Just another thought - I think the creation from innerBlocks could add a bit of a protection/fallback as well in some cases. Perhaps there is a template part block with inner blocks in the content passed into the editor that does not have a corresponding entity (maybe it was defined in markup in an unconventional way with no actual corresponding file, or maybe some other circumstance). In that case, instead of the block failing and either loading the placeholder or the final unresolved file spinner, it would automatically trigger creation of 'Untitled Template Part' and the content would still be available as expected. 🤔

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

When the template part block cannot find an entity, the placeholder is rendered and handles what needs to happen for the creation of that entity. Moving some of that creation to one place and leaving the rest of it in another seems like over-separation.

Agreed, there is a lot of business logic there. But I don't see that as a reason to clutter it with more logic if it's not necessary.

I think I see what you're conveying here. Correct me if I'm wrong, but we're saying that the concerns that we're separating are:

  1. the inability for a template part block to find an entity
  2. template part creation itself.

This is where I disagree, but at the same time, I want to acknowledge that I might frame the concerns in separation of concerns differently because of past experiences at other companies (which may not translate to Automattic). To me it feels more natural to consolidate all business logic in the parent, but the more I think about it, the more I see my disagreements may also be a matter of opinion.

Ultimately, the functionality in this PR works well, I believe I understand your reasoning more clearly (chime in if you feel like I'm missing anything big! 🙏 ), and all of my questions have been resolved, so +1 from me 🚀

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

Just another thought - I think the creation from innerBlocks could add a bit of a protection/fallback as well in some cases.

Oh also an interesting point! Giving this some thought 🤔

@Addison-Stavlo
Copy link
Contributor

Correct me if I'm wrong, but we're saying that the concerns that we're separating are:

  • the inability for a template part block to find an entity
  • template part creation itself.

Thats the way I see how the concerns should be separated:

  • Parent -> concerned with finding the entity, and whether to display the entity vs. the placeholder
  • Placeholder -> concerned with determining when/how to create or select the entity

I think what you are proposing would be more:

  • Parent -> concerned with finding the entity, and determining what type of creation may need to happen
  • Parent (or new child component) -> concerned with triggering creation involving pre-existing inner content.
  • Placeholder -> concerned only with manual selection/blank entity creation.

I think both are valid and will work, and we have a different opinion on which makes more sense?

@jeyip
Copy link
Contributor

jeyip commented Oct 23, 2020

I think both are valid and will work, and we have a different opinion on which makes more sense?

Yeah! I think that's a good way to describe this. I agree that both ways will work 👍 It's a difference of opinion, and I definitely don't think that should stop this PR from being merged.

@Addison-Stavlo Addison-Stavlo force-pushed the add/convert-to-template-part-button branch from e1ee1c1 to 50039d7 Compare October 23, 2020 19:16
@Addison-Stavlo Addison-Stavlo merged commit 07b3ab2 into master Oct 23, 2020
@Addison-Stavlo Addison-Stavlo deleted the add/convert-to-template-part-button branch October 23, 2020 20:02
@github-actions github-actions bot added this to the Gutenberg 9.3 milestone Oct 23, 2020
@mtias
Copy link
Member

mtias commented Oct 26, 2020

Thanks for pushing this one through!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Design Feedback Needs general design feedback.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants