Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving [s2Member-List /] search functionality. Closes websharks/s2member#155, closes websharks/s2member#394 #68

Merged
merged 1 commit into from
Jan 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 64 additions & 71 deletions s2member-pro/includes/classes/member-list.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public static function query($args = array())
}
unset($_key, $_value); // Housekeeping.

if(strlen($args['search']) >= 2 && strpos($args['search'], '*') === FALSE && strpos($args['search'], '"') === FALSE)
$args['search'] = '*'.$args['search'].'*';

if(!$args['search_columns']) // Use defaults?
$args['search_columns'] = $default_args['search_columns'];

Expand All @@ -96,25 +99,76 @@ public static function query($args = array())
if($args['number'] < 1) $args['number'] = 1; // Make sure this is always >= 1.
$args['offset'] = ($page - 1) * $args['number']; // Calculate dynamically.

// Run search, returning only User IDs in the result.
$search_query = new WP_User_Query($args); // See: <https://codex.wordpress.org/Class_Reference/WP_User_Query>
$user_ids = $search_query->get_results();

// Also search s2Member Custom Fields, if necessary. Returns array of User IDs.
$search_query_s2custom = self::search_s2_custom_fields($args, $original_args);
$user_ids_query = new WP_User_Query($args);
$user_ids = $user_ids_query->get_results();
$user_ids_from_s2_custom_fields = self::search_s2_custom_fields($args, $original_args);

if(!empty($search_query_s2custom))
if(!empty($user_ids_from_s2_custom_fields))
{
$user_ids = array_merge($user_ids, $search_query_s2custom);
$user_ids = array_merge($user_ids, $user_ids_from_s2_custom_fields);
$user_ids = array_unique($user_ids);
}
$args['fields'] = 'all_with_meta';
// See: <https://codex.wordpress.org/Class_Reference/WP_User_Query>
if(!$user_ids) // The search is already known to be empty?
return array('query' => $user_ids_query, 'pagination' => self::paginate($page, 0, $args['number']));

$args['include'] = $user_ids;
$args['fields'] = 'all_with_meta';
unset($args['search'], $args['search_columns']);
$query = new WP_User_Query(array('fields' => 'all_with_meta', 'include' => $user_ids));

return array('query' => $query, 'pagination' => self::paginate($page, (integer)$query->get_total(), $args['number']));
}

/**
* Searches s2Member Custom Fields; an extension to the self::query() method.
*
* @param array $args Arguments passed to self::query() after self::query() merged the defaults.
* @param array $original_args Original arguments passed by the shortcode before self::query() merged the defaults.
*
* @return array An array of User IDs.
*/
protected static function search_s2_custom_fields($args, $original_args)
{
global $wpdb; // Global database object reference.
/** @var \wpdb $wpdb For IDEs that need a reference. */

if(empty($args['search']))
return array(); // Nothing to do.

if(!empty($original_args['search_columns']))
if(!preg_grep('/(?:^|\W)s2member_custom_field_\w+/', $args['search_columns']))
return array(); // Nothing to do.

$matching_custom_fields_regex_frag = '';
$include_user_ids = array();

if(empty($original_args['search_columns']))
$matching_custom_fields_regex_frag = '.*';

else if(($custom_field_columns = preg_grep('/(?:^|\W)s2member_custom_field_\w+/', $args['search_columns'])))
{
foreach($custom_field_columns as $_column)
if(preg_match('/(?:^|\W)s2member_custom_field_(?P<field_id>\w+)/', $_column, $_m))
$matching_custom_fields_regex_frag .= preg_quote(trim($_m['field_id'])).'|';
$matching_custom_fields_regex_frag = rtrim($matching_custom_fields_regex_frag, '|');
unset($_column, $_m); // Housekeeping.
}
if($matching_custom_fields_regex_frag)
{
$search_regex_frag = preg_quote($args['search']);
$search_regex_frag = str_replace('"', '', $search_regex_frag);
$search_regex_frag = str_replace('\\*', '[^"]*', $search_regex_frag);
$regex = '(^|\{)s\:[0-9]+\:"('.$matching_custom_fields_regex_frag.')";s\:[0-9]+\:"'.$search_regex_frag.'"'; // e.g. `a:1:{s:12:"country_code";s:3:"USA";}`.
$_users = $wpdb->get_results("SELECT `user_id` as `ID` FROM `".$wpdb->usermeta."` WHERE `meta_key` = '".$wpdb->prefix."s2member_custom_fields' AND `meta_value` REGEXP '".esc_sql($regex)."'");

if($_users && is_array($_users))
foreach($_users as $_user)
$include_user_ids[] = $_user->ID;
unset($_user); // Housekeeping.
}
return $include_user_ids;
}

