Файловый менеджер - Редактировать - /var/www/xthruster/html/wp-content/uploads/flags/query-control.tar
Назад
classes/elementor-related-query.php 0000644 00000012634 14721647100 0013475 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Classes; use Elementor\Widget_Base; use ElementorPro\Core\Utils; class Elementor_Related_Query extends Elementor_Post_Query { private $fallback_args; private $related_post_id; /** * Elementor_Post_Query constructor. * * @param Widget_Base $widget * @param string $group_query_name * @param array $query_args * @param array $fallback_args */ public function __construct( $widget, $group_query_name, $query_args = [], $fallback_args = [] ) { parent::__construct( $widget, $group_query_name, $query_args ); $this->related_post_id = -1; $this->fallback_args = $fallback_args; } /** * 1) build query args * 2) invoke callback to fine-tune query-args * 3) generate WP_Query object * 4) if no results & fallback is set, generate a new WP_Query with fallback args * 5) return WP_Query * * @return \WP_Query */ public function get_query() { $query = parent::get_query(); if ( ! $query->post_count && $this->is_valid_fallback() ) { $query = $this->get_fallback_query( $query ); } return $query; } protected function get_fallback_query( $original_query ) { $this->set_fallback_query_args(); $this->set_fallback_arg_by_settings( 'posts_per_page', $original_query->query_vars['posts_per_page'] ); $this->set_fallback_arg_by_settings( 'post__not_in', $original_query->query_vars['post__not_in'] ); /** * Fallback query arguments. * * Filters the query arguments for the fallback query. This hook allows * developers to alter those arguments. * * @param array $fallback_args An array of WordPress query arguments. * @param Widget_Base $widget An instance of Elementor widget. */ $this->fallback_args = apply_filters( 'elementor/query/fallback_query_args', $this->fallback_args, $this->widget ); return new \WP_Query( $this->fallback_args ); } private function is_valid_fallback() { $related_callback = $this->get_widget_settings( 'related_fallback' ); if ( empty( $related_callback ) ) { return false; } $valid = false; switch ( $this->get_widget_settings( 'related_fallback' ) ) { case 'fallback_recent': $valid = true; break; case 'fallback_by_id': $fallback_id = $this->get_widget_settings( 'fallback_ids' ); if ( ! empty( $fallback_id ) ) { $valid = true; } break; } return $valid; } protected function set_common_args() { parent::set_common_args(); $post_id = get_queried_object_id(); $this->related_post_id = is_singular() && ( 0 !== $post_id ) ? $post_id : null; $this->query_args['post_type'] = get_post_type( $this->related_post_id ); } protected function set_post_exclude_args() { parent::set_post_exclude_args(); if ( $this->related_post_id ) { $post_not_in = isset( $this->query_args['post__not_in'] ) ? $this->query_args['post__not_in'] : []; $post_not_in[] = $this->related_post_id; $this->query_args['post__not_in'] = $post_not_in; } } protected function build_terms_query_include( $control_id ) { /** * Build tax_query for the "related posts" query: * 1) find the list of taxonomies associated with the current-post * 2) extract the ids for each taxonomy * 3) build tax_query array accordingly * */ if ( null === $this->get_widget_settings( 'include' ) || null === $this->get_widget_settings( 'related_taxonomies' ) || ! $this->maybe_in_array( 'terms', $this->get_widget_settings( 'include' ) ) ) { return; } $taxonomies = $this->get_widget_settings( 'related_taxonomies' ); $terms = []; if ( is_string( $taxonomies ) ) { $terms[ $taxonomies ] = wp_get_post_terms( $this->related_post_id, $taxonomies, [ 'fields' => 'tt_ids' ] ); } else { foreach ( $taxonomies as $taxonomy ) { $terms[ $taxonomy ] = wp_get_post_terms( $this->related_post_id, $taxonomy, [ 'fields' => 'tt_ids' ] ); } } $this->insert_tax_query( $terms, false ); } protected function set_author_args() { if ( ! $this->maybe_in_array( 'authors', $this->get_widget_settings( 'include' ) ) ) { return; } $this->query_args['author__in'] = get_post_field( 'post_author', $this->related_post_id ); } /** * @param string $key * @param mixed $value * @param string $control_name */ private function set_fallback_arg_by_settings( $key, $value, $control_name = '' ) { if ( empty( $this->fallback_args[ $key ] ) ) { $settings = $this->widget->get_settings(); $this->fallback_args[ $key ] = ( '' === $control_name || empty( $settings[ $this->prefix . $control_name ] ) ) ? $value : $settings[ $this->prefix . $control_name ]; } } /** * @return string|array */ public function get_post_types() { $public_post_types = Utils::get_public_post_types(); $active_post_type = get_post_type(); return ! empty( $active_post_type ) ? $active_post_type : array_keys( $public_post_types ); } protected function set_fallback_query_args() { $this->set_fallback_arg_by_settings( 'ignore_sticky_posts', true ); $this->set_fallback_arg_by_settings( 'post_status', 'publish' ); $this->set_fallback_arg_by_settings( 'post_type', $this->get_post_types() ); if ( 'fallback_by_id' === $this->get_widget_settings( 'related_fallback' ) ) { $this->set_fallback_arg_by_settings( 'post__in', [ 0 ], 'fallback_ids' ); $this->set_fallback_arg_by_settings( 'orderby', 'rand' ); } else { //recent posts $this->set_fallback_arg_by_settings( 'orderby', 'date' ); $this->set_fallback_arg_by_settings( 'order', 'DESC' ); } } } classes/elementor-post-query.php 0000644 00000030722 14721647100 0013040 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Classes; use Elementor\Widget_Base; use ElementorPro\Modules\QueryControl\Module; use ElementorPro\Core\Utils; /** * Class Elementor_Post_Query * Wrapper for WP_Query. * Used by the various widgets for generating the query, according to the controls added using Group_Control_Query. * Each class instance is associated with the specific widget that is passed in the class constructor. */ class Elementor_Post_Query { /** @var Widget_Base */ protected $widget; protected $query_args; protected $prefix; protected $widget_settings; /** * Elementor_Post_Query constructor. * * @param Widget_Base $widget * @param string $group_query_name * @param array $query_args */ public function __construct( $widget, $group_query_name, $query_args = [] ) { $this->widget = $widget; $this->prefix = $group_query_name . '_'; $this->query_args = $query_args; $settings = $this->widget->get_settings_for_display(); $defaults = $this->get_query_defaults(); $this->widget_settings = wp_parse_args( $settings, $defaults ); } /** * 1) build query args * 2) invoke callback to fine-tune query-args * 3) generate WP_Query object * 4) if no results & fallback is set, generate a new WP_Query with fallback args * 5) return WP_Query * * @return \WP_Query */ public function get_query() { $this->get_query_args(); $offset_control = $this->get_widget_settings( 'offset' ); $query_id = $this->get_widget_settings( 'query_id' ); if ( ! empty( $query_id ) ) { add_action( 'pre_get_posts', [ $this, 'pre_get_posts_query_filter' ] ); } if ( ! $this->is_manual_selection() && 0 < $offset_control ) { /** * @see https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination */ add_action( 'pre_get_posts', [ $this, 'fix_query_offset' ], 1 ); add_filter( 'found_posts', [ $this, 'fix_query_found_posts' ], 1, 2 ); } $query = new \WP_Query( $this->query_args );// SQL_CALC_FOUND_ROWS is used. remove_action( 'pre_get_posts', [ $this, 'pre_get_posts_query_filter' ] ); remove_action( 'pre_get_posts', [ $this, 'fix_query_offset' ], 1 ); remove_filter( 'found_posts', [ $this, 'fix_query_found_posts' ], 1 ); Module::add_to_avoid_list( wp_list_pluck( $query->posts, 'ID' ) ); /** * Elementor Pro query results. * * Fires before the actual query is run. This hook allows developers * to alter individual query results. * * @param \WP_Query $query An instance of WordPress query. * @param Widget_Base $widget An instance of Elementor widget. */ do_action( 'elementor/query/query_results', $query, $this->widget ); return $query; } protected function get_query_defaults() { $defaults = [ $this->prefix . 'post_type' => 'post', $this->prefix . 'posts_ids' => [], $this->prefix . 'orderby' => 'date', $this->prefix . 'order' => 'desc', $this->prefix . 'offset' => 0, $this->prefix . 'posts_per_page' => 3, ]; return $defaults; } public function get_query_args() { $post_type = $this->get_widget_settings( 'post_type' ); if ( 'current_query' === $post_type ) { $current_query_vars = $GLOBALS['wp_query']->query_vars; /** * Add custom paged option support. It's necessary for ajax and individual pagination support */ if ( ! empty( $this->query_args['has_custom_pagination'] ) && true === $this->query_args['has_custom_pagination'] ) { $current_query_vars['paged'] = $this->query_args['paged']; } /** * Current query variables. * * Filters the query variables for the current query. This hook allows * developers to alter those variables. * * @since 1.0.0 * * @param array $current_query_vars Current query variables. */ $current_query_vars = apply_filters( 'elementor/query/get_query_args/current_query', $current_query_vars ); $this->query_args = $current_query_vars; return $current_query_vars; } $this->set_common_args(); $this->set_order_args(); $this->set_pagination_args(); $this->set_post_include_args(); if ( ! $this->is_manual_selection() ) { $this->set_post_exclude_args(); $this->set_avoid_duplicates(); $this->set_terms_args(); $this->set_author_args(); $this->set_date_args(); } /** * Current query arguments. * * Filters the query arguments for the current query. This hook allows * developers to alter those arguments. * * @param array $query_args An array of WordPress query arguments. * @param Widget_Base $widget An instance of Elementor widget. */ $this->query_args = apply_filters( 'elementor/query/query_args', $this->query_args, $this->widget ); return $this->query_args; } protected function set_pagination_args() { $this->set_query_arg( 'posts_per_page', $this->get_widget_settings( 'posts_per_page' ) ); $sticky_post = $this->get_widget_settings( 'ignore_sticky_posts' ) ? true : false; $this->set_query_arg( 'ignore_sticky_posts', $sticky_post ); } protected function set_common_args() { $this->query_args['post_status'] = 'publish'; // Hide drafts/private posts for admins if ( $this->is_manual_selection() ) { $post_types = Utils::get_public_post_types(); $this->query_args['post_type'] = array_keys( $post_types ); } else { $this->query_args['post_type'] = $this->get_widget_settings( 'post_type' ); } } protected function set_post_include_args() { if ( $this->is_manual_selection() ) { $this->set_query_arg( 'post__in', $this->get_widget_settings( 'posts_ids' ) ); if ( empty( $this->query_args['post__in'] ) ) { // If no selection - return an empty query $this->query_args['post__in'] = [ 0 ]; } $this->set_query_arg( 'ignore_sticky_posts', true, true ); } } private function is_manual_selection(): bool { return 'by_id' === $this->get_widget_settings( 'post_type' ); } protected function set_post_exclude_args() { $exclude = $this->get_widget_settings( 'exclude' ); if ( empty( $exclude ) ) { return; } $post__not_in = []; if ( $this->maybe_in_array( 'current_post', $exclude ) ) { if ( is_singular() ) { $post__not_in[] = get_queried_object_id(); } } $exclude_ids = $this->get_widget_settings( 'exclude_ids' ); if ( $this->maybe_in_array( 'manual_selection', $exclude ) && ! empty( $exclude_ids ) ) { $post__not_in = array_merge( $post__not_in, $exclude_ids ); } $this->set_query_arg( 'post__not_in', $post__not_in ); } protected function set_avoid_duplicates() { if ( 'yes' === $this->get_widget_settings( 'avoid_duplicates' ) ) { $post__not_in = isset( $this->query_args['post__not_in'] ) ? $this->query_args['post__not_in'] : []; $post__not_in = array_merge( $post__not_in, Module::$displayed_ids ); $this->set_query_arg( 'post__not_in', $post__not_in, true ); } } protected function set_terms_args() { if ( $this->is_manual_selection() ) { return; } $this->build_terms_query_include( 'include_term_ids' ); $this->build_terms_query_exclude( 'exclude_term_ids' ); } protected function build_terms_query_include( $control_id ) { $this->build_terms_query( 'include', $control_id ); } protected function build_terms_query_exclude( $control_id ) { $this->build_terms_query( 'exclude', $control_id, true ); } protected function build_terms_query( $tab_id, $control_id, $exclude = false ) { $tab_id = $this->get_widget_settings( $tab_id ); $settings_terms = $this->get_widget_settings( $control_id ); if ( empty( $tab_id ) || empty( $settings_terms ) || ! $this->maybe_in_array( 'terms', $tab_id ) ) { return; } $terms = []; // Switch to term_id in order to get all term children (sub-categories): foreach ( $settings_terms as $id ) { $term_data = get_term_by( 'term_taxonomy_id', $id ); if ( false !== $term_data ) { $taxonomy = $term_data->taxonomy; $terms[ $taxonomy ][] = $id; } } $this->insert_tax_query( $terms, $exclude ); } protected function insert_tax_query( $terms, $exclude ) { $tax_query = []; foreach ( $terms as $taxonomy => $ids ) { $query = [ 'taxonomy' => $taxonomy, 'field' => 'term_taxonomy_id', 'terms' => $ids, ]; if ( $exclude ) { $query['operator'] = 'NOT IN'; } $tax_query[] = $query; } if ( empty( $tax_query ) ) { return; } if ( empty( $this->query_args['tax_query'] ) ) { $this->query_args['tax_query'] = $tax_query; } else { $this->query_args['tax_query']['relation'] = 'AND'; $this->query_args['tax_query'][] = $tax_query; } } protected function set_author_args() { $include_authors = $this->get_widget_settings( 'include_authors' ); if ( ! empty( $include_authors ) && $this->maybe_in_array( 'authors', $this->get_widget_settings( 'include' ) ) ) { $this->set_query_arg( 'author__in', $include_authors ); } $exclude_authors = $this->get_widget_settings( 'exclude_authors' ); if ( ! empty( $exclude_authors ) && $this->maybe_in_array( 'authors', $this->get_widget_settings( 'exclude' ) ) ) { //exclude only if not explicitly included if ( empty( $this->query_args['author__in'] ) ) { $this->set_query_arg( 'author__not_in', $exclude_authors ); } } } protected function set_order_args() { $order = $this->get_widget_settings( 'order' ); if ( ! empty( $order ) ) { $this->set_query_arg( 'orderby', $this->get_widget_settings( 'orderby' ) ); $this->set_query_arg( 'order', $this->get_widget_settings( 'order' ) ); } } protected function set_date_args() { $select_date = $this->get_widget_settings( 'select_date' ); if ( ! empty( $select_date ) ) { $date_query = []; switch ( $select_date ) { case 'today': $date_query['after'] = '-1 day'; break; case 'week': $date_query['after'] = '-1 week'; break; case 'month': $date_query['after'] = '-1 month'; break; case 'quarter': $date_query['after'] = '-3 month'; break; case 'year': $date_query['after'] = '-1 year'; break; case 'exact': $after_date = $this->get_widget_settings( 'date_after' ); if ( ! empty( $after_date ) ) { $date_query['after'] = $after_date; } $before_date = $this->get_widget_settings( 'date_before' ); if ( ! empty( $before_date ) ) { $date_query['before'] = $before_date; } $date_query['inclusive'] = true; break; } $this->set_query_arg( 'date_query', $date_query ); } } /** * @param string $control_name * * @return mixed|null */ protected function get_widget_settings( $control_name ) { $control_name = $this->prefix . $control_name; return isset( $this->widget_settings[ $control_name ] ) ? $this->widget_settings[ $control_name ] : null; } /** * @param $key * @param $value * @param false $override */ protected function set_query_arg( $key, $value, $override = false ) { if ( ! isset( $this->query_args[ $key ] ) || $override ) { $this->query_args[ $key ] = $value; } } /** * @param string $value * @param mixed $maybe_array * * @return bool */ protected function maybe_in_array( $value, $maybe_array ) { return is_array( $maybe_array ) ? in_array( $value, $maybe_array, true ) : $value === $maybe_array; } /** * @param \WP_Query $wp_query */ public function pre_get_posts_query_filter( $wp_query ) { if ( $this->widget ) { $query_id = $this->get_widget_settings( 'query_id' ); $widget_name = $this->widget->get_name(); /** * Elementor Pro query arguments. * * Fires before the actual query is run. This hook allows developers to * alter individual queries by id. * * The dynamic portions of the hook name, `$widget_name` & `$query_id`, * refers to the widget name and query id respectively. * * @since 2.1.0 * * @param \WP_Query $wp_query An instance of WordPress query. * @param Widget_Base $widget An instance of Elementor widget */ do_action( "elementor/query/{$query_id}", $wp_query, $this->widget ); } } /** * @param \WP_Query $query */ public function fix_query_offset( &$query ) { $offset = $this->get_widget_settings( 'offset' ); if ( $offset && $query->is_paged ) { $query->query_vars['offset'] = $offset + ( ( $query->query_vars['paged'] - 1 ) * $query->query_vars['posts_per_page'] ); } else { $query->query_vars['offset'] = $offset; } } /** * @param int $found_posts * @param \WP_Query $query * * @return int */ public function fix_query_found_posts( $found_posts, $query ) { $offset = $this->get_widget_settings( 'offset' ); if ( $offset ) { $found_posts -= $offset; } return $found_posts; } } module.php 0000644 00000071746 14721647100 0006563 0 ustar 00 <?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; } } controls/group-control-posts.php 0000644 00000020307 14721647100 0013104 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Controls; use Elementor\Controls_Manager; use Elementor\Group_Control_Base; use ElementorPro\Core\Utils; use ElementorPro\Modules\QueryControl\Module; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } /** * Class Group_Control_Posts * * @deprecated 2.5.0 Use `Group_Control_Query` and `Elementor_Post_Query` classes instead. */ class Group_Control_Posts extends Group_Control_Base { const INLINE_MAX_RESULTS = 15; protected static $fields; public static function get_type() { return 'posts'; } /** * @deprecated 2.4.0 Use Control's settings `export=false` instead. * * @param $element * @param $control_id * * @return mixed */ public static function on_export_remove_setting_from_element( $element, $control_id ) { _deprecated_function( __METHOD__, '2.4.0' ); unset( $element['settings'][ $control_id . '_posts_ids' ] ); unset( $element['settings'][ $control_id . '_authors' ] ); foreach ( Utils::get_public_post_types() as $post_type => $label ) { $taxonomy_filter_args = [ 'show_in_nav_menus' => true, 'object_type' => [ $post_type ], ]; $taxonomies = get_taxonomies( $taxonomy_filter_args, 'objects' ); foreach ( $taxonomies as $taxonomy => $object ) { unset( $element['settings'][ $control_id . '_' . $taxonomy . '_ids' ] ); } } return $element; } protected function init_fields() { $fields = []; $fields['post_type'] = [ 'label' => esc_html__( 'Source', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, ]; $fields['posts_ids'] = [ 'label' => esc_html__( 'Search & Select', 'elementor-pro' ), 'type' => Module::QUERY_CONTROL_ID, 'post_type' => '', 'options' => [], 'label_block' => true, 'multiple' => true, 'filter_type' => 'by_id', 'condition' => [ 'post_type' => 'by_id', ], 'export' => false, ]; $fields['authors'] = [ 'label' => esc_html__( 'Author', 'elementor-pro' ), 'label_block' => true, 'type' => Module::QUERY_CONTROL_ID, 'multiple' => true, 'default' => [], 'options' => [], 'filter_type' => 'author', 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], 'export' => false, ]; return $fields; } protected function prepare_fields( $fields ) { $args = $this->get_args(); $post_type_args = []; if ( ! empty( $args['post_type'] ) ) { $post_type_args['post_type'] = $args['post_type']; } $post_types = Utils::get_public_post_types( $post_type_args ); $post_types_options = $post_types; $post_types_options['by_id'] = esc_html__( 'Manual Selection', 'elementor-pro' ); $post_types_options['current_query'] = esc_html__( 'Current Query', 'elementor-pro' ); $fields['post_type']['options'] = $post_types_options; $fields['post_type']['default'] = key( $post_types ); $fields['posts_ids']['object_type'] = array_keys( $post_types ); $taxonomy_filter_args = [ 'show_in_nav_menus' => true, ]; $taxonomies = get_taxonomies( $taxonomy_filter_args, 'objects' ); // bypass bug in WP_List_Util::filter() causing wrong array comparison // when a taxonomy belongs to several post-types (e.g. when using woocommerce-product-add-ons) // ( using simple '==' rather than in_array() or array_intersect() ). $filtered_taxonomies = []; if ( ! empty( $args['post_type'] ) ) { foreach ( $taxonomies as $taxonomy => $obj ) { $tax_array = (array) $obj; if ( in_array( $args['post_type'], $tax_array['object_type'] ) ) { $filtered_taxonomies[ $taxonomy ] = $obj; } } } else { $filtered_taxonomies = $taxonomies; } foreach ( $filtered_taxonomies as $taxonomy => $object ) { $taxonomy_args = [ 'label' => $object->label, 'type' => Module::QUERY_CONTROL_ID, 'label_block' => true, 'multiple' => true, 'object_type' => $taxonomy, 'options' => [], 'condition' => [ 'post_type' => $object->object_type, ], 'export' => false, ]; $count = wp_count_terms( $taxonomy ); $options = []; // For large websites, use Ajax to search if ( $count > self::INLINE_MAX_RESULTS ) { $taxonomy_args['type'] = Module::QUERY_CONTROL_ID; $taxonomy_args['filter_type'] = 'taxonomy'; } else { $taxonomy_args['type'] = Controls_Manager::SELECT2; $terms = get_terms( [ 'taxonomy' => $taxonomy, 'hide_empty' => false, ] ); foreach ( $terms as $term ) { $options[ $term->term_id ] = $term->name; } $taxonomy_args['options'] = $options; } $fields[ $taxonomy . '_ids' ] = $taxonomy_args; } return parent::prepare_fields( $fields ); } protected function get_default_options() { return [ 'popover' => false, ]; } protected function fix_offset( $query_args, $settings, $prefix = '' ) { if ( 0 < $settings[ $prefix . 'offset' ] ) { /** * Due to a WordPress bug, the offset will be set later, in $this->fix_query_offset() * @see https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination */ $query_args['offset_to_fix'] = $settings[ $prefix . 'offset' ]; } return $query_args; } protected function build_query_args( $settings, $control_id_prefix ) { $prefix = $control_id_prefix . '_'; $post_type = $settings[ $prefix . 'post_type' ]; $query_args = [ 'orderby' => $settings['orderby'], 'order' => $settings['order'], 'ignore_sticky_posts' => 1, 'post_status' => 'publish', // Hide drafts/private posts for admins ]; if ( 'by_id' === $post_type ) { $post_types = Utils::get_public_post_types(); $query_args['post_type'] = array_keys( $post_types ); $query_args['posts_per_page'] = -1; $query_args['post__in'] = $settings[ $prefix . 'posts_ids' ]; if ( empty( $query_args['post__in'] ) ) { // If no selection - return an empty query $query_args['post__in'] = [ 0 ]; } } else { $query_args['post_type'] = $post_type; $query_args['posts_per_page'] = $settings['posts_per_page']; $query_args['tax_query'] = []; $query_args = $this->fix_offset( $query_args, $settings ); $taxonomies = get_object_taxonomies( $post_type, 'objects' ); foreach ( $taxonomies as $object ) { $setting_key = $prefix . $object->name . '_ids'; if ( ! empty( $settings[ $setting_key ] ) ) { $query_args['tax_query'][] = [ 'taxonomy' => $object->name, 'field' => 'term_id', 'terms' => $settings[ $setting_key ], ]; } } } if ( ! empty( $settings[ $prefix . 'authors' ] ) ) { $query_args['author__in'] = $settings[ $prefix . 'authors' ]; } $post__not_in = []; if ( ! empty( $settings['exclude'] ) ) { if ( in_array( 'current_post', $settings['exclude'], true ) ) { $post_id = Utils::_unstable_get_super_global_value( $_REQUEST, 'post_id' ); if ( wp_doing_ajax() && $post_id ) { $post__not_in[] = $post_id; } elseif ( is_singular() ) { $post__not_in[] = get_queried_object_id(); } } if ( in_array( 'manual_selection', $settings['exclude'], true ) && ! empty( $settings['exclude_ids'] ) ) { $post__not_in = array_merge( $post__not_in, $settings['exclude_ids'] ); } } if ( ! empty( $settings['avoid_duplicates'] ) && 'yes' === $settings['avoid_duplicates'] ) { $post__not_in = array_merge( $post__not_in, Module::$displayed_ids ); } $query_args['post__not_in'] = $post__not_in; return $query_args; } public function get_query_args( $control_id_prefix, $settings ) { $defaults = [ $control_id_prefix . '_post_type' => 'post', $control_id_prefix . '_posts_ids' => [], 'orderby' => 'date', 'order' => 'desc', 'posts_per_page' => 3, 'offset' => 0, ]; $settings = wp_parse_args( $settings, $defaults ); $post_type = $settings[ $control_id_prefix . '_post_type' ]; if ( 'current_query' === $post_type ) { $current_query_vars = $GLOBALS['wp_query']->query_vars; /** * Current query variables. * * Filters the query variables for the current query. * * @since 1.0.0 * * @param array $current_query_vars Current query variables. */ $current_query_vars = apply_filters( 'elementor_pro/query_control/get_query_args/current_query', $current_query_vars ); return $current_query_vars; } return $this->build_query_args( $settings, $control_id_prefix ); } } controls/query.php 0000644 00000002575 14721647100 0010300 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Controls; use Elementor\Control_Select2; use ElementorPro\Modules\QueryControl\Module; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } class Query extends Control_Select2 { public function get_type() { return 'query'; } /** * 'query' can be used for passing query args in the structure and format used by WP_Query. * @return array */ protected function get_default_settings() { return array_merge( parent::get_default_settings(), [ 'query' => '', ] ); } /** * Update control settings using mapping config * * @param $value * @param array $control_args * @param array $config * * @return mixed */ public function on_import_update_settings( $value, array $control_args, array $config ) { switch ( $control_args['autocomplete']['object'] ) { case Module::QUERY_OBJECT_POST: case Module::QUERY_OBJECT_LIBRARY_TEMPLATE: return $this->replace_id_from_mapping( $value, $config['post_ids'] ); case Module::QUERY_OBJECT_TAX: return $this->replace_id_from_mapping( $value, $config['term_ids'] ); default: return $value; } } /** * replace id from config * * @param mixed $value * @param array $mapping * * @return string */ private function replace_id_from_mapping( $value, array $mapping ): string { return $mapping[ $value ] ?? $value; } } controls/template-query.php 0000644 00000003075 14721647100 0012105 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Controls; use Elementor\Control_Select2; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } class Template_Query extends Control_Select2 { const CONTROL_ID = 'template_query'; /** * @return string */ public function get_type() { return static::CONTROL_ID; } public function content_template() { parent::content_template(); ?> <div class="elementor-template-query-control-actions"> <# if ( data.actions.new.visible ) { #> <button type="button" class="elementor-button" data-action="new" data-after-action="{{ data.actions.new.after_action }}" > {{ data.actions.new.label }} </button> <# } #> <# if ( data.actions.edit.visible ) { #> <button type="button" class="elementor-button" data-action="edit" data-after-action="{{ data.actions.edit.after_action }}" > {{ data.actions.edit.label }} </button> <# } #> </div> <?php } /** * @return array */ protected function get_default_settings() { return array_replace_recursive( parent::get_default_settings(), [ 'query' => '', 'actions' => [ 'new' => [ 'visible' => false, 'label' => __( 'Create template', 'elementor-pro' ), 'document_config' => [ 'type' => null, ], 'after_action' => 'switch_document', ], 'edit' => [ 'visible' => false, 'label' => __( 'Edit template', 'elementor-pro' ), 'after_action' => 'switch_document', ], ], ] ); } } controls/group-control-taxonomy.php 0000644 00000001722 14721647100 0013612 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Controls; use Elementor\Controls_Manager; class Group_Control_Taxonomy extends Group_Control_Query { public static function get_type() { return 'taxonomy-query'; } protected function get_fields_array( $name ) { $tab_keys = $this->get_tabs_keys( $name . '_' ); $fields = parent::get_fields_array( $name ); $new_fields = []; foreach ( $fields as $key => $field ) { if ( 'query_args' === $key ) { $new_fields['filter_by'] = [ 'label' => esc_html__( 'Filter By', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, 'default' => 'show_all', 'options' => [ 'show_all' => esc_html__( 'Show All', 'elementor-pro' ), 'manual_selection' => esc_html__( 'Manual Selection', 'elementor-pro' ), ], 'tabs_wrapper' => $tab_keys['tabs_wrapper'], 'inner_tab' => $tab_keys['include_wrapper'], ]; } $new_fields[ $key ] = $field; } return $new_fields; } } controls/group-control-related.php 0000644 00000007316 14721647100 0013361 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Controls; use Elementor\Controls_Manager; use ElementorPro\Core\Utils; use ElementorPro\Modules\QueryControl\Module as Query_Module; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } class Group_Control_Related extends Group_Control_Query { public static function get_type() { return 'related-query'; } /** * Build the group-controls array * Note: this method completely overrides any settings done in Group_Control_Posts * @param string $name * * @return array */ protected function init_fields_by_name( $name ) { $fields = parent::init_fields_by_name( $name ); $tabs_wrapper = $name . '_query_args'; $include_wrapper = $name . '_query_include'; $fields['post_type']['options']['related'] = esc_html__( 'Related', 'elementor-pro' ); $fields['include_term_ids']['condition']['post_type!'][] = 'related'; $fields['related_taxonomies']['condition']['post_type'][] = 'related'; $fields['include_authors']['condition']['post_type!'][] = 'related'; $fields['exclude_authors']['condition']['post_type!'][] = 'related'; $fields['avoid_duplicates']['condition']['post_type!'][] = 'related'; $fields['offset']['condition']['post_type!'][] = 'related'; $related_taxonomies = [ 'label' => esc_html__( 'Term', 'elementor-pro' ), 'type' => Controls_Manager::SELECT2, 'options' => $this->get_supported_taxonomies(), 'label_block' => true, 'multiple' => true, 'condition' => [ 'include' => 'terms', 'post_type' => [ 'related', ], ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $include_wrapper, ]; $related_fallback = [ 'label' => esc_html__( 'Fallback', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, 'options' => [ 'fallback_none' => esc_html__( 'None', 'elementor-pro' ), 'fallback_by_id' => esc_html__( 'Manual Selection', 'elementor-pro' ), 'fallback_recent' => esc_html__( 'Recent Posts', 'elementor-pro' ), ], 'default' => 'fallback_none', 'description' => esc_html__( 'Displayed if no relevant results are found. Manual selection display order is random', 'elementor-pro' ), 'condition' => [ 'post_type' => 'related', ], 'separator' => 'before', ]; $fallback_ids = [ 'label' => esc_html__( 'Search & Select', 'elementor-pro' ), 'type' => Query_Module::QUERY_CONTROL_ID, 'options' => [], 'label_block' => true, 'multiple' => true, 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_POST, ], 'condition' => [ 'post_type' => 'related', 'related_fallback' => 'fallback_by_id', ], 'export' => false, ]; $fields = \Elementor\Utils::array_inject( $fields, 'include_term_ids', [ 'related_taxonomies' => $related_taxonomies ] ); $fields = \Elementor\Utils::array_inject( $fields, 'offset', [ 'related_fallback' => $related_fallback ] ); $fields = \Elementor\Utils::array_inject( $fields, 'related_fallback', [ 'fallback_ids' => $fallback_ids ] ); return $fields; } protected function get_supported_taxonomies() { $supported_taxonomies = []; $public_types = Utils::get_public_post_types(); foreach ( $public_types as $type => $title ) { $taxonomies = get_object_taxonomies( $type, 'objects' ); foreach ( $taxonomies as $key => $tax ) { if ( ! array_key_exists( $key, $supported_taxonomies ) ) { $label = $tax->label; if ( in_array( $tax->label, $supported_taxonomies ) ) { $label = $tax->label . ' (' . $tax->name . ')'; } $supported_taxonomies[ $key ] = $label; } } } return $supported_taxonomies; } protected static function init_presets() { parent::init_presets(); static::$presets['related'] = [ 'related_fallback', 'fallback_ids', ]; } } controls/group-control-query.php 0000644 00000035076 14721647100 0013112 0 ustar 00 <?php namespace ElementorPro\Modules\QueryControl\Controls; use Elementor\Controls_Manager; use Elementor\Group_Control_Base; use ElementorPro\Core\Utils; use ElementorPro\Modules\QueryControl\Module as Query_Module; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } class Group_Control_Query extends Group_Control_Base { protected static $presets; protected static $fields; public static function get_type() { return 'query-group'; } protected function init_args( $args ) { parent::init_args( $args ); $args = $this->get_args(); static::$fields = $this->init_fields_by_name( $args['name'] ); } protected function init_fields() { $args = $this->get_args(); return $this->init_fields_by_name( $args['name'] ); } protected function get_fields_array( $name ) { $fields = []; $tab_keys = $this->get_tabs_keys( $name ); $name .= '_'; $fields['post_type'] = [ 'label' => esc_html__( 'Source', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, 'options' => [ 'by_id' => esc_html__( 'Manual Selection', 'elementor-pro' ), 'current_query' => esc_html__( 'Current Query', 'elementor-pro' ), ], ]; $fields['query_args'] = [ 'type' => Controls_Manager::TABS, ]; $tabs_wrapper = $tab_keys['tabs_wrapper']; $include_wrapper = $tab_keys['include_wrapper']; $exclude_wrapper = $tab_keys['exclude_wrapper']; $fields['query_include'] = [ 'type' => Controls_Manager::TAB, 'label' => esc_html__( 'Include', 'elementor-pro' ), 'tabs_wrapper' => $tabs_wrapper, 'condition' => [ 'post_type!' => [ 'current_query', 'by_id', ], ], ]; $fields['posts_ids'] = [ 'label' => esc_html__( 'Search & Select', 'elementor-pro' ), 'type' => Query_Module::QUERY_CONTROL_ID, 'options' => [], 'label_block' => true, 'multiple' => true, 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_POST, ], 'condition' => [ 'post_type' => 'by_id', ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $include_wrapper, 'export' => false, ]; $fields['include'] = [ 'label' => esc_html__( 'Include By', 'elementor-pro' ), 'type' => Controls_Manager::SELECT2, 'multiple' => true, 'options' => [ 'terms' => esc_html__( 'Term', 'elementor-pro' ), 'authors' => esc_html__( 'Author', 'elementor-pro' ), ], 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], 'label_block' => true, 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $include_wrapper, ]; $fields['include_term_ids'] = [ 'label' => esc_html__( 'Term', 'elementor-pro' ), 'description' => esc_html__( 'Terms are items in a taxonomy. The available taxonomies are: Categories, Tags, Formats and custom taxonomies.', 'elementor-pro' ), 'type' => Query_Module::QUERY_CONTROL_ID, 'options' => [], 'label_block' => true, 'multiple' => true, 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_CPT_TAX, 'display' => 'detailed', ], 'group_prefix' => $name, 'condition' => [ 'include' => 'terms', 'post_type!' => [ 'by_id', 'current_query', ], ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $include_wrapper, ]; $fields['include_authors'] = [ 'label' => esc_html__( 'Author', 'elementor-pro' ), 'label_block' => true, 'type' => Query_Module::QUERY_CONTROL_ID, 'multiple' => true, 'default' => [], 'options' => [], 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_AUTHOR, ], 'condition' => [ 'include' => 'authors', 'post_type!' => [ 'by_id', 'current_query', ], ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $include_wrapper, 'export' => false, ]; $fields['query_exclude'] = [ 'type' => Controls_Manager::TAB, 'label' => esc_html__( 'Exclude', 'elementor-pro' ), 'tabs_wrapper' => $tabs_wrapper, 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], ]; $fields['exclude'] = [ 'label' => esc_html__( 'Exclude By', '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' ), 'terms' => esc_html__( 'Term', 'elementor-pro' ), 'authors' => esc_html__( 'Author', 'elementor-pro' ), ], 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], 'label_block' => true, 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $exclude_wrapper, ]; $fields['exclude_ids'] = [ 'label' => esc_html__( 'Search & Select', 'elementor-pro' ), 'type' => Query_Module::QUERY_CONTROL_ID, 'options' => [], 'label_block' => true, 'multiple' => true, 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_POST, ], 'condition' => [ 'exclude' => 'manual_selection', 'post_type!' => [ 'by_id', 'current_query', ], ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $exclude_wrapper, 'export' => false, ]; $fields['exclude_term_ids'] = [ 'label' => esc_html__( 'Term', 'elementor-pro' ), 'type' => Query_Module::QUERY_CONTROL_ID, 'options' => [], 'label_block' => true, 'multiple' => true, 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_CPT_TAX, 'display' => 'detailed', ], 'group_prefix' => $name, 'condition' => [ 'exclude' => 'terms', 'post_type!' => [ 'by_id', 'current_query', ], ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $exclude_wrapper, 'export' => false, ]; $fields['exclude_authors'] = [ 'label' => esc_html__( 'Author', 'elementor-pro' ), 'type' => Query_Module::QUERY_CONTROL_ID, 'options' => [], 'label_block' => true, 'multiple' => true, 'autocomplete' => [ 'object' => Query_Module::QUERY_OBJECT_AUTHOR, 'display' => 'detailed', ], 'condition' => [ 'exclude' => 'authors', 'post_type!' => [ 'by_id', 'current_query', ], ], 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $exclude_wrapper, 'export' => false, ]; $fields['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. This only effects the frontend.', 'elementor-pro' ), 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $exclude_wrapper, 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], ]; $fields['offset'] = [ 'label' => esc_html__( 'Offset', 'elementor-pro' ), 'type' => Controls_Manager::NUMBER, 'default' => 0, 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], 'description' => esc_html__( 'Use this setting to skip over posts (e.g. \'2\' to skip over 2 posts).', 'elementor-pro' ), 'tabs_wrapper' => $tabs_wrapper, 'inner_tab' => $exclude_wrapper, ]; $fields['select_date'] = [ 'label' => esc_html__( 'Date', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, 'post_type' => '', 'options' => [ 'anytime' => esc_html__( 'All', 'elementor-pro' ), 'today' => esc_html__( 'Past Day', 'elementor-pro' ), 'week' => esc_html__( 'Past Week', 'elementor-pro' ), 'month' => esc_html__( 'Past Month', 'elementor-pro' ), 'quarter' => esc_html__( 'Past Quarter', 'elementor-pro' ), 'year' => esc_html__( 'Past Year', 'elementor-pro' ), 'exact' => esc_html__( 'Custom', 'elementor-pro' ), ], 'default' => 'anytime', 'multiple' => false, 'condition' => [ 'post_type!' => [ 'by_id', 'current_query', ], ], 'separator' => 'before', ]; $fields['date_before'] = [ 'label' => esc_html__( 'Before', 'elementor-pro' ), 'type' => Controls_Manager::DATE_TIME, 'post_type' => '', 'label_block' => false, 'multiple' => false, 'placeholder' => esc_html__( 'Choose', 'elementor-pro' ), 'condition' => [ 'select_date' => 'exact', 'post_type!' => [ 'by_id', 'current_query', ], ], 'description' => esc_html__( 'Setting a ‘Before’ date will show all the posts published until the chosen date (inclusive).', 'elementor-pro' ), ]; $fields['date_after'] = [ 'label' => esc_html__( 'After', 'elementor-pro' ), 'type' => Controls_Manager::DATE_TIME, 'post_type' => '', 'label_block' => false, 'multiple' => false, 'placeholder' => esc_html__( 'Choose', 'elementor-pro' ), 'condition' => [ 'select_date' => 'exact', 'post_type!' => [ 'by_id', 'current_query', ], ], 'description' => esc_html__( 'Setting an ‘After’ date will show all the posts published since the chosen date (inclusive).', 'elementor-pro' ), ]; $fields['orderby'] = [ 'label' => esc_html__( 'Order By', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, 'default' => 'post_date', 'options' => [ 'post_date' => esc_html__( 'Date', 'elementor-pro' ), 'post_title' => esc_html__( 'Title', 'elementor-pro' ), 'menu_order' => esc_html__( 'Menu Order', 'elementor-pro' ), 'modified' => esc_html__( 'Last Modified', 'elementor-pro' ), 'comment_count' => esc_html__( 'Comment Count', 'elementor-pro' ), 'rand' => esc_html__( 'Random', 'elementor-pro' ), ], 'condition' => [ 'post_type!' => 'current_query', ], ]; $fields['order'] = [ 'label' => esc_html__( 'Order', 'elementor-pro' ), 'type' => Controls_Manager::SELECT, 'default' => 'desc', 'options' => [ 'asc' => esc_html__( 'ASC', 'elementor-pro' ), 'desc' => esc_html__( 'DESC', 'elementor-pro' ), ], 'condition' => [ 'post_type!' => 'current_query', ], ]; $fields['posts_per_page'] = [ 'label' => esc_html__( 'Posts Per Page', 'elementor-pro' ), 'type' => Controls_Manager::NUMBER, 'default' => 3, 'condition' => [ 'post_type!' => 'current_query', ], ]; $fields['ignore_sticky_posts'] = [ 'label' => esc_html__( 'Ignore Sticky Posts', 'elementor-pro' ), 'type' => Controls_Manager::SWITCHER, 'default' => 'yes', 'condition' => [ 'post_type' => 'post', ], 'description' => esc_html__( 'Sticky-posts ordering is visible on frontend only', 'elementor-pro' ), ]; $fields['query_id'] = [ 'label' => esc_html__( 'Query ID', 'elementor-pro' ), 'type' => Controls_Manager::TEXT, 'default' => '', 'ai' => [ 'active' => false, ], 'description' => esc_html__( 'Give your Query a custom unique id to allow server side filtering', 'elementor-pro' ), 'separator' => 'before', 'dynamic' => [ 'active' => true, ], ]; return $fields; } /** * Build the group-controls array * Note: this method completely overrides any settings done in Group_Control_Posts * @param string $name * * @return array */ protected function init_fields_by_name( $name ) { $fields = $this->get_fields_array( $name ); static::init_presets(); return $fields; } /** * Presets: filter controls subsets to be be used by the specific Group_Control_Query instance. * * Possible values: * 'full' : (default) all presets * 'include' : the 'include' tab - by id, by taxonomy, by author * 'exclude': the 'exclude' tab - by id, by taxonomy, by author * 'advanced_exclude': extend the 'exclude' preset with 'avoid-duplicates' & 'offset' * 'date': date query controls * 'pagination': posts per-page * 'order': sort & ordering controls * 'query_id': allow saving a specific query for future usage. * * Usage: * full: build a Group_Controls_Query with all possible controls, * when 'full' is passed, the Group_Controls_Query will ignore all other preset values. * $this->add_group_control( * Group_Control_Query::get_type(), * [ * ... * 'presets' => [ 'full' ], * ... * ] ); * * Subset: build a Group_Controls_Query with subset of the controls, * in the following example, the Query controls will set only the 'include' & 'date' query args. * $this->add_group_control( * Group_Control_Query::get_type(), * [ * ... * 'presets' => [ 'include', 'date' ], * ... * ] ); */ protected static function init_presets() { $tabs = [ 'query_args', 'query_include', 'query_exclude', ]; static::$presets['include'] = array_merge( $tabs, [ 'include', 'include_ids', 'include_term_ids', 'include_authors', ] ); static::$presets['exclude'] = array_merge( $tabs, [ 'exclude', 'exclude_ids', 'exclude_term_ids', 'exclude_authors', ] ); static::$presets['advanced_exclude'] = array_merge( static::$presets['exclude'], [ 'avoid_duplicates', 'offset', ] ); static::$presets['date'] = [ 'select_date', 'date_before', 'date_after', ]; static::$presets['pagination'] = [ 'posts_per_page', 'ignore_sticky_posts', ]; static::$presets['order'] = [ 'orderby', 'order', ]; static::$presets['query_id'] = [ 'query_id', ]; } private function filter_by_presets( $presets, $fields ) { if ( in_array( 'full', $presets, true ) ) { return $fields; } $control_ids = []; foreach ( static::$presets as $key => $preset ) { $control_ids = array_merge( $control_ids, $preset ); } foreach ( $presets as $preset ) { if ( array_key_exists( $preset, static::$presets ) ) { $control_ids = array_diff( $control_ids, static::$presets[ $preset ] ); } } foreach ( $control_ids as $remove ) { unset( $fields[ $remove ] ); } return $fields; } protected function prepare_fields( $fields ) { $args = $this->get_args(); if ( ! empty( $args['presets'] ) ) { $fields = $this->filter_by_presets( $args['presets'], $fields ); } $post_type_args = []; if ( ! empty( $args['post_type'] ) ) { $post_type_args['post_type'] = $args['post_type']; } $post_types = Utils::get_public_post_types( $post_type_args ); $fields['post_type']['options'] = array_merge( $post_types, $fields['post_type']['options'] ); $fields['post_type']['default'] = key( $post_types ); $fields['posts_ids']['object_type'] = array_keys( $post_types ); //skip parent, go directly to grandparent return Group_Control_Base::prepare_fields( $fields ); } protected function get_child_default_args() { $args = parent::get_child_default_args(); $args['presets'] = [ 'full' ]; return $args; } protected function get_default_options() { return [ 'popover' => false, ]; } protected function get_tabs_keys( $name ) { return [ 'tabs_wrapper' => $name . '_query_args', 'include_wrapper' => $name . '_query_include', 'exclude_wrapper' => $name . '_query_exclude', ]; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.3-4ubuntu2.24 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка