Skip to:
Content
Pages
Categories
Search
Top
Bottom

Filter activities by friends and groups


  • richtelford
    Participant

    @richtelford

    I’m running the latest versions of BP and WP. On the main activities page (for logged in user) I have a requirement to show activities by the user, the user’s friends and also activities from groups the user is a member of.

    I can do the first bit to get activities from user and friends:

    
    <?php
    $user_ids = wfw_bp_get_user_and_friends_id();
    $actions = 'activity_update,rtmedia_update,new_blog_post,joined_group,created_group';
    $args = array(
    	bp_ajax_querystring( 'activity' ),
    	'user_id' => $user_ids,
    	'action' => $actions
    );
    
    <?php if ( bp_has_activities( $args ) ) : ?>
    

    I can also get activities from groups that the user is a member of but I can’t do both at the same time. How can I modify this to get both activities of the user and friends but also groups the user is a member of?

    Additionally, I would also like to extend this further to get the above and also activities from groups that have a certain group meta value regardless of membership. E.g. show activities from groups where meta value = “swimming”. I can do this but not at the same time as getting activities from friends.

    I’m happy to code and more than competent with PHP just looking for some advice as I’m relatively new to BuddyPress (3 weeks). I had considered running an additional bp_has_activites() and merging the results with the initial query. Or is it possible to chain filters together (that would be cool).

    Many thanks.

