-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Add docs for extending the Query Loop block via variations #44137
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
Changes from 1 commit
f0a62b9
57c509a
23ecd7a
6c51dfd
89d88bf
8439831
c327579
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Specifically: * Added the complete code at the beginning * Change `isActive` from array to function * Reworded a few things * Added information about custom logic and other hints
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,46 @@ Let's go on a journey, for example, of setting up a variation that could fit a p | |
|
|
||
| ### Offer sensible defaults | ||
|
|
||
| Your first step would be to create a variation which will be set up in such a way to provide a block variation which will display by default a list of books instead of blog posts. You would start with something like this: | ||
| Your first step would be to create a variation which will be set up in such a way to provide a block variation which will display by default a list of books instead of blog posts. The full variation code will look something like this: | ||
|
|
||
| ```js | ||
| const MY_VARIATION_NAME = 'my-plugin/books-list'; | ||
|
|
||
| registerBlockVariation( 'core/query', { | ||
| name: MY_VARIATION_NAME, | ||
| title: 'Books List', | ||
| description: 'Displays a list of books', | ||
| isActive: ( { namespace, query } ) => { | ||
| return ( | ||
| namespace === MY_VARIATION_NAME | ||
| && query.postType === 'book' | ||
| ); | ||
| }, | ||
| icon: /** An SVG icon can go here*/, | ||
| attributes: { | ||
| namespace: MY_VARIATION_NAME, | ||
| query: { | ||
| perPage: 6, | ||
| pages: 0, | ||
| offset: 0, | ||
| postType: 'book', | ||
| order: 'desc', | ||
| orderBy: 'date', | ||
| author: '', | ||
| search: '', | ||
| exclude: [], | ||
| sticky: '', | ||
| inherit: false, | ||
| }, | ||
| }, | ||
| scope: [ 'inserter' ], | ||
| } | ||
| ); | ||
| ``` | ||
|
|
||
| If that sounds like a lot, don't fret, let's go through each of the properties here and see why they are there and what they are doing. | ||
|
|
||
| Essentially, you would start with something like this: | ||
|
|
||
| ```js | ||
| registerBlockVariation( 'core/query', { | ||
|
|
@@ -58,16 +97,21 @@ At this point, your custom variation will be virtually indistinguishable from a | |
|
|
||
| There is one slight problem you might have realized after implementing this variation: while it is transparent to the user as they are inserting it, Gutenberg will still recognize the variation as a Query Loop block at its core and so, after its insertion, it will show up as a Query Loop block in the tree view of the editor, for instance. | ||
|
|
||
| We need a way to tell the editor that this block is indeed your specific variation. This is what the `isActive` property is made for: it's a way to determine whether a certain variation is active based on the block's attributes. You might be tempted to then do something like this: | ||
| We need a way to tell the editor that this block is indeed your specific variation. This is what the `isActive` property is made for: it's a way to determine whether a certain variation is active based on the block's attributes. You could use it like this: | ||
|
|
||
| ```js | ||
| { | ||
| /** ...variation properties */ | ||
| isActive: [ 'postType' ], | ||
| isActive: ( { namespace, query } ) => { | ||
| return ( | ||
| namespace === MY_VARIATION_NAME | ||
| && query.postType === 'book' | ||
| ); | ||
| }, | ||
| } | ||
| ``` | ||
|
|
||
| In this way, Gutenberg will recognize the block as your variation any time the `postType` matches `book`! That's awesome, but the problem is that now Gutenberg will recognize the block as your specific variation any time the `postType` is set to `book`, which is not what we want: other plugins might want to publish variations based on the `book` post type, or we might just not want the variation to be recognized every time the user sets the type to `book` manually through the editor settings. | ||
| You might have been tempted to only compare the `postType`: in this way, Gutenberg will recognize the block as your variation any time the `postType` matches `book`! That's awesome, but the problem is that now Gutenberg will recognize the block as your specific variation any time the `postType` is set to `book`, which is not what we want: other plugins might want to publish variations based on the `book` post type, or we might just not want the variation to be recognized every time the user sets the type to `book` manually through the editor settings. | ||
|
|
||
| That's why the Query Loop block exposes a special attribute called `namespace`: it really doesn't do anything inside the block implementation, and it's used as an easy way for extenders to recognize and scope their own variation. So you would use it like so: | ||
|
|
||
|
|
@@ -92,7 +136,7 @@ Even with all of this, your custom post type might have unique requirements: it | |
|
|
||
| Let's say you don't use at all the `sticky` attribute in your books, so that would be totally irrelevant to the customization of your block. In order to not confuse the users as to what a setting might do, and only exposing a clear UX to them, we want this control to be unavailable. Furthermore, let's say that you don't use the `author` field at all, which generally indicates the person who has added that post to the database, instead you use a custom `bookAuthor` field. As such, not only keeping the `author` filter would be confusing, it would outright break your query. | ||
|
|
||
| For this reason, the Query Loop block supports a property called `allowedControls` which accepts an array of keys of the controls we want to whitelist. By default, we accept all the controls, but as soon as we provide an array to this property, we want to be specific and whitelist only the controls which are going to be relevant for us! | ||
| For this reason, the Query Loop block supports a property called `allowedControls` which accepts an array of keys of the controls we want to display on the inspector sidebar. By default, we accept all the controls, but as soon as we provide an array to this property, we want to be specific and specify only the controls which are going to be relevant for us! | ||
|
|
||
| As of version 13.9, the following controls are available: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add the GB version or the WP one here ? 🤔
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good question, I went with GB as my first draft, but it depends on what's the usual convention for the docs and if the context in which they appear makes it clear they are for GB or WP. Just let me know and I'll act accordingly.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can leave this discussion open for documentation folks to chime in. In general we will need some other small changes in some other files for the documentation to work, but we can add them in the end, when the copy is finalized. |
||
|
|
||
|
|
@@ -117,13 +161,15 @@ Notice that we have also disabled the `postType` control: when the user selects | |
|
|
||
| ### Adding additional controls | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Up to this point here this guide is super clear and easy to understand. I personally find this final section to be a little confusing. The example code uses a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @fabiankaegy, thanks for the feedback. Is the In my latest commit I changed the comment above the code to this: Does it sound more appropriate? I mean, I can also provide the full code for |
||
|
|
||
| Because our plugin uses custom attributes that we need to query, we want the users of our block to be able to select those instead of the ones we have just disabled from the core inspector controls. We can do this via a [React HOC](https://reactjs.org/docs/higher-order-components.html), like so: | ||
| Because our plugin uses custom attributes that we need to query, we want to add our own controls to allow the users to select those instead of the ones we have just disabled from the core inspector controls. We can do this via a [React HOC](https://reactjs.org/docs/higher-order-components.html) hooked into a [block filter](https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/), like so: | ||
|
|
||
| ```jsx | ||
| export const withBookQueryControls = ( BlockEdit ) => ( props ) => { | ||
| // We only want to add these controls if it is our variation, | ||
| // so here we can implement a logic to check for that, similiar | ||
| // so here we can implement a custom logic to check for that, similiar | ||
| // to the `isActive` function described above. | ||
| // The following assumes that you wrote a custom `isMyBooksVariation` | ||
| // function to handle that. | ||
| return isMyBooksVariation( props ) ? ( | ||
| <> | ||
| <BlockEdit { ...props } /> | ||
|
|
@@ -175,6 +221,8 @@ if( 'my-plugin/books-list' === $block[ 'attrs' ][ 'namespace' ] ) { | |
| } | ||
| ``` | ||
|
|
||
| (In the code above, we assume you have some way to access the block, for example within a [`pre_render_block`](https://developer.wordpress.org/reference/hooks/pre_render_block/) filter, but the specific solution can be different depending on the use-case, so this is not a firm recommendation). | ||
|
|
||
| ### Making your custom query work on the editor side | ||
|
|
||
| To finish up our custom variation, we might want the editor to react to changes in our custom query and display an appropriate preview accordingly. This is not required for a functioning block, but it enables a fully integrated user experience for the consumers of your block. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to add the full block variation here, and then explain the specific parts.
It's also important to note that due to the Query Loop setup with patterns and
scope:blockvariations , the selected pattern's attribute will be used except forpostTypeandinheritquery properties.To elaborate on this, if for example we have set
perPage:10and we select a pattern with aperPage:3, the resultingperPagewill be3. To circumvent this(for now) we need to declare some startinginnerBlocksin our variation like:In addition to the above, in the case of having declared
innerBlocks, we need to make sure to add to our variation more attributes(example here). This is because of the core handling ofobjectblock attributes where we set the defaults only if the top level attribute is not set - in our casequery.I hope I'll be able to fix this for 6.1 to handle specific Query Loop variation patterns, so the extenders could offer specific patterns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this PR is going to land now, it would be better to add info about it and we could probably skip some of the details I mention above about the
innerBlocksetc..