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

Provide API to create Query Block Variations #25607

Closed
mariohamann opened this issue Sep 24, 2020 · 7 comments
Closed

Provide API to create Query Block Variations #25607

mariohamann opened this issue Sep 24, 2020 · 7 comments
Labels
[Block] Query Loop Affects the Query Loop Block [Type] Discussion For issues that are high-level and not yet ready to implement.

Comments

@mariohamann
Copy link

mariohamann commented Sep 24, 2020

@mapk mentioned the idea of block variations for Query Block in #25198 and in a chat we had yesterday (thanks again! :)) – and I would like to expand this idea.

Base: The Query Block

This is the base for all following variations and is used in FSE. In FSE it should get the most important paramaters from the theme (no need to select e. g. Categories in archive.php – it would completely break the current logic of WP archives.) Therefore it just needs some basic settings in the sidebar. Those (default) settings could be defined as:

{
    "title": "Query",
    "description": "Display a set of posts/pages as the result of a query.",
    "query": "WP_Query",
    "slug": "jobs",
    "display_settings": {
        "posts_per_page": true,
        "offset": true,
        "pagination": true,
        "orderby": true,
        "order": true
    }
}

These parameters would provide the following block settings in sidebar:
image

Use Case 1: List some posts

There are a lot of use cases to show some defined blocks in a page, e. g. "Hall of fame" (3 most commented posts), "Topic specific posts" (showing e. g. 5 of posts of a specified category) etc. The idea is: Having a strong API we could simply create a new variation of the Query Block, passing some paramters and we are done.

functions.php

register_query_block(
   'Query\Posts',
   array(
       'paramaters' => 'query_params.json'
   )
);

query_params.json

{
    "title": "Posts",
    "description": "Display blog posts.",
    "post_type": "post",
    "display_settings": {
        "sticky": true,
        "pagination": false,
    },
    "taxonomies": [
        "categories",
        "tags"
    ],
    "search": true
}

This would create the following for sidebar settings, making it possible to create e. g. a Hall of fame of similiar:

image

Use Case 2: List some posts – with different callback

@iamtakashi provided some nice ideas for the query block: #25502 #25501 #25503 In fact, if a Plugin Developer could inherit the settings of the Block above and if s:he could change the callback to have a different output in an API, it would be no problem to add some JavaScript, different HTML etc. etc. The Query block just returns the post – the output is handled by the callback.

functions.php

register_query_block(
   'GreatDev\Posts\Carousel',
   array(
       'inherent_parameters' => 'Query\Posts'
       'paramaters' => 'query_params.json'
       'callback':           'GreatDev\GreatBlocks\block_carousel_output',
   )
);

image

Use Case 3: Custom Post Type

I often create Custom Post Types, e. g. for Jobs, Events, Persons. For my own CPTs I often find myself writing a simple Shortcode to create a simple Query, listing e. g. Jobs. If I want a better UI for authors I invest some more time and create a block (I have to admit: often with ACF...) to let them select e. g. categories. Short codes feel and are old fashioned, Block development is often very time consuming.
If we could write Block variations with a strong API, I would just need to register the variation with its own callback and add a new query_params.json:

{
    "title": "Persons",
    "description": "Display Person",
    "post_type": "person",
    "applied_filters": true,
    "display_settings": {
            "posts_per_page": false,
            "offset": true,
            "pagination": false
        },
        "taxonomies": [
            "department",
            "positions"
        ]
    }
}

image

Use Case 4: List Categories

We already have a block (or widget?) to list categories. If we could use the Query Block as a base, the whole code to register the block with its settings would be:

register_query_block(
   'Query\Categories',
   array(
       'paramaters' => 'params.json'
       'callback'   => 'WP\QueryBlock\categories_output'
   )
);
{
    "title": "Categories",
    "description": "List blog categories.",
    "query": "WP_TERM",
    "taxonmy": "category",
    "display_settings": {
        "items": true,
        "offset": false,
        "show_empty": true,
        "posts_per_page": true,
        "pagination": false
    },
    "search": true
}

