diff --git a/inc/Config/Block/RemoteDataBlock.php b/inc/Config/Block/RemoteDataBlock.php
new file mode 100644
index 000000000..314ad5b2d
--- /dev/null
+++ b/inc/Config/Block/RemoteDataBlock.php
@@ -0,0 +1,62 @@
+ 'Display',
+ 'query_key' => ConfigRegistry::DEPRECATED_DISPLAY_QUERY_KEY,
+ ];
+ unset( $config[ self::DEPRECATED_RENDER_QUERY_KEY ] );
+ }
+
+ if ( isset( $config[ self::DEPRECATED_SELECTION_QUERIES_KEY ] ) ) {
+ // Get the selection queries, inflate them, and add them to the queries array using the type as the key.
+ foreach ( $config[ self::DEPRECATED_SELECTION_QUERIES_KEY ] as $selection_query ) {
+ $queries[ $selection_query['type'] ] = $selection_query['query'];
+ }
+
+ unset( $config[ self::DEPRECATED_SELECTION_QUERIES_KEY ] );
+ }
+
+ // Set queries.
+ $config[ ConfigRegistry::QUERIES_KEY ] = $queries;
+ $config[ ConfigRegistry::PLACEHOLDERS_KEY ] = $placeholders;
+
+ return $config;
+ }
+}
diff --git a/inc/Editor/BlockManagement/BlockRegistration.php b/inc/Editor/BlockManagement/BlockRegistration.php
index 7519b4ca9..25ce6d8ec 100644
--- a/inc/Editor/BlockManagement/BlockRegistration.php
+++ b/inc/Editor/BlockManagement/BlockRegistration.php
@@ -8,6 +8,7 @@
use RemoteDataBlocks\Telemetry\Telemetry;
use RemoteDataBlocks\Editor\BlockPatterns\BlockPatterns;
use RemoteDataBlocks\REST\RemoteDataController;
+
use function register_block_type;
class BlockRegistration {
@@ -83,24 +84,40 @@ public static function register_block_configuration( array $config ): array {
$block_path = REMOTE_DATA_BLOCKS__PLUGIN_DIRECTORY . '/build/blocks/remote-data-container';
// Set available bindings from the display query output mappings.
- $available_bindings = [];
- $output_schema = $config['queries'][ ConfigRegistry::DISPLAY_QUERY_KEY ]->get_output_schema();
- foreach ( $output_schema['type'] ?? [] as $key => $mapping ) {
- $available_bindings[ $key ] = [
- 'name' => $mapping['name'],
- 'type' => $mapping['type'],
- ];
+ $available_bindings_for_queries = [];
+ $display_queries_to_selectors = $config['display_queries_to_selectors'] ?? [];
+
+ $patterns = $config['patterns'] ?? [];
+
+ // Using array_keys here triggers a psalm error, so it's set to $_ instead.
+ // Supressing the psalm error is a not a good idea, so instead this is the better solution.
+ // ToDo: Fix the psalm error, and see if array_keys could be used here again.
+ foreach ( $display_queries_to_selectors as $display_query_key => $_ ) {
+ $display_query = $config['queries'][ $display_query_key ];
+ $available_bindings_for_query = [];
+ $output_schema = $display_query->get_output_schema();
+ foreach ( $output_schema['type'] ?? [] as $key => $mapping ) {
+ $available_bindings_for_query[ $key ] = [
+ 'name' => $mapping['name'],
+ 'type' => $mapping['type'],
+ ];
+ }
+
+ $available_bindings_for_queries[ $display_query_key ] = $available_bindings_for_query;
+
+ $default_pattern_name = BlockPatterns::register_default_block_pattern( $block_name, $config['title'], $display_query_key, $display_query );
+ $patterns[ $display_query_key ] = $default_pattern_name;
}
// Create the localized data that will be used by our block editor script.
$block_config = [
- 'availableBindings' => $available_bindings,
+ 'availableBindings' => $available_bindings_for_queries,
'availableOverrides' => $config['overrides'] ?? [],
'instructions' => $config['instructions'],
'name' => $block_name,
'dataSourceType' => ConfigStore::get_data_source_type( $block_name ),
- 'patterns' => $config['patterns'],
- 'selectors' => $config['selectors'],
+ 'patterns' => $patterns,
+ 'displayQueriesToSelectors' => $display_queries_to_selectors,
'settings' => [
'category' => self::$block_category['slug'],
'icon' => $config['icon'] ?? 'cloud',
@@ -117,10 +134,6 @@ public static function register_block_configuration( array $config ): array {
$script_handle = $block_type->editor_script_handles[0] ?? '';
- // Register a default pattern that simply displays the available data.
- $default_pattern_name = BlockPatterns::register_default_block_pattern( $block_name, $config['title'], $config['queries'][ ConfigRegistry::DISPLAY_QUERY_KEY ] );
- $block_config['patterns']['default'] = $default_pattern_name;
-
return [ $block_config, $script_handle ];
}
}
diff --git a/inc/Editor/BlockManagement/ConfigRegistry.php b/inc/Editor/BlockManagement/ConfigRegistry.php
index 59b05a691..d747d5abe 100644
--- a/inc/Editor/BlockManagement/ConfigRegistry.php
+++ b/inc/Editor/BlockManagement/ConfigRegistry.php
@@ -4,13 +4,12 @@
defined( 'ABSPATH' ) || exit();
+use RemoteDataBlocks\Config\Block\RemoteDataBlock;
use RemoteDataBlocks\Logging\Logger;
use RemoteDataBlocks\Config\Query\HttpQuery;
use RemoteDataBlocks\Config\Query\QueryInterface;
use RemoteDataBlocks\Editor\BlockPatterns\BlockPatterns;
use RemoteDataBlocks\Logging\LoggerInterface;
-use RemoteDataBlocks\Validation\ConfigSchemas;
-use RemoteDataBlocks\Validation\Validator;
use WP_Error;
use function parse_blocks;
@@ -20,11 +19,11 @@
class ConfigRegistry {
private static LoggerInterface $logger;
- public const RENDER_QUERY_KEY = 'render_query';
- public const SELECTION_QUERIES_KEY = 'selection_queries';
- public const DISPLAY_QUERY_KEY = 'display';
+ public const DEPRECATED_DISPLAY_QUERY_KEY = 'display';
+ public const PLACEHOLDERS_KEY = 'placeholders';
public const LIST_QUERY_KEY = 'list';
public const SEARCH_QUERY_KEY = 'search';
+ public const QUERIES_KEY = 'queries';
public static function init( ?LoggerInterface $logger = null ): void {
self::$logger = $logger ?? new Logger();
@@ -32,100 +31,156 @@ public static function init( ?LoggerInterface $logger = null ): void {
}
public static function register_block( array $block_config = [] ): bool|WP_Error {
- // Validate the provided user configuration.
- $schema = ConfigSchemas::get_remote_data_block_config_schema();
- $validator = new Validator( $schema, static::class, '$block_config' );
- $validated = $validator->validate( $block_config );
+ // Validate the provided block configuration.
+ $block_config = RemoteDataBlock::from_array( $block_config );
- if ( is_wp_error( $validated ) ) {
- return $validated;
+ if ( is_wp_error( $block_config ) ) {
+ self::$logger->error( $block_config->get_error_message() );
+ return $block_config;
}
// Check if the block has already been registered.
+ $block_config = $block_config->to_array();
$block_title = $block_config['title'];
$block_name = ConfigStore::get_block_name( $block_title );
if ( ConfigStore::is_registered_block( $block_name ) ) {
return self::create_error( $block_title, sprintf( 'Block %s has already been registered', $block_name ) );
}
- $display_query = self::inflate_query( $block_config[ self::RENDER_QUERY_KEY ]['query'] );
- $input_schema = $display_query->get_input_schema();
- $output_schema = $display_query->get_output_schema();
- $is_collection = true === ( $output_schema['is_collection'] ?? false );
+ // Ensure that the block has queries.
+ if ( empty( $block_config[ self::QUERIES_KEY ] ) ) {
+ return self::create_error( $block_title, 'Block configuration must have a non-empty "queries" array' );
+ }
- // Check if any variables are required
- $has_required_variables = array_reduce(
- array_column( $input_schema, 'required' ),
- fn( $carry, $required ) => $carry || ( $required ?? true ),
- false
- );
+ $queries = [];
+ $display_queries_to_selectors_map = [];
+
+ // Either use the placeholders from the config, or build them from the queries.
+ // Placeholders are meant to determine the queries that'll be visually represented
+ // in the block's UI upon initial insertion.
+ if ( ! empty( $block_config[ self::PLACEHOLDERS_KEY ] ) ) {
+ $placeholders = $block_config[ self::PLACEHOLDERS_KEY ];
+ // Pre-validate the placeholders, to ensure they exist.
+ foreach ( $placeholders as $placeholder ) {
+ if ( ! isset( $block_config[ self::QUERIES_KEY ][ $placeholder['query_key'] ] ) ) {
+ return self::create_error( $block_title, sprintf( 'Query "%s" not found for placeholder "%s"', $placeholder['query_key'], $placeholder['name'] ) );
+ }
+ }
+ } else {
+ $placeholders = [];
+ // Using array_keys here triggers a psalm error, so it's set to $_ instead.
+ // Supressing the psalm error is a not a good idea, so instead this is the better solution.
+ // ToDo: Fix the psalm error, and see if array_keys could be used here again.
+ foreach ( $block_config[ self::QUERIES_KEY ] as $query_key => $_ ) {
+ $placeholders[] = [
+ 'name' => self::get_query_name_from_key( $query_key ),
+ 'query_key' => $query_key,
+ ];
+ }
+ }
- // Build the base configuration for the block. This is our own internal
- // configuration, not what will be passed to WordPress's register_block_type.
- // @see BlockRegistration::register_block_type::register_blocks.
- $config = [
- 'description' => '',
- 'icon' => $block_config['icon'] ?? 'cloud',
- 'instructions' => $block_config['instructions'] ?? null,
- 'name' => $block_name,
- 'overrides' => $block_config['overrides'] ?? [],
- 'patterns' => [],
- 'queries' => [
- self::DISPLAY_QUERY_KEY => $display_query,
- ],
- 'selectors' => [
- [
- 'image_url' => $display_query->get_image_url(),
- 'inputs' => self::map_input_variables( $input_schema ),
- 'name' => $has_required_variables ? 'Manual input' : ( $is_collection ? 'Load collection' : 'Load item' ),
- 'query_key' => self::DISPLAY_QUERY_KEY,
- 'type' => $has_required_variables ? 'manual-input' : 'load-without-input',
- ],
- ],
- 'title' => $block_title,
- ];
+ foreach ( $placeholders as $placeholder ) {
+ $selectors = [];
- // Register "selectors" which allow the user to use a query to assist in
- // selecting data for display by the block.
- foreach ( $block_config[ self::SELECTION_QUERIES_KEY ] ?? [] as $selection_query ) {
- $from_query = self::inflate_query( $selection_query['query'] );
- $from_query_type = $selection_query['type'];
- $to_query = $display_query;
+ $placeholder_query_key = $placeholder['query_key'];
+ $placeholder_query = self::inflate_query( $block_config[ self::QUERIES_KEY ][ $placeholder_query_key ] );
+ $queries[ $placeholder_query_key ] = $placeholder_query;
- $config['queries'][ $from_query::class ] = $from_query;
+ $placeholder_query_input_schema = $placeholder_query->get_input_schema();
+ $placeholder_query_output_schema = $placeholder_query->get_output_schema();
- $from_input_schema = $from_query->get_input_schema();
- $from_output_schema = $from_query->get_output_schema();
+ // We first generate the manual input selector for the placeholder query.
+ $is_collection = true === ( $placeholder_query_output_schema['is_collection'] ?? false );
+ $has_required_variables = array_reduce(
+ array_column( $placeholder_query_input_schema, 'required' ),
+ fn( $carry, $required ) => $carry || ( $required ?? true ),
+ false
+ );
- foreach ( array_keys( $to_query->get_input_schema() ) as $to ) {
- if ( ! isset( $from_output_schema['type'][ $to ] ) ) {
- return self::create_error( $block_title, sprintf( 'Cannot map key "%1$s" from %2$s query. The display query for this block requires a "%1$s" key as an input, but it is not present in the output schema for the %2$s query. Try adding a "%1$s" mapping to the output schema for the %2$s query.', esc_html( $to ), $from_query_type ) );
+ $selector_config = [
+ 'image_url' => $placeholder_query->get_image_url(),
+ 'inputs' => self::map_input_variables( $placeholder_query_input_schema ),
+ 'name' => $has_required_variables ? 'Manual input' : ( $is_collection ? 'Load collection' : 'Load item' ),
+ 'query_key' => $placeholder_query_key,
+ 'type' => $has_required_variables ? 'manual-input' : 'load-without-input',
+ ];
+
+ $selectors[] = $selector_config;
+
+ // We run through all the queries to find compatible selectors.
+ foreach ( $block_config[ self::QUERIES_KEY ] as $selector_query_key => $selector_query ) {
+ // Don't match the placeholder to itself, as that's already been done.
+ if ( $selector_query_key === $placeholder_query_key ) {
+ continue;
+ }
+
+ $selector_query = self::inflate_query( $selector_query );
+ $queries[ $selector_query_key ] = $selector_query;
+
+ $selector_query_input_schema = $selector_query->get_input_schema();
+ $selector_query_output_schema = $selector_query->get_output_schema();
+
+ // Infer the type of the selector query.
+ // ToDo: Add support for multiple types.
+ $inferred_selector_query_type = self::infer_query_type( $selector_query_input_schema, $selector_query_output_schema );
+ if ( 'unknown' === $inferred_selector_query_type ) {
+ continue;
}
- }
- if ( self::SEARCH_QUERY_KEY === $from_query_type ) {
- $search_input_count = count( array_filter( $from_input_schema, function ( array $input_var ): bool {
- return 'ui:search_input' === $input_var['type'];
- } ) );
+ // If the output schema is not an array, skip.
+ if ( ! is_array( $selector_query_output_schema['type'] ) ) {
+ continue;
+ }
+
+ // Find the fields that are present in both the selector's output schema and the placeholder's input schema.
+ $intersecting_keys = array_intersect_key( $selector_query_output_schema['type'], $placeholder_query_input_schema );
+
+ // Skip this, if they don't intersect.
+ if ( empty( $intersecting_keys ) ) {
+ continue;
+ }
- if ( 1 !== $search_input_count ) {
- return self::create_error( $block_title, 'A search query must have one input variable with type "ui:search_input"' );
+ // Ensure the fields found have the same name and type in both the schemas.
+ $valid_intersecting_keys = self::validate_selector_query_mapping( $intersecting_keys, $placeholder_query_input_schema, $selector_query_output_schema );
+ if ( empty( $valid_intersecting_keys ) ) {
+ continue;
}
+
+ // Now we generate the selector query's config as a selector for the placeholder query.
+ $selector_config = [
+ 'image_url' => $selector_query->get_image_url(),
+ 'inputs' => self::map_input_variables( $selector_query_input_schema ),
+ 'name' => self::get_query_name_from_key( $selector_query_key ),
+ 'query_key' => $selector_query_key,
+ 'type' => $inferred_selector_query_type,
+ ];
+
+ // Add the selector to the beginning of the selectors array.
+ array_unshift(
+ $selectors,
+ $selector_config
+ );
}
- // Add the selector to the configuration.
- array_unshift(
- $config['selectors'],
- [
- 'image_url' => $from_query->get_image_url(),
- 'inputs' => self::map_input_variables( $from_input_schema ),
- 'name' => $selection_query['display_name'] ?? ucfirst( $from_query_type ),
- 'query_key' => $from_query::class,
- 'type' => $from_query_type,
- ]
- );
+ $display_queries_to_selectors_map[ $placeholder_query_key ] = [
+ 'name' => $placeholder['name'],
+ 'selectors' => $selectors,
+ ];
}
+ // Build the block configuration.
+ $config = [
+ 'description' => '',
+ 'icon' => $block_config['icon'] ?? 'cloud',
+ 'instructions' => $block_config['instructions'] ?? null,
+ 'name' => $block_name,
+ 'overrides' => $block_config['overrides'] ?? [],
+ 'patterns' => [],
+ 'queries' => $queries,
+ 'display_queries_to_selectors' => $display_queries_to_selectors_map,
+ 'title' => $block_title,
+ ];
+
// Register patterns which can be used with the block.
foreach ( $block_config['patterns'] ?? [] as $pattern ) {
$parsed_blocks = parse_blocks( $pattern['html'] );
@@ -146,6 +201,30 @@ public static function register_block( array $block_config = [] ): bool|WP_Error
return true;
}
+ private static function validate_selector_query_mapping( array $intersecting_keys, array $display_query_input_schema, array $output_schema ): array {
+ return array_filter( $intersecting_keys, function ( $key ) use ( $display_query_input_schema, $output_schema ) {
+ $display_query_fields = $display_query_input_schema[ $key ];
+
+ // If the name doesn't match, skip.
+ if ( $display_query_fields['name'] !== $output_schema['type'][ $key ]['name'] ) {
+ return false;
+ }
+
+ // If the display query field is an id:list and the output schema field is an id, allow it as that's valid.
+ if ( 'id:list' === $display_query_fields['type'] && 'id' === $output_schema['type'][ $key ]['type'] ) {
+ return true;
+ }
+
+ // If the types don't match, skip.
+ if ( $display_query_fields['type'] !== $output_schema['type'][ $key ]['type'] ) {
+ return false;
+ }
+
+ // If the types match, allow it.
+ return true;
+ }, ARRAY_FILTER_USE_KEY );
+ }
+
private static function register_block_pattern( string $block_name, string $pattern_title, string $pattern_content ): string {
// Add the block arg to any bindings present in the pattern.
$pattern_name = 'remote-data-blocks/' . sanitize_title_with_dashes( $pattern_title, '', 'save' );
@@ -195,4 +274,27 @@ function ( string $slug, array $input_var ): array {
array_values( $input_schema )
);
}
+
+ private static function get_query_name_from_key( string $key ): string {
+ // Replace any non-alphanumeric characters with spaces and convert to title case
+ return ucwords( preg_replace( '/[^a-zA-Z0-9]/', ' ', $key ) );
+ }
+
+ private static function infer_query_type( array $input_schema, array $output_schema ): string {
+ // If any input variable has type 'ui:search_input', it's a search query.
+ foreach ( $input_schema as $input_var ) {
+ if ( isset( $input_var['type'] ) && 'ui:search_input' === $input_var['type'] ) {
+ return self::SEARCH_QUERY_KEY;
+ }
+ }
+
+ // If output_schema has 'is_collection' true, it's a list query.
+ if ( isset( $output_schema['is_collection'] ) && true === $output_schema['is_collection'] ) {
+ return self::LIST_QUERY_KEY;
+ }
+
+ // This will happen if a query has not been configured correctly as a search or list query.
+ // So we error out, to replace the previous way of validating when the type was set.
+ return 'unknown';
+ }
}
diff --git a/inc/Editor/BlockManagement/ConfigStore.php b/inc/Editor/BlockManagement/ConfigStore.php
index 6ed252ce0..562c5f7f2 100644
--- a/inc/Editor/BlockManagement/ConfigStore.php
+++ b/inc/Editor/BlockManagement/ConfigStore.php
@@ -4,7 +4,6 @@
defined( 'ABSPATH' ) || exit();
-use RemoteDataBlocks\Config\Query\QueryInterface;
use RemoteDataBlocks\Integrations\GenericHttp\GenericHttpDataSource;
use RemoteDataBlocks\Logging\Logger;
use RemoteDataBlocks\Logging\LoggerInterface;
@@ -78,12 +77,15 @@ public static function get_data_source_type( string $block_name ): ?string {
return null;
}
- $query = $config['queries'][ ConfigRegistry::DISPLAY_QUERY_KEY ] ?? null;
- if ( ! ( $query instanceof QueryInterface ) ) {
+ $display_queries_to_selectors = $config['display_queries_to_selectors'] ?? [];
+ if ( empty( $display_queries_to_selectors ) ) {
return null;
}
- $data_source = $query->get_data_source();
+ // Get the first display query's data source type.
+ $display_query_key = array_keys( $display_queries_to_selectors )[0];
+ $display_query = $config['queries'][ $display_query_key ];
+ $data_source = $display_query->get_data_source();
if ( $data_source instanceof GenericHttpDataSource ) {
return $data_source->get_service_name();
}
diff --git a/inc/Editor/BlockPatterns/BlockPatterns.php b/inc/Editor/BlockPatterns/BlockPatterns.php
index 02f614d9f..bb5a12921 100644
--- a/inc/Editor/BlockPatterns/BlockPatterns.php
+++ b/inc/Editor/BlockPatterns/BlockPatterns.php
@@ -73,7 +73,7 @@ private static function populate_template( string $template_name, array $attribu
* @param QueryInterface $display_query The display query.
* @return string The registered pattern name.
*/
- public static function register_default_block_pattern( string $block_name, string $block_title, QueryInterface $display_query ): string {
+ public static function register_default_block_pattern( string $block_name, string $block_title, string $display_query_key, QueryInterface $display_query ): string {
self::load_templates();
// Loop through output variables and generate a pattern. Each text field will
@@ -112,7 +112,7 @@ public static function register_default_block_pattern( string $block_name, strin
$bindings['heading']['content'] = [ $field, $name ];
break;
}
-
+
$bindings['paragraphs'][] = [
'content' => [ $field, $name ],
];
@@ -177,7 +177,7 @@ public static function register_default_block_pattern( string $block_name, strin
$content = self::populate_template( 'empty', [] );
}
- $pattern_name = sprintf( '%s/pattern', $block_name );
+ $pattern_name = sprintf( '%s/%s-pattern', $block_name, $display_query_key );
register_block_pattern(
$pattern_name,
@@ -188,6 +188,7 @@ public static function register_default_block_pattern( string $block_name, strin
'content' => $content,
'inserter' => true,
'source' => 'plugin',
+ 'keywords' => [ $display_query_key ],
]
);
diff --git a/inc/Editor/DataBinding/BlockBindings.php b/inc/Editor/DataBinding/BlockBindings.php
index 79ffbccf6..a0825a377 100644
--- a/inc/Editor/DataBinding/BlockBindings.php
+++ b/inc/Editor/DataBinding/BlockBindings.php
@@ -133,7 +133,7 @@ private static function execute_queries( array $block_context ): array|WP_Error
$remote_data = $remote_data->to_array();
$block_name = $remote_data['blockName'];
$enabled_overrides = $remote_data['enabledOverrides'] ?? [];
- $query_key = $remote_data['queryKey'] ?? ConfigRegistry::DISPLAY_QUERY_KEY;
+ $query_key = $remote_data['queryKey'] ?? ConfigRegistry::DEPRECATED_DISPLAY_QUERY_KEY;
$array_of_input_variables = $remote_data['queryInputs'];
$block_config = ConfigStore::get_block_configuration( $block_name );
diff --git a/inc/ExampleApi/ExampleApi.php b/inc/ExampleApi/ExampleApi.php
index 28751ee98..94e06114a 100644
--- a/inc/ExampleApi/ExampleApi.php
+++ b/inc/ExampleApi/ExampleApi.php
@@ -119,13 +119,14 @@ public static function register_remote_data_block(): void {
register_remote_data_block( [
'title' => self::$block_title,
- 'render_query' => [
- 'query' => $get_record_query,
+ 'queries' => [
+ 'display' => $get_record_query,
+ 'get_table' => $get_table_query,
],
- 'selection_queries' => [
+ 'placeholders' => [
[
- 'query' => $get_table_query,
- 'type' => 'list',
+ 'query_key' => 'display',
+ 'name' => 'Get Record',
],
],
] );
diff --git a/inc/REST/RemoteDataController.php b/inc/REST/RemoteDataController.php
index 21667bd71..ab78763b7 100644
--- a/inc/REST/RemoteDataController.php
+++ b/inc/REST/RemoteDataController.php
@@ -36,7 +36,13 @@ public static function register_rest_routes(): void {
return null !== ConfigStore::get_block_configuration( $value );
},
],
- 'query_key' => [
+ 'display_query_key' => [
+ 'required' => true,
+ 'sanitize_callback' => function ( $value ) {
+ return strval( $value );
+ },
+ ],
+ 'selector_query_key' => [
'required' => true,
'sanitize_callback' => function ( $value ) {
return strval( $value );
@@ -54,11 +60,12 @@ public static function register_rest_routes(): void {
public static function execute_queries( WP_REST_Request $request ): array|WP_Error {
$block_name = $request->get_param( 'block_name' );
- $query_key = $request->get_param( 'query_key' );
+ $display_query_key = $request->get_param( 'display_query_key' );
+ $selector_query_key = $request->get_param( 'selector_query_key' );
$query_inputs = $request->get_param( 'query_inputs' );
$block_config = ConfigStore::get_block_configuration( $block_name );
- $query = $block_config['queries'][ $query_key ];
+ $query = $block_config['queries'][ $selector_query_key ];
$query_response = $query->execute_batch( $query_inputs );
if ( is_wp_error( $query_response ) ) {
@@ -72,7 +79,8 @@ public static function execute_queries( WP_REST_Request $request ): array|WP_Err
[
'block_name' => $block_name,
'result_id' => wp_generate_uuid4(),
- 'query_key' => $query_key,
+ 'display_query_key' => $display_query_key,
+ 'selector_query_key' => $selector_query_key,
],
$query_response
);
diff --git a/inc/Validation/ConfigSchemas.php b/inc/Validation/ConfigSchemas.php
index 1ef1970fb..3760f456e 100644
--- a/inc/Validation/ConfigSchemas.php
+++ b/inc/Validation/ConfigSchemas.php
@@ -7,7 +7,6 @@
use RemoteDataBlocks\Config\Query\HttpQuery;
use RemoteDataBlocks\Config\Query\QueryInterface;
use RemoteDataBlocks\Config\QueryRunner\QueryRunnerInterface;
-use RemoteDataBlocks\Editor\BlockManagement\ConfigRegistry;
/**
* ConfigSchemas class.
@@ -86,27 +85,21 @@ private static function generate_remote_data_block_config_schema(): array {
] )
)
),
- 'render_query' => Types::object( [
- 'query' => Types::one_of(
- Types::instance_of( QueryInterface::class ),
- Types::serialized_config_for( HttpQuery::class ),
- ),
- ] ),
- 'selection_queries' => Types::nullable(
+ 'placeholders' => Types::nullable(
Types::list_of(
Types::object( [
- 'display_name' => Types::nullable( Types::string() ),
- 'query' => Types::one_of(
- Types::instance_of( QueryInterface::class ),
- Types::serialized_config_for( HttpQuery::class ),
- ),
- 'type' => Types::enum(
- ConfigRegistry::LIST_QUERY_KEY,
- ConfigRegistry::SEARCH_QUERY_KEY
- ),
- ] )
+ 'name' => Types::string(),
+ 'query_key' => Types::string(),
+ ] ),
)
),
+ 'queries' => Types::record(
+ Types::string(),
+ Types::one_of(
+ Types::instance_of( QueryInterface::class ),
+ Types::serialized_config_for( HttpQuery::class ),
+ ),
+ ),
'overrides' => Types::nullable(
Types::list_of(
Types::object( [
diff --git a/src/block-editor/filters/withBlockBinding.tsx b/src/block-editor/filters/withBlockBinding.tsx
index 5cbef56c1..115a94c58 100644
--- a/src/block-editor/filters/withBlockBinding.tsx
+++ b/src/block-editor/filters/withBlockBinding.tsx
@@ -17,11 +17,11 @@ import {
PATTERN_OVERRIDES_CONTEXT_KEY,
} from '@/config/constants';
import { getBoundBlockClassName, getMismatchedAttributes } from '@/utils/block-binding';
-import { getBlockAvailableBindings, getBlockTitle } from '@/utils/localized-block-data';
+import { getAvailableBindingsForQuery, getBlockTitle } from '@/utils/localized-block-data';
interface BoundBlockEditProps {
attributes: RemoteDataInnerBlockAttributes;
- availableBindings: AvailableBindings;
+ availableBindings: AvailableBindingsForQuery;
blockName: string;
children: JSX.Element;
remoteDataName: string;
@@ -105,12 +105,24 @@ export const withBlockBinding = createHigherOrderComponent( BlockEdit => {
) => {
const { attributes, context, name, previewIndex: index = 0, setAttributes } = props;
const { remoteData } = useRemoteDataContext( context );
- const availableBindings = getBlockAvailableBindings( remoteData?.blockName ?? '' );
- const hasAvailableBindings = Boolean( Object.keys( availableBindings ).length );
const { hasMultiSelection } = useSelect< BlockEditorStoreSelectors >( blockEditorStore );
// If the block does not have a remote data context, render it as usual.
- if ( ! remoteData || ! hasAvailableBindings ) {
+ if ( ! remoteData ) {
+ return ;
+ }
+
+ const displayQueryKey = remoteData.displayQueryKey;
+
+ const availableBindings = getAvailableBindingsForQuery(
+ remoteData?.blockName ?? '',
+ displayQueryKey ?? ''
+ );
+
+ const hasAvailableBindings = Boolean( Object.keys( availableBindings ).length );
+
+ // If the block does not have any bindings, render it as usual.
+ if ( ! hasAvailableBindings ) {
return ;
}
diff --git a/src/block-editor/format-types/inline-binding/components/InlineBindingSelectFieldPopover.tsx b/src/block-editor/format-types/inline-binding/components/InlineBindingSelectFieldPopover.tsx
index a00a12517..c597bc15d 100644
--- a/src/block-editor/format-types/inline-binding/components/InlineBindingSelectFieldPopover.tsx
+++ b/src/block-editor/format-types/inline-binding/components/InlineBindingSelectFieldPopover.tsx
@@ -11,6 +11,7 @@ import { __ } from '@wordpress/i18n';
import { WPFormat, useAnchor } from '@wordpress/rich-text';
import { InlineBindingSelectField } from '@/block-editor/format-types/inline-binding/components/InlineBindingSelection';
+import { getFirstDisplayQueryKey } from '@/utils/localized-block-data';
interface InlineBindingSelectFieldPopoverProps {
contentRef: React.RefObject< HTMLElement >;
@@ -28,6 +29,10 @@ export function InlineBindingSelectFieldPopover( props: InlineBindingSelectField
} );
const { remoteData, selectedField, type } = props.fieldSelection;
+ // ToDo: We are picking the first display query for now.
+ const displayQueryKey =
+ remoteData?.displayQueryKey ?? getFirstDisplayQueryKey( remoteData?.blockName ?? '' );
+
return (
props.onSelectField( { ...data, action: 'update_field_shortcode' }, fieldValue )
diff --git a/src/block-editor/format-types/inline-binding/components/InlineBindingSelectNew.tsx b/src/block-editor/format-types/inline-binding/components/InlineBindingSelectNew.tsx
index 93646a47e..58d5e6196 100644
--- a/src/block-editor/format-types/inline-binding/components/InlineBindingSelectNew.tsx
+++ b/src/block-editor/format-types/inline-binding/components/InlineBindingSelectNew.tsx
@@ -4,7 +4,11 @@ import { __ } from '@wordpress/i18n';
import { chevronRightSmall } from '@wordpress/icons';
import { DataViewsModal } from '@/blocks/remote-data-container/components/modals/DataViewsModal';
-import { getBlocksConfig } from '@/utils/localized-block-data';
+import {
+ getBlocksConfig,
+ getFirstDisplayQueryKey,
+ getSelectorsForDisplayQuery,
+} from '@/utils/localized-block-data';
type InlineBindingSelectNewProps = Omit< DropdownMenuProps, 'label' > & {
onSelectField: ( data: FieldSelection, fieldValue: string ) => void;
@@ -41,9 +45,10 @@ export function InlineBindingSelectNew( props: InlineBindingSelectNewProps ) {
Object.entries( blocksByType ).map( ( [ dataSourceType, configs ] ) => (
{ configs.map( blockConfig => {
- // For now, we will use the first compatible selector, but this
- // should be improved.
- const compatibleSelector = blockConfig.selectors.find( selector =>
+ // ToDo: We are picking the first display query, and the first compatible selector for now.
+ const displayQueryKey = getFirstDisplayQueryKey( blockConfig.name );
+ const selectors = getSelectorsForDisplayQuery( blockConfig.name, displayQueryKey );
+ const compatibleSelector = selectors.find( selector =>
[ 'list', 'search' ].includes( selector.type )
);
@@ -57,7 +62,8 @@ export function InlineBindingSelectNew( props: InlineBindingSelectNewProps ) {
blockName={ blockConfig.name }
headerImage={ compatibleSelector.image_url }
onSelectField={ onSelectField }
- queryKey={ compatibleSelector.query_key }
+ selectorQueryKey={ compatibleSelector.query_key }
+ displayQueryKey={ displayQueryKey }
renderTrigger={ ( { onClick } ) => (