Viewing 10 replies - 1 through 10 (of 10 total)

  • danbp
    Moderator

    @danbp

    Take a look to component class file, you will find anything related to how components and their filter are built. All component have such a file.

    Is it possible to chain filters ? I don’t think so, or under condition to write a very complex query. And activities are ajaxified !

    In bp-activities-class.php:307 you’ll find 'meta_query' => false, // Filter by activitymeta, so i presume, you know what you can do with this argument. 😉

    See also bp_parse_args, who let you filter the activity loop very easily.


    richtelford
    Participant

    @richtelford

    Hi @danbp. Okay so essentially what you are saying is I need to write a complex custom query?

    I’ve been examining the Buddypress class and function files in detail over the last few weeks due to the lack of documentation for BuddyPress – not a criticism btw. Yep I’m familiar with meta_query and using that already to get groups by meta_value. I wrote a function for returning activity IDs based on group meta:

    function wfw_get_group_activities_by_sport($sports = array())
    {
    	global $bp,$wpdb;
    
    	if(!$sports)
    		return false;
    
    	// GET GROUP IDS WHICH HAVE CHOSEN SPORT SELECTED
    	foreach($sports as $sport)
    	{
    		$meta_query[] = array(
    			"key" => "group_sport",
    			"value" => $sport,
    			"compare" => 'LIKE'
    		);
    	}
    
    	if(count($meta_query) > 1)
    		$meta_query = array_merge(array('relation' => 'OR'), $meta_query);
    
    	$group_arr = BP_Groups_Group::get(array(
    		'per_page'=>-1,
    		'meta_query' => $meta_query
    	));	
    
    	if(!$group_arr['total'] || !$group_arr['groups'])
    		return false;
    
    	foreach($group_arr['groups'] as $group)
    	{
    		$group_id_array[] = $group->;id;
    	}
    
    	$item_id = implode(",", $group_id_array);
    
    	$sql = "SELECT id FROM {$bp->activity->table_name} WHERE component = 'groups' AND item_id IN ({$item_id})";
    	$activity_id_array = $wpdb->get_col( $sql);	
    	
    	if(!$activity_id_array)
    		return false;
    
    	$activity_id = implode(',', $activity_id_array);
    
    	return $activity_id;
    }

    which I can then use to filter results:

    $activity_id = wfw_get_group_activities_by_sport(array($_GET['sport']));
    
    $filter = '&in='.$activity_id.'&object=groups';
    				
    if ($activity_id && bp_has_activities( bp_ajax_querystring( 'activity' ).$filter ) ) :  ?>

    Now I just need to somehow combine what I’m using but it sounds like a complex query is the way to go. I was looking for a more elegant solution using BP functions to achieve this but I guess it’s not yet possible.

    Anybody else have experience in this?

    Thanks.


    danbp
    Moderator

    @danbp

    Please use ` to surround code, not ‘ or use the code button.


    richtelford
    Participant

    @richtelford

    I think I might have to run a couple of queries to get the list of activity IDs I need and then feed that in to bp_has_activities() using “include” or “in” parameters so I don’t need to mess too much with the templating.

    The problem is that over time the comma-separated list of activity IDs is going to get enormous. I don’t like the sound of that.


    richtelford
    Participant

    @richtelford

    I’ll have a go with a complex query now and let you know how it goes. Still open to other suggestions as well…


    richtelford
    Participant

    @richtelford

    After researching a bit further I think I could easily achieve what I’d like if only this function (in bp-activity-classes.php line 1186):

    
    /**
    	 * Create filter SQL clauses.
    	 *
    	 * @since BuddyPress (1.5.0)
    	 *
    	 * @param array $filter_array {
    	 *     Fields and values to filter by.
    	 *     @type array|string|id $user_id User ID(s).
    	 *     @type array|string $object Corresponds to the 'component'
    	 *           column in the database.
    	 *     @type array|string $action Corresponds to the 'type' column
    	 *           in the database.
    	 *     @type array|string|int $primary_id Corresponds to the 'item_id'
    	 *           column in the database.
    	 *     @type array|string|int $secondary_id Corresponds to the
    	 *           'secondary_item_id' column in the database.
    	 *     @type int $offset Return only those items with an ID greater
    	 *           than the offset value.
    	 *     @type string $since Return only those items that have a
    	 *           date_recorded value greater than a given MySQL-formatted
    	 *           date.
    	 * }
    	 * @return string The filter clause, for use in a SQL query.
    	 */
    	public static function get_filter_sql( $filter_array ) {
    
    		$filter_sql = array();
    
    		if ( !empty( $filter_array['user_id'] ) ) {
    			$user_sql = BP_Activity_Activity::get_in_operator_sql( 'a.user_id', $filter_array['user_id'] );
    			if ( !empty( $user_sql ) )
    				$filter_sql[] = $user_sql;
    		}
    
    		if ( !empty( $filter_array['object'] ) ) {
    			$object_sql = BP_Activity_Activity::get_in_operator_sql( 'a.component', $filter_array['object'] );
    			if ( !empty( $object_sql ) )
    				$filter_sql[] = $object_sql;
    		}
    
    		if ( !empty( $filter_array['action'] ) ) {
    			$action_sql = BP_Activity_Activity::get_in_operator_sql( 'a.type', $filter_array['action'] );
    			if ( ! empty( $action_sql ) )
    				$filter_sql[] = $action_sql;
    		}
    
    		if ( !empty( $filter_array['primary_id'] ) ) {
    			$pid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.item_id', $filter_array['primary_id'] );
    			if ( !empty( $pid_sql ) )
    				$filter_sql[] = $pid_sql;
    		}
    
    		if ( !empty( $filter_array['secondary_id'] ) ) {
    			$sid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.secondary_item_id', $filter_array['secondary_id'] );
    			if ( !empty( $sid_sql ) )
    				$filter_sql[] = $sid_sql;
    		}
    
    		if ( ! empty( $filter_array['offset'] ) ) {
    			$sid_sql = absint( $filter_array['offset'] );
    			$filter_sql[] = "a.id >= {$sid_sql}";
    		}
    
    		if ( ! empty( $filter_array['since'] ) ) {
    			// Validate that this is a proper Y-m-d H:i:s date
    			// Trick: parse to UNIX date then translate back
    			$translated_date = date( 'Y-m-d H:i:s', strtotime( $filter_array['since'] ) );
    			if ( $translated_date === $filter_array['since'] ) {
    				$filter_sql[] = "a.date_recorded > '{$translated_date}'";
    			}
    		}
    
    		if ( empty( $filter_sql ) )
    			return false;
    
    		return join( ' AND ', $filter_sql );
    	}

    would allow filters to be combined with OR rather than AND. That way I could easily filter on a bunch of user_ids and group_ids which would get me the results I’m after. I might try extending the class and overriding that function. Watch this space!


    richtelford
    Participant

    @richtelford

    Separate issue but I think I’ve found a bug in the BP_Groups_Group::get() function when performing meta_query with OR relationship.

    Currently I have 4 groups to test with. Each group is assigned a meta_key => group_sport with values “running”, “swimming”, “mountain”, “winter” respectively. When I perform this:

    
    $meta_query = array(
    'relation' => 'OR',
    array(
    	"key" => "group_sport",
    	"value" => 'mountain',
    	"compare" => 'LIKE'
    ),
    array(
    	"key" => "group_sport",
    	"value" => 'running',
    	"compare" => 'LIKE'
    ));
    
    $group_arr = BP_Groups_Group::get(array(
    	'per_page'=>-1,
    	'meta_query' => $meta_query
    ));	
    

    it retrieves mountain and running but also incorrectly retrieves swimming and winter.

    On further investigation I noticed that table joins in BP_Groups_Group::get() and get_meta_query_sql() are done using commas rather than INNER JOIN, etc. I changed the functions to use INNER JOIN instead and it now works correctly. Can anyone else confirm this please? I’ll post on the Trac as well.


    richtelford
    Participant

    @richtelford

    I’ve managed to achieve what I wanted – fetching activities for the user, the user’s friends, groups that the user is a member of and groups which are tagged with the sports the user is interested in. I’ve added some custom filtering within BuddyPress core functions – I prefer to use filters and hooks but modifying core was my only option in this case.

    My bp_has_activities() request now looks like this:

    
    $args = array(
    	bp_ajax_querystring( 'activity' ),
    	'custom_filter' => array(
    		'relation' => 'OR',
    		array(
    			'user_id' => $user_ids,
    		),
    		array(
    			'group_id' => $group_ids
    		)
    	)
    );
    ?>
    
    <?php if ( bp_has_activities( $args ) ) : ?>
    

    I can share code with anyone interested in this.

    Also fixed a bug in the BP_Groups_Group::get() meta_query code which I’ve detailed above and is now on BP Trac here:

    https://buddypress.trac.wordpress.org/ticket/5874


    shanebp
    Moderator

    @shanebp

    from the ticket: ‘ I changed the functions to use INNER JOIN instead…’

    Please add a comment to the ticket showing the code after your changes.
    Or even better, submit a patch on the ticket. Create the patch against trunk.


    richtelford
    Participant

    @richtelford

    I’d like confirmation of the bug by a 3rd party before making a patch for it. Is this something you can check @shanebp?

Viewing 10 replies - 1 through 10 (of 10 total)
  • The topic ‘Filter activities by friends and groups’ is closed to new replies.
Skip to toolbar