image

Use Case 5: Single Post Selector

There exist a lot of plugins, which are based on the idea of showing a single post of custom post type, e. g. showing a single Contact Form, being a CPT (Caldera Forms, CF7). If the API would be strong enough, a plugin author could simply write the following code to return one single Post:

register_query_block(
   'Query\Categories',
   array(
       'paramaters' => 'params.json',
       'callback'   => 'GreatDev\ContactForm\contact_form_output'
   )
);
{
    "title": "Contact form",
    "description": "Display Contact Form",
    "post_type": "contact_form",
    "other_settings": {
        "Contact form": {
            "ui": "selector",
            "content": "%post%",
            "helptext": "You can create a new contact form <a>here</a>."
        }
    }
}

image

Further ideas

Showing selectors for meta fields, Media queries to list images, multiple select defined single posts (like in WooCommerce Blocks to list specified blocks), show products of a category etc. etc. – the possibilities are endless. :)

I hope it's fine to cc some other people @ntsekouras @aristath @annezazu

Here is a Figma file with every Use case I described above with description, PHP and JSON examples, sidebar and possible output: https://www.figma.com/file/YE8pjhnO0vHzFx7iDUW9mW/Query-Block-variations?node-id=0%3A1

@ntsekouras
Copy link
Contributor

Hey @mariohamann - thanks for your time on this and all the feedback in the design issue!

For reference the tracking issue for Query block is here: #24762

As I usually say in discussions for Query block, there are a lot to be figured out, but here are my thoughts :)

Both tracking and design issues mention the block variations and this refers to the existing variation API (https://developer.wordpress.org/block-editor/packages/packages-blocks/#registerBlockVariation). While it's great you proposed a new API, I think we could achieve these results with the existing APIs.

To me it seems that the ultimate goal here to have the query related attributes to Query block and all other display options to the other PostBlocks that would be inside Query block, with the sole exception of showing posts as list/grid (at least for now). For example if we want to show the avatar or not of the author is a responsibility of PostAuthor block and not the Query (check my comment here:#25198 (comment)).

Also we shouldn't need a config object to conditionally display settings, as some of them would probably be disabled or hidden based on the current context.

What the block variations will achieve is having some of their attributes, like categories preset. What we need to do is to find the best design to show all the available query related options.

For example to achieve the first use case (3 most commented posts) we would have a variation like this:

{
	name: 'most-comments,
	title: __( 'Most comments' ),
	attributes: {
		query: { order: 'desc', orderBy: 'comment_count'} // although this orderBy param is not supported by current REST API :)
	}

}

Regarding use cases 2 and 4, a related comment by me is here:#25503 (comment). In a gist, while they are good explorations, I believe are out of Query block's scope. These could be new blocks since they are generic. For example a Carousel block could show just images.

A lot of the display of entities questions will be more clear when we implement some block variations and this requires to clarify how to handle some technical nuances about the usage of InnerBlocks and the template property that is being used. There is already a way to add attributes to the template property, so when this is solved, we will have a way to create a block variation that would pass the wanted display options to their innerBlocks.

I would propose to close this issue and look for a way forward with the existing APIs. Next steps would be to make progress in the design you've also been part of here: #25198 and see what display options would be useful for PostBlocks, like PostExcerpt etc..

@mariohamann
Copy link
Author

mariohamann commented Sep 24, 2020

Thank you very much for your feedback, your clarifications and your thoughts!

I realize that I'm thinking too much from the PHP perspective (more thinking of WP_Query instead of wp-json/wp/v2/posts ) – therefore, I would like to revise my approach, tryiing to be as short as possible (questions are bold below).

Summarizing the Query Block concept for myself

  1. Query Block allows to fetch data from /wp-json/wp/v2/posts with the possibility to use the filters mentioned here
  2. Return will be an array of Post objects like described in the Post schema
  3. Blocks inside the query block inherit the fields of the posts and display them.

Revising the "API concept"

So thinking of a Custom Post Type "jobs":

  1. Developer creates a variation of Query Block with variation API – ideally to fetch posts from /wp-json/wp/v2/jobs endpoint. Unfortunately as far as I know, in Core there are no REST filters by custoom taxonomies or Meta fields. So I see: the concept of a settings.json wouldn't work out at the moment. But: Will it be possible to use another endpoint in the variation?
  2. Return will be an array of "jobs" with the same REST scheme as above + Custom Fields and Taxees being registered for REST. Great.
  3. Now we need a new block, as there are some different Fields etc. I'm coming more from the PHP corner, so I hope it's okay to ask: Do you see any possibility to use a PHP callback in Step 3, which gets the returned Posts as an input and make with them whatever it wants?

I'm completely fine with closing the issue or giving it less focus for the moment especially facing 5.6! But as e. g. @sc0ttkclark asked for a way to easily extend the Query Block in #24934 (comment), maybe it's a good starting point for further development after 5.6?

@ntsekouras
Copy link
Contributor

Query Block allows to fetch data from /wp-json/wp/v2/posts with the possibility to use the filters mentioned here
Return will be an array of Post objects like described in the Post schema

Correct.

Blocks inside the query block inherit the fields of the posts and display them.

Not quite, but the result is the same. Blocks inside Query get query params from React context and make the queries themselves. There is also a way to change params of that parent query. You can check core/query-loop and core/query-pagination block as examples.

Custom taxonomies and custom post types support should be implemented and in general with the progress of Query block, there will be needed additions to the REST API.

Will it be possible to use another endpoint in the variant?

What do you mean here? Like what?

@sc0ttkclark asked for a way to easily extend the Query Block in #24934 (comment)

The query block could be extended like any other block with filters API: https://developer.wordpress.org/block-editor/developers/filters/block-filters/.

If you feel I didn't answer something or needs clarification, please ask. :)

@mariohamann
Copy link
Author

mariohamann commented Sep 25, 2020

Thanks for all clarifications!

Custom taxonomies and custom post types support should be implemented and in general with the progress of Query block, there will be needed additions to the REST API.

As described in #25377 (comment) in my opinion this should be possible for even a MVP. Maybe you can have a look over there?

What do you mean here? Like what?

A variation for woocommerce products would use /wp-json/wc/v3/products, a variation for a new custom post type would e. g. use the default route /wp-json/wp/v2/name_of_post_type_route. So we would need a filter for a query block to set this route instead of /wp-json/wp/v2/posts.

The query block could be extended like any other block with filters API: https://developer.wordpress.org/block-editor/developers/filters/block-filters/

Again thinking more from the PHP world: We have the filter render_block (forgot it, although I have already used it...). If the $block_content is the output of the /wp-json/wp/v2/posts-Query as JSON, we could simply convert the output to PHP object with json_decode and (in combination with wp_enqueue_scripts + if(has_block) to enqueue special CSS or js) do with it whatever we want, e. g. creating easily a list to build something like #25505.

apply_filters( 'render_block', $block_content, 'name_of_block_variation ){
$posts = json_decode($block_content);
?>
<ul>
<?php
foreach($posts as $post){
?>
    <li>
        <a href="<?= $post->link; ?>">
            <?= $post->title->rendered ?>
        </a>
    </li>
<?php
}
?>
</ul>
<?php
}

(Working example for the inner part of the filter incl. simplified JSON-Output of /wp-json/wp/v2/posts over here on sandbox.onlinephpfunctions.com)

Summary:

  • If the return of the Query Block is the output of /wp-json/wp/v2/posts, this would create lots of possibilities and make it very easy to create all those variations @iamtakashi proposed, as we wouldn't need any child blocks.
  • And if we can change the REST endpoint to fit the endpoint of a Custom Post Type (+ later the possibility to use custom taxonomies), I think I would never ever use shortcodes again. :)

@ntsekouras
Copy link
Contributor

As described in #25377 (comment) in my opinion this should be possible for even a MVP. Maybe you can have a look over there?

Yes. It definitely needs a lot of work. Just consider that this block was introduced in code base just about three months ago.

I have actually started exploring the implementation of custom post types.

Again thinking more from the PHP world: We have the filter render_block (forgot it, although I have already used it...). If the $block_content is the output of the /wp-json/wp/v2/posts-Query as JSON, we could simply convert the output to PHP object with json_decode and (in combination with wp_enqueue_scripts + if(has_block) to enqueue special CSS or js) do with it whatever we want, e. g. creating easily a list to build something like #25505.

Actually the $content is not used, but built based on the query params provided by the block context. You can check the index.php of core/query-loop block (https://github.com/WordPress/gutenberg/blob/master/packages/block-library/src/query-loop/index.php).

And if we can change the REST endpoint to fit the endpoint of a Custom Post Type (+ later the possibility to use custom taxonomies), I think I would never ever use shortcodes again. :)

That would be great and we will work towards that :)

