Skip to content

Curate queries within a block #530

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

Open
wants to merge 88 commits into
base: trunk
Choose a base branch
from

Conversation

ingeniumed
Copy link
Contributor

@ingeniumed ingeniumed commented May 12, 2025

Description

This PR is meant to be a continuation of #405.

The goal is to allow grouping multiple queries within a block, in the block editor. It'll allow query curation based on the data source within the block editor. So as an example, a couple of queries targetting the products in your shopify site could be grouped in the shopify block saving you the time of inserting these individually.

As part of this the schema was changed:

New Schema Changes

Block Registration

queries: This is the list of queries to be registered. There's no need to separate them or to mention their linkage.
display_queries: The queries that are display queries from the list of queries provided.

A big big shoutout to @brookewp as her work in #405 is what I'm building on 🙏🏾

In addition:

  • Multiple block bindings support was added alongside multiple patterns for each display query
  • All deprecation warnings resulting from components have been fixed
  • Second migration framework targeting the block configuration has been added. Previously, we only had one for handling individual queries.

Screenshots

How existing blocks that aren't updated look like:

CleanShot 2025-05-30 at 13 49 00

How new blocks that use multiple display queries look like:

CleanShot 2025-05-30 at 13 49 25

The config object for this block:

CleanShot 2025-05-30 at 13 50 08

Video Demonstration

Note that the first block doesn't have the artist title while the second block does. It's meant to highlight different outputs schemas for the two display queries.

CleanShot 2025-05-30 at 13 58 46

@ingeniumed ingeniumed self-assigned this May 12, 2025
@ingeniumed ingeniumed changed the title Add Multiple queries to single block (WIP) (WIP) Add Multiple queries to single block May 12, 2025
@ingeniumed
Copy link
Contributor Author

ingeniumed commented Jun 11, 2025

I've re-done the entire config system based on the feedback provided by @chriszarate. The new config format looks as follows:

	register_remote_data_block( [
		'title' => 'Art Institute of Chicago',
		'icon' => 'art',
		'queries' => [
			// Changing the name of this query to anything but display will break existing blocks content.
			'display' => $get_art_query,
			'search_art' => $search_art_query,
		],
		'placeholders' => [
			[
				'name' => 'Get Art',
				'query_key' => 'display',
			],
		],
	] );

I've kept placeholders as I couldn't come up with a better name and frankly that works. The placeholders config is entirely option, but if it is provided the name and query_key are compulsory. If the placeholders config isn't provided then every query is a display query and a selector query for any other display query.

I've also updated the example blocks to use the new config format. I went back and forth for this, as that would reduce the amount of changes in this PR. But, it's better to just isolate all the changes in this PR then. Lemme know if it's better to move this to another PR as I'm happy to do that.

Items I've punted to a future PR that I won't tackle in this PR:

  • Adding icon support for the placeholders config. Right now, this is omitted entirely as it'll be optional anyways.
  • Adding support for inferring multiple types for a selector. Right now, we have support for one selector only anyways.
  • Allowing the picking of the display query or selector query in inline-bindings. Right now just the first display query, and the first compatible selector is picked.
  • Fixing the psalm error when array_keys is used in some places.

None of these are critical to the merging of this PR and feature imo.

