Member Loop only MemberPress members
-
Hello,
I know there are quite a few topics already on excluding people from the Members Loop, but this one is a bit different.
I’m trying to exclude people who do not have MemberPress Memberships. I’ve seen several based on user role and extending the directory via a custom query (https://buddypress.org/support/topic/extend-bp_members-custom-query/), but nothing related to MemberPress. I’m really hoping I will not need to do as this custom query guy did it and ping my database for every member to see if a membership exists.Here is how I’m attempting to do it without luck (within members-loop.php which is located in wp-content/themes/THEME/buddypress/members):
<?php while ( bp_members() ) : bp_the_member(); ?> <?php if(user_can(bp_get_member_user_id(), 'mepr-active', 'memberships: 36, 37, 38, 189, 198, 325, 1141, 1142, 1143, 1127, 1130, 1138')): ?>
-
You can pass a string of ids to the
exclude
parameter ofbp_has_members
.How you gather the ids of the members you want to exclude is up to you.
Perhaps MemberPress has a function for getting all the user ids with a membership.
If so, then use theinclude
parameter instead.<?php // gather the ids of the members you want to exclude. // for example, say you end up with an array of user_ids: $exclude_these_users = array( 3, 7 ); $exclude_string = '&exclude=' . implode (", ", $exclude_these_users); ?> <?php if ( bp_has_members( bp_ajax_querystring( 'members' ) . $exclude_string ) ) : ?>
Hey @shanebp thank you so much for your fast response!
Unfortunately, MemberPress support didn’t know of a function that gets user IDs with specific memberships so they handed me this SQL query:
SELECT DISTINCT user_id FROM wp_mepr_transactions WHERE status IN('confirmed','complete') AND (expires_at >= NOW() OR expires_at = '0000-00-00 00:00:00') AND product_id = 123;
Where I would need to change my Product ID to match the Membership ID. I’m assuming I would just add this SQL query to your code bit:
<?php //get ids of members I want to include by grabbing members from db $memberPressMembers = $wpdb->get_results("SELECT DISTINCT user_id FROM wp_mepr_transactions WHERE status IN('confirmed','complete') AND (expires_at >= NOW() OR expires_at = '0000-00-00 00:00:00') AND product_id = MEMBERSHIPID"); $include_string = '&include=' . implode(", ", $memberPressMembers); ?> <?php if ( bp_has_members( bp_ajax_querystring( 'members' ) . $include_string ) ) : ?>
This would only call my database 1 time to grab all members who have those specific IDs.
Is that correct? Am I missing anything? When I attempted this I kept getting a 500 error on my admin_ajax.
Hello,
So I found that if I change my $memberPressMembers to:
$memberPressMembers = $wpdb->get_results("SELECT DISTINCT user_id FROM wp_mepr_transactions WHERE status IN('confirmed','complete') AND (expires_at >= NOW() OR expires_at = '0000-00-00 00:00:00') AND product_id = MEMBERSHIPID", ARRAY_N);
Then I actually can see my list of IDs when I do this:
echo '<script>console.log(' . json_encode($memberPressMembers, JSON_HEX_TAG) . ');</script>';
The only issue is, if I do this but add the $include_string to the bp_has_members line it displays no members.
I believe this is because ARRAY_N is placing all of my items into arrays. Looking at the console log I see that the arrays split at 100 records (0-99, 100-199, etc.).I’ve also tried then taking my memberPressMembers variable and adding each into an array ($include_these_users) like so:
foreach($memberPressMember as $member){ array_push($include_these_users, $member); }
with no luck.
Could you help me in forming my variable so it will work in the include_string?Thank you! I should probably note, I’m attempting all of this code within members-loop.php. I’m assuming this is still the correct spot to do this as the bp_has_members(bp_ajax_querystring(‘members’)) is part of the loop.
Try removing the
ARRAY_N
.Instead of
$wpdb->get_results
try$wpdb->get_col
which should return a one dimensional array of ids.https://codex.wordpress.org/Class_Reference/wpdb#SELECT_a_Column
Thank you so much! In case you couldn’t tell I’m not that familiar with accessing the database.
This completely worked, just in case anyone needs this for the future here is what I used:
<?php //get ids of members I want to include by grabbing members from db $memberPressMembers = $wpdb->get_col("SELECT DISTINCT user_id FROM wp_mepr_transactions WHERE status IN('confirmed','complete') AND (expires_at >= NOW() OR expires_at = '0000-00-00 00:00:00')"); $include_string = '&include=' . implode(", ", $memberPressMembers); //print out array of IDs to console to find how many people we are getting //echo '<script>console.log(' . json_encode($memberPressMembers, JSON_HEX_TAG) . ');</script>'; ?> <?php if ( bp_has_members( bp_ajax_querystring( 'members' ). $include_string ) ) : ?>
I didn’t actually need product id, because I want anyone who has an active membership to appear here, but be careful about a lot of “OR” statements as this could lead to grabbing people who also have a pending transaction as well (displaying people with pending but not complete transactions). If you want specific memberships I would probably add
AND product_id IN (MEMBERSHIPIDs)
Thanks again for all of your help @shanebp!
Please note the above solution won’t work if you have a custom table prefix (i.e. different than “wp_”).
I’ve put together this function using the bp_after_has_members_parse_args filter. Posting it here in case anyone needs it. So far it looks like it works fine./** * Only list active MemberPress members in the members directory. * sources: * https://buddydev.com/hiding-users-on-buddypress-based-site * https://buddypress.org/support/topic/member-loop-only-memberpress-members/ * @param array $args args. * * @return array */ function tmp_only_show_members_in_directory( $args ) { // do not exclude in admin. if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return $args; } global $wpdb; $member_ids = $wpdb->get_col("SELECT DISTINCT user_id FROM ".$wpdb->prefix."mepr_transactions WHERE status IN('confirmed','complete') AND (expires_at >= NOW() OR expires_at = '0000-00-00 00:00:00')"); $args['include'] = $member_ids; return $args; } add_filter( 'bp_after_has_members_parse_args', 'tmp_only_show_members_in_directory' );
Thank you for posting this. I’m planning to use it.
Could you possibly explain what the “do not exclude in admin” test is doing?Thanks so much!
-Mike
// do not exclude in admin. if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return $args; }
It means do NOT run the rest of the function if viewing a screen in wp-admin.
So ajax calls do not qualify for that condition.Also – in the query, you can avoid the use of dot notation:
$member_ids = $wpdb->get_col("SELECT DISTINCT user_id FROM {$wpdb->prefix}mepr_transactions
etcI’ve been testing this and found out that the code as is done in my previous post will break the members search feature from 3rd party plugins. So I modified this to use the “exclude” argument instead of the “include”.
Since doing this is going to be a heavy call on the server, I’ve decided to store my exclusion list in the DB as an option. I’m sure this could be done with transients so feel free to improve changing the storage of the array in a transient.
Note: shanebp mentioned this does not apply to ajax calls but it’s a filter to the members query so won’t it run whenever a call to the members is done no matter if it’s ajax or not if we exclude that piece of code?
Revised code follows. I tested this and it works fine for me.
/** * Only list active MemberPress members in the members directory. * sources: * https://buddydev.com/hiding-users-on-buddypress-based-site * https://buddypress.org/support/topic/member-loop-only-memberpress-members/ * @param array $args args. * * @return array */ function tmp_only_show_members_in_directory( $args ) { // do not exclude in admin. if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return $args; } $args['exclude'] = tmp_get_users_to_exclude_from_directory(); return $args; } add_filter( 'bp_after_has_members_parse_args', 'tmp_only_show_members_in_directory' ); /** * Returns an array of IDs to exclude, runs the queries if empty * @return false|mixed|void */ function tmp_get_users_to_exclude_from_directory() { $ids_to_exclude = get_option('tmp_update_members_to_exclude_from_directory'); if (empty($ids_to_exclude) || !is_array($ids_to_exclude) || count($ids_to_exclude) < 1) { tmp_update_members_to_exclude_from_directory(); } return get_option('tmp_update_members_to_exclude_from_directory'); } // Scheduled Action Hook function tmp_update_members_to_exclude_from_directory() { global $wpdb; $member_ids = $wpdb->get_col("SELECT DISTINCT user_id FROM ".$wpdb->prefix."mepr_transactions WHERE status IN('confirmed','complete') AND (expires_at >= NOW() OR expires_at = '0000-00-00 00:00:00')"); $user_ids = get_users(['fields'=>'ID']); $user_ids_to_exclude = array_diff($user_ids, $member_ids); return update_option('tmp_update_members_to_exclude_from_directory',$user_ids_to_exclude); } add_action( 'hook_name', 'tmp_update_members_to_exclude_from_directory' ); // Schedule Cron Job Event function tmp_update_members_to_exclude_from_directory_job() { if ( ! wp_next_scheduled( 'tmp_update_members_to_exclude_from_directory' ) ) { wp_schedule_event( current_time( 'timestamp' ), 'twicedaily', 'tmp_update_members_to_exclude_from_directory' ); } } add_action( 'wp', 'tmp_update_members_to_exclude_from_directory_job' );
For what it’s worth, I’ve *almost* gotten all this to work, but have one more slight problem with the profile. I actually just posted about it here:
But then I just remembered this thread, and I thought I would put this pointer in, just in case anyone else has the same issue.
- You must be logged in to reply to this topic.