CVE-2020-6859: Authorization Bypass Through User-Controlled Key (CWE-639)
value: Multiple Insecure Direct Object Reference vulnerabilities in includes/core/class-files.php in the Ultimate Member plugin through 2.1.2 for WordPress allow remote attackers to change other users' profiles and cover photos via a modified user_id parameter. This is related to ajax_image_upload and ajax_resize_image.
CWE description: The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
CVSS v3 base score: 5.3
Published: 2020-01-13T17:15Z
Repository: https://github.com/ultimatemember/ultimatemember
Language: PHP
Files changed: includes/admin/core/class-admin-settings.php, includes/core/class-files.php, includes/core/class-member-directory-meta.php, includes/core/class-member-directory.php, templates/members.php
Commit date: 2020-01-08 15:19:24 +0200
Commit message: - fixed vulnerability with uploading cover/profile photo for other user ID;
- re-written member directory meta queries;
- fixed search line additional slashes;

Diff: diff --git a/includes/admin/core/class-admin-settings.php b/includes/admin/core/class-admin-settings.php
index f082b4cd..4ee96a5f 100644
--- a/includes/admin/core/class-admin-settings.php
+++ b/includes/admin/core/class-admin-settings.php
@@ -118,10 +118,11 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
 					$metakeys[] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
 				}
 
 				//member directory data
 				$metakeys[] = 'um_member_directory_data';
+				$metakeys[] = '_um_verified';
 
 				$skip_fields = UM()->builtin()->get_fields_without_metakey();
 				$skip_fields = array_merge( $skip_fields, UM()->member_directory()->core_search_fields );
 
 				$real_usermeta = $wpdb->get_col( "SELECT DISTINCT meta_key FROM {$wpdb->usermeta}" );
diff --git a/includes/core/class-files.php b/includes/core/class-files.php
index c766748c..cc2f8650 100644
--- a/includes/core/class-files.php
+++ b/includes/core/class-files.php
@@ -285,10 +285,16 @@ if ( ! class_exists( 'um\core\Files' ) ) {
 			if ( $coord_n != 3 ) {
 				wp_send_json_error( esc_js( __( 'Invalid coordinates', 'ultimate-member' ) ) );
 			}
 
 			$user_id = empty( $_REQUEST['user_id'] ) ? get_current_user_id() : $_REQUEST['user_id'];
+
+			if ( ! UM()->roles()->um_current_user_can( 'edit', $user_id ) ) {
+				$ret['error'] = esc_js( __( 'You haven\'t ability to edit this user', 'ultimate-member' ) );
+				wp_send_json_error( $ret );
+			}
+
 			$image_path = um_is_file_owner( $src, $user_id, true );
 			if ( ! $image_path ) {
 				wp_send_json_error( esc_js( __( 'Invalid file ownership', 'ultimate-member' ) ) );
 			}
 
@@ -317,10 +323,15 @@ if ( ! class_exists( 'um\core\Files' ) ) {
 			$user_id = empty( $_POST['user_id'] ) ? get_current_user_id() : $_POST['user_id'];
 
 			UM()->fields()->set_id = $_POST['set_id'];
 			UM()->fields()->set_mode = $_POST['set_mode'];
 
+			if ( ! UM()->roles()->um_current_user_can( 'edit', $user_id ) ) {
+				$ret['error'] = __( 'You haven\'t ability to edit this user', 'ultimate-member' );
+				wp_send_json_error( $ret );
+			}
+
 			/**
 			 * UM hook
 			 *
 			 * @type filter
 			 * @title um_image_upload_nonce
diff --git a/includes/core/class-member-directory-meta.php b/includes/core/class-member-directory-meta.php
index 2776f7e1..2f25f16b 100644
--- a/includes/core/class-member-directory-meta.php
+++ b/includes/core/class-member-directory-meta.php
@@ -16,13 +16,16 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 
 
 		/**
 		 * @var string
 		 */
-		var $sql_where = '';
-		var $meta_iteration = 1;
 		var $joins = array();
+		var $where_clauses = array();
+
+		var $roles = array();
+		var $general_meta_joined = false;
+
 		var $sql_limit = '';
 		var $sql_order = '';
 
 
 		/**
@@ -170,10 +173,250 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 				);
 			}
 		}
 
 
+		/**
+		 * @param $directory_data
+		 * @param $field
+		 * @param $value
+		 * @param $i
+		 * @param bool $is_default
+		 */
+		function handle_filter_query( $directory_data, $field, $value, $i, $is_default = false ) {
+			global $wpdb;
+
+			$blog_id = get_current_blog_id();
+
+			switch ( $field ) {
+				default:
+
+					$filter_type = $this->filter_types[ $field ];
+
+					/**
+					 * UM hook
+					 *
+					 * @type filter
+					 * @title um_query_args_{$field}__filter
+					 * @description Change field's query for search at Members Directory
+					 * @input_vars
+					 * [{"var":"$field_query","type":"array","desc":"Field query"}]
+					 * @change_log
+					 * ["Since: 2.0"]
+					 * @usage
+					 * <?php add_filter( 'um_query_args_{$field}__filter_meta', 'function_name', 10, 4 ); ?>
+					 * @example
+					 * <?php
+					 * add_filter( 'um_query_args_{$field}__filter_meta', 'my_query_args_filter', 10, 4 );
+					 * function my_query_args_filter( $field_query ) {
+					 *     // your code here
+					 *     return $field_query;
+					 * }
+					 * ?>
+					 */
+					$skip_default = apply_filters( "um_query_args_{$field}__filter_meta", false, $this, $field, $value, $filter_type, $is_default );
+
+					if ( ! $skip_default ) {
+
+						switch ( $filter_type ) {
+							default:
+
+								do_action( "um_query_args_{$field}_{$filter_type}__filter_meta", $field, $value, $filter_type, $i, $is_default );
+								break;
+
+							case 'text':
+
+								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+
+								$value = trim( stripslashes( $value ) );
+
+								$this->where_clauses[] = $wpdb->prepare( "umm{$i}.um_key = %s AND umm{$i}.um_value = %s", $field, $value );
+
+								if ( ! $is_default ) {
+									$this->custom_filters_in_query[ $field ] = $value;
+								}
+
+								break;
+
+							case 'select':
+								if ( ! is_array( $value ) ) {
+									$value = array( $value );
+								}
+
+								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+
+								$values_array = array();
+								foreach ( $value as $single_val ) {
+									$single_val = stripslashes( $single_val );
+
+									$values_array[] = $wpdb->prepare( "umm{$i}.um_value LIKE %s", '%"' . trim( $single_val ) . '"%' );
+									$values_array[] = $wpdb->prepare( "umm{$i}.um_value LIKE %s", '%' . serialize( strval( trim( $single_val ) ) ) . '%' );
+									$values_array[] = $wpdb->prepare( "umm{$i}.um_value = %s", trim( $single_val ) );
+
+									if ( is_numeric( $single_val ) ) {
+										$values_array[] = $wpdb->prepare( "umm{$i}.um_value LIKE %s", '%' . serialize( intval( trim( $single_val ) ) ) . '%' );
+									}
+								}
+
+								$values = implode( ' OR ', $values_array );
+
+								$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND ( {$values} ) )", $field );
+
+								if ( ! $is_default ) {
+									$this->custom_filters_in_query[ $field ] = $value;
+								}
+
+								break;
+							case 'slider':
+
+								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+
+								$min = min( $value );
+								$max = max( $value );
+
+								$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND umm{$i}.um_value BETWEEN %d AND %d )", $field, $min, $max );
+
+								if ( ! $is_default ) {
+									$this->custom_filters_in_query[ $field ] = $value;
+								}
+
+								break;
+							case 'datepicker':
+
+								$offset = 0;
+								if ( ! $is_default ) {
+									if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
+										$offset = (int) $_POST['gmt_offset'];
+									}
+								} else {
+									$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
+									if ( is_numeric( $gmt_offset ) ) {
+										$offset = $gmt_offset;
+									}
+								}
+
+								$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
+								$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
+								$from_date = date( 'Y/m/d', $from_date );
+								$to_date = date( 'Y/m/d', $to_date );
+
+								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+
+								$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND umm{$i}.um_value BETWEEN %s AND %s )", $field, $from_date, $to_date );
+
+								if ( ! $is_default ) {
+									$this->custom_filters_in_query[ $field ] = array( $from_date, $to_date );
+								}
+
+								break;
+							case 'timepicker':
+
+								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+								if ( $value[0] == $value[1] ) {
+									$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND umm{$i}.um_value = %s )", $field, $value[0] );
+								} else {
+									$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND CAST( umm{$i}.um_value AS TIME ) BETWEEN %s AND %s )", $field, $value[0], $value[1] );
+								}
+
+								if ( ! $is_default ) {
+									$this->custom_filters_in_query[ $field ] = $value;
+								}
+
+								break;
+						}
+
+					}
+
+					break;
+				case 'role':
+					$value = array_map( 'strtolower', $value );
+
+					if ( empty( $this->roles ) && ! is_multisite() ) {
+						$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";
+						$this->roles = $value;
+					}
+
+					$roles_clauses = array();
+					foreach ( $value as $role ) {
+						$roles_clauses[] = $wpdb->prepare( "umm_roles.um_value LIKE %s", '%"' . $role . '"%' );
+					}
+
+					$this->where_clauses[] = '( ' . implode( ' OR ', $roles_clauses ) . ' )';
+
+					if ( ! $is_default ) {
+						$this->custom_filters_in_query[ $field ] = $value;
+					}
+
+					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 ) ) );
+					$to_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ) + 1, date( 'Y', time() - ( max( $value ) + 1 ) * YEAR_IN_SECONDS ) ) );
+
+					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+
+					$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = 'birth_date' AND umm{$i}.um_value BETWEEN %s AND %s )", $from_date, $to_date );
+
+					if ( ! $is_default ) {
+						$this->custom_filters_in_query[ $field ] = array( $to_date, $from_date );
+					}
+
+					break;
+				case 'user_registered':
+
+					$offset = 0;
+					if ( ! $is_default ) {
+						if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
+							$offset = (int) $_POST['gmt_offset'];
+						}
+					} else {
+						$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
+						if ( is_numeric( $gmt_offset ) ) {
+							$offset = $gmt_offset;
+						}
+					}
+
+					$from_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', min( $value ) ) . "+$offset hours" ) );
+					$to_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', max( $value ) ) . "+$offset hours" ) );
+
+					$this->where_clauses[] = $wpdb->prepare( "u.user_registered BETWEEN %s AND %s", $from_date, $to_date );
+
+					if ( ! $is_default ) {
+						$this->custom_filters_in_query[ $field ] = $value;
+					}
+
+					break;
+				case 'last_login':
+
+					$offset = 0;
+					if ( ! $is_default ) {
+						if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
+							$offset = (int) $_POST['gmt_offset'];
+						}
+					} else {
+						$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
+						if ( is_numeric( $gmt_offset ) ) {
+							$offset = $gmt_offset;
+						}
+					}
+
+					$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
+					$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
+
+					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
+
+					$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = '_um_last_login' AND umm{$i}.um_value BETWEEN %s AND %s )", $from_date, $to_date );
+
+					if ( ! $is_default ) {
+						$this->custom_filters_in_query[ $field ] = $value;
+					}
+
+					break;
+			}
+		}
+
+
 		/**
 		 * Main Query function for getting members via AJAX
 		 */
 		function ajax_get_members() {
 			UM()->check_ajax_nonce();
@@ -204,11 +447,11 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 							$users_array[] = $exists_id;
 						}
 					}
 
 					if ( ! empty( $users_array ) ) {
-						$this->sql_where .= " AND u.ID IN ( '" . implode( "','", $users_array ) . "' )";
+						$this->where_clauses[] = "u.ID IN ( '" . implode( "','", $users_array ) . "' )";
 					}
 				}
 			}
 
 
@@ -221,71 +464,76 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 			if ( $directory_data['has_cover_photo'] == 1 ) {
 				$cover_photo_where = " AND umm_general.um_value LIKE '%s:11:\"cover_photo\";b:1;%'";
 			}
 
 			if ( ! UM()->roles()->um_user_can( 'can_edit_everyone' ) ) {
-				$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
-
-				$this->sql_where .= " AND ( umm_general.um_key = 'um_member_directory_data' AND 
+				if ( ! $this->general_meta_joined ) {
+					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
+					$this->general_meta_joined = true;
+				}
+				$this->where_clauses[] = "( umm_general.um_key = 'um_member_directory_data' AND 
 				umm_general.um_value LIKE '%s:14:\"account_status\";s:8:\"approved\";%' AND umm_general.um_value LIKE '%s:15:\"hide_in_members\";b:0;%'{$profile_photo_where}{$cover_photo_where} )";
 			} else {
 				if ( ! empty( $cover_photo_where ) || ! empty( $profile_photo_where ) ) {
-					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
-
-					$this->sql_where .= " AND ( umm_general.um_key = 'um_member_directory_data'{$profile_photo_where}{$cover_photo_where} )";
+					if ( ! $this->general_meta_joined ) {
+						$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
+						$this->general_meta_joined = true;
+					}
+					$this->where_clauses[] = "( umm_general.um_key = 'um_member_directory_data'{$profile_photo_where}{$cover_photo_where} )";
 				}
 			}
 
-			$roles = array();
+			//$this->roles = array();
 			if ( UM()->roles()->um_user_can( 'can_view_all' ) ) {
 				$view_roles = um_user( 'can_view_roles' );
 
 				if ( ! $view_roles ) {
 					$view_roles = array();
 				}
 
-				$roles = array_merge( $roles, maybe_unserialize( $view_roles ) );
+				$this->roles = array_merge( $this->roles, maybe_unserialize( $view_roles ) );
 			}
 
 			if ( ! empty( $directory_data['roles'] ) ) {
-				if ( ! empty( $roles ) ) {
-					$roles = array_intersect( $roles, maybe_unserialize( $directory_data['roles'] ) );
+				if ( ! empty( $this->roles ) ) {
+					$this->roles = array_intersect( $this->roles, maybe_unserialize( $directory_data['roles'] ) );
 				} else {
-					$roles = array_merge( $roles, maybe_unserialize( $directory_data['roles'] ) );
+					$this->roles = array_merge( $this->roles, maybe_unserialize( $directory_data['roles'] ) );
 				}
 			}
 
-			if ( ! empty( $roles ) ) {
+			if ( ! empty( $this->roles ) ) {
 				$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";
 
 				$roles_clauses = array();
-				foreach ( $roles as $role ) {
-					$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
+				foreach ( $this->roles as $role ) {
+					$roles_clauses[] = $wpdb->prepare( 'umm_roles.um_value LIKE %s', '%"' . $role . '"%' );
 				}
 
-				$roles_search = implode( ' OR ', $roles_clauses );
-
-				$this->sql_where .= " AND ( {$roles_search} )";
+				$this->where_clauses[] = '( ' . implode( ' OR ', $roles_clauses ) . ' )';
 			} else {
 				if ( is_multisite() ) {
 					// select users who have capabilities for current blog
 					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";
-					$this->sql_where .= " AND umm_roles.um_value IS NOT NULL ";
+					$this->where_clauses[] = "umm_roles.um_value IS NOT NULL";
 				}
 			}
 
 
 			if ( ! empty( $_POST['search'] ) ) {
+				$search_line = trim( stripslashes( $_POST['search'] ) );
+
 				$searches = array();
 				foreach ( $this->core_search_fields as $field ) {
-					$searches[] = $wpdb->prepare( "u.{$field} LIKE %s", '%' . trim( $_POST['search'] ) . '%' );
+					$searches[] = $wpdb->prepare( "u.{$field} LIKE %s", '%' . $search_line . '%' );
 				}
 
 				$core_search = implode( ' OR ', $searches );
 
 				$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_search ON umm_search.user_id = u.ID";
-				$this->sql_where .= " AND ( umm_search.um_value = '" . trim( $_POST['search'] ) . "' OR umm_search.um_value LIKE '%" . trim( $_POST['search'] ) . "%' OR umm_search.um_value LIKE '%" . trim( serialize( strval( $_POST['search'] ) ) ) . "%' OR {$core_search})";
+
+				$this->where_clauses[] = $wpdb->prepare( "( umm_search.um_value = %s OR umm_search.um_value LIKE %s OR umm_search.um_value LIKE %s OR {$core_search})", $search_line, '%' . $search_line . '%', '%' . serialize( strval( $search_line ) ) . '%' );
 
 				$this->is_search = true;
 			}
 
 
@@ -311,213 +559,11 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 					// skip private invisible fields
 					if ( ! um_can_view_field( $attrs ) ) {
 						continue;
 					}
 
-					switch ( $field ) {
-						default:
-
-							$filter_type = $this->filter_types[ $field ];
-
-							/**
-							 * UM hook
-							 *
-							 * @type filter
-							 * @title um_query_args_{$field}__filter
-							 * @description Change field's query for search at Members Directory
-							 * @input_vars
-							 * [{"var":"$field_query","type":"array","desc":"Field query"}]
-							 * @change_log
-							 * ["Since: 2.0"]
-							 * @usage
-							 * <?php add_filter( 'um_query_args_{$field}__filter', 'function_name', 10, 1 ); ?>
-							 * @example
-							 * <?php
-							 * add_filter( 'um_query_args_{$field}__filter', 'my_query_args_filter', 10, 1 );
-							 * function my_query_args_filter( $field_query ) {
-							 *     // your code here
-							 *     return $field_query;
-							 * }
-							 * ?>
-							 */
-							$field_query = apply_filters( "um_query_args_{$field}__filter", false, $field, $value, $filter_type );
-
-							if ( ! $field_query ) {
-
-								switch ( $filter_type ) {
-									default:
-
-										$field_query = apply_filters( "um_query_args_{$field}_{$filter_type}__filter", false, $field, $value, $filter_type );
-
-										break;
-									case 'text':
-
-										$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-
-										$value = trim( stripslashes( $value ) );
-
-										$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value = '{$value}' )";
-
-										$this->custom_filters_in_query[ $field ] = $value;
-
-										break;
-
-									case 'select':
-										if ( is_array( $value ) ) {
-
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-
-											$values_array = array();
-											foreach ( $value as $single_val ) {
-												$single_val = stripslashes( $single_val );
-
-												$values_array[] = "umm" . $i . ".um_value LIKE '%\"" . trim( $single_val ) . "\"%'";
-												$values_array[] = "umm" . $i . ".um_value LIKE '%" . serialize( strval( trim( $single_val ) ) ) . "%'";
-												$values_array[] = "umm" . $i . ".um_value = '" . trim( $single_val ) . "'";
-
-												if ( is_numeric( $single_val ) ) {
-													$values_array[] = "umm" . $i . ".um_value LIKE '%" . serialize( intval( trim( $single_val ) ) ) . "%'";
-												}
-											}
-
-											$values = implode( ' OR ', $values_array );
-
-											$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND ( {$values} ) )";
-										}
-
-										$this->custom_filters_in_query[ $field ] = $value;
-
-										break;
-									case 'slider':
-
-										$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-
-										$min = min( $value );
-										$max = max( $value );
-
-										$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value BETWEEN {$min} AND {$max} )";
-
-										$this->custom_filters_in_query[ $field ] = $value;
-
-										break;
-									case 'datepicker':
-
-										$offset = 0;
-										if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
-											$offset = (int) $_POST['gmt_offset'];
-										}
-
-										$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
-										$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
-										$from_date = date( 'Y/m/d', $from_date );
-										$to_date = date( 'Y/m/d', $to_date );
-
-
-										$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-
-										$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
-
-										$this->custom_filters_in_query[ $field ] = array( $from_date, $to_date );
-
-										break;
-									case 'timepicker':
-
-										if ( $value[0] == $value[1] ) {
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-											$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value = '{$value[0]}' )";
-										} else {
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-											$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND CAST( umm" . $i . ".um_value AS TIME ) BETWEEN {$value[0]} AND {$value[1]} )";
-										}
-
-										$this->custom_filters_in_query[ $field ] = $value;
-
-										break;
-								}
-
-							}
-
-							if ( ! empty( $field_query ) && $field_query !== true ) {
-								$this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $field_query ) );
-							}
-
-							break;
-						case 'role':
-							$value = array_map( 'strtolower', $value );
-
-							if ( ! empty( $roles ) || is_multisite() ) {
-								$roles_clauses = array();
-								foreach ( $value as $role ) {
-									$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
-								}
-
-								$roles_search = implode( ' OR ', $roles_clauses );
-
-								$this->sql_where .= " AND ( {$roles_search} )";
-							} else {
-								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";
-
-								$roles = $value;
-
-								$roles_clauses = array();
-								foreach ( $value as $role ) {
-									$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
-								}
-
-								$roles_search = implode( ' OR ', $roles_clauses );
-
-								$this->sql_where .= " AND ( {$roles_search} )";
-							}
-
-							$this->custom_filters_in_query[ $field ] = $value;
-
-							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 ) ) );
-							$to_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ) + 1, date( 'Y', time() - ( max( $value ) + 1 ) * YEAR_IN_SECONDS ) ) );
-
-							$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-
-							$this->sql_where .= " AND ( umm" . $i . ".um_key = 'birth_date' AND umm" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
-
-							$this->custom_filters_in_query[ $field ] = array( $to_date, $from_date );
-
-							break;
-						case 'user_registered':
-
-							$offset = 0;
-							if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
-								$offset = (int) $_POST['gmt_offset'];
-							}
-
-							$from_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', min( $value ) ) . "+$offset hours" ) );
-							$to_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', max( $value ) ) . "+$offset hours" ) );
-
-							$this->sql_where .= " AND ( u.user_registered BETWEEN {$from_date} AND {$to_date} )";
-
-							$this->custom_filters_in_query[ $field ] = $value;
-
-							break;
-						case 'last_login':
-
-							$offset = 0;
-							if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
-								$offset = (int) $_POST['gmt_offset'];
-							}
-
-							$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
-							$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
-
-							$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
-
-							$this->sql_where .= " AND ( umm" . $i . ".um_key = '_um_last_login' AND umm" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
-
-							$this->custom_filters_in_query[ $field ] = $value;
-
-							break;
-					}
+					$this->handle_filter_query( $directory_data, $field, $value, $i );
 
 					$i++;
 				}
 			}
 
@@ -527,203 +573,15 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 				$default_filters = array();
 				if ( ! empty( $directory_data['search_filters'] ) ) {
 					$default_filters = maybe_unserialize( $directory_data['search_filters'] );
 				}
 