return (
<>
<div { ...blockProps }>
<EditErrorBoundary blockTitle={ getBlockTitle( props.blockName ) }>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is having an ErrorBoundary here, and in the Edit component the right way to handle errors from each component? At the top level, the error from inside QueryComponent wasn't handled, but it was when it was split into two like this. Realistically, does Edit even need an error boundary now? I kept it to be safe but I feel like it could be skipped.

@ingeniumed ingeniumed requested a review from chriszarate June 11, 2025 04:01
),
] ),
'selection_queries' => Types::nullable(
'placeholders' => Types::nullable(
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: I might lean towards placeholder (singular) since it refers to the UI component, not the buttons / actions it contains.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On one hand, I get where you are coming from since the UI itself is just 1 block. But on the other hand, it feels weird to call it a singular placeholder when several buttons are showing and each of those buttons corresponds to an entirely different query. With the support for multiple display queries, and multiple schemas it's likely even the UI would be different once the query is picked.

query_key: string;
type: string;
}[];
patterns: Record< string, string >;
Copy link
Member

Choose a reason for hiding this comment

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

Why did this type widen?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In order to allow for multiple schemas to be mapped to the block bindings for each query, the patterns had to be differentiated as well. So I store the query_key in the keywords, and then map that name to the pattern. Since the query_key is dynamic, the types had to be widened.

Copy link
Member

Choose a reason for hiding this comment

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

Since we are allowing multiple schemas to be mapped to a single block (via distinct "display" query keys), I think the block bindings need to store the query key in their source args. That way we know if they are compatible by inspecting the binding (instead of via manually managed keywords). We can enhance the existing hasBlockBinding util for this purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me explain what I did a bit more, because we might be talking about two different areas:

  • Patterns: This is meant to register different patterns for each display query. Since each query could have a different schema, it's important to differentiate the patterns. So each pattern has the display query stored as the keyword when registering. Then, the patterns are mapped using that query key in REMOTE_DATA_BLOCKS. So when trying to show the pattern selection screen, the correct pattern is picked out from REMOTE_DATA_BLOCKS and then selected from the pattern store in the block editor. I have a gif up top showing two art institute queries with this setup that would help make that clear.

  • Block bindings: This is meant to register different block bindings per query, based on their schema. This is purely for building REMOTE_DATA_BLOCKS and shares the code with the pattern registration. In the UI code, this map is useful for performing CRUD operations on the binding based on the query the block is using. This would be the UI sidebar where we pick the fields (can change based on the query's schema) for example.

Hopefully I haven't misunderstood what you mean. The main goal was to translate the user provided block/query config into information that the client could use to actually build out the new placeholder UI feature.

Copy link
Member

Choose a reason for hiding this comment

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

Patterns: This is meant to register different patterns for each display query.

Understood here, all that makes sense. But instead of using keywords to maintain a correspondence between patterns and display queries, we should store the query key in the block binding source args. That way the correspondence is data-driven and between the things that actually have the relationship (bindings and query keys). We can use / improve a fn like hasBlockBinding to determine if a pattern corresponds to a display query by inspecting the bindings inside of the pattern.

It will also help us highlight (in the UI) situations where bindings "wander" or the display query is changed. In those situations, in the future, we can let the user know that their binding is broken.

Block bindings: This is meant to register different block bindings per query, based on their schema. This is purely for building REMOTE_DATA_BLOCKS and shares the code with the pattern registration. In the UI code, this map is useful for performing CRUD operations on the binding based on the query the block is using.

I think I'm lost here. There is still only one block binding source that is registered. Its behavior is controlled by the ancestor block context (remoteData attribute) and the binding source args.

Copy link
Contributor Author

@ingeniumed ingeniumed Jun 16, 2025

Choose a reason for hiding this comment

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

I like the idea, as it'll add more inference across the code rather than having the server send out the config to use.

That said, I don't think this change should be done in this PR. I'd push to punt that to another one. This PR has been open for a bit, it's big enough in its scope and works well enough that I'd like to push off any more changes unless they are really needed. IMO, the proposed changes aren't needed in this PR (note: not saying not at all, just in this PR).

They are part of the future changes stemming from a large number of areas that have been revealed to work the way they do because we assumed 1 query key called display would be used. While, I have attempted to change that as much as possible or to the extent possible while keeping the PR from blowing there's a lot still to be done. It's not new features, just QOL improvements imo.

@ingeniumed ingeniumed requested a review from chriszarate June 16, 2025 03:24
@ingeniumed ingeniumed requested a review from a team June 29, 2025 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants