Adding new 'Order By' on members loop
-
Hi
So I am trying to add a new ‘Order By’ on the members loop. I have found this in bp-blogs-classes.php and duplicated the ‘alphabetical’ one and renamed it ‘price’ which shows up on the members loop page. However I now need to edit the query so that it actually searches the correct xprofile field.
What I’m confused by is:
$order_sql = "ORDER BY bm_name.meta_value ASC";
What is:
bm_name.meta_value
Could I just replace this with some SQL to search the correct tables?
-
You don’t need to touch any core files to add an Order By.
Example for adding a Contributor option, put in bp-custom.php or theme/functions.php
// add order options to members loop function ch_member_order_options() { ?> <option value="contributing"><?php _e( 'Contributing Members', 'buddypress' ); ?></option> <?php } add_action( 'bp_members_directory_order_options', 'ch_member_order_options' ); // filter ajax members by contributing function ch_filter_ajax_querystring( $querystring = '', $object = '' ) { if( $object != 'members' ) return $querystring; $defaults = array( 'type' => 'active', 'action' => 'active', 'scope' => 'all', 'page' => 1, 'user_id' => 0, 'search_terms' => '', 'exclude' => false, ); $ch_querystring = wp_parse_args( $querystring, $defaults ); if( $ch_querystring['type'] == 'contributing' ) { // to get members by xprofile field, you need some custom sql here // here's an example: //https://codex.buddypress.org/developer/loops-reference/the-members-loop/#code-examples $users = get_users( array( 'fields' => array( 'ID' ), 'role' => 'contributor' ) ); $users_str = ''; foreach ( $users as $user ) { $users_str .= $user->ID . ','; } $users_str = rtrim($users_str, ","); $ch_querystring['include'] = $users_str; $ch_querystring['type'] = 'alphabetical'; return $ch_querystring; } else return $querystring; } add_filter( 'bp_ajax_querystring', 'ch_filter_ajax_querystring', 20, 2 );
@shanebp I thought I shouldn’t be modifying core files, but wasn’t sure how else to do it. I’ll give the above a go and see how it works.
@shanebp Thank you so much for your help. I got that working. I managed to query based on the new buddypress member types and also an xprofile field which is great.
One weird issue, I can’t see to order them accurately by the xprofile field (which is price). No matter whether I make SQL ORDER BY ASC or DESC the results always appear in the same order in the members loop. The SQL is definitely returning the results in the correct order as I have done a var_dump and checked.
Could it be something to do with
$ch_querystring['type'] = 'price';
I have changed this to a different ‘type’ and it does change the results, but not to display them in the order I want.
Note that right before the return, I switch to
$ch_querystring['type'] = 'alphabetical';
There is no['type'] = 'price';
in the class.Not sure about this, but instead of
$ch_querystring['include'] = $users_str;
Try
$ch_querystring['user_ids'] = $users_str;
@shanebp I tried
$ch_querystring['user_ids'] = $users_str;
but I think that only works for bp_user_query();. I saw the example before about how to sort by last name by @danbp and I think I should be able to modify this, but I can’t seem to get it to work:public function alphabetize_by_last_name( $bp_user_query ) { if ( 'alphabetical' == $bp_user_query->query_vars['type'] ) $bp_user_query->uid_clauses['orderby'] = "ORDER BY substring_index(u.display_name, ' ', -1)"; } add_action ( 'bp_pre_user_query', 'alphabetize_by_last_name' );
Also, another weird thing is when I change ‘Order By’ to ‘Price’, all of the results show up, but they ignore what is in the search box. I added some code to take the search parameter in the URL and if you reload the page with the search parameter and ‘Price’ as ‘Order By’ then it filters the results as expected, both with ‘Order By’ and with the search term.
If you then change the ‘Order By’ to another option such as ‘Alphabetical’ and then back to ‘Price’, then the AJAX results don’t take into account the search terms. Not sure if I’ve just made a stupid mistake.
function ch_member_order_options() { ?> <option value="price"><?php _e( 'Price', 'buddypress' ); ?></option> <?php } add_action( 'bp_members_directory_order_options', 'ch_member_order_options' ); // filter ajax members by contributing function ch_filter_ajax_querystring( $querystring = '', $object = '' ) { if( $object != 'members' ) return $querystring; $defaults = array( 'type' => 'active', 'action' => 'active', 'scope' => 'all', 'page' => 1, 'user_id' => 0, 'search_terms' => '', 'exclude' => false, ); $ch_querystring = wp_parse_args( $querystring, $defaults ); if( $ch_querystring['type'] == 'price' ) { $path = $_SERVER['DOCUMENT_ROOT']; $path .= "/wp-load.php"; require_once($path); global $wpdb; $field_id = 5; $user_query = $wpdb->get_col("SELECT object_id FROM " . $wpdb->prefix . "term_relationships WHERE term_taxonomy_id = " . $field_id); $users_str = ''; foreach ( $user_query as $user ) { $users_str .= $user . ','; } $users_str = rtrim($users_str, ","); $user_ord = $wpdb->get_col("SELECT user_id FROM " . $wpdb->prefix . "bp_xprofile_data WHERE user_id in (" . $users_str . ") AND field_id=18 ORDER BY value ASC"); $user_ordf = ''; foreach ($user_ord as $user_o) { $user_ordf .= $user_o . ','; } $user_ordf = rtrim($user_ordf,","); $ch_querystring['include'] = $user_ordf; $ch_querystring['type'] = 'alphabetical'; $search_terms = $_GET['s']; if(!empty($search_terms)) { $ch_querystring['search_terms'] = $search_terms; } //var_dump($ch_querystring); return $ch_querystring; } else return $querystring; } add_filter( 'bp_ajax_querystring', 'ch_filter_ajax_querystring', 20, 2 );
@shanebp So I have sort of made progress. I found this post by @eberger3. He seemed to be trying to do something similar to me. With his code I have now managed to order the results by price, which is great, but I am also experiencing the same issues he had:
- The pagination doesn’t work
- The member count shows ‘Viewing 1 member’ when there are many more
- The “search members” box doesn’t work. It returns the entire directory
Is this because I am using bp_user_query and not bp_ajax_querystring?
<?php function ch_member_order_options() { ?> <option value="price"><?php _e( 'Price', 'buddypress' ); ?></option> <?php } add_action( 'bp_members_directory_order_options', 'ch_member_order_options' ); add_action( 'bp_pre_user_query', 'sort_by_price' ); function sort_by_price( $bp_user_query ) { // Only run this if one of our custom options is selected if ( in_array( $bp_user_query->query_vars['type'], array( 'price') ) ) { global $wpdb; $field_id = 5; $user_query = $wpdb->get_col("SELECT object_id FROM " . $wpdb->prefix . "term_relationships WHERE term_taxonomy_id = " . $field_id); $users_str = ''; foreach ( $user_query as $user ) { $users_str .= $user . ','; } $users_str = rtrim($users_str, ","); // Adjust SELECT $bp_user_query->uid_clauses['select'] = "SELECT user_id FROM " . $wpdb->prefix . "bp_xprofile_data"; // Adjust WHERE $bp_user_query->uid_clauses['where'] = "WHERE user_id in (" . $users_str . ") AND field_id=18"; // Adjust ORDER BY $bp_user_query->uid_clauses['orderby'] = "ORDER BY CAST(value as UNSIGNED) ASC"; $bp_user_query->uid_clauses['per_page'] = 10; } } ?>
Edit: I can see this thread is in Installation category. This was a mistake. I should have but it into ‘How To’ or ‘Creating and Extending’ I can’t change this though.
This works for me. It’s basically just a cleaner version of what eberger3 did.
You’ll have to hack the ‘where’ clauses if you want to include search terms.function add_sortby_price() { ?> <option value="price">Price</option> <?php } add_action( 'bp_members_directory_order_options', 'add_sortby_price' ); function users_sortby_price( $object ) { global $wpdb, $bp; // Only run this if price option is selected if ( ! in_array( $object->query_vars['type'], array( 'price' ) ) ) return; $field_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s", $object->query_vars['type'] ) ); $object->uid_name = 'user_id'; $object->uid_table = $bp->profile->table_name_data; $object->uid_clauses['select'] = "SELECT u.{$object->uid_name} as id FROM {$object->uid_table} u"; $object->uid_clauses['where'] = " WHERE " . $wpdb->prepare( "u.field_id = %d", $field_id ); $object->uid_clauses['orderby'] = "ORDER BY u.value"; $object->uid_clauses['order'] = "ASC"; } add_action( 'bp_pre_user_query', 'users_sortby_price' );
@shanebp – That is cleaner and works, but pagination still doesn’t. Is it not possible to pass in the BP_User_Query parameters such as per_page in this format:
$object->query_vars['per_page'] = 10;
Tried this, but it seems to not work.
Do I need to use bp_pre_user_query_construct instead? I’m guessing I need to create a new function passing in these parameters?
Edit: I created a new function passing in this parameter:
$query->query_vars['per_page'] = 10;
I then add a new action for bp_pre_user_query_construct. This does indeed limit the first page’s results to 10; however it doesn’t display pagination to go to page 2 and it shows “1 – 11 of 11 Members” instead of “1 – 10 of 11 Members”.
The
per_page
sql is actually in$object->uid_clauses['limit']
as you can see by studying the BP_User_Query class.To get pagination to work, you need to filter on
bp_ajax_querystring
There is probably an easier way to do this, but this works for me: gist
Note that
per_page
is hardcoded to 2, in two places.@shanebp – Thank you this works really well. Weird, bug though. If you use the text search box, this breaks the pagination (without me editing any of your code). I’m guessing it has something to do with the URL parameters?
?s=examplesearch&members_search_submit=Search
This doesn’t break the pagination on the first page, but on page 2 and then when clicking back to page 1. The label displaying the number of members etc. is wrong and also the number of results per page is then wrong as it displays all results.
Interestingly, is it not possible to pass additional parameters either via members-loop.php? e.g.
if ( bp_has_members( bp_ajax_querystring( 'members' ).'member_type=expert' ) ) :
or via your code in bp-custom.php? I’m thinking I’m getting something mixed up when trying to add these additional parameters. It’s because I wanted to make use of the new ‘member_type’ in the latest version of BuddyPress but using a ‘member_type=exampletype’ doesn’t seem to work.
Hi @shanebp – I was wondering if you knew why the pagination doesn’t work when there is a URL parameter in the URL?
Also, am I missing something obvious why this wouldn’t be working with the XProfile Search plugin?
Is there an easy way to REMOVE ‘Order By’ options?
Do either of you know how I would add this to a member loop on a group page?
@joshklekamp – Add the code to bp-custom.php; however the code is slightly buggy so you would need to test it. If you can figure out why the pagination doesn’t work if there are URL parameters then please do let me know.
To be honest, if someone could point out how to create a completely new ‘Order By’ option from scratch how they are in the core files then I’d probably go down that route, but I’m not sure how to do that without actually editing the core files. Is there anyway I can hook into that part of the code?
I could then pretty much just copy one of the ‘Order By’ options that currently exists and then just edit the SQL to order by the XProfile field that I want.
codex is your friend ! Read here if it helps you.
@danbp – Thanks for this. I think I’d seen that before. I can create the new option for ‘Order By’, my issue is actually making it work properly. In that article, I’m not really understanding how I can create a simple ‘Order By’ for a numerical XProfile field.
I used @shanebp code above and it works with pagination unless there is a URL parameter, after which it breaks when navigating from page 2 to any other page. It doesn’t work with a search query ‘s=’ or with BP Profile Search. I think there is something I’m not getting.
The code on the page you provided seems a lot longer than the code shanebp provided above. I think this is really confusing me!
@danbp – I’m guessing this is the function I need order_by_most_favorited() to edit to work with XProfile fields?
I’ll try it now and see if it works with XProfile fields.
@danbp – Sorry to have so many questions. The example in the link you provided is for the activity loop, but I am trying to get this working for the members loop. Will it still work the same or do I have to take a completely different approach to this?
I guess you have to read again the doc i linked.
See after the Ninja warrior trick, The very last step is to finally display the favorite count into the entry template of the Activity component[…]
- The topic ‘Adding new 'Order By' on members loop’ is closed to new replies.