-				$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
-
 				if ( ! empty( $default_filters ) ) {
 					$i = 1;
 					foreach ( $default_filters as $field => $value ) {
-						//unable default filter in case if we select other value in frontend filters
-		//				if ( in_array( $field, array_keys( $this->custom_filters_in_query ) ) ) {
-		//					continue;
-		//				}
-
-						switch ( $field ) {
-							default:
-
-								$filter_type = $this->filter_types[ $field ];
-
-								/**
-								 * UM hook
-								 *
-								 * @type filter
-								 * @title um_query_args_{$field}__filter
-								 * @description Change field's query for search at Members Directory
-								 * @input_vars
-								 * [{"var":"$field_query","type":"array","desc":"Field query"}]
-								 * @change_log
-								 * ["Since: 2.0"]
-								 * @usage
-								 * <?php add_filter( 'um_query_args_{$field}__filter', 'function_name', 10, 1 ); ?>
-								 * @example
-								 * <?php
-								 * add_filter( 'um_query_args_{$field}__filter', 'my_query_args_filter', 10, 1 );
-								 * function my_query_args_filter( $field_query ) {
-								 *     // your code here
-								 *     return $field_query;
-								 * }
-								 * ?>
-								 */
-								$field_query = apply_filters( "um_query_args_{$field}__filter", false, $field, $value, $filter_type );
-
-								if ( ! $field_query ) {
-
-									switch ( $filter_type ) {
-										default:
-
-											$field_query = apply_filters( "um_query_args_{$field}_{$filter_type}__filter", false, $field, $value, $filter_type );
-
-											break;
-										case 'text':
-
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-
-											$value = trim( stripslashes( $value ) );
-
-											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value = '{$value}' )";
-
-											$this->custom_filters_in_query[ $field ] = $value;
-
-											break;
-										case 'select':
-											if ( ! is_array( $value ) ) {
-												$value = array( $value );
-											}
-
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-
-											$values_array = array();
-											foreach ( $value as $single_val ) {
-												$single_val = stripslashes( $single_val );
-
-												$values_array[] = "ummd" . $i . ".um_value LIKE '%\"" . trim( $single_val ) . "\"%'";
-												$values_array[] = "ummd" . $i . ".um_value LIKE '%" . serialize( strval( trim( $single_val ) ) ) . "%'";
-												$values_array[] = "ummd" . $i . ".um_value = '" . trim( $single_val ) . "'";
-
-												if ( is_numeric( $single_val ) ) {
-													$values_array[] = "ummd" . $i . ".um_value LIKE '%" . serialize( intval( trim( $single_val ) ) ) . "%'";
-												}
-											}
-
-											$values = implode( ' OR ', $values_array );
-
-											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ( {$values} ) )";
-
-											break;
-										case 'slider':
-
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-
-											$min = min( $value );
-											$max = max( $value );
-
-											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value BETWEEN {$min} AND {$max} )";
-
-											break;
-										case 'datepicker':
-
-											$offset = 0;
-											if ( is_numeric( $gmt_offset ) ) {
-												$offset = $gmt_offset;
-											}
-
-											$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
-											$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
-											$from_date = date( 'Y/m/d', $from_date );
-											$to_date = date( 'Y/m/d', $to_date );
-
-
-											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-
-											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
-
-											break;
-										case 'timepicker':
-
-											if ( $value[0] == $value[1] ) {
-												$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-												$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value = '{$value[0]}' )";
-											} else {
-												$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-												$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND CAST( ummd" . $i . ".um_value AS TIME ) BETWEEN {$value[0]} AND {$value[1]} )";
-											}
-
-											break;
-									}
-
-								}
-
-								break;
-							case 'role':
-//								$value = explode( '||', $value );
-//								$value = array_map( 'strtolower', $value );
-
-								$value = array_map( 'strtolower', $value );
-
-								if ( ! empty( $roles ) || is_multisite() ) {
-									$roles_clauses = array();
-									foreach ( $value as $role ) {
-										$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
-									}
-
-									$roles_search = implode( ' OR ', $roles_clauses );
-
-									$this->sql_where .= " AND ( {$roles_search} )";
-								} else {
-									$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";
-
-									$roles = $value;
-
-									$roles_clauses = array();
-									foreach ( $value as $role ) {
-										$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
-									}
-
-									$roles_search = implode( ' OR ', $roles_clauses );
-
-									$this->sql_where .= " AND ( {$roles_search} )";
-								}
-
-								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 ) ) );
-								$to_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ) + 1, date( 'Y', time() - ( max( $value ) + 1 ) * YEAR_IN_SECONDS ) ) );
-
-								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-
-								$this->sql_where .= " AND ( ummd" . $i . ".um_key = 'birth_date' AND ummd" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
-
 
-								break;
-							case 'user_registered':
-								$offset = 0;
-								if ( is_numeric( $gmt_offset ) ) {
-									$offset = $gmt_offset;
-								}
-
-								$from_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', min( $value ) ) . "+$offset hours" ) );
-								$to_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', max( $value ) ) . "+$offset hours" ) );
-
-								$this->sql_where .= " AND ( u.user_registered BETWEEN {$from_date} AND {$to_date} )";
-
-								break;
-							case 'last_login':
-								$offset = 0;
-								if ( is_numeric( $gmt_offset ) ) {
-									$offset = $gmt_offset;
-								}
-
-								$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
-								$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
-
-								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
-
-								$this->sql_where .= " AND ( ummd" . $i . ".um_key = '_um_last_login' AND ummd" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
-								break;
-						}
+						$this->handle_filter_query( $directory_data, $field, $value, $i, true );
 
 						$i++;
 					}
 				}
 			}
@@ -818,11 +676,11 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 				} else {
 					$this->sql_order = " ORDER BY u.{$sortby} {$order} ";
 				}
 			}
 
-			$this->sql_order = apply_filters( 'um_modify_sortby_parameter', $this->sql_order, $sortby );
+			$this->sql_order = apply_filters( 'um_modify_sortby_parameter_meta', $this->sql_order, $sortby );
 
 
 			$profiles_per_page = $directory_data['profiles_per_page'];
 			if ( UM()->mobile()->isMobile() && isset( $directory_data['profiles_per_page_mobile'] ) ) {
 				$profiles_per_page = $directory_data['profiles_per_page_mobile'];
@@ -839,20 +697,30 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 			// limit
 			if ( isset( $query_number ) && $query_number > 0 ) {
 				$this->sql_limit .= $wpdb->prepare( 'LIMIT %d, %d', $query_number * ( $query_paged - 1 ), $number );
 			}
 
-			$sql_join = implode( ' ', $this->joins );
-
 			do_action( 'um_pre_users_query', $this, $directory_data, $sortby );
 
+			$sql_join = implode( ' ', $this->joins );
+			$sql_where = implode( ' AND ', $this->where_clauses );
+			$sql_where = ! empty( $sql_where ) ? ' AND ' . $sql_where : '';
+
 			global $wpdb;
+
+			/*var_dump( "SELECT SQL_CALC_FOUND_ROWS DISTINCT u.ID
+				FROM {$wpdb->users} AS u
+				{$sql_join}
+				WHERE 1=1 {$sql_where}
+				{$this->sql_order}
+				{$this->sql_limit}" );*/
+
 			$user_ids = $wpdb->get_col(
 				"SELECT SQL_CALC_FOUND_ROWS DISTINCT u.ID 
 				FROM {$wpdb->users} AS u
 				{$sql_join}
-				WHERE 1=1 {$this->sql_where}
+				WHERE 1=1 {$sql_where}
 				{$this->sql_order}
 				{$this->sql_limit}"
 			);
 
 			$total_users = (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' );
@@ -874,67 +742,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
 			um_reset_user();
 			// end of user card
 
 			wp_send_json_success( array( 'pagination' => $pagination_data, 'users' => $users, 'is_search' => $this->is_search ) );
 		}
-
-
-		/**
-		 * Get data array for pagination
-		 *
-		 *
-		 * @param array $directory_data
-		 * @param int $total_users
-		 *
-		 * @return array
-		 */
-		function calculate_pagination( $directory_data, $total_users ) {
-
-			$current_page = ! empty( $_POST['page'] ) ? $_POST['page'] : 1;
-
-			$total_users = ( ! empty( $directory_data['max_users'] ) && $directory_data['max_users'] <= $total_users ) ? $directory_data['max_users'] : $total_users;
-
-			// number of profiles for mobile
-			$profiles_per_page = $directory_data['profiles_per_page'];
-			if ( UM()->mobile()->isMobile() && isset( $directory_data['profiles_per_page_mobile'] ) ) {
-				$profiles_per_page = $directory_data['profiles_per_page_mobile'];
-			}
-
-			$total_pages = 1;
-			if ( ! empty( $profiles_per_page ) ) {
-				$total_pages = ceil( $total_users / $profiles_per_page );
-			}
-
-			if ( ! empty( $total_pages ) ) {
-				$index1 = 0 - ( $current_page - 2 ) + 1;
-				$to = $current_page + 2;
-				if ( $index1 > 0 ) {
-					$to += $index1;
-				}
-
-				$index2 = $total_pages - ( $current_page + 2 );
-				$from = $current_page - 2;
-				if ( $index2 < 0 ) {
-					$from += $index2;
-				}
-
-				$pages_to_show = range(
-					( $from > 0 ) ? $from : 1,
-					( $to <= $total_pages ) ? $to : $total_pages
-				);
-			}
-
-
-			$pagination_data = array(
-				'pages_to_show' => ( ! empty( $pages_to_show ) && count( $pages_to_show ) > 1 ) ? array_values( $pages_to_show ) : array(),
-				'current_page'  => $current_page,
-				'total_pages'   => $total_pages,
-				'total_users'   => $total_users,
-			);
-
-			$pagination_data['header'] = $this->convert_tags( $directory_data['header'], $pagination_data );
-			$pagination_data['header_single'] = $this->convert_tags( $directory_data['header_single'], $pagination_data );
-
-			return $pagination_data;
-		}
 	}
 }