I don't have all the answers yet, but iterating on this will help all of us find the best path forward.

@mcsf
Copy link
Contributor

mcsf commented Sep 25, 2020

Hi, @mariohamann and @ntsekouras. This discussion touches a lot of different parts, so I'll jump right to a few observations:

  1. Developer creates a variant of Query Block with variant API – ideally to fetch posts from /wp-json/wp/v2/jobs endpoint. Unfortunately as far as I know, in Core there are no REST filters by custoom taxonomies or Meta fields. So I see: the concept of a settings.json wouldn't work out at the moment. But: Will it be possible to use another endpoint in the variant?

The Query Loop block, responsible for the actual querying (whereas Query is solely responsible for managing the intended query params), relies on two systems for querying:

3. Now we need a new block, as there are some different Fields etc. I'm coming more from the PHP corner, so I hope it's okay to ask: Do you see any possibility to use a PHP callback in Step 3, which gets the returned Posts as an input and make with them whatever it wants?

I'd like to address the phrase "Now we need a new block". Needing a new block shouldn't be a problem. :) There's always a search for balance in Gutenberg between providing blocks that are highly generic and flexible but hard to master, and providing a larger number of specialised blocks that are more likely to serve most user needs with barely any learning curve. The balance sits somewhere in between both ends of the spectrum. This is why Gutenberg provides both a Columns block and a Media & Text block.

The point I'm making is that creating dedicated blocks is encouraged. It's also why there's a lot of emphasis on providing good reusable components and solid APIs for blocks and querying. In my mind, something like #25505 is a much better candidate for a dedicated block type — whether it's a core type or a third-party type.

  • If the return of the Query Block is the output of /wp-json/wp/v2/posts, this would create lots of possibilities and make it very easy to create all those variants iamtakashi proposed, as we wouldn't need any child blocks.
  • Similarly to the previous point, child blocks are a great thing! They can provide a much better experience to developers and users alike. It means that we have more room to see what feels best. Combined with block variations, it can mean that users may search for something like "Sortable Table" in the global inserter and that this will insert the following tree: Query { QueryLoop { SortedTableItem } }, for example.
  • Retaining block objects and HTML output as the primary kinds of data being returned is much more important than returning query output (whether in JSON or PHP). Any manipulation of the actual query results should be done using the appropriate query-related filters.

we could simply convert the output to PHP object with json_decode and (in combination with wp_enqueue_scripts + if(has_block) to enqueue special CSS or js)

Enqueueing of scripts and styles is already supported natively in the framework on a per-block-type basis, reinforcing the idea that, oftentimes, a dedicated block really is the best choice.

@aristath aristath added [Block] Query Loop Affects the Query Loop Block [Type] Discussion For issues that are high-level and not yet ready to implement. labels Sep 25, 2020
@mariohamann mariohamann changed the title Provide API to create Query Block Variants Provide API to create Query Block Variations Oct 9, 2020
@ntsekouras
Copy link
Contributor

Thanks for your efforts and exploration here Mario! I'll close this issue now as we have moved forward with using the current Block Variations API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Query Loop Affects the Query Loop Block [Type] Discussion For issues that are high-level and not yet ready to implement.
Projects
None yet
Development

No branches or pull requests

4 participants