<?php
namespace ElementorPro\Modules\QueryControl;
use Elementor\Controls_Manager;
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
use Elementor\Core\Editor\Editor;
use Elementor\TemplateLibrary\Source_Local;
use Elementor\Widget_Base;
use ElementorPro\Base\Module_Base;
use ElementorPro\Core\Utils;
use ElementorPro\Modules\QueryControl\Controls\Group_Control_Taxonomy;
use ElementorPro\Modules\QueryControl\Controls\Template_Query;
use ElementorPro\Modules\QueryControl\Classes\Elementor_Post_Query;
use ElementorPro\Modules\QueryControl\Classes\Elementor_Related_Query;
use ElementorPro\Modules\QueryControl\Controls\Group_Control_Posts;
use ElementorPro\Modules\QueryControl\Controls\Group_Control_Query;
use ElementorPro\Modules\QueryControl\Controls\Group_Control_Related;
use ElementorPro\Modules\QueryControl\Controls\Query;
use ElementorPro\Plugin;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Module extends Module_Base {
const QUERY_CONTROL_ID = 'query';
const AUTOCOMPLETE_ERROR_CODE = 'QueryControlAutocomplete';
const GET_TITLES_ERROR_CODE = 'QueryControlGetTitles';
// Supported objects for query:
const QUERY_OBJECT_POST = 'post';
const QUERY_OBJECT_TAX = 'tax';
const QUERY_OBJECT_AUTHOR = 'author';
const QUERY_OBJECT_USER = 'user';
const QUERY_OBJECT_LIBRARY_TEMPLATE = 'library_template';
const QUERY_OBJECT_ATTACHMENT = 'attachment';
// Objects that are manipulated by js (not sent in AJAX):
const QUERY_OBJECT_CPT_TAX = 'cpt_tax';
const QUERY_OBJECT_JS = 'js';
public static $displayed_ids = [];
private static $supported_objects_for_query = [
self::QUERY_OBJECT_POST,
self::QUERY_OBJECT_TAX,
self::QUERY_OBJECT_AUTHOR,
self::QUERY_OBJECT_USER,
self::QUERY_OBJECT_LIBRARY_TEMPLATE,
self::QUERY_OBJECT_ATTACHMENT,
];
public function __construct() {
parent::__construct();
$this->add_actions();
}
public static function add_to_avoid_list( $ids ) {
self::$displayed_ids = array_unique( array_merge( self::$displayed_ids, $ids ) );
}
public static function get_avoid_list_ids() {
return self::$displayed_ids;
}
/**
* @deprecated 2.5.0 Use `Group_Control_Query` class capabilities instead.
*
* @param Widget_Base $widget
*/
public static function add_exclude_controls( $widget ) {
Plugin::elementor()->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '2.5.0', 'class Group_Control_Query' );
$widget->add_control(
'exclude',
[
'label' => esc_html__( 'Exclude', 'elementor-pro' ),
'type' => Controls_Manager::SELECT2,
'multiple' => true,
'options' => [
'current_post' => esc_html__( 'Current Post', 'elementor-pro' ),
'manual_selection' => esc_html__( 'Manual Selection', 'elementor-pro' ),
],
'label_block' => true,
]
);
$widget->add_control(
'exclude_ids',
[
'label' => esc_html__( 'Search & Select', 'elementor-pro' ),
'type' => self::QUERY_CONTROL_ID,
'autocomplete' => [
'object' => self::QUERY_OBJECT_POST,
],
'options' => [],
'label_block' => true,
'multiple' => true,
'condition' => [
'exclude' => 'manual_selection',
],
]
);
$widget->add_control(
'avoid_duplicates',
[
'label' => esc_html__( 'Avoid Duplicates', 'elementor-pro' ),
'type' => Controls_Manager::SWITCHER,
'default' => '',
'description' => esc_html__( 'Set to Yes to avoid duplicate posts from showing up on the page. This only affects the frontend.', 'elementor-pro' ),
]
);
}
public function get_name() {
return 'query-control';
}
private function search_taxonomies( $query_params, $query_data, $data ) {
$by_field = $query_data['query']['by_field'];
$terms = get_terms( $query_params );
$results = [];
foreach ( $terms as $term ) {
$results[] = [
'id' => $term->{$by_field},
'text' => $this->get_term_name( $term, $query_data['display'], $data ),
];
}
return $results;
}
/**
* 'autocomplete' => [
* 'object' => 'post|tax|user|library_template|attachment|js', // required
* 'display' => 'minimal(default)|detailed|custom_filter_name',
* 'by_field' => 'term_taxonomy_id(default)|term_id', // relevant only if `object` is tax|cpt_tax
* 'query' => [
* 'post_type' => 'any|post|page|custom-post-type', // can be an array for multiple post types.
* // 'any' should not be used if 'object' is 'tax' or 'cpt_tax'.
* ...
* ],
* ],
*
* 'object' (required): the queried object.
* supported values:
* '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, will first use get_object_taxonomies() to build 'taxonomy'
* args then invoke get_terms().
* When both 'taxonomy' and 'post_type' are provided, 'post_type' is ignored.
* 'cpt_tax' : Used in frontend only, will be replaced to 'tax' by js.
* Will use get_object_taxonomies() to build 'taxonomy' args then use get_terms().
* 'user' : will use WP_User_Query() with the args defined in 'query'.
* 'author' : will use WP_User_Query() with pre-defined args.
* 'library_template' : will use WP_Query() with post_type = Source_Local::CPT.
* 'attachment' : will use WP_Query() with post_type = attachment.
* 'js' : Query data is populated by JavaScript.
* By the time the data is sent to the server,
* the 'object' value should be replaced with one of the other valid 'object' values and
* the Query array populated accordingly.
* user_defined : will invoke apply_filters() using the user_defined value as filter name,
* `elementor/query/[get_value_titles|get_autocomplete]/{user_defined}`.
*
* 'display': output format
* supported values:
* 'minimal' (default) : name only
* 'detailed' : for Post & Taxonomies -> `[Taxonomy|Post-Type] : [parent] ... [parent] > name`
* for Users & Authors -> `name [email]`
* user_defined : will invoke apply_filters using the user_defined value as filter name,
* `elementor/query/[get_value_titles|get_autocomplete]/display/{user_defined}`
*
* `by_field`: value of 'id' field in taxonomy query. Relevant only if `object` is tax|cpt_tax
* supported values:
* 'term_taxonomy_id'(default)
* 'term_id'
*
* 'query': array of args to be passed "as-is" to the relevant query function (see 'object').
*
**
*
* @param array $data
*
* @return array | \WP_Error
*/
private function autocomplete_query_data( $data ) {
if ( empty( $data['autocomplete'] ) || empty( $data['q'] ) || empty( $data['autocomplete']['object'] ) ) {
return new \WP_Error( self::AUTOCOMPLETE_ERROR_CODE, 'Empty or incomplete data' );
}
$autocomplete = $data['autocomplete'];
if ( in_array( $autocomplete['object'], self::$supported_objects_for_query, true ) ) {
$method_name = 'autocomplete_query_for_' . $autocomplete['object'];
if ( empty( $autocomplete['display'] ) ) {
$autocomplete['display'] = 'minimal';
$data['autocomplete'] = $autocomplete;
}
$query = $this->$method_name( $data );
if ( is_wp_error( $query ) ) {
return $query;
}
$autocomplete['query'] = $query;
}
return $autocomplete;
}
private function autocomplete_query_for_post( $data ) {
if ( ! isset( $data['autocomplete']['query'] ) ) {
return new \WP_Error( self::AUTOCOMPLETE_ERROR_CODE, 'Missing autocomplete[`query`] data' );
}
$query = $data['autocomplete']['query'];
if ( empty( $query['post_type'] ) ) {
$query['post_type'] = 'any';
}
$query['posts_per_page'] = -1;
$query['s'] = $data['q'];
return $query;
}
private function autocomplete_query_for_library_template( $data ) {
$query = $data['autocomplete']['query'];
$query['post_type'] = Source_Local::CPT;
$query['orderby'] = 'meta_value';
$query['order'] = 'ASC';
if ( empty( $query['posts_per_page'] ) ) {
$query['posts_per_page'] = -1;
}
$query['s'] = $data['q'];
return $query;
}
private function autocomplete_query_for_attachment( $data ) {
$query = $this->autocomplete_query_for_post( $data );
if ( is_wp_error( $query ) ) {
return $query;
}
$query['post_type'] = 'attachment';
$query['post_status'] = 'inherit';
return $query;
}
private function autocomplete_query_for_tax( $data ) {
$query = $data['autocomplete']['query'];
if ( empty( $query['taxonomy'] ) && ! empty( $query['post_type'] ) ) {
$query['taxonomy'] = get_object_taxonomies( $query['post_type'] );
}
$query['search'] = $data['q'];
$query['hide_empty'] = false;
return $query;
}
private function autocomplete_query_for_author( $data ) {
$query = $this->autocomplete_query_for_user( $data );
if ( is_wp_error( $query ) ) {
return $query;
}
return $this->add_edit_capability_to_user_query( $query );
}
private function autocomplete_query_for_user( $data ) {
$query = $data['autocomplete']['query'];
if ( ! empty( $query ) ) {
return $query;
}
$query = [
'fields' => [
'ID',
'display_name',
],
'search' => '*' . $data['q'] . '*',
'search_columns' => [
'user_login',
'user_nicename',
],
];
if ( 'detailed' === $data['autocomplete']['display'] ) {
$query['fields'][] = 'user_email';
}
return $query;
}
private function get_titles_query_data( $data ) {
if ( empty( $data['get_titles'] ) || empty( $data['id'] ) || empty( $data['get_titles']['object'] ) ) {
return new \WP_Error( self::GET_TITLES_ERROR_CODE, 'Empty or incomplete data' );
}
$get_titles = $data['get_titles'];
if ( empty( $get_titles['query'] ) ) {
$get_titles['query'] = [];
}
if ( in_array( $get_titles['object'], self::$supported_objects_for_query, true ) ) {
$method_name = 'get_titles_query_for_' . $get_titles['object'];
$query = $this->$method_name( $data );
if ( is_wp_error( $query ) ) {
return $query;
}
$get_titles['query'] = $query;
}
if ( empty( $get_titles['display'] ) ) {
$get_titles['display'] = 'minimal';
}
return $get_titles;
}
private function get_titles_query_for_post( $data ) {
$query = $data['get_titles']['query'];
if ( empty( $query['post_type'] ) ) {
$query['post_type'] = 'any';
}
$query['posts_per_page'] = -1;
$query['post__in'] = (array) $data['id'];
return $query;
}
private function get_titles_query_for_attachment( $data ) {
$query = $this->get_titles_query_for_post( $data );
$query['post_type'] = 'attachment';
$query['post_status'] = 'inherit';
return $query;
}
private function get_titles_query_for_tax( $data ) {
$by_field = empty( $data['get_titles']['by_field'] ) ? 'term_taxonomy_id' : $data['get_titles']['by_field'];
return [
$by_field => (array) $data['id'],
'hide_empty' => false,
];
}
private function get_titles_query_for_library_template( $data ) {
$query = $data['get_titles']['query'];
$query['post_type'] = Source_Local::CPT;
$query['orderby'] = 'meta_value';
$query['order'] = 'ASC';
if ( empty( $query['posts_per_page'] ) ) {
$query['posts_per_page'] = -1;
}
return $query;
}
private function get_titles_query_for_author( $data ) {
$query = $this->get_titles_query_for_user( $data );
$query['has_published_posts'] = true;
return $this->add_edit_capability_to_user_query( $query );
}
private function get_titles_query_for_user( $data ) {
$query = $data['get_titles']['query'];
if ( ! empty( $query ) ) {
return $query;
}
$query = [
'fields' => [
'ID',
'display_name',
],
'include' => (array) $data['id'],
];
if ( 'detailed' === $data['get_titles']['display'] ) {
$query['fields'][] = 'user_email';
}
return $query;
}
/**
* @deprecated 2.6.0 use new `autocomplete` format
*
* @param $data
*
* @return mixed
*/
private function extract_post_type( $data ) {
if ( ! empty( $data['query'] ) && ! empty( $data['query']['post_type'] ) ) {
return $data['query']['post_type'];
}
return $data['object_type'];
}
/**
* @deprecated 2.6.0 use new `autocomplete` format
*
* @param $data
*
* @return array
* @throws \Exception
*/
public function ajax_posts_filter_autocomplete_deprecated( $data ) {
$document = Utils::_unstable_get_document_for_edit( $data['editor_post_id'] );
if ( empty( $data['filter_type'] ) || empty( $data['q'] ) ) {
throw new \Exception( 'Bad request.' );
}
$results = [];
switch ( $data['filter_type'] ) {
case 'taxonomy':
$query_params = [
'taxonomy' => $this->extract_post_type( $data ),
'search' => $data['q'],
'hide_empty' => false,
];
$terms = get_terms( $query_params );
if ( is_wp_error( $terms ) ) {
break;
}
global $wp_taxonomies;
foreach ( $terms as $term ) {
$term_name = $this->get_term_name_with_parents( $term );
if ( ! empty( $data['include_type'] ) ) {
$text = $wp_taxonomies[ $term->taxonomy ]->labels->name . ': ' . $term_name;
} else {
$text = $term_name;
}
$results[] = [
'id' => $term->term_taxonomy_id,
'text' => $text,
];
}
break;
case 'by_id':
case 'post':
$query_params = [
'post_type' => $this->extract_post_type( $data ),
's' => $data['q'],
'posts_per_page' => -1,
];
if ( 'attachment' === $query_params['post_type'] ) {
$query_params['post_status'] = 'inherit';
}
$query = new \WP_Query( $query_params );
foreach ( $query->posts as $post ) {
$post_type_obj = get_post_type_object( $post->post_type );
if ( ! empty( $data['include_type'] ) ) {
$text = $post_type_obj->labels->name . ': ' . $post->post_title;
} else {
$text = ( $post_type_obj->hierarchical ) ? $this->get_post_name_with_parents( $post ) : $post->post_title;
}
$results[] = [
'id' => $post->ID,
'text' => esc_html( $text ),
];
}
break;
case 'author':
$query_params = [
'has_published_posts' => true,
'fields' => [
'ID',
'display_name',
],
'search' => '*' . $data['q'] . '*',
'search_columns' => [
'user_login',
'user_nicename',
],
];
$query_params = $this->add_edit_capability_to_user_query( $query_params );
$user_query = new \WP_User_Query( $query_params );
foreach ( $user_query->get_results() as $author ) {
$results[] = [
'id' => $author->ID,
'text' => $author->display_name,
];
}
break;
default:
$results = apply_filters( 'elementor/query/get_autocomplete/' . $data['filter_type'], [], $data );
}
return [
'results' => $results,
];
}
/**
* @param array $data
*
* @return array
* @throws \Exception
*/
public function ajax_posts_filter_autocomplete( array $data ) {
if ( ! current_user_can( Editor::EDITING_CAPABILITY ) ) {
throw new \Exception( 'Access denied.' );
}
$query_data = $this->autocomplete_query_data( $data );
if ( is_wp_error( $query_data ) ) {
/** @var \WP_Error $query_data */
throw new \Exception( $query_data->get_error_code() . ':' . $query_data->get_error_message() );
}
$results = [];
$display = $query_data['display'];
$query_args = $query_data['query'];
$query_args['no_found_rows'] = true;
switch ( $query_data['object'] ) {
case self::QUERY_OBJECT_TAX:
$by_field = ! empty( $query_data['by_field'] ) ? $query_data['by_field'] : 'term_taxonomy_id';
$terms = get_terms( $query_args );
if ( is_wp_error( $terms ) ) {
break;
}
foreach ( $terms as $term ) {
if ( apply_filters( "elementor/query/get_autocomplete/tax/{$display}", true, $term, $data ) ) {
$results[] = [
'id' => $term->{$by_field},
'text' => $this->get_term_name( $term, $display, $data ),
];
}
}
break;
case self::QUERY_OBJECT_ATTACHMENT:
case self::QUERY_OBJECT_POST:
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
if ( apply_filters( "elementor/query/get_autocomplete/custom/{$display}", true, $post, $data ) ) {
$text = $this->format_post_for_display( $post, $display, $data );
$results[] = [
'id' => $post->ID,
'text' => $text,
];
}
}
break;
case self::QUERY_OBJECT_LIBRARY_TEMPLATE:
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
$document = Plugin::elementor()->documents->get( $post->ID );
if ( $document ) {
$text = esc_html( $post->post_title ) . ' (' . $document->get_post_type_title() . ')';
$results[] = [
'id' => $post->ID,
'text' => $text,
];
}
}
break;
case self::QUERY_OBJECT_USER:
case self::QUERY_OBJECT_AUTHOR:
$user_query = new \WP_User_Query( $query_args );
foreach ( $user_query->get_results() as $user ) {
if ( apply_filters( "elementor/query/get_autocomplete/user/{$display}", true, $user, $data ) ) {
$results[] = [
'id' => $user->ID,
'text' => $this->format_user_for_display( $user, $display, $data ),
];
}
}
break;
default:
$results = apply_filters( 'elementor/query/get_autocomplete/' . $query_data['filter_type'], $results, $data );
}
return [
'results' => $results,
];
}
/**
* @param $request
*
* @return array
* @throws \Exception
* @deprecated 2.6.0 use new `autocomplete` format
*
*/
public function ajax_posts_control_value_titles_deprecated( $request ) {
$document = Utils::_unstable_get_document_for_edit( $request['editor_post_id'] );
$ids = (array) $request['id'];
$results = [];
switch ( $request['filter_type'] ) {
case 'taxonomy':
$terms = get_terms(
[
'term_taxonomy_id' => $ids,
'hide_empty' => false,
]
);
if ( is_wp_error( $terms ) ) {
break;
}
global $wp_taxonomies;
foreach ( $terms as $term ) {
$term_name = $this->get_term_name_with_parents( $term );
if ( ! empty( $request['include_type'] ) ) {
$text = $wp_taxonomies[ $term->taxonomy ]->labels->name . ': ' . $term_name;
} else {
$text = $term_name;
}
$results[ $term->{$by_field} ] = $text;
}
break;
case 'by_id':
case 'post':
$query = new \WP_Query(
[
'post_type' => 'any',
'post__in' => $ids,
'posts_per_page' => -1,
]
);
foreach ( $query->posts as $post ) {
$results[ $post->ID ] = esc_html( $post->post_title );
}
break;
case 'author':
$query_params = [
'has_published_posts' => true,
'fields' => [
'ID',
'display_name',
],
'include' => $ids,
];
$query_params = $this->add_edit_capability_to_user_query( $query_params );
$user_query = new \WP_User_Query( $query_params );
foreach ( $user_query->get_results() as $author ) {
$results[ $author->ID ] = $author->display_name;
}
break;
default:
$results = apply_filters( 'elementor/query/get_value_titles/' . $request['filter_type'], [], $request );
}
return $results;
}
/**
* @throws \Exception
*/
public function ajax_posts_control_value_titles( $request ) {
if ( ! current_user_can( Editor::EDITING_CAPABILITY ) ) {
throw new \Exception( 'Access denied.' );
}
$query_data = $this->get_titles_query_data( $request );
if ( is_wp_error( $query_data ) ) {
return [];
}
$display = $query_data['display'];
$query_args = $query_data['query'];
$query_args['no_found_rows'] = true;
$results = [];
switch ( $query_data['object'] ) {
case self::QUERY_OBJECT_TAX:
$by_field = ! empty( $query_data['by_field'] ) ? $query_data['by_field'] : 'term_taxonomy_id';
// The term_id is not working in 2022-01-18, this is a hack to replace the term id with
// `include`, the code is a legacy code so the solution is minimal as possible.
if ( isset( $query_args['term_id'] ) ) {
$query_args['include'] = array_map( 'intval', $query_args['term_id'] );
}
$terms = get_terms( $query_args );
if ( is_wp_error( $terms ) ) {
break;
}
foreach ( $terms as $term ) {
if ( apply_filters( "elementor/query/get_value_titles/tax/{$display}", true, $term, $request ) ) {
$results[ $term->{$by_field} ] = $this->get_term_name( $term, $display, $request, 'get_value_titles' );
}
}
break;
case self::QUERY_OBJECT_ATTACHMENT:
case self::QUERY_OBJECT_POST:
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
if ( apply_filters( "elementor/query/get_value_titles/custom/{$display}", true, $post, $request ) ) {
$results[ $post->ID ] = $this->format_post_for_display( $post, $display, $request, 'get_value_titles' );
}
}
break;
case self::QUERY_OBJECT_LIBRARY_TEMPLATE:
$query = new \WP_Query( $query_args );
foreach ( $query->posts as $post ) {
$document = Plugin::elementor()->documents->get( $post->ID );
if ( $document ) {
$results[ $post->ID ] = htmlentities( esc_html( $post->post_title ) ) . ' (' . $document->get_post_type_title() . ')';
}
}
break;
case self::QUERY_OBJECT_AUTHOR:
case self::QUERY_OBJECT_USER:
$user_query = new \WP_User_Query( $query_args );
foreach ( $user_query->get_results() as $user ) {
if ( apply_filters( "elementor/query/get_value_titles/user/{$display}", true, $user, $request ) ) {
$results[ $user->ID ] = $this->format_user_for_display( $user, $display, $request, 'get_value_titles' );
}
}
break;
default:
$results = apply_filters( "elementor/query/get_value_titles/{$query_data['filter_type']}", $results, $request );
}
return $results;
}
private function get_term_name( $term, $display, $request, $filter_name = 'get_autocomplete' ) {
global $wp_taxonomies;
$term_name = $this->get_term_name_with_parents( $term );
switch ( $display ) {
case 'detailed':
$text = $wp_taxonomies[ $term->taxonomy ]->labels->name . ': ' . $term_name;
break;
case 'minimal':
$text = $term_name;
break;
default:
$text = apply_filters( "elementor/query/{$filter_name}/display/{$display}", $term_name, $request );
break;
}
return $text;
}
/**
* @param \WP_Post $post
* @param string $display
* @param array $data
* @param string $filter_name
*
* @return mixed|string|void
*/
private function format_post_for_display( $post, $display, $data, $filter_name = 'get_autocomplete' ) {
$post_type_obj = get_post_type_object( $post->post_type );
switch ( $display ) {
case 'minimal':
$text = ( $post_type_obj->hierarchical ) ? $this->get_post_name_with_parents( $post ) : $post->post_title;
break;
case 'detailed':
$text = $post_type_obj->labels->name . ': ' . ( $post_type_obj->hierarchical ) ? $this->get_post_name_with_parents( $post ) : $post->post_title;
break;
default:
$text = apply_filters( "elementor/query/{$filter_name}/display/{$display}", $post->post_title, $post->ID, $data );
break;
}
return esc_html( $text );
}
/**
* @param \WP_User $user
* @param string $display
* @param array $data
* @param string $filter_name
*
* @return string
*/
private function format_user_for_display( $user, $display, $data, $filter_name = 'get_autocomplete' ) {
switch ( $display ) {
case 'minimal':
$text = $user->display_name;
break;
case 'detailed':
$text = sprintf( '%s (%s)', $user->display_name, $user->user_email );
break;
default:
$text = apply_filters( "elementor/query/{$filter_name}/display/{$display}", $user, $data );
break;
}
return $text;
}
private function query_data_compatibility( $data ) {
if ( isset( $data['query']['filter_type'] ) ) {
$data['filter_type'] = $data['query']['filter_type'];
}
if ( isset( $data['query']['object_type'] ) ) {
$data['object_type'] = $data['query']['object_type'];
}
if ( isset( $data['query']['include_type'] ) ) {
$data['include_type'] = $data['query']['include_type'];
}
if ( isset( $data['query']['post_type'] ) ) {
$data['post_type'] = $data['query']['post_type'];
}
return $data;
}
public function register_controls( Controls_Manager $controls_manager ) {
$controls_manager->add_group_control( Group_Control_Posts::get_type(), new Group_Control_Posts() );
$controls_manager->add_group_control( Group_Control_Query::get_type(), new Group_Control_Query() );
$controls_manager->add_group_control( Group_Control_Related::get_type(), new Group_Control_Related() );
$controls_manager->add_group_control( Group_Control_Taxonomy::get_type(), new Group_Control_Taxonomy() );
$controls_manager->register( new Query() );
$controls_manager->register( new Template_Query() );
}
/**
* get_term_name_with_parents
* @param \WP_Term $term
* @param int $max
*
* @return string
*/
private function get_term_name_with_parents( \WP_Term $term, $max = 3 ) {
if ( 0 === $term->parent ) {
return $term->name;
}
$separator = is_rtl() ? ' < ' : ' > ';
$test_term = $term;
$names = [];
while ( $test_term->parent > 0 ) {
$test_term = get_term( $test_term->parent );
if ( ! $test_term ) {
break;
}
$names[] = $test_term->name;
}
$names = array_reverse( $names );
if ( count( $names ) < ( $max ) ) {
return implode( $separator, $names ) . $separator . $term->name;
}
$name_string = '';
for ( $i = 0; $i < ( $max - 1 ); $i++ ) {
$name_string .= $names[ $i ] . $separator;
}
return $name_string . '...' . $separator . $term->name;
}
/**
* get post name with parents
* @param \WP_Post $post
* @param int $max
*
* @return string
*/
private function get_post_name_with_parents( $post, $max = 3 ) {
if ( 0 === $post->post_parent ) {
return $post->post_title;
}
$separator = is_rtl() ? ' < ' : ' > ';
$test_post = $post;
$names = [];
while ( $test_post->post_parent > 0 ) {
$test_post = get_post( $test_post->post_parent );
if ( ! $test_post ) {
break;
}
$names[] = $test_post->post_title;
}
$names = array_reverse( $names );
if ( count( $names ) < ( $max ) ) {
return implode( $separator, $names ) . $separator . $post->post_title;
}
$name_string = '';
for ( $i = 0; $i < ( $max - 1 ); $i++ ) {
$name_string .= $names[ $i ] . $separator;
}
return $name_string . '...' . $separator . $post->post_title;
}
/**
* @deprecated 2.5.0 Use `Elementor_Post_Query` class capabilities instead.
*
* @param string $control_id
* @param array $settings
*
* @return array
*/
public function get_query_args( $control_id, $settings ) {
Plugin::elementor()->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '2.5.0', 'class Elementor_Post_Query' );
$controls_manager = Plugin::elementor()->controls_manager;
/** @var Group_Control_Posts $posts_query */
$posts_query = $controls_manager->get_control_groups( Group_Control_Posts::get_type() );
return $posts_query->get_query_args( $control_id, $settings );
}
/**
* @param \Elementor\Widget_Base $widget
* @param string $name
* @param array $query_args
* @param array $fallback_args
*
* @return \WP_Query
*/
public function get_query( $widget, $name, $query_args = [], $fallback_args = [] ) {
$prefix = $name . '_';
$post_type = $widget->get_settings( $prefix . 'post_type' );
if ( 'related' === $post_type ) {
$elementor_query = new Elementor_Related_Query( $widget, $name, $query_args, $fallback_args );
} else {
$elementor_query = new Elementor_Post_Query( $widget, $name, $query_args );
}
return $elementor_query->get_query();
}
/**
* @param Ajax $ajax_manager
*/
public function register_ajax_actions( $ajax_manager ) {
$ajax_manager->register_ajax_action( 'query_control_value_titles', [ $this, 'ajax_posts_control_value_titles' ] );
$ajax_manager->register_ajax_action( 'pro_panel_posts_control_filter_autocomplete', [ $this, 'ajax_posts_filter_autocomplete' ] );
/**
* @deprecated 2.6.0 use new `autocomplete` format
*/
$ajax_manager->register_ajax_action( 'query_control_value_titles_deprecated', [ $this, 'ajax_posts_control_value_titles_deprecated' ] );
$ajax_manager->register_ajax_action( 'pro_panel_posts_control_filter_autocomplete_deprecated', [ $this, 'ajax_posts_filter_autocomplete_deprecated' ] );
}
protected function add_actions() {
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
add_action( 'elementor/controls/register', [ $this, 'register_controls' ] );
}
/**
* In WordPress 5.9 the 'who' query param was deprecated, this method
* adding the new `capability` query param to the query and still support old versions of WordPress.
*
* @param $query
*
* @return mixed
*/
private function add_edit_capability_to_user_query( $query ) {
// Capability queries were only introduced in WP 5.9.
if ( version_compare( $GLOBALS['wp_version'], '5.9-alpha', '>=' ) ) {
$query['capability'] = [ 'edit_posts' ];
} else {
$query['who'] = 'authors';
}
return $query;
}
}