\ No newline at end of file
diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php
index 11ac2533..1aa31494 100644
--- a/includes/core/class-member-directory.php
+++ b/includes/core/class-member-directory.php
@@ -1250,24 +1250,24 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
 				// complex using with change_meta_sql function
 
 				$meta_query = array(
 					'relation' => 'OR',
 					array(
-						'value'     => trim( $_POST['search'] ),
+						'value'     => trim( stripslashes( $_POST['search'] ) ),
 						'compare'   => '=',
 					),
 					array(
-						'value'     => trim( $_POST['search'] ),
+						'value'     => trim( stripslashes( $_POST['search'] ) ),
 						'compare'   => 'LIKE',
 					),
 					array(
-						'value'     => trim( serialize( strval( $_POST['search'] ) ) ),
+						'value'     => trim( serialize( strval( stripslashes( $_POST['search'] ) ) ) ),
 						'compare'   => 'LIKE',
 					),
 				);
 
-				$meta_query = apply_filters( 'um_member_directory_general_search_meta_query', $meta_query, $_POST['search'] );
+				$meta_query = apply_filters( 'um_member_directory_general_search_meta_query', $meta_query, stripslashes( $_POST['search'] ) );
 
 				$this->query_args['meta_query'][] = $meta_query;
 
 				$this->is_search = true;
 			}
