Query Control Autocomplete Refactoring

Cover image

Purpose:

Standardize the way the various widgets access the Query-Control Module’s autocomplete & show-title functionality.

Audience: widgets developers.

This change was introduced in Elementor Pro 2.6.0.
The old API is deprecated and will be declared “end of life” in Elementor Pro 2.10.0 or 3.0.0 (whichever is earlier).

Method:

Each widget using the ElementorPro\Modules\QueryControl\Module::QUERY_CONTROL_ID control, should specify an autocomplete array, according to the following syntax:

$this->add_control(
	'my_unique_control_id',
	[
		//...
		'type' => ElementorPro\Modules\QueryControl\Module::QUERY_CONTROL_ID,
		'autocomplete' => [
			'object' => ElementorPro\Modules\QueryControl\Module::QUERY_OBJECT_TAX,
			'display' => 'detailed',
			'by_field' => 'term_taxonomy_id',
			'query' => [],
		],
	]
);

“autocomplete” Properties:

object (required)(string) : The object to query, accepts:

  • post: will use WP_Query(), if query[‘post_type’] is empty or missing, will default to ‘any’.
  • tax: will use get_terms(). When `post_type` is provided, get_object_taxonomies() is used to build that `taxonomy` args that are passed to get_terms(). When both `taxonomy` and `post_type` are provided, ‘post_type’ is ignored.
  • user: will use WP_User_Query() with the args defined in ‘query‘, if none are provided, will default to search fields: `ID` and `display_name` and search columns: `user_login` and `user_nicename`.
  • author: will use WP_User_Query(). The following pre-defined args are always added to the query args:
    • $query[‘who’] = ‘authors’
    • $query[‘has_published_posts’] = true
  • library_template: will use WP_Query() with add the following to the query args:
    • $query[‘post_type’] = Elementor\TemplateLibrary\Source_Local::CPT;
    • $query[‘orderby’] = ‘meta_value’;
    • $query[‘order’] = ‘ASC’;
  • attachment: will use WP_Query() with post_type = attachment. The following pre-defined args are always added to the query args:
    • $query[‘post_type’] = ‘attachment’;
    • $query[‘post_status’] = ‘inherit’;

display (string) : Output formating, accepts :

  • minimal: (default) name only.
  • detailed: name and context, according to one of the following patterns:
    • Post & Taxonomies: `<Taxonomy name|Post-Type name> : [parent] … [parent] > name`
    • Users & Authors: `name <email>`
  • user defined: representing a user-defined hook, note that each `object` value requires a different hook string:
`object` valueHook name
tax“elementor/query/get_autocomplete/tax/{user defined value}”
post | attachment“elementor/query/get_autocomplete/custom/{user defined value}”
user | author“elementor/query/get_autocomplete/user/{user defined value}”

by_field (string) : The Id field that is used for the term query, relevant only if `object` is set to either ‘tax’ or ’cpt_tax’.

query (array) : Array of args, as defined in WordPress, to be passed “as-is” to the relevant WordPress query object or function, see `object`.

Example:

Before:

// In your Widget you would have
$this->add_control(
	'template_id',
	[
		'label' => __( 'Choose Template', 'elementor-pro' ),
		'type' => ElementorPro\Modules\QueryControl\Module::QUERY_CONTROL_ID,
		'filter_type' => 'library_widget_templates',
		'label_block' => true,
	]
);
// And to support it you whould also have

add_filter( 'elementor_pro/query_control/get_autocomplete/library_widget_templates', function ( array $results, array $data ) {
	$document_types = ElementorPro\Plugin::elementor()->documents->get_document_types( [
		'show_in_library' => true,
	] );
	$query_params = [
		'post_type' => \Elementor\TemplateLibrary\Source_Local::CPT,
		'posts_per_page' => -1,
		'meta_query' => [
			[
				'key' => Elementor\Core\Base\Document::TYPE_META_KEY,
				'value' => array_keys( $document_types ),
				'compare' => 'IN',
			],
		],
	];

	$query = new \WP_Query( $query_params );

	foreach ( $query->posts as $post ) {
		$document = \Elementor\Plugin::instance()->documents->get( $post->ID );

		if ( $document ) {
			$results[] = [
				'id' => $post->ID,
				'text' => $post->post_title,
			];
		}
	}
	return $results;
}, 10, 2 );

add_filter( 'elementor_pro/query_control/get_value_titles/library_widget_templates', function ( $results, $data ) {
	$document = \Elementor\Plugin::instance()->documents->get( $data['id'] );

	if ( $document ) {
		$results[ $data['id'] ] = $document->get_post()->post_title;
	}

	return $results;
}, 10, 2 );

After:

// In your widget
$document_types = ElementorPro\Plugin::elementor()->documents->get_document_types( [
		'show_in_library' => true,
	] );
$this->add_control(
	'template_id',
	[
		'label' => __( 'Choose Template', 'elementor-pro' ),
		'type' => ElementorPro\Modules\QueryControl\Module::QUERY_CONTROL_ID,
		'label_block' => true,
		'autocomplete' => [
			'object' => ElementorPro\Modules\QueryControl\Module::QUERY_OBJECT_LIBRARY_TEMPLATE,
			'query' => [
				'meta_query' => [
					[
						'key' => Elementor\Core\Base\Document::TYPE_META_KEY,
						'value' => array_keys( $document_types ),
						'compare' => 'IN',
					],
				],
			],
		],
	]
);

As you can see the control already accepts the query arguments so there is no need to add supporting filters.

Author

Ohad Raz
Ohad Raz

Leave a Reply

Your email address will not be published. Required fields are marked *