relations->get_active_relations(); if ( ! $relations ) { return; } $relations_list = array( 'related_children' => __( 'filters children items list by parents IDs', 'jet-engine' ), 'related_parents' => __( 'filters parents items list by children IDs', 'jet-engine' ) ); $relations_options = array(); foreach ( $relations as $relation_item ) { $relations_options[$relation_item->get_id()] = $relation_item->get_relation_name(); } foreach ( $relations_list as $relation_key => $relation_label ) { $relation_dynamic_query_item = new class( $relation_key, $relation_label, $relations_options ) { public function __construct( $key, $label, $options ) { $this->key = $key; $this->label = $label; $this->options = $options; } public function get_name() { return $this->key; } public function get_label() { return 'JetEngine: ' . $this->label; } public function get_extra_args() { return array( 'relation' => array( 'type' => 'select', 'title' => __( 'Relation', 'jet-engine' ), 'placeholder' => __( 'Select relation...', 'jet-engine' ), 'options' => $this->options, ), ); } public function get_delimiter() { return '*'; } }; $dynamic_query_manager->register_item( $relation_dynamic_query_item ); } } /** * Check if relations was requested for indexing - tries to get posts for relations * * @param [type] $result [description] * @param [type] $metadata [description] * @return [type] [description] */ public function index_posts_relations( $result, $metadata ) { return array_merge( $result, $this->get_related_meta( $metadata, 'post' ) ); } /** * Check if relations was requested for indexing - tries to get users for relations * * @param [type] $result [description] * @param [type] $metadata [description] * @return [type] [description] */ public function index_users_relations( $result, $metadata ) { return array_merge( $result, $this->get_related_meta( $metadata, 'user' ) ); } /** * Re-index relations indexer data on each update of post or user * * @param [type] $result [description] * @param [type] $filter_data [description] * @return [type] [description] */ public function index_single_item( $result, $filters_data, $type ) { if ( empty( $filters_data['meta_query'] ) ) { return $result; } return array_merge( $result, $this->get_related_meta( $filters_data['meta_query'], $type, true ) ); } /** * Check if relation object mets indexer type requirements * * @return boolean [description] */ public function is_supported_type( $type, $object ) { switch ( $type ) { case 'post': return jet_engine()->relations->types_helper->object_is( $object, 'posts' ); case 'user': return jet_engine()->relations->types_helper->object_is( $object, 'mix', 'users' ); } return false; } /** * Returns related items data for indexer * * @param [type] $metadata [description] * @param [type] $type [description] * @return [type] [description] */ public function get_related_meta( $metadata = array(), $type = 'post', $flush = false ) { $result = array(); foreach ( array( 'normal', 'serialized', 'range' ) as $data_type ) { if ( empty( $metadata[ $data_type ] ) ) { continue; } foreach ( $metadata[ $data_type ] as $query_var => $data ) { if ( ! $this->is_relation_filter( $query_var ) ) { continue; } $query_var_data = explode( '*', $query_var ); $rel_type = $query_var_data[0]; $rel_id = ! empty( $query_var_data[1] ) ? $query_var_data[1] : false; if ( ! $rel_id ) { continue; } $relation = jet_engine()->relations->get_active_relations( $rel_id ); if ( ! $relation ) { continue; } if ( $flush ) { global $wpdb; $wpdb->delete( \Jet_Smart_Filters_DB::get_table_full_name( 'indexer' ), array( 'item_key' => $query_var, ) ); } if ( empty( $data ) ) { switch ( $rel_type ) { case 'related_children': if ( $this->is_supported_type( $type, $relation->get_args( 'child_object' ) ) ) { $data = $relation->get_parents( null, 'ids' ); } break; case 'related_parents': if ( $this->is_supported_type( $type, $relation->get_args( 'parent_object' ) ) ) { $data = $relation->get_children( null, 'ids' ); } break; } } $data = array_unique( $data ); foreach ( $data as $value ) { $rel_ids = false; switch ( $rel_type ) { case 'related_children': if ( $this->is_supported_type( $type, $relation->get_args( 'child_object' ) ) ) { $rel_ids = $relation->get_children( $value, 'ids' ); } break; case 'related_parents': if ( $this->is_supported_type( $type, $relation->get_args( 'parent_object' ) ) ) { $rel_ids = $relation->get_parents( $value, 'ids' ); } break; } if ( ! empty( $rel_ids ) ) { foreach ( $rel_ids as $id ) { $result[] = array( 'item_id' => $id, 'item_key' => $query_var, 'item_value' => $value, 'item_query' => 'meta_query', 'type' => $type, ); } } } } } return $result; } /** * Add relation query arguments * * @param [type] $args [description] */ public function add_relation_query( $args ) { if ( empty( $args['meta_query'] ) ) { return $args; } $found = false; foreach ( $args['meta_query'] as $key => $data ) { if ( ! empty( $data['key'] ) && $this->is_relation_filter( $data['key'] ) ) { $args = $this->add_relation_args( $args, $data ); $found = true; } } if ( $found ) { foreach ( $args['meta_query'] as $key => $data ) { if ( ! empty( $data['key'] ) && $this->is_relation_filter( $data['key'] ) ) { unset( $args['meta_query'][ $key ] ); } } } return $args; } /** * Prevent relation meta keys from indexing with default CCT logic * * @param [type] $result [description] * @param [type] $key [description] * @return [type] [description] */ public function prevent_default_indexing_cct_relations( $result, $key ) { return $this->is_relation_filter( $key ); } /** * Index CCT relations meta * * @param [type] $data [description] * @param [type] $provider [description] * @param [type] $query_args [description] * @param [type] $indexer [description] * @return [type] [description] */ public function index_cct_relations( $data, $provider, $query_args, $indexer ) { if ( ! class_exists( '\Jet_Engine\Modules\Custom_Content_Types\Module' ) ) { return $data; } $props_args = explode( '/', $provider ); $provider_name = $props_args[0]; $provider_id = $props_args[1]; $props = jet_smart_filters()->query->get_query_props( $provider_name, $provider_id ); if ( empty( $props ) || empty( $props['query_type'] ) || 'custom-content-type' !== $props['query_type'] ) { return $data; } if ( empty( $props['query_meta'] ) || empty( $props['query_meta']['content_type'] ) ) { return $data; } $content_type = \Jet_Engine\Modules\Custom_Content_Types\Module::instance()->manager->get_content_types( $props['query_meta']['content_type'] ); if ( ! $content_type ) { return $data; } $indexing_data = $indexer->indexing_data[ $provider ]; if ( empty( $indexing_data ) || empty( $indexing_data['meta_query'] ) ) { return $data; } foreach ( $indexing_data['meta_query'] as $key => $options ) { $key_data = explode( '|', $key ); $suffix = ! empty( $key_data[1] ) ? $key_data[1] : false; $key = $key_data[0]; if ( false !== strpos( $key, ',' ) ) { $key = str_replace( ', ', ',', $key ); $keys = explode( ',', $key ); } else { $keys = array( $key ); } foreach ( $keys as $key ) { if ( ! $this->is_relation_filter( $key ) ) { continue; } $rel_id = $this->get_relation_id_from_key( $key ); if ( ! $rel_id || ! $relation = jet_engine()->relations->get_active_relations( $rel_id ) ) { continue; } $col = $this->is_children_filter( $key ) ? 'parent_object_id' : 'child_object_id'; $counts = $relation->db->raw_query( "SELECT $col AS id, COUNT(*) AS count FROM %table% WHERE rel_id = $rel_id GROUP BY $col;" ); $key_counts = array_fill_keys( $options, 0 ); foreach ( $counts as $option ) { $option_id = absint( $option->id ); $key_counts[ $option_id ] = $option->count; } $data['meta_query'][ $key ] = $key_counts; } } return $data; } /** * Extract relation ID from key * @param [type] $key [description] * @return [type] [description] */ public function get_relation_id_from_key( $key ) { return str_replace( array( 'related_children*', 'related_parents*' ), '', $key ); } /** * Check if given filter key is relation-associated key * * @param [type] $key [description] * @return boolean [description] */ public function is_relation_filter( $key ) { return ( $this->is_children_filter( $key ) || $this->is_parents_filter( $key ) ); } /** * Chek if is children related items filter * * @param [type] $key [description] * @return boolean [description] */ public function is_children_filter( $key ) { return false !== strpos( $key, 'related_children*' ); } /** * Chek if is parents related items filter * * @param [type] $key [description] * @return boolean [description] */ public function is_parents_filter( $key ) { return false !== strpos( $key, 'related_parents*' ); } /** * Adds realtion query arguments to existing filter query args * * @param [type] $args [description] * @param [type] $data [description] */ public function add_relation_args( $args, $data ) { $key = $data['key']; $key = explode( '*', $key ); $type = $key[0]; $rel_id = ! empty( $key[1] ) ? $key[1] : false; if ( ! $rel_id ) { return $args; } $relation = jet_engine()->relations->get_active_relations( $rel_id ); if ( ! $relation ) { return $args; } $rel_ids = false; $object = false; switch ( $type ) { case 'related_children': $object = $relation->get_args( 'child_object' ); $rel_ids = $relation->get_children( $data['value'], 'ids' ); break; case 'related_parents': $object = $relation->get_args( 'parent_object' ); $rel_ids = $relation->get_parents( $data['value'], 'ids' ); break; } if ( false === $rel_ids || ! $object ) { return $args; } if ( empty( $rel_ids ) ) { $rel_ids = array( 'not-found' ); } $new_args = jet_engine()->relations->types_helper->filtered_query_args( $object, $rel_ids ); if ( ! empty( $args['post__in'] ) && ! empty( $new_args['post__in'] ) ) { $args['post__in'] = array_intersect( $args['post__in'], $new_args['post__in'] ); // Not found posts. if ( empty( $args['post__in'] ) ) { $args['post__in'] = array( PHP_INT_MAX ); } $result = $args; } else { $result = array_merge_recursive( $args, $new_args ); } return $result; } }