diff --git a/includes/core/class-member-directory-meta.php b/includes/core/class-member-directory-meta.php index 7b187931..563d8bcc 100644 --- a/includes/core/class-member-directory-meta.php +++ b/includes/core/class-member-directory-meta.php @@ -224,6 +224,27 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) { $blog_id = get_current_blog_id(); + /** + * Filters member directory select-type filter relation in query. + * + * @param {string} $relation Relation `OR` or `AND`. `OR` by default. + * @param {string} $field Field key. + * + * @return {string} Relation. + * + * @since 2.8.5 + * @hook um_members_directory_select_filter_relation + * + * @example Change relation to 'AND'. + * function my_um_members_directory_select_filter_relation( $relation, $field ) { + * // your code here + * $relation = 'AND'; + * return $relation; + * } + * add_filter( 'um_members_directory_select_filter_relation', 'my_um_members_directory_select_filter_relation', 10, 2 ); + */ + $relation = apply_filters( 'um_members_directory_select_filter_relation', 'OR', $field ); + switch ( $field ) { default: $filter_type = $this->filter_types[ $field ]; @@ -328,27 +349,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) { // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias is pre-escaped. } - /** - * Filters change select filter relation. - * - * @param {string} $relation. - * @param {string} $field field key. - * - * @return {string} relation. - * - * @since 2.8.5 - * @hook um_members_directory_filter_select_meta - * - * @example Change relation to 'AND'. - * function my_um_members_directory_filter_select_meta( $relation, $field ) { - * // your code here - * $relation = 'AND'; - * return $relation; - * } - * add_filter( 'um_members_directory_filter_select_meta', 'my_um_members_directory_filter_select_meta', 10, 2 ); - */ - $relation = apply_filters( 'um_members_directory_filter_select_meta', 'OR', $field ); - $values = implode( ' ' . esc_sql( $relation ) . ' ', $values_array ); + $values = implode( ' ' . esc_sql( $relation ) . ' ', $values_array ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias and $values variables are pre-escaped or $wpdb->prepare. $this->where_clauses[] = $wpdb->prepare( "( {$join_alias}.um_key = %s AND ( {$values} ) )", $field ); @@ -441,7 +442,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) { } // $roles_clauses is pre-prepared. - $this->where_clauses[] = '( ' . implode( ' OR ', $roles_clauses ) . ' )'; + $this->where_clauses[] = '( ' . implode( ' ' . esc_sql( $relation ) . ' ', $roles_clauses ) . ' )'; if ( ! $is_default ) { $this->custom_filters_in_query[ $field ] = $value; @@ -534,7 +535,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) { // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias is pre-escaped. } - $values = implode( ' OR ', $values_array ); + $values = implode( ' ' . esc_sql( $relation ) . ' ', $values_array ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias and $values variables are pre-escaped or $wpdb->prepare. $this->where_clauses[] = $wpdb->prepare( "( {$join_alias}.um_key = %s AND ( {$values} ) )", $field ); diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php index a6acb377..c73f6382 100644 --- a/includes/core/class-member-directory.php +++ b/includes/core/class-member-directory.php @@ -1785,6 +1785,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { * Handle filters request */ function filters( $directory_data ) { + global $wpdb; //filters $filter_query = array(); if ( ! empty( $directory_data['search_fields'] ) ) { @@ -1817,6 +1818,9 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { continue; } + /** This filter is documented in includes/core/class-member-directory-meta.php */ + $relation = apply_filters( 'um_members_directory_select_filter_relation', 'OR', $field ); + switch ( $field ) { default: $filter_type = $this->filter_types[ $field ]; @@ -1872,26 +1876,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { case 'select': if ( is_array( $value ) ) { - /** - * Filters change select filter relation. - * - * @param {array} $args query args. - * @param {string} $field field key. - * - * @return {array} query args. - * - * @since 2.8.5 - * @hook um_members_directory_filter_select - * - * @example Change relation to 'AND'. - * function my_um_members_directory_filter_select( $args, $field ) { - * // your code here - * $args = array( 'relation' => 'AND' ) - * return $args; - * } - * add_filter( 'um_members_directory_filter_select', 'my_um_members_directory_filter_select', 10, 2 ); - */ - $field_query = apply_filters( 'um_members_directory_filter_select', array( 'relation' => 'OR' ), $field ); + $field_query = array( 'relation' => esc_sql( $relation ) ); foreach ( $value as $single_val ) { $single_val = trim( stripslashes( $single_val ) ); @@ -1997,21 +1982,35 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { case 'role': $value = array_map( 'strtolower', $value ); - if ( ! empty( $this->query_args['role__in'] ) ) { - $this->query_args['role__in'] = is_array( $this->query_args['role__in'] ) ? $this->query_args['role__in'] : array( $this->query_args['role__in'] ); - $default_role = array_intersect( $this->query_args['role__in'], $value ); - $um_role = array_diff( $value, $default_role ); - - foreach ( $um_role as $key => &$val ) { - $val = 'um_' . str_replace( ' ', '-', $val ); + if ( 'OR' !== $relation ) { + $role__in_clauses = array( 'relation' => $relation ); + foreach ( $value as $role ) { + $role__in_clauses[] = array( + 'key' => $wpdb->get_blog_prefix() . 'capabilities', + 'value' => '"' . $role . '"', + 'compare' => 'LIKE', + ); } - $this->query_args['role__in'] = array_merge( $default_role, $um_role ); + + $this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $role__in_clauses ) ); + + $this->custom_filters_in_query[ $field ] = $value; } else { - $this->query_args['role__in'] = $value; + if ( ! empty( $this->query_args['role__in'] ) ) { + $this->query_args['role__in'] = is_array( $this->query_args['role__in'] ) ? $this->query_args['role__in'] : array( $this->query_args['role__in'] ); + $default_role = array_intersect( $this->query_args['role__in'], $value ); + $um_role = array_diff( $value, $default_role ); + + foreach ( $um_role as $key => &$val ) { + $val = 'um_' . str_replace( ' ', '-', $val ); + } + $this->query_args['role__in'] = array_merge( $default_role, $um_role ); + } else { + $this->query_args['role__in'] = $value; + } + + $this->custom_filters_in_query[ $field ] = $this->query_args['role__in']; } - - $this->custom_filters_in_query[ $field ] = $this->query_args['role__in']; - break; case 'birth_date': $from_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ), date( 'Y', time() - min( $value ) * YEAR_IN_SECONDS ) ) ); @@ -2083,7 +2082,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { break; case 'gender': if ( is_array( $value ) ) { - $field_query = array( 'relation' => 'OR' ); + $field_query = array( 'relation' => $relation ); foreach ( $value as $single_val ) { $single_val = trim( stripslashes( $single_val ) );