@@ -1288,11 +1288,11 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
 		 * @return mixed
 		 */
 		function change_meta_sql( $sql, $queries, $type, $primary_table, $primary_id_column, $context ) {
 			if ( ! empty( $_POST['search'] ) ) {
 				global $wpdb;
-				$search = trim( $_POST['search'] );
+				$search = trim( stripslashes( $_POST['search'] ) );
 				if ( ! empty( $search ) ) {
 
 					$meta_value = '%' . $wpdb->esc_like( $search ) . '%';
 					$search_meta      = $wpdb->prepare( '%s', $meta_value );
 
@@ -1868,19 +1868,19 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
 		/**
 		 * Get data array for pagination
 		 *
 		 *
 		 * @param array $directory_data
-		 * @param \WP_User_Query $result
+		 * @param int $total_users
 		 *
 		 * @return array
 		 */
-		function calculate_pagination( $directory_data, $result ) {
+		function calculate_pagination( $directory_data, $total_users ) {
 
 			$current_page = ! empty( $_POST['page'] ) ? $_POST['page'] : 1;
 
-			$total_users = ( ! empty( $directory_data['max_users'] ) && $directory_data['max_users'] <= $result->total_users ) ? $directory_data['max_users'] : $result->total_users;
+			$total_users = ( ! empty( $directory_data['max_users'] ) && $directory_data['max_users'] <= $total_users ) ? $directory_data['max_users'] : $total_users;
 
 			// number of profiles for mobile
 			$profiles_per_page = $directory_data['profiles_per_page'];
 			if ( UM()->mobile()->isMobile() && isset( $directory_data['profiles_per_page_mobile'] ) ) {
 				$profiles_per_page = $directory_data['profiles_per_page_mobile'];
@@ -2290,11 +2290,11 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
 			 * }
 			 * ?>
 			 */
 			do_action( 'um_user_after_query', $this->query_args, $user_query );
 
-			$pagination_data = $this->calculate_pagination( $directory_data, $user_query );
+			$pagination_data = $this->calculate_pagination( $directory_data, $user_query->total_users );
 
 			$user_ids = ! empty( $user_query->results ) ? array_unique( $user_query->results ) : array();
 
 			/**
 			 * UM hook
diff --git a/templates/members.php b/templates/members.php
index 52cb675c..48bf7bed 100644
--- a/templates/members.php
+++ b/templates/members.php
@@ -73,11 +73,11 @@ $current_page = ( ! empty( $_GET[ 'page_' . $unique_hash ] ) && is_numeric( $_GE
 //Search
 $search = isset( $args['search'] ) ? $args['search'] : false;
 $show_search = empty( $args['roles_can_search'] ) || ( ! empty( $priority_user_role ) && in_array( $priority_user_role, $args['roles_can_search'] ) );
 $search_from_url = '';
 if ( $search && $show_search ) {
-	$search_from_url = ! empty( $_GET[ 'search_' . $unique_hash ] ) ? $_GET[ 'search_' . $unique_hash ] : '';
+	$search_from_url = ! empty( $_GET[ 'search_' . $unique_hash ] ) ? stripslashes( $_GET[ 'search_' . $unique_hash ] ) : '';
 }
 
 
 //Filters
 $filters = isset( $args['filters'] ) ? $args['filters'] : false;

Vulnerable code: 		var $sql_where = '';
		var $meta_iteration = 1;
						$this->sql_where .= " AND u.ID IN ( '" . implode( "','", $users_array ) . "' )";
				$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";

				$this->sql_where .= " AND ( umm_general.um_key = 'um_member_directory_data' AND 
					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";

					$this->sql_where .= " AND ( umm_general.um_key = 'um_member_directory_data'{$profile_photo_where}{$cover_photo_where} )";
			$roles = array();
				$roles = array_merge( $roles, maybe_unserialize( $view_roles ) );
				if ( ! empty( $roles ) ) {
					$roles = array_intersect( $roles, maybe_unserialize( $directory_data['roles'] ) );
					$roles = array_merge( $roles, maybe_unserialize( $directory_data['roles'] ) );
			if ( ! empty( $roles ) ) {
				foreach ( $roles as $role ) {
					$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
				$roles_search = implode( ' OR ', $roles_clauses );

				$this->sql_where .= " AND ( {$roles_search} )";
					$this->sql_where .= " AND umm_roles.um_value IS NOT NULL ";
					$searches[] = $wpdb->prepare( "u.{$field} LIKE %s", '%' . trim( $_POST['search'] ) . '%' );
				$this->sql_where .= " AND ( umm_search.um_value = '" . trim( $_POST['search'] ) . "' OR umm_search.um_value LIKE '%" . trim( $_POST['search'] ) . "%' OR umm_search.um_value LIKE '%" . trim( serialize( strval( $_POST['search'] ) ) ) . "%' OR {$core_search})";
					switch ( $field ) {
						default:

							$filter_type = $this->filter_types[ $field ];

							/**
							 * UM hook
							 *
							 * @type filter
							 * @title um_query_args_{$field}__filter
							 * @description Change field's query for search at Members Directory
							 * @input_vars
							 * [{"var":"$field_query","type":"array","desc":"Field query"}]
							 * @change_log
							 * ["Since: 2.0"]
							 * @usage
							 * <?php add_filter( 'um_query_args_{$field}__filter', 'function_name', 10, 1 ); ?>
							 * @example
							 * <?php
							 * add_filter( 'um_query_args_{$field}__filter', 'my_query_args_filter', 10, 1 );
							 * function my_query_args_filter( $field_query ) {
							 *     // your code here
							 *     return $field_query;
							 * }
							 * ?>
							 */
							$field_query = apply_filters( "um_query_args_{$field}__filter", false, $field, $value, $filter_type );

							if ( ! $field_query ) {

								switch ( $filter_type ) {
									default:

										$field_query = apply_filters( "um_query_args_{$field}_{$filter_type}__filter", false, $field, $value, $filter_type );

										break;
									case 'text':

										$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";

										$value = trim( stripslashes( $value ) );

										$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value = '{$value}' )";

										$this->custom_filters_in_query[ $field ] = $value;

										break;

									case 'select':
										if ( is_array( $value ) ) {

											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";

											$values_array = array();
											foreach ( $value as $single_val ) {
												$single_val = stripslashes( $single_val );

												$values_array[] = "umm" . $i . ".um_value LIKE '%\"" . trim( $single_val ) . "\"%'";
												$values_array[] = "umm" . $i . ".um_value LIKE '%" . serialize( strval( trim( $single_val ) ) ) . "%'";
												$values_array[] = "umm" . $i . ".um_value = '" . trim( $single_val ) . "'";

												if ( is_numeric( $single_val ) ) {
													$values_array[] = "umm" . $i . ".um_value LIKE '%" . serialize( intval( trim( $single_val ) ) ) . "%'";
												}
											}

											$values = implode( ' OR ', $values_array );

											$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND ( {$values} ) )";
										}

										$this->custom_filters_in_query[ $field ] = $value;

										break;
									case 'slider':

										$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";

										$min = min( $value );
										$max = max( $value );

										$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value BETWEEN {$min} AND {$max} )";

										$this->custom_filters_in_query[ $field ] = $value;

										break;
									case 'datepicker':

										$offset = 0;
										if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
											$offset = (int) $_POST['gmt_offset'];
										}

										$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
										$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
										$from_date = date( 'Y/m/d', $from_date );
										$to_date = date( 'Y/m/d', $to_date );


										$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";

										$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";

										$this->custom_filters_in_query[ $field ] = array( $from_date, $to_date );

										break;
									case 'timepicker':

										if ( $value[0] == $value[1] ) {
											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
											$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND umm" . $i . ".um_value = '{$value[0]}' )";
										} else {
											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";
											$this->sql_where .= " AND ( umm" . $i . ".um_key = '{$field}' AND CAST( umm" . $i . ".um_value AS TIME ) BETWEEN {$value[0]} AND {$value[1]} )";
										}

										$this->custom_filters_in_query[ $field ] = $value;

										break;
								}

							}

							if ( ! empty( $field_query ) && $field_query !== true ) {
								$this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $field_query ) );
							}

							break;
						case 'role':
							$value = array_map( 'strtolower', $value );

							if ( ! empty( $roles ) || is_multisite() ) {
								$roles_clauses = array();
								foreach ( $value as $role ) {
									$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
								}

								$roles_search = implode( ' OR ', $roles_clauses );

								$this->sql_where .= " AND ( {$roles_search} )";
							} else {
								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";

								$roles = $value;

								$roles_clauses = array();
								foreach ( $value as $role ) {
									$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
								}

								$roles_search = implode( ' OR ', $roles_clauses );

								$this->sql_where .= " AND ( {$roles_search} )";
							}

							$this->custom_filters_in_query[ $field ] = $value;

							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 ) ) );
							$to_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ) + 1, date( 'Y', time() - ( max( $value ) + 1 ) * YEAR_IN_SECONDS ) ) );

							$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";

							$this->sql_where .= " AND ( umm" . $i . ".um_key = 'birth_date' AND umm" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";

							$this->custom_filters_in_query[ $field ] = array( $to_date, $from_date );

							break;
						case 'user_registered':

							$offset = 0;
							if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
								$offset = (int) $_POST['gmt_offset'];
							}

							$from_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', min( $value ) ) . "+$offset hours" ) );
							$to_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', max( $value ) ) . "+$offset hours" ) );

							$this->sql_where .= " AND ( u.user_registered BETWEEN {$from_date} AND {$to_date} )";

							$this->custom_filters_in_query[ $field ] = $value;

							break;
						case 'last_login':

							$offset = 0;
							if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
								$offset = (int) $_POST['gmt_offset'];
							}

							$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
							$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59

							$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm" . $i . " ON umm" . $i . ".user_id = u.ID";

							$this->sql_where .= " AND ( umm" . $i . ".um_key = '_um_last_login' AND umm" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";

							$this->custom_filters_in_query[ $field ] = $value;

							break;
					}
				$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );

						//unable default filter in case if we select other value in frontend filters
		//				if ( in_array( $field, array_keys( $this->custom_filters_in_query ) ) ) {
		//					continue;
		//				}

						switch ( $field ) {
							default:

								$filter_type = $this->filter_types[ $field ];

								/**
								 * UM hook
								 *
								 * @type filter
								 * @title um_query_args_{$field}__filter
								 * @description Change field's query for search at Members Directory
								 * @input_vars
								 * [{"var":"$field_query","type":"array","desc":"Field query"}]
								 * @change_log
								 * ["Since: 2.0"]
								 * @usage
								 * <?php add_filter( 'um_query_args_{$field}__filter', 'function_name', 10, 1 ); ?>
								 * @example
								 * <?php
								 * add_filter( 'um_query_args_{$field}__filter', 'my_query_args_filter', 10, 1 );
								 * function my_query_args_filter( $field_query ) {
								 *     // your code here
								 *     return $field_query;
								 * }
								 * ?>
								 */
								$field_query = apply_filters( "um_query_args_{$field}__filter", false, $field, $value, $filter_type );

								if ( ! $field_query ) {

									switch ( $filter_type ) {
										default:

											$field_query = apply_filters( "um_query_args_{$field}_{$filter_type}__filter", false, $field, $value, $filter_type );

											break;
										case 'text':

											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";

											$value = trim( stripslashes( $value ) );

											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value = '{$value}' )";

											$this->custom_filters_in_query[ $field ] = $value;

											break;
										case 'select':
											if ( ! is_array( $value ) ) {
												$value = array( $value );
											}

											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";

											$values_array = array();
											foreach ( $value as $single_val ) {
												$single_val = stripslashes( $single_val );

												$values_array[] = "ummd" . $i . ".um_value LIKE '%\"" . trim( $single_val ) . "\"%'";
												$values_array[] = "ummd" . $i . ".um_value LIKE '%" . serialize( strval( trim( $single_val ) ) ) . "%'";
												$values_array[] = "ummd" . $i . ".um_value = '" . trim( $single_val ) . "'";

												if ( is_numeric( $single_val ) ) {
													$values_array[] = "ummd" . $i . ".um_value LIKE '%" . serialize( intval( trim( $single_val ) ) ) . "%'";
												}
											}

											$values = implode( ' OR ', $values_array );

											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ( {$values} ) )";

											break;
										case 'slider':

											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";

											$min = min( $value );
											$max = max( $value );

											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value BETWEEN {$min} AND {$max} )";

											break;
										case 'datepicker':

											$offset = 0;
											if ( is_numeric( $gmt_offset ) ) {
												$offset = $gmt_offset;
											}

											$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
											$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
											$from_date = date( 'Y/m/d', $from_date );
											$to_date = date( 'Y/m/d', $to_date );


											$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";

											$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";

											break;
										case 'timepicker':

											if ( $value[0] == $value[1] ) {
												$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
												$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND ummd" . $i . ".um_value = '{$value[0]}' )";
											} else {
												$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";
												$this->sql_where .= " AND ( ummd" . $i . ".um_key = '{$field}' AND CAST( ummd" . $i . ".um_value AS TIME ) BETWEEN {$value[0]} AND {$value[1]} )";
											}

											break;
									}

								}

								break;
							case 'role':
