Group Meta Queries: Usage Example
Since version 1.8, it is possible to filter groups by Metadata. For instance you can add a meta_query parameter to the bp_has_groups() function. To make this possible, BuddyPress uses a built-in WordPress class : WP_Meta_Query (you will find a link to its WordPress codex page at the bottom of this article).
This feature can help plugin developers to extend the way groups are filtered, or query groups to search for a particular group meta your plugin is using. For example, if a plugin is adding a groupmeta to groups when its group component is activated, it can use a group meta query to list all the groups that activated their component.
To illustrate an usage example, you can test the following tutorial. Its goal is to add a new option to the select boxes (Order by filters) that are available on the Groups directory page and on the member’s profile group page. This option will list the groups that the community Administrator featured. This is your roadmap:
Steps
- Create a new meta box in the Edit Group Administration screen
- Filter bp_ajax_querystring to eventually extend the groups query
- Pause: the meta_query parameter in details
- Add your new option to select boxes
- Additional resources
Create a new meta box in the Edit Group Administration screen
For the purpose of this example, you will need to first create the Administration part to let the community Administrator feature the groups of his choice from the Group Administration screen. To do so, from the functions.php
of your active theme, you can add these first lines.
//it's important to check if the Groups component is active if( bp_is_active( 'groups' ) ) : /** * This is a quick and dirty class to illustrate "bpgmq" * bpgmq stands for BuddyPress Group Meta Query... * The goal is to store a groupmeta in order to let the community administrator * feature a group. * Featured groups will be filterable from the groups directory thanks to a new option * and to a filter applied on bp_ajax_query_string() * * This class is an example, it would be much better to use the group extension API */ class bpgmq_feature_group { public function __construct() { $this->setup_hooks(); } private function setup_hooks() { // in Group Administration screen, you add a new metabox to display a checkbox to featured the displayed group add_action( 'bp_groups_admin_meta_boxes', array( $this, 'admin_ui_edit_featured' ) ); // Once the group is saved you store a groupmeta in db, the one you will search for in your group meta query add_action( 'bp_group_admin_edit_after', array( $this, 'admin_ui_save_featured'), 10, 1 ); } /** * registers a new metabox in Edit Group Administration screen, edit group panel */ public function admin_ui_edit_featured() { add_meta_box( 'bpgmq_feature_group_mb', __( 'Featured Group' ), array( &$this, 'admin_ui_metabox_featured'), get_current_screen()->id, 'side', 'core' ); } /** * Displays the meta box */ public function admin_ui_metabox_featured( $item = false ) { if( empty( $item ) ) return; // Using groups_get_groupmeta to check if the group is featured $is_featured = groups_get_groupmeta( $item->id, '_bpgmq_featured_group' ); ?> <p> <input type="checkbox" id="bpgmq-featured-cb" name="bpgmq-featured-cb" value="1" <?php checked( 1, $is_featured );?>> <?php _e( 'Mark this group as featured' );?> </p> <?php wp_nonce_field( 'bpgmq_featured_save_' . $item->id, 'bpgmq_featured_admin' ); } function admin_ui_save_featured( $group_id = 0 ) { if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) || empty( $group_id ) ) return false; check_admin_referer( 'bpgmq_featured_save_' . $group_id, 'bpgmq_featured_admin' ); // You need to check if the group was featured so that you can eventually delete the group meta $was_featured = groups_get_groupmeta( $group_id, '_bpgmq_featured_group' ); $to_feature = !empty( $_POST['bpgmq-featured-cb'] ) ? true : false; if( !empty( $to_feature ) && empty( $was_featured ) ) groups_update_groupmeta( $group_id, '_bpgmq_featured_group', 1 ); if( empty( $to_feature ) && !empty( $was_featured ) ) groups_delete_groupmeta( $group_id, '_bpgmq_featured_group' ); } } /** * Let's launch ! * * Using bp_is_active() in this case is not needed * But i think it's a good practice to use this kind of check * just in case :) */ function bpgmq_feature_group() { if( bp_is_active( 'groups') ) return new BPGMQ_Feature_Group(); } add_action( 'bp_init', 'bpgmq_feature_group' );
Once done, if you go in the Groups Administration screen and choose to edit a particular group, you should see a new meta box on the right as shown on this screen capture :
What have you just achieved ?
You’ve created a class that will add a groupmeta named “_bpgmq_featured_group” (line 67 of the above code) if the community Administrator activated the checkbox. Now you can use this groupmeta in order to only display/get the featured groups.
Filter bp_ajax_querystring to eventually extend the groups query
In order to do this, you need to add a new hook in your setup_hooks() function (line 18 of the above code). Add this code under line 22:
/* The groups loop uses bp_ajax_querystring( 'groups' ) to filter the groups depending on the selected option */ add_filter( 'bp_ajax_querystring', array( $this, 'filter_ajax_querystring' ), 20, 2 );
As explained in the comments, this will filter the bp_ajax_querystring() function so that you can extend it to include your meta_query. Note that “20” tells WordPress to run this filter at a greater priority than the default one (10). Doing so, you make sure BuddyPress first applies the needed filters before yours. “2” tells WordPress your filter waits for 2 arguments. Now, you need to actually create the filter_ajax_querystring() function in your class without forgetting to return a value as a WordPress filter requires one. So after the admin_ui_save_featured() function, but before the end of your class, add these lines:
public function filter_ajax_querystring( $querystring = '', $object = '' ) { /* bp_ajax_querystring is also used by other components, so you need to check the object is groups, else simply return the querystring and stop the process */ if( $object != 'groups' ) return $querystring; // Let's rebuild the querystring as an array to ease the job $defaults = array( 'type' => 'active', 'action' => 'active', 'scope' => 'all', 'page' => 1, 'user_id' => 0, 'search_terms' => '', 'exclude' => false, ); $bpgmq_querystring = wp_parse_args( $querystring, $defaults ); /* if your featured option has not been requested simply return the querystring to stop the process */ if( $bpgmq_querystring['type'] != 'featured' ) return $querystring; /* this is your meta_query */ $bpgmq_querystring['meta_query'] = array( array( 'key' => '_bpgmq_featured_group', 'value' => 1, 'type' => 'numeric', 'compare' => '=' ) ); // using a filter will help other plugins to eventually extend this feature return apply_filters( 'bpgmq_filter_ajax_querystring', $bpgmq_querystring, $querystring ); }
What have you just achieved ?
Each time BuddyPress uses the function bp_ajax_querystring() to filter its components, your filter_ajax_querystring() function will be run. As you are targeting the groups loop, the first thing you need to do is to stop the process and return the original ajax query string if the you are not in a groups loop. Hopefully, line 5 of the above code is doing so! If you actually are in a groups loop, then you need to parse the query string in order to build an array that will be easier to manipulate (see line 8 to 19). You will be able to check for the “type” argument to make sure the selected option is “featured”. If not, you need to stop the process and return the original query string (see line 24 to 25). The user requested the “featured” groups, it is time you build the object of this tutorial : the Group meta query (see line 27 to 35). Finally, it is a good practice to eventually let other plugins extend your code, that’s why i encourage you to use the apply_filters() function and to include your value and the original one in arguments (line 38).
Pause: the meta_query parameter in details
Your meta_query is a multidimensional array. Each array has a goal. In your case you only need one array as you want to query the group by one Metadata (groupmeta). But if you need to do so on more than one Metadata, then you need a first array to tell BuddyPress what will be the relation to apply. Should the query be filtered by first AND second groupmeta or by first OR second groupmeta. Then as you have a second groupmeta, you need to build a third array to configure the second one. And so on, if you have more than 2 Metadatas to filter the groups with. Your meta_query parameter could have looked this way :
$bpgmq_querystring['meta_query'] = array( array( 'relation' => 'OR', // Optional, defaults to "AND" ), array( 'key' => '_bpgmq_featured_group', 'value' => 1, 'type' => 'numeric', 'compare' => '=' ), array( 'key' => '_second_groupmeta', 'value' => 'group', 'compare' => 'LIKE' ) );
Add your new option to select boxes
Back to your “featured” functionality. Your last touch will be to add a featured option to the select box (Order by) of the Groups directory page and the one of the member’s profile group page. If you omit the second one, then you would create a confusion for the user. As BuddyPress is using cookies to remember the way the group was last filtered, if the filter was “featured” in Groups directory, then in member’s profile group page the groups will be filtered this way too, but the wrong value would be set in the select box as no correspondence would have been found. So it’s important, you add your option in the two areas. First you need to add these lines in the setup_hooks() function of your class:
/* finally you create your options in the different select boxes */ // you need to do it for the Groups directory add_action( 'bp_groups_directory_order_options', array( $this, 'featured_option' ) ); // and for the groups tab of the user's profile add_action( 'bp_member_group_order_options', array( $this, 'featured_option' ) );
Finally, do not forget to add the featured_option() function to your class. So before the end of it insert these lines:
public function featured_option() { ?> <option value="featured"><?php _e( 'Featured' ); ?></option> <?php }
Once done, if you go in the Groups directory or in the member’s profile groups page, you should see a new option in the “Order by” select boxes as shown on this screen capture :
What have you just achieved ?
I think you almost built a plugin 😉 It might be a good idea to improve this code by using the BP_Group_Extension API.
Additional resources
- You can learn more about WP_Meta_Query and its arguments from the WordPress Codex
- You can learn more about BP_Group_Extension from its Codex page
- You can find the complete class in this gist