Bits & Babble

A blog in development.

How to Add Custom Fields to s2Member User Search

December 9, 2014  

I recently setup a membership site for a client based on the s2Member® Pro plugin. The site required location data related to users to be searchable. This location data was outside of the standard user meta information searchable by WP_User_Query, which s2Member users for it’s search. So after going through the initial setup and configuration, I needed to figure out how to add custom fields to s2Member user search pages.

Please note that access to the user search functionality requires the Pro version of s2Member.

s2Member Search Template

The s2Member plugin has a couple of built-in shortcodes for searching and displaying your site’s user base. The shortcodes, s2Member-List and s2Member-List-Search-Box, have quite a few options built in. The former displays a list of users based on your criteria, while the latter displays a search form to allow a user to refine the search when linked to the search list.

To put additional fields on the search form those shortcodes use, you’ll need to customize the member-list-search-box.php template. Copy the template from the s2Member Pro plugin (s2member-pro/includes/templates/members/member-list-search-box.php) to your theme directory. I kept the filename in my theme the same for simplicity.

Add Custom Fields to s2Member User Search

In my case, I needed to be able to search within a given radius from a zip code. So I added a simple select box to the form. The template is setup to display the form within a table, so I just added a new row to the table with my select box.

1
2
3
4
5
6
7
8
9
10
11
12
13
<tr>
  <td>
    <?php $distance = $_REQUEST[ 'distance' ]; ?>
    <select name="distance">
      <option value="5" <?php if ( '5' == $distance ) { echo 'selected="selected"'; } ?>>5 miles</option>
      <option value="10" <?php if ( '10' == $distance ) { echo 'selected="selected"'; } ?>>10 miles</option>
      <option value="25" <?php if ( '25' == $distance ) { echo 'selected="selected"'; } ?>>25 miles</option>
      <option value="50" <?php if ( '50' == $distance ) { echo 'selected="selected"'; } ?>>50 miles</option>
      <option value="100" <?php if ( '100' == $distance ) { echo 'selected="selected"'; } ?>>100 miles</option>
      <option value="250" <?php if ( '250' == $distance ) { echo 'selected="selected"'; } ?>>250 miles</option>
    </select>
  </td>
</tr>

<tr> <td> <?php $distance = $_REQUEST[ 'distance' ]; ?> <select name="distance"> <option value="5" <?php if ( '5' == $distance ) { echo 'selected="selected"'; } ?>>5 miles</option> <option value="10" <?php if ( '10' == $distance ) { echo 'selected="selected"'; } ?>>10 miles</option> <option value="25" <?php if ( '25' == $distance ) { echo 'selected="selected"'; } ?>>25 miles</option> <option value="50" <?php if ( '50' == $distance ) { echo 'selected="selected"'; } ?>>50 miles</option> <option value="100" <?php if ( '100' == $distance ) { echo 'selected="selected"'; } ?>>100 miles</option> <option value="250" <?php if ( '250' == $distance ) { echo 'selected="selected"'; } ?>>250 miles</option> </select> </td> </tr>

There’s nothing fancy there. It’s just a few distance options and some checks to see what the previous selected distance was.

With the s2Member-List-Search-Box shortcode, we can now specify our custom template. It will look something like [s2Member-List-Search-Box action="" placeholder="Type your zip code..." template="themes/my-theme/member-list-search-box.php"].

Making It Work

Now the form looks useful, but it doesn’t yet do what we need it to do. As I mentioned earlier, the s2Member-List shortcode uses the WP_User_Query class to fetch the list of users, so we can use the pre_get_users hook to alter the query to fit our needs.

First, we need a way to let our pre_get_users hook to know we’re coming from the s2Member user search. To do so, we add a search_column option to the shortcode, like so [s2Member-List enable_list_search="yes" search_columns="my_custom_hook"]. We just need to look for our custom column name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
add_action( 'pre_get_users', 'my_pre_get_users' );
 
function my_pre_get_users( $query ) {
 
  if ( in_array( 'my_custom_hook', $query->query_vars[ 'search_columns' ] ) ) {
 
    $zip = $query->query_vars[ 'search' ];
    unset( $query->query_vars[ 'search' ] );
 
    $users = get_users_from_zip( $zip, $_REQUEST[ 'distance' ] );
 
    if ( empty( $users ) )
      $users = array( 0 ); // bit of a hack to ensure zero results
 
    $query->query_vars[ 'include' ] = $users;
 
  }
 
}

add_action( 'pre_get_users', 'my_pre_get_users' ); function my_pre_get_users( $query ) { if ( in_array( 'my_custom_hook', $query->query_vars[ 'search_columns' ] ) ) { $zip = $query->query_vars[ 'search' ]; unset( $query->query_vars[ 'search' ] ); $users = get_users_from_zip( $zip, $_REQUEST[ 'distance' ] ); if ( empty( $users ) ) $users = array( 0 ); // bit of a hack to ensure zero results $query->query_vars[ 'include' ] = $users; } }

There’s a bit of psuedo-code going on here, but first let’s get to the stuff we know for sure. After adding and defining our hook, we see an immediate conditional inside the hook function (line 5). What we’re doing is verifying the my_custom_hook from the s2Member-List shortcode. This ensures that we’re coming from the proper WP_User_Query search. It’s a bit of “magic string”, but we’re trying to work within the s2Member framework.

Next, we have this get_users_from_zip function. This is the psuedo-code where all of my geocoding logic that is beyond the scope of this post resides. What you need to know is that it’s essentially doing its own user search based upon the given parameters—finding all of the users within some distance of a zip code—and returning a list of user ids.

On line 11, I wanted to show you that in order to return an empty list of users from the WP_User_Query, we need to ensure the query can’t find anything, which we do by specifying a user id (0) that cannot exist.

Finally, we make sure the resulting query only gives us the users we already know we need, which we do by setting the include variable of the WP_User_Query.

What It All Means…

Because the s2Member plugin uses the WP_User_Query class for its search, and the user data we’re searching for is outside the capabilities of that class, we’re essentially doing two user searches. If we were building a user search page from scratch, we could avoid that annoyance. However, if you’re already using s2Member Pro, and depending on the nature of your search, it may be a worthwhile trade-off to add custom fields to s2Member user search pages.

No Comments

By SPENCER SOKOL
  • About
  • Twitter
  • Studio 27

Categories

  • Alloy
  • Android
  • Appcelerator Titanium
  • Babble
  • Debugging
  • Genesis
  • iOS
  • s2Member
  • Woocommerce
  • Wordpress

About Spencer Sokol

Spencer co-founded Studio 27, a small web and application design and development company in Indianapolis. He has spent many years in both the development and testing side of the software industry, and generally avoids talking to people face to face.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • About
  • Indianapolis Design & Development
Copyright © 2019 Spencer Sokol