//								$value = explode( '||', $value );
//								$value = array_map( 'strtolower', $value );

								$value = array_map( 'strtolower', $value );

								if ( ! empty( $roles ) || is_multisite() ) {
									$roles_clauses = array();
									foreach ( $value as $role ) {
										$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
									}

									$roles_search = implode( ' OR ', $roles_clauses );

									$this->sql_where .= " AND ( {$roles_search} )";
								} else {
									$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";

									$roles = $value;

									$roles_clauses = array();
									foreach ( $value as $role ) {
										$roles_clauses[] = "umm_roles.um_value LIKE '%\"" . $role . "\"%'";
									}

									$roles_search = implode( ' OR ', $roles_clauses );

									$this->sql_where .= " AND ( {$roles_search} )";
								}

								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 ) ) );
								$to_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ) + 1, date( 'Y', time() - ( max( $value ) + 1 ) * YEAR_IN_SECONDS ) ) );

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";

								$this->sql_where .= " AND ( ummd" . $i . ".um_key = 'birth_date' AND ummd" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";

								break;
							case 'user_registered':
								$offset = 0;
								if ( is_numeric( $gmt_offset ) ) {
									$offset = $gmt_offset;
								}

								$from_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', min( $value ) ) . "+$offset hours" ) );
								$to_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', max( $value ) ) . "+$offset hours" ) );

								$this->sql_where .= " AND ( u.user_registered BETWEEN {$from_date} AND {$to_date} )";

								break;
							case 'last_login':
								$offset = 0;
								if ( is_numeric( $gmt_offset ) ) {
									$offset = $gmt_offset;
								}

								$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
								$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata ummd" . $i . " ON ummd" . $i . ".user_id = u.ID";

								$this->sql_where .= " AND ( ummd" . $i . ".um_key = '_um_last_login' AND ummd" . $i . ".um_value BETWEEN {$from_date} AND {$to_date} )";
								break;
						}
			$this->sql_order = apply_filters( 'um_modify_sortby_parameter', $this->sql_order, $sortby );
			$sql_join = implode( ' ', $this->joins );

				WHERE 1=1 {$this->sql_where}


		/**
		 * Get data array for pagination
		 *
		 *
		 * @param array $directory_data
		 * @param int $total_users
		 *
		 * @return array
		 */
		function calculate_pagination( $directory_data, $total_users ) {

			$current_page = ! empty( $_POST['page'] ) ? $_POST['page'] : 1;

			$total_users = ( ! empty( $directory_data['max_users'] ) && $directory_data['max_users'] <= $total_users ) ? $directory_data['max_users'] : $total_users;

			// number of profiles for mobile
			$profiles_per_page = $directory_data['profiles_per_page'];
			if ( UM()->mobile()->isMobile() && isset( $directory_data['profiles_per_page_mobile'] ) ) {
				$profiles_per_page = $directory_data['profiles_per_page_mobile'];
			}

			$total_pages = 1;
			if ( ! empty( $profiles_per_page ) ) {
				$total_pages = ceil( $total_users / $profiles_per_page );
			}

			if ( ! empty( $total_pages ) ) {
				$index1 = 0 - ( $current_page - 2 ) + 1;
				$to = $current_page + 2;
				if ( $index1 > 0 ) {
					$to += $index1;
				}

				$index2 = $total_pages - ( $current_page + 2 );
				$from = $current_page - 2;
				if ( $index2 < 0 ) {
					$from += $index2;
				}

				$pages_to_show = range(
					( $from > 0 ) ? $from : 1,
					( $to <= $total_pages ) ? $to : $total_pages
				);
			}


			$pagination_data = array(
				'pages_to_show' => ( ! empty( $pages_to_show ) && count( $pages_to_show ) > 1 ) ? array_values( $pages_to_show ) : array(),
				'current_page'  => $current_page,
				'total_pages'   => $total_pages,
				'total_users'   => $total_users,
			);

			$pagination_data['header'] = $this->convert_tags( $directory_data['header'], $pagination_data );
			$pagination_data['header_single'] = $this->convert_tags( $directory_data['header_single'], $pagination_data );

			return $pagination_data;
		}
						'value'     => trim( $_POST['search'] ),
						'value'     => trim( $_POST['search'] ),
						'value'     => trim( serialize( strval( $_POST['search'] ) ) ),
				$meta_query = apply_filters( 'um_member_directory_general_search_meta_query', $meta_query, $_POST['search'] );
				$search = trim( $_POST['search'] );
		 * @param \WP_User_Query $result
		function calculate_pagination( $directory_data, $result ) {
			$total_users = ( ! empty( $directory_data['max_users'] ) && $directory_data['max_users'] <= $result->total_users ) ? $directory_data['max_users'] : $result->total_users;
			$pagination_data = $this->calculate_pagination( $directory_data, $user_query );
	$search_from_url = ! empty( $_GET[ 'search_' . $unique_hash ] ) ? $_GET[ 'search_' . $unique_hash ] : '';
Fixed code: 				$metakeys[] = '_um_verified';

			if ( ! UM()->roles()->um_current_user_can( 'edit', $user_id ) ) {
				$ret['error'] = esc_js( __( 'You haven\'t ability to edit this user', 'ultimate-member' ) );
				wp_send_json_error( $ret );
			}

			if ( ! UM()->roles()->um_current_user_can( 'edit', $user_id ) ) {
				$ret['error'] = __( 'You haven\'t ability to edit this user', 'ultimate-member' );
				wp_send_json_error( $ret );
			}

		var $where_clauses = array();

		var $roles = array();
		var $general_meta_joined = false;

		/**
		 * @param $directory_data
		 * @param $field
		 * @param $value
		 * @param $i
		 * @param bool $is_default
		 */
		function handle_filter_query( $directory_data, $field, $value, $i, $is_default = false ) {
			global $wpdb;

			$blog_id = get_current_blog_id();

			switch ( $field ) {
				default:

					$filter_type = $this->filter_types[ $field ];

					/**
					 * UM hook
					 *
					 * @type filter
					 * @title um_query_args_{$field}__filter
					 * @description Change field's query for search at Members Directory
					 * @input_vars
					 * [{"var":"$field_query","type":"array","desc":"Field query"}]
					 * @change_log
					 * ["Since: 2.0"]
					 * @usage
					 * <?php add_filter( 'um_query_args_{$field}__filter_meta', 'function_name', 10, 4 ); ?>
					 * @example
					 * <?php
					 * add_filter( 'um_query_args_{$field}__filter_meta', 'my_query_args_filter', 10, 4 );
					 * function my_query_args_filter( $field_query ) {
					 *     // your code here
					 *     return $field_query;
					 * }
					 * ?>
					 */
					$skip_default = apply_filters( "um_query_args_{$field}__filter_meta", false, $this, $field, $value, $filter_type, $is_default );

					if ( ! $skip_default ) {

						switch ( $filter_type ) {
							default:

								do_action( "um_query_args_{$field}_{$filter_type}__filter_meta", $field, $value, $filter_type, $i, $is_default );
								break;

							case 'text':

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";

								$value = trim( stripslashes( $value ) );

								$this->where_clauses[] = $wpdb->prepare( "umm{$i}.um_key = %s AND umm{$i}.um_value = %s", $field, $value );

								if ( ! $is_default ) {
									$this->custom_filters_in_query[ $field ] = $value;
								}

								break;

							case 'select':
								if ( ! is_array( $value ) ) {
									$value = array( $value );
								}

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";

								$values_array = array();
								foreach ( $value as $single_val ) {
									$single_val = stripslashes( $single_val );

									$values_array[] = $wpdb->prepare( "umm{$i}.um_value LIKE %s", '%"' . trim( $single_val ) . '"%' );
									$values_array[] = $wpdb->prepare( "umm{$i}.um_value LIKE %s", '%' . serialize( strval( trim( $single_val ) ) ) . '%' );
									$values_array[] = $wpdb->prepare( "umm{$i}.um_value = %s", trim( $single_val ) );

									if ( is_numeric( $single_val ) ) {
										$values_array[] = $wpdb->prepare( "umm{$i}.um_value LIKE %s", '%' . serialize( intval( trim( $single_val ) ) ) . '%' );
									}
								}

								$values = implode( ' OR ', $values_array );

								$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND ( {$values} ) )", $field );

								if ( ! $is_default ) {
									$this->custom_filters_in_query[ $field ] = $value;
								}

								break;
							case 'slider':

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";

								$min = min( $value );
								$max = max( $value );

								$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND umm{$i}.um_value BETWEEN %d AND %d )", $field, $min, $max );

								if ( ! $is_default ) {
									$this->custom_filters_in_query[ $field ] = $value;
								}

								break;
							case 'datepicker':

								$offset = 0;
								if ( ! $is_default ) {
									if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
										$offset = (int) $_POST['gmt_offset'];
									}
								} else {
									$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
									if ( is_numeric( $gmt_offset ) ) {
										$offset = $gmt_offset;
									}
								}

								$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
								$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
								$from_date = date( 'Y/m/d', $from_date );
								$to_date = date( 'Y/m/d', $to_date );

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";

								$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND umm{$i}.um_value BETWEEN %s AND %s )", $field, $from_date, $to_date );

								if ( ! $is_default ) {
									$this->custom_filters_in_query[ $field ] = array( $from_date, $to_date );
								}

								break;
							case 'timepicker':

								$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";
								if ( $value[0] == $value[1] ) {
									$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND umm{$i}.um_value = %s )", $field, $value[0] );
								} else {
									$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = %s AND CAST( umm{$i}.um_value AS TIME ) BETWEEN %s AND %s )", $field, $value[0], $value[1] );
								}

								if ( ! $is_default ) {
									$this->custom_filters_in_query[ $field ] = $value;
								}

								break;
						}

					}

					break;
				case 'role':
					$value = array_map( 'strtolower', $value );

					if ( empty( $this->roles ) && ! is_multisite() ) {
						$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_roles ON ( umm_roles.user_id = u.ID AND umm_roles.um_key = '" . $wpdb->get_blog_prefix( $blog_id ) . "capabilities' )";
						$this->roles = $value;
					}

					$roles_clauses = array();
					foreach ( $value as $role ) {
						$roles_clauses[] = $wpdb->prepare( "umm_roles.um_value LIKE %s", '%"' . $role . '"%' );
					}

					$this->where_clauses[] = '( ' . implode( ' OR ', $roles_clauses ) . ' )';

					if ( ! $is_default ) {
						$this->custom_filters_in_query[ $field ] = $value;
					}

					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 ) ) );
					$to_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ) + 1, date( 'Y', time() - ( max( $value ) + 1 ) * YEAR_IN_SECONDS ) ) );

					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";

					$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = 'birth_date' AND umm{$i}.um_value BETWEEN %s AND %s )", $from_date, $to_date );

					if ( ! $is_default ) {
						$this->custom_filters_in_query[ $field ] = array( $to_date, $from_date );
					}

					break;
				case 'user_registered':

					$offset = 0;
					if ( ! $is_default ) {
						if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
							$offset = (int) $_POST['gmt_offset'];
						}
					} else {
						$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
						if ( is_numeric( $gmt_offset ) ) {
							$offset = $gmt_offset;
						}
					}

					$from_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', min( $value ) ) . "+$offset hours" ) );
					$to_date = date( 'Y-m-d H:s:i', strtotime( date( 'Y-m-d H:s:i', max( $value ) ) . "+$offset hours" ) );

					$this->where_clauses[] = $wpdb->prepare( "u.user_registered BETWEEN %s AND %s", $from_date, $to_date );

					if ( ! $is_default ) {
						$this->custom_filters_in_query[ $field ] = $value;
					}

					break;
				case 'last_login':

					$offset = 0;
					if ( ! $is_default ) {
						if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
							$offset = (int) $_POST['gmt_offset'];
						}
					} else {
						$gmt_offset = get_post_meta( $directory_data['form_id'], '_um_search_filters_gmt', true );
						if ( is_numeric( $gmt_offset ) ) {
							$offset = $gmt_offset;
						}
					}

					$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
					$to_date   = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59

					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm{$i} ON umm{$i}.user_id = u.ID";

					$this->where_clauses[] = $wpdb->prepare( "( umm{$i}.um_key = '_um_last_login' AND umm{$i}.um_value BETWEEN %s AND %s )", $from_date, $to_date );

					if ( ! $is_default ) {
						$this->custom_filters_in_query[ $field ] = $value;
					}

					break;
			}
		}


						$this->where_clauses[] = "u.ID IN ( '" . implode( "','", $users_array ) . "' )";
				if ( ! $this->general_meta_joined ) {
					$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
					$this->general_meta_joined = true;
				}
				$this->where_clauses[] = "( umm_general.um_key = 'um_member_directory_data' AND 
					if ( ! $this->general_meta_joined ) {
						$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
						$this->general_meta_joined = true;
					}
					$this->where_clauses[] = "( umm_general.um_key = 'um_member_directory_data'{$profile_photo_where}{$cover_photo_where} )";
			//$this->roles = array();
				$this->roles = array_merge( $this->roles, maybe_unserialize( $view_roles ) );
				if ( ! empty( $this->roles ) ) {
					$this->roles = array_intersect( $this->roles, maybe_unserialize( $directory_data['roles'] ) );
					$this->roles = array_merge( $this->roles, maybe_unserialize( $directory_data['roles'] ) );
			if ( ! empty( $this->roles ) ) {
				foreach ( $this->roles as $role ) {
					$roles_clauses[] = $wpdb->prepare( 'umm_roles.um_value LIKE %s', '%"' . $role . '"%' );
				$this->where_clauses[] = '( ' . implode( ' OR ', $roles_clauses ) . ' )';
					$this->where_clauses[] = "umm_roles.um_value IS NOT NULL";
				$search_line = trim( stripslashes( $_POST['search'] ) );

					$searches[] = $wpdb->prepare( "u.{$field} LIKE %s", '%' . $search_line . '%' );

				$this->where_clauses[] = $wpdb->prepare( "( umm_search.um_value = %s OR umm_search.um_value LIKE %s OR umm_search.um_value LIKE %s OR {$core_search})", $search_line, '%' . $search_line . '%', '%' . serialize( strval( $search_line ) ) . '%' );
					$this->handle_filter_query( $directory_data, $field, $value, $i );
						$this->handle_filter_query( $directory_data, $field, $value, $i, true );
			$this->sql_order = apply_filters( 'um_modify_sortby_parameter_meta', $this->sql_order, $sortby );
			$sql_join = implode( ' ', $this->joins );
			$sql_where = implode( ' AND ', $this->where_clauses );
			$sql_where = ! empty( $sql_where ) ? ' AND ' . $sql_where : '';


			/*var_dump( "SELECT SQL_CALC_FOUND_ROWS DISTINCT u.ID
				FROM {$wpdb->users} AS u
				{$sql_join}
				WHERE 1=1 {$sql_where}
				{$this->sql_order}
				{$this->sql_limit}" );*/

				WHERE 1=1 {$sql_where}
						'value'     => trim( stripslashes( $_POST['search'] ) ),
						'value'     => trim( stripslashes( $_POST['search'] ) ),
						'value'     => trim( serialize( strval( stripslashes( $_POST['search'] ) ) ) ),
				$meta_query = apply_filters( 'um_member_directory_general_search_meta_query', $meta_query, stripslashes( $_POST['search'] ) );
				$search = trim( stripslashes( $_POST['search'] ) );
		 * @param int $total_users
		function calculate_pagination( $directory_data, $total_users ) {
			$total_users = ( ! empty( $directory_data['max_users'] ) && $directory_data['max_users'] <= $total_users ) ? $directory_data['max_users'] : $total_users;
			$pagination_data = $this->calculate_pagination( $directory_data, $user_query->total_users );
	$search_from_url = ! empty( $_GET[ 'search_' . $unique_hash ] ) ? stripslashes( $_GET[ 'search_' . $unique_hash ] ) : '';