/**
* Pagination handler.
*
Expand Down Expand Up @@ -176,66 +230,5 @@ protected static function paginate($current_page, $total_results, $per_page, $cu

return $pagination;
}

/**
* Searches s2Member Custom Fields; an extension to the self::query() method.
*
* @param array $args Arguments passed to self::query() after self::query() merged the defaults
* @param array $original_args Original arguments passed by the shortcode before self::query() merged the defaults
*
* @return array An array of User IDs
*/
protected static function search_s2_custom_fields($args, $original_args)
{
if(empty($args['search']))
return array(); // Nothing to do.

if(!empty($original_args['search_columns']) && !preg_grep('/(?:^|\W)s2member_custom_field_\w+/', $args['search_columns']))
return array(); // Nothing to do.

$s2custom_fields_sql = '';
$include_user_ids = array();

if(empty($original_args['search_columns']))
{
// Search all custom fields since there no search columns supplied
$s2custom_fields_sql = '.*';
}
elseif($s2custom_field_columns = preg_grep('/(?:^|\W)s2member_custom_field_\w+/', $args['search_columns']))
{
foreach($s2custom_field_columns as $_column)
{
// There are s2Member Custom Field columns to search. Let's extract the field ids
preg_match('/(?:^|\W)s2member_custom_field_(?P<field_id>\w+)/', $_column, $matches);

if(!empty($matches['field_id']))
{
// Build a pipe-limited string of field ids to use as part of the SQL REGEXP
$s2custom_fields_sql .= preg_quote(trim($matches['field_id'])).'|';
}
}
// Strip trailing pipe character
$s2custom_fields_sql = rtrim($s2custom_fields_sql, '|');
}
if(!empty($s2custom_fields_sql))
{
// Build the regex to find users who have s2Member Custom Fields that contain the search term (or any value if no search term is provided)
$regex = '(^|\{)s\:[0-9]+\:"('.$s2custom_fields_sql.')";s\:[0-9]+\:"'.preg_quote($args['search']).'"'; // Example database data: a:1:{s:12:"country_code";s:3:"USA";}

// Run the database search
global $wpdb;
/** @var \wpdb $wpdb This line for IDEs that need a reference. */
$_users = $wpdb->get_results("SELECT `user_id` as `ID` FROM `".$wpdb->usermeta."` WHERE `meta_key` = '".$wpdb->prefix."s2member_custom_fields' AND `meta_value` REGEXP '".esc_sql($regex)."'");

// Did we find any matches?
if(is_array($_users) && count($_users) > 0)
{
// Build an array of User IDs to be included in the search results
foreach($_users as $_user)
$include_user_ids[] = $_user->ID;
}
}
return !empty($include_user_ids) ? $include_user_ids : array();
}
}
}
8 changes: 4 additions & 4 deletions s2member-pro/includes/classes/sc-member-list-in.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static function shortcode($attr = array(), $content = '', $shortcode = ''
'show_display_name' => 'yes',
'link_display_name' => '', // /members/%%nicename%%/

'show_fields' => ''
'show_fields' => '',
);
if(!empty($attr['orderby']) && in_array($attr['orderby'], array('login', 'nicename', 'email', 'url', 'display_name'), TRUE))
$defaults['order'] = 'ASC'; // A more logical default when dealing with alphabetic ordering.
Expand Down Expand Up @@ -127,7 +127,7 @@ public static function shortcode($attr = array(), $content = '', $shortcode = ''
$args['meta_query'][] = array(
'key' => $wpdb->get_blog_prefix().'capabilities',
'value' => '"'.$_role.'"',
'compare' => 'LIKE'
'compare' => 'LIKE',
);
if($attr['rlc_satisfy'] === 'ANY') // Default is `ALL` (i.e. `AND`).
$args['meta_query']['relation'] = 'OR';
Expand All @@ -140,7 +140,7 @@ public static function shortcode($attr = array(), $content = '', $shortcode = ''
$args['meta_query'][] = array(
'key' => $wpdb->get_blog_prefix().'capabilities',
'value' => '"s2member_level'.$_level.'"',
'compare' => 'LIKE'
'compare' => 'LIKE',
);
if($attr['rlc_satisfy'] === 'ANY') // Default is `ALL` (i.e. `AND`).
$args['meta_query']['relation'] = 'OR';
Expand All @@ -153,7 +153,7 @@ public static function shortcode($attr = array(), $content = '', $shortcode = ''
$args['meta_query'][] = array(
'key' => $wpdb->get_blog_prefix().'capabilities',
'value' => '"access_s2member_ccap_'.$_ccap.'"',
'compare' => 'LIKE'
'compare' => 'LIKE',
);
if($attr['rlc_satisfy'] === 'ANY') // Default is `ALL` (i.e. `AND`).
$args['meta_query']['relation'] = 'OR';
Expand Down