/** * @ticket BP7237 * @ticket BP6643 * @ticket BP7245 */ public function test_last_activity_should_bust_activity_with_last_activity_cache() { global $wpdb; $u1 = $this->factory->user->create(); $u2 = $this->factory->user->create(); $time_1 = date('Y-m-d H:i:s', time() - HOUR_IN_SECONDS); $time_2 = date('Y-m-d H:i:s', time() - HOUR_IN_SECONDS * 2); bp_update_user_last_activity($u1, $time_1); bp_update_user_last_activity($u2, $time_2); $activity_args_a = array('filter' => array('object' => buddypress()->members->id, 'action' => 'last_activity'), 'max' => 1); $activity_args_b = array('filter' => array('action' => 'new_member'), 'fields' => 'ids'); // Prime bp_activity and bp_activity_with_last_activity caches. $a1 = bp_activity_get($activity_args_a); $expected = array($u1, $u2); $found = array_map('intval', wp_list_pluck($a1['activities'], 'user_id')); $this->assertSame($expected, $found); $b1 = bp_activity_get($activity_args_b); // Bump u2 activity so it should appear first. $new_time = date('Y-m-d H:i:s', time() - HOUR_IN_SECONDS); bp_update_user_last_activity($u2, $new_time); $a2 = bp_activity_get($activity_args_a); $expected = array($u2, $u1); $found = array_map('intval', wp_list_pluck($a2['activities'], 'user_id')); $this->assertSame($expected, $found); $num_queries = $wpdb->num_queries; // bp_activity cache should not have been touched. $b2 = bp_activity_get($activity_args_b); $this->assertEqualSets($b1, $b2); $this->assertSame($num_queries, $wpdb->num_queries); }
function bp_media_activity_parent_content_filter($activity_content) { global $activities_template; $defaults = array('hide_user' => false); if (!($parent_id = $activities_template->activity->item_id)) { return false; } if (!isset($bp_media_hidden_activity_cache[$parent_id])) { $activities = bp_activity_get(array('in' => $parent_id)); if (isset($activities['activities'][0])) { $bp_media_hidden_activity_cache[$parent_id] = $activities['activities'][0]; } } if (empty($bp_media_hidden_activity_cache[$parent_id])) { return false; } if (empty($bp_media_hidden_activity_cache[$parent_id]->content)) { $content = $bp_media_hidden_activity_cache[$parent_id]->action; } else { $content = $bp_media_hidden_activity_cache[$parent_id]->action . ' ' . $bp_media_hidden_activity_cache[$parent_id]->content; } // Remove the time since content for backwards compatibility $content = str_replace('<span class="time-since">%s</span>', '', $content); // Remove images $content = preg_replace('/<img[^>]*>/Ui', '', $content); return $content; return $activity_content; }
/** * @group bp_xprofile_updated_profile_activity */ public function test_bp_xprofile_updated_profile_activity_no_existing_activity() { $d = $this->setup_updated_profile_data(); // Fake new/old values to ensure a change $old_values = array($this->updated_profile_data['f'] => array('value' => 'foo', 'visibility' => 'public')); $new_values = array($this->updated_profile_data['f'] => array('value' => 'foo2', 'visibility' => 'public')); $this->assertTrue(bp_xprofile_updated_profile_activity($d['u'], array($d['f']), false, $old_values, $new_values)); $existing = bp_activity_get(array('max' => 1, 'filter' => array('user_id' => $d['u'], 'object' => buddypress()->profile->id, 'action' => 'updated_profile'), 'count_total' => 'count_query')); $this->assertEquals(1, $existing['total']); }
/** * @group bp_activity_clear_cache_for_activity */ public function test_bp_activity_clear_cache_for_activity() { $u = $this->factory->user->create(); $a = $this->factory->activity->create(array('component' => buddypress()->activity->id, 'type' => 'activity_update', 'user_id' => $u, 'content' => 'foo bar')); $a_fp = bp_activity_get(array('type' => 'activity_update', 'user' => array('filter' => array('user_id' => $u)))); $activity_updated = new BP_Activity_Activity($a); $activity_updated->content = 'bar foo'; $activity_updated->save(); $a_fp = bp_activity_get(array('type' => 'activity_update', 'user' => array('filter' => array('user_id' => $u)))); $this->assertSame('bar foo', $a_fp['activities'][0]->content); }
public function getResults($search) { $results = array(); if (!$this->isEnabled()) { return $results; } $results = bp_activity_get(array('filter' => array('action' => 'activity_update'), 'search_terms' => $search)); return array_map(function ($activity) use($search) { return new Expert_Finder_Activity_Stream_Result($activity, $this->options['A'], $search); }, $results['activities']); }
/** * Make sure doc activity is deleted when the doc is deleted */ function test_delete_activity_on_doc_deletion() { $doc_id = $this->factory->doc->create(); $activity_args = array('component' => 'docs', 'item_id' => 1, 'secondary_item_id' => $doc_id, 'type' => 'bp_doc_edited'); $activity_id = $this->factory->activity->create($activity_args); $activity_args2 = array('component' => 'docs', 'item_id' => 1, 'secondary_item_id' => $doc_id, 'type' => 'bp_doc_created'); $activity_id2 = $this->factory->activity->create($activity_args2); // Now delete using the api method bp_docs_trash_doc($doc_id); $activities = bp_activity_get(array('filter' => array('secondary_id' => $doc_id, 'component' => 'docs'))); $this->assertEquals($activities['activities'], array()); }
function bp_media_upgrade_to_2_2() { global $wpdb; remove_filter('bp_activity_get_user_join_filter', 'bp_media_activity_query_filter', 10); /* @var $wpdb wpdb */ $media_files = new WP_Query(array('post_type' => 'bp_media', 'posts_per_page' => -1)); $media_files = $media_files->posts; $wall_posts_album_ids = array(); if (is_array($media_files) && count($media_files)) { foreach ($media_files as $media_file) { $attachment_id = get_post_meta($media_file->ID, 'bp_media_child_attachment', true); $child_activity = get_post_meta($media_file->ID, 'bp_media_child_activity', true); update_post_meta($attachment_id, 'bp_media_child_activity', $child_activity); $attachment = get_post($attachment_id, ARRAY_A); if (isset($wall_posts_album_ids[$media_file->post_author])) { $wall_posts_id = $wall_posts_album_ids[$media_file->post_author]; } else { $wall_posts_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_title = 'Wall Posts' AND post_author = '" . $media_file->post_author . "' AND post_type='bp_media_album'"); if ($wall_posts_id == null) { $album = new BP_Media_Album(); $album->add_album('Wall Posts', $media_file->post_author); $wall_posts_id = $album->get_id(); } if (!$wall_posts_id) { continue; //This condition should never be encountered } $wall_posts_album_ids[$media_file->post_author] = $wall_posts_id; } $attachment['post_parent'] = $wall_posts_id; wp_update_post($attachment); update_post_meta($attachment_id, 'bp-media-key', $media_file->post_author); $activity = bp_activity_get(array('in' => intval($child_activity))); if (isset($activity['activities'][0]->id)) { $activity = $activity['activities'][0]; } $bp_media = new BP_Media_Host_Wordpress($attachment_id); $args = array('content' => $bp_media->get_media_activity_content(), 'id' => $child_activity, 'type' => 'media_upload', 'action' => apply_filters('bp_media_added_media', sprintf(__('%1$s added a %2$s', 'bp-media'), bp_core_get_userlink($media_file->post_author), '<a href="' . $bp_media->get_url() . '">' . $bp_media->get_media_activity_type() . '</a>')), 'primary_link' => $bp_media->get_url(), 'item_id' => $attachment_id, 'recorded_time' => $activity->date_recorded); $act_id = bp_media_record_activity($args); bp_activity_delete_meta($child_activity, 'bp_media_parent_post'); wp_delete_post($media_file->ID); } } update_option('bp_media_db_version', BP_MEDIA_DB_VERSION); add_action('admin_notices', 'bp_media_database_updated_notice'); wp_cache_flush(); }
function wangguard_bp_activity_spam_all_user_data($user_id = 0) { global $bp, $wpdb; // Do not delete user data unless a logged in user says so if (empty($user_id)) { return false; } // Get all the user's activities. $activities = bp_activity_get(array('display_comments' => 'stream', 'filter' => array('user_id' => $user_id), 'show_hidden' => true)); // Mark each as spam foreach ((array) $activities['activities'] as $activity) { // Create an activity object $activity_obj = new BP_Activity_Activity(); foreach ($activity as $k => $v) { $activity_obj->{$k} = $v; } // Mark as spam bp_activity_mark_as_spam($activity_obj); /* * If Akismet is present, update the activity history meta. * * This is usually taken care of when BP_Activity_Activity::save() happens, but * as we're going to be updating all the activity statuses directly, for efficency, * we need to update manually. */ if (!empty($bp->activity->akismet)) { $bp->activity->akismet->update_activity_spam_meta($activity_obj); } // Tidy up unset($activity_obj); } // Mark all of this user's activities as spam $wpdb->query($wpdb->prepare("UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id)); // Call an action for plugins to use do_action('bp_activity_spam_all_user_data', $user_id, $activities['activities']); }
/** * Posts an activity item on doc save * * @package BuddyPress Docs * @since 1.0-beta * * @param obj $query The query object created in BP_Docs_Query and passed to the * bp_docs_doc_saved filter * @return int $activity_id The id number of the activity created */ function post_activity($query) { global $bp; // todo: exception for autosave? if (!bp_is_active('activity')) { return false; } $doc_id = !empty($query->doc_id) ? $query->doc_id : false; if (!$doc_id) { return false; } $last_editor = get_post_meta($doc_id, 'bp_docs_last_editor', true); // Throttle 'doc edited' posts. By default, one per user per hour if (!$query->is_new_doc) { // Look for an existing activity item corresponding to this user editing // this doc $already_args = array('max' => 1, 'sort' => 'DESC', 'show_hidden' => 1, 'filter' => array('user_id' => $last_editor, 'action' => 'bp_doc_edited', 'secondary_id' => $doc_id)); $already_activity = bp_activity_get($already_args); // If any activity items are found, compare its date_recorded with time() to // see if it's within the allotted throttle time. If so, don't record the // activity item if (!empty($already_activity['activities'])) { $date_recorded = $already_activity['activities'][0]->date_recorded; $drunix = strtotime($date_recorded); if (time() - $drunix <= apply_filters('bp_docs_edit_activity_throttle_time', 60 * 60)) { return; } } } $doc = get_post($doc_id); // Set the action. Filterable so that other integration pieces can alter it $action = ''; $user_link = bp_core_get_userlink($last_editor); $doc_url = bp_docs_get_doc_link($doc_id); $doc_link = '<a href="' . $doc_url . '">' . $doc->post_title . '</a>'; if ($query->is_new_doc) { $action = sprintf(__('%1$s created the doc %2$s', 'bp-docs'), $user_link, $doc_link); } else { $action = sprintf(__('%1$s edited the doc %2$s', 'bp-docs'), $user_link, $doc_link); } $action = apply_filters('bp_docs_activity_action', $action, $user_link, $doc_link, $query->is_new_doc, $query); // Get a canonical name for the component. This is a nightmare because of the way // the current component and root slug relate in BP 1.3+ if (function_exists('bp_is_current_component')) { foreach ($bp->active_components as $comp => $value) { if (bp_is_current_component($comp)) { $component = $comp; break; } } } else { $component = bp_current_component(); } // This is only temporary! This item business needs to be component-neutral $item = isset($bp->groups->current_group->id) ? $bp->groups->current_group->id : false; // Set the type, to be used in activity filtering $type = $query->is_new_doc ? 'bp_doc_created' : 'bp_doc_edited'; $args = array('user_id' => $last_editor, 'action' => $action, 'primary_link' => $doc_url, 'component' => $component, 'type' => $type, 'item_id' => $query->item_id, 'secondary_item_id' => $doc_id, 'recorded_time' => bp_core_current_time(), 'hide_sitewide' => apply_filters('bp_docs_hide_sitewide', false, false, $doc, $item, $component)); do_action('bp_docs_before_activity_save', $args); $activity_id = bp_activity_add(apply_filters('bp_docs_activity_args', $args)); do_action('bp_docs_after_activity_save', $activity_id, $args); return $activity_id; }
protected function activity_exists_for_post_type($item_id, $secondary_item_id, $action, $display_comments = false) { $a = bp_activity_get(array('display_comments' => $display_comments, 'filter' => array('action' => $action, 'primary_id' => $item_id, 'secondary_id' => $secondary_item_id))); return !empty($a['activities']); }
/** * Deletes the blog comment when the associated activity comment is deleted. * * Note: This is hooked on the 'bp_activity_delete_comment_pre' filter instead * of the 'bp_activity_delete_comment' action because we need to fetch the * activity comment children before they are deleted. * * @since 2.0.0 * @since 2.5.0 Add the $delected parameter * * @param bool $retval Whether BuddyPress should continue or not. * @param int $parent_activity_id The parent activity ID for the activity comment. * @param int $activity_id The activity ID for the pending deleted activity comment. * @param bool $deleted Whether the comment was deleted or not. * @return bool */ function bp_blogs_sync_delete_from_activity_comment($retval, $parent_activity_id, $activity_id, &$deleted) { // Check if parent activity is a blog post. $parent_activity = new BP_Activity_Activity($parent_activity_id); // if parent activity isn't a post type having the buddypress-activity support, stop now! if (!bp_activity_type_supports($parent_activity->type, 'post-type-comment-tracking')) { return $retval; } // Fetch the activity comments for the activity item. $activity = bp_activity_get(array('in' => $activity_id, 'display_comments' => 'stream', 'spam' => 'all')); // Get all activity comment IDs for the pending deleted item. $activity_ids = bp_activity_recurse_comments_activity_ids($activity); $activity_ids[] = $activity_id; // Handle multisite // switch to the blog where the comment was made. switch_to_blog($parent_activity->item_id); // Remove associated blog comments. bp_blogs_remove_associated_blog_comments($activity_ids, current_user_can('moderate_comments')); // Multisite again! restore_current_blog(); // Rebuild activity comment tree // emulate bp_activity_delete_comment(). BP_Activity_Activity::rebuild_activity_comment_tree($parent_activity_id); // Avoid the error message although the comments were successfully deleted $deleted = true; // We're overriding the default bp_activity_delete_comment() functionality // so we need to return false. return false; }
/** * Create activity for paper edits. * * Edit activity is throttled: no more than one activity item per 60 minutes. * * @param int $post_id ID of the post. * @param WP_Post $post_after New post. * @param WP_Post $post_before Old post. */ function cacsp_create_edit_activity($post_id, WP_Post $post_after, WP_Post $post_before) { if ('cacsp_paper' !== $post_after->post_type) { return; } // We only want to record edits of published posts. Drafts don't get activity, and BP handles publishing. if ('publish' !== $post_before->post_status || 'publish' !== $post_after->post_status) { return; } // The author of the edit is the one who wrote the last revision. if ($revisions = wp_get_post_revisions($post_id)) { // Grab the last revision, but not an autosave. foreach ($revisions as $revision) { if (false !== strpos($revision->post_name, "{$revision->post_parent}-revision")) { $last_revision = $revision; break; } } } // Either revisions are disabled, or something else has gone wrong. Just use the post author. if (!isset($last_revision)) { $rev_author = $post_after->post_author; } else { $rev_author = $last_revision->post_author; } // Throttle. $existing = bp_activity_get(array('filter_query' => array(array('column' => 'component', 'value' => 'cacsp'), array('column' => 'type', 'value' => 'new_cacsp_edit'), array('column' => 'secondary_item_id', 'value' => $post_id), array('column' => 'user_id', 'value' => $rev_author)), 'update_meta_cache' => false, 'per_page' => 1)); if (!empty($existing['activities'])) { /** * Filters the number of seconds in the edit throttle. * * This prevents activity stream flooding by multiple edits of the same paper. * * @param int $throttle_period Defaults to 6 hours. */ $throttle_period = apply_filters('bpeo_event_edit_throttle_period', 6 * HOUR_IN_SECONDS); if (time() - strtotime($existing['activities'][0]->date_recorded) < $throttle_period) { return; } } // Poor man's diff. https://coderwall.com/p/3j2hxq/find-and-format-difference-between-two-strings-in-php $old = $post_before->post_content; $new = $post_after->post_content; $from_start = strspn($old ^ $new, ""); $from_end = strspn(strrev($old) ^ strrev($new), ""); $old_end = strlen($old) - $from_end; $new_end = strlen($new) - $from_end; $start = substr($new, 0, $from_start); $end = substr($new, $new_end); $new_diff = substr($new, $from_start, $new_end - $from_start); // Take a few words before the diff. $_start = explode(' ', $start); $_start = implode(' ', array_slice($_start, -5)); $content = bp_create_excerpt('…' . $_start . $new_diff . $end); $activity_id = bp_activity_add(array('content' => $content, 'component' => 'cacsp', 'type' => 'new_cacsp_edit', 'primary_link' => get_permalink($post_id), 'user_id' => $rev_author, 'item_id' => get_current_blog_id(), 'secondary_item_id' => $post_id, 'hide_sitewide' => false)); }
/** * Create an activity item for a newly published post type post. * * @since 2.2.0 * * @param int $post_id ID of the new post. * @param WP_Post|null $post Post object. * @param int $user_id ID of the post author. * @return int|bool The ID of the activity on success. False on error. */ function bp_activity_post_type_publish($post_id = 0, $post = null, $user_id = 0) { if (!is_a($post, 'WP_Post')) { return; } // Get the post type tracking args. $activity_post_object = bp_activity_get_post_type_tracking_args($post->post_type); if ('publish' != $post->post_status || !empty($post->post_password) || empty($activity_post_object->action_id)) { return; } if (empty($post_id)) { $post_id = $post->ID; } $blog_id = get_current_blog_id(); if (empty($user_id)) { $user_id = (int) $post->post_author; } // Bail if an activity item already exists for this post. $existing = bp_activity_get(array('filter' => array('action' => $activity_post_object->action_id, 'primary_id' => $blog_id, 'secondary_id' => $post_id))); if (!empty($existing['activities'])) { return; } /** * Filters whether or not to post the activity. * * This is a variable filter, dependent on the post type, * that lets components or plugins bail early if needed. * * @since 2.2.0 * * @param bool $value Whether or not to continue. * @param int $blog_id ID of the current site. * @param int $post_id ID of the current post being published. * @param int $user_id ID of the current user or post author. */ if (false === apply_filters("bp_activity_{$post->post_type}_pre_publish", true, $blog_id, $post_id, $user_id)) { return; } // Record this in activity streams. $blog_url = get_home_url($blog_id); $post_url = add_query_arg('p', $post_id, trailingslashit($blog_url)); // Backward compatibility filters for the 'blogs' component. if ('blogs' == $activity_post_object->component_id) { $activity_content = apply_filters('bp_blogs_activity_new_post_content', $post->post_content, $post, $post_url, $post->post_type); $activity_primary_link = apply_filters('bp_blogs_activity_new_post_primary_link', $post_url, $post_id, $post->post_type); } else { $activity_content = $post->post_content; $activity_primary_link = $post_url; } $activity_args = array('user_id' => $user_id, 'content' => $activity_content, 'primary_link' => $activity_primary_link, 'component' => $activity_post_object->component_id, 'type' => $activity_post_object->action_id, 'item_id' => $blog_id, 'secondary_item_id' => $post_id, 'recorded_time' => $post->post_date_gmt); if (!empty($activity_args['content'])) { // Create the excerpt. $activity_summary = bp_activity_create_summary($activity_args['content'], $activity_args); // Backward compatibility filter for blog posts. if ('blogs' == $activity_post_object->component_id) { $activity_args['content'] = apply_filters('bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post->post_type); } else { $activity_args['content'] = $activity_summary; } } // Set up the action by using the format functions. $action_args = array_merge($activity_args, array('post_title' => $post->post_title, 'post_url' => $post_url)); $activity_args['action'] = call_user_func_array($activity_post_object->format_callback, array('', (object) $action_args)); // Make sure the action is set. if (empty($activity_args['action'])) { return; } else { // Backward compatibility filter for the blogs component. if ('blogs' == $activity_post_object->component_id) { $activity_args['action'] = apply_filters('bp_blogs_record_activity_action', $activity_args['action']); } } $activity_id = bp_activity_add($activity_args); /** * Fires after the publishing of an activity item for a newly published post type post. * * @since 2.2.0 * * @param int $activity_id ID of the newly published activity item. * @param WP_Post $post Post object. * @param array $activity_args Array of activity arguments. */ do_action('bp_activity_post_type_published', $activity_id, $post, $activity_args); return $activity_id; }
function __construct($page, $per_page, $max, $include, $sort, $filter, $search_terms, $display_comments, $show_hidden, $exclude = false, $in = false) { global $bp; $this->pag_page = isset($_REQUEST['acpage']) ? intval($_REQUEST['acpage']) : $page; $this->pag_num = isset($_REQUEST['num']) ? intval($_REQUEST['num']) : $per_page; // Check if blog/forum replies are disabled $this->disable_blogforum_replies = isset($bp->site_options['bp-disable-blogforum-comments']) ? $bp->site_options['bp-disable-blogforum-comments'] : false; // Get an array of the logged in user's favorite activities $this->my_favs = maybe_unserialize(bp_get_user_meta($bp->loggedin_user->id, 'bp_favorite_activities', true)); // Fetch specific activity items based on ID's if (!empty($include)) { $this->activities = bp_activity_get_specific(array('activity_ids' => explode(',', $include), 'max' => $max, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'sort' => $sort, 'display_comments' => $display_comments, 'show_hidden' => $show_hidden)); } else { $this->activities = bp_activity_get(array('display_comments' => $display_comments, 'max' => $max, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'sort' => $sort, 'search_terms' => $search_terms, 'filter' => $filter, 'show_hidden' => $show_hidden, 'exclude' => $exclude, 'in' => $in)); } if (!$max || $max >= (int) $this->activities['total']) { $this->total_activity_count = (int) $this->activities['total']; } else { $this->total_activity_count = (int) $max; } $this->activities = $this->activities['activities']; if ($max) { if ($max >= count($this->activities)) { $this->activity_count = count($this->activities); } else { $this->activity_count = (int) $max; } } else { $this->activity_count = count($this->activities); } $this->full_name = $bp->displayed_user->fullname; // Fetch parent content for activity comments so we do not have to query in the loop foreach ((array) $this->activities as $activity) { if ('activity_comment' != $activity->type) { continue; } $parent_ids[] = $activity->item_id; } if (!empty($parent_ids)) { $activity_parents = bp_activity_get_specific(array('activity_ids' => $parent_ids)); } if (!empty($activity_parents['activities'])) { foreach ($activity_parents['activities'] as $parent) { $this->activity_parents[$parent->id] = $parent; } unset($activity_parents); } if ((int) $this->total_activity_count && (int) $this->pag_num) { $this->pag_links = paginate_links(array('base' => add_query_arg('acpage', '%#%'), 'format' => '', 'total' => ceil((int) $this->total_activity_count / (int) $this->pag_num), 'current' => (int) $this->pag_page, 'prev_text' => _x('←', 'Activity pagination previous text', 'buddypress'), 'next_text' => _x('→', 'Activity pagination next text', 'buddypress'), 'mid_size' => 1)); } }
/** * Remove a blog comment activity item from the activity stream. * * @param int $comment_id ID of the comment to be removed. */ function bp_blogs_remove_comment($comment_id) { global $wpdb; // activity comments are disabled for blog posts // which means that individual activity items exist for blog comments if (bp_disable_blogforum_comments()) { // Delete the individual activity stream item bp_blogs_delete_activity(array('item_id' => $wpdb->blogid, 'secondary_item_id' => $comment_id, 'type' => 'new_blog_comment')); // activity comments are enabled for blog posts // remove the associated activity item } else { // get associated activity ID from comment meta $activity_id = get_comment_meta($comment_id, 'bp_activity_comment_id', true); // delete the associated activity comment // // also removes child post comments and associated activity comments if (!empty($activity_id) && bp_is_active('activity')) { // fetch the activity comments for the activity item $activity = bp_activity_get(array('in' => $activity_id, 'display_comments' => 'stream')); // get all activity comment IDs for the pending deleted item if (!empty($activity['activities'])) { $activity_ids = bp_activity_recurse_comments_activity_ids($activity); $activity_ids[] = $activity_id; // delete activity items foreach ($activity_ids as $activity_id) { bp_activity_delete(array('id' => $activity_id)); } // remove associated blog comments bp_blogs_remove_associated_blog_comments($activity_ids); // rebuild activity comment tree BP_Activity_Activity::rebuild_activity_comment_tree($activity['activities'][0]->item_id); } } } /** * Fires after a blog comment activity item was removed from activity stream. * * @since BuddyPress (1.0.0) * * @param int $blogid Item ID for the blog associated with the removed comment. * @param int $comment_id ID of the comment being removed. * @param int $value ID of the current logged in user. */ do_action('bp_blogs_remove_comment', $wpdb->blogid, $comment_id, bp_loggedin_user_id()); }
/** * Process the repair tool * * In case something went wrong with group activities (visibility, component...), * this tool should repair the problematic activities. * * @package WP Idea Stream * @subpackage buddypress/activity * * @since 2.0.0 * * @global $wpdb * @uses bp_is_active() to check if a component is active * @uses wp_list_pluck() to pluck a certain field out of each object in a list. * @uses bp_activity_get() to get all ideastream activities * @uses wp_filter_object_list() to filter a list of objects, based on a set of key => value arguments. * @uses wp_parse_id_list() to sanitize a list of ids * @uses get_post_meta() to get the group id the idea is attached to * @uses groups_get_groups() to get the needed groups * @uses WP_Idea_Stream_Activity::bulk_edit_activity() to update the activities (component/item_id/visibility) * @return array the result of the repair operation. */ public function repair_activities() { global $wpdb; $buddypress = buddypress(); $blog_id = get_current_blog_id(); // Description of this tool, displayed to the user $statement = __('Making sure IdeaStream activities are consistent: %s', 'wp-idea-stream'); // Default to failure text $result = __('No activity needs to be repaired.', 'wp-idea-stream'); // Default to unrepaired $repair = 0; if (!bp_is_active('groups')) { return; } $ideastream_types = wp_list_pluck($this->activity_actions, 'type'); // Get all activities $ideastream_activities = bp_activity_get(array('filter' => array('action' => $ideastream_types), 'show_hidden' => true, 'spam' => 'all', 'per_page' => false)); if (is_array($ideastream_activities['activities'])) { $idea_comments = array(); $idea_posts = array(); $to_repair = array(); $attached_component = array('comment' => array($buddypress->groups->id => array(), $buddypress->blogs->id => array()), 'post' => array($buddypress->groups->id => array(), $buddypress->blogs->id => array())); foreach ($ideastream_activities['activities'] as $activity) { if (false !== strpos($activity->type, 'comment')) { $idea_comments[$activity->id] = $activity->secondary_item_id; $attached_component['comment'][$activity->component][] = $activity->id; } else { $idea_posts[$activity->id] = $activity->secondary_item_id; $attached_component['post'][$activity->component][] = $activity->id; } } // Gets the comment activities to repair if (!empty($idea_comments)) { // I don't think get_comments() allow us to get comments // using a list of comment ids.. $in = implode(',', wp_parse_id_list($idea_comments)); $sql = array('select' => "SELECT c.comment_ID, m.meta_value as group_id", 'from' => "FROM {$wpdb->comments} c LEFT JOIN {$wpdb->postmeta} m", 'on' => "ON (c.comment_post_ID = m.post_id )", 'where' => $wpdb->prepare("WHERE comment_ID IN ({$in}) AND m.meta_key = %s", '_ideastream_group_id')); $idea_comments_check = $wpdb->get_results(join(' ', $sql), OBJECT_K); foreach ($idea_comments as $activity_comment_id => $comment_secondary_id) { if (!empty($idea_comments_check[$comment_secondary_id]) && !in_array($activity_comment_id, $attached_component['comment'][$buddypress->groups->id])) { $to_repair['groups'][$idea_comments_check[$comment_secondary_id]->group_id][] = $activity_comment_id; } else { if (empty($idea_comments_check[$comment_secondary_id]) && in_array($activity_comment_id, $attached_component['comment'][$buddypress->groups->id])) { $to_repair['blogs'][] = $activity_comment_id; } } } } // Gets the idea activities to repair if (!empty($idea_posts)) { add_filter('wp_idea_stream_ideas_get_status', 'wp_idea_stream_ideas_get_all_status', 10, 1); // Get user's ideas posted in the group $idea_posts_check = wp_idea_stream_ideas_get_ideas(array('per_page' => -1, 'include' => $idea_posts, 'meta_query' => array(array('key' => '_ideastream_group_id', 'compare' => 'EXIST')))); $idea_posts_check = wp_list_pluck($idea_posts_check['ideas'], 'ID'); remove_filter('wp_idea_stream_ideas_get_status', 'wp_idea_stream_ideas_get_all_status', 10, 1); foreach ($idea_posts as $activity_post_id => $post_secondary_id) { if (in_array($post_secondary_id, $idea_posts_check) && !in_array($activity_post_id, $attached_component['post'][$buddypress->groups->id])) { $group_id = get_post_meta($post_secondary_id, '_ideastream_group_id', true); if (!empty($group_id)) { $to_repair['groups'][$group_id][] = $activity_post_id; } } else { if (!in_array($post_secondary_id, $idea_posts_check) && in_array($activity_post_id, $attached_component['post'][$buddypress->groups->id])) { $to_repair['blogs'][] = $activity_post_id; } } } } } if (!empty($to_repair['groups'])) { // Get the groups to have their status $groups = groups_get_groups(array('show_hidden' => true, 'populate_extras' => false, 'include' => join(',', array_keys($to_repair['groups'])), 'per_page' => false)); if (!empty($groups['groups'])) { $public_groups = wp_filter_object_list($groups['groups'], array('status' => 'public'), 'and', 'id'); foreach ($to_repair['groups'] as $item_id => $repair_activities) { $hide_sitewide = 0; if (!in_array($item_id, $public_groups)) { $hide_sitewide = 1; } self::bulk_edit_activity($repair_activities, $hide_sitewide, $buddypress->groups->id, $item_id); $repair += count($repair_activities); } } } if (!empty($to_repair['blogs'])) { self::bulk_edit_activity($to_repair['blogs'], 0, $buddypress->blogs->id, $blog_id); $repair += count($to_repair['blogs']); } // Setup success/fail messaging if (!empty($repair)) { $result = sprintf(__('%d repared', 'wp-idea-stream'), $repair); } // All done! return array(0, sprintf($statement, $result)); }
/** * Add action links to Stream drop row in admin list screen * * @filter wp_stream_action_links_{connector} * * @param array $links Previous links registered * @param object $record Stream record * * @return array Action links */ public static function action_links($links, $record) { if (in_array($record->context, array('components'))) { $option_key = wp_stream_get_meta($record, 'option_key', true); if ('bp-active-components' === $option_key) { $links[__('Edit', 'stream')] = add_query_arg(array('page' => 'bp-components'), admin_url('admin.php')); } elseif ('bp-pages' === $option_key) { $page_id = wp_stream_get_meta($record, 'page_id', true); $links[__('Edit setting', 'stream')] = add_query_arg(array('page' => 'bp-page-settings'), admin_url('admin.php')); if ($page_id) { $links[__('Edit Page', 'stream')] = get_edit_post_link($page_id); $links[__('View', 'stream')] = get_permalink($page_id); } } } elseif (in_array($record->context, array('settings'))) { $links[__('Edit setting', 'stream')] = add_query_arg(array('page' => wp_stream_get_meta($record, 'page', true)), admin_url('admin.php')); } elseif (in_array($record->context, array('groups'))) { $group_id = wp_stream_get_meta($record, 'id', true); $group = groups_get_group(array('group_id' => $group_id)); if ($group) { // Build actions URLs $base_url = bp_get_admin_url('admin.php?page=bp-groups&gid=' . $group_id); $delete_url = wp_nonce_url($base_url . '&action=delete', 'bp-groups-delete'); $edit_url = $base_url . '&action=edit'; $visit_url = bp_get_group_permalink($group); $links[__('Edit group', 'stream')] = $edit_url; $links[__('View group', 'stream')] = $visit_url; $links[__('Delete group', 'stream')] = $delete_url; } } elseif (in_array($record->context, array('activity'))) { $activity_id = wp_stream_get_meta($record, 'id', true); $activities = bp_activity_get(array('in' => $activity_id, 'spam' => 'all')); if (!empty($activities['activities'])) { $activity = reset($activities['activities']); $base_url = bp_get_admin_url('admin.php?page=bp-activity&aid=' . $activity->id); $spam_nonce = esc_html('_wpnonce=' . wp_create_nonce('spam-activity_' . $activity->id)); $delete_url = $base_url . "&action=delete&{$spam_nonce}"; $edit_url = $base_url . '&action=edit'; $ham_url = $base_url . "&action=ham&{$spam_nonce}"; $spam_url = $base_url . "&action=spam&{$spam_nonce}"; if ($activity->is_spam) { $links[__('Ham', 'stream')] = $ham_url; } else { $links[__('Edit', 'stream')] = $edit_url; $links[__('Spam', 'stream')] = $spam_url; } $links[__('Delete', 'stream')] = $delete_url; } } elseif (in_array($record->context, array('profile_fields'))) { $field_id = wp_stream_get_meta($record, 'field_id', true); $group_id = wp_stream_get_meta($record, 'group_id', true); if (empty($field_id)) { // is a group action $links[__('Edit', 'stream')] = add_query_arg(array('page' => 'bp-profile-setup', 'mode' => 'edit_group', 'group_id' => $group_id), admin_url('users.php')); $links[__('Delete', 'stream')] = add_query_arg(array('page' => 'bp-profile-setup', 'mode' => 'delete_group', 'group_id' => $group_id), admin_url('users.php')); } else { $field = new BP_XProfile_Field($field_id); if (empty($field->type)) { return $links; } $links[__('Edit', 'stream')] = add_query_arg(array('page' => 'bp-profile-setup', 'mode' => 'edit_field', 'group_id' => $group_id, 'field_id' => $field_id), admin_url('users.php')); $links[__('Delete', 'stream')] = add_query_arg(array('page' => 'bp-profile-setup', 'mode' => 'delete_field', 'field_id' => $field_id), admin_url('users.php')); } } return $links; }
/** * Delete activity associated with a Doc * * Run on transition_post_status, to catch deletes from all locations * * @since 1.3 * * @param string $new_status * @param string $old_status * @param obj WP_Post object */ function bp_docs_delete_doc_activity($new_status, $old_status, $post) { if (!bp_is_active('activity')) { return; } if (bp_docs_get_post_type_name() != $post->post_type) { return; } if ('trash' != $new_status) { return; } $activities = bp_activity_get(array('filter' => array('secondary_id' => $post->ID, 'component' => 'docs'))); foreach ((array) $activities['activities'] as $activity) { bp_activity_delete(array('id' => $activity->id)); } }
protected function activity_exists_for_post($post_id) { $a = bp_activity_get(array('component' => buddypress()->blogs->id, 'action' => 'new_blog_post', 'item_id' => get_current_blog_id(), 'secondary_item_id' => $post_id)); return !empty($a['activities']); }
/** * Constructor method. * * The arguments passed to this class constructor are of the same * format as {@link BP_Activity_Activity::get()}. * * @since 1.5.0 * * @see BP_Activity_Activity::get() for a description of the argument * structure, as well as default values. * * @param array $args { * Array of arguments. Supports all arguments from * BP_Activity_Activity::get(), as well as 'page_arg' and * 'include'. Default values for 'per_page' and 'display_comments' * differ from the originating function, and are described below. * @type string $page_arg The string used as a query parameter in * pagination links. Default: 'acpage'. * @type array|bool $include Pass an array of activity IDs to * retrieve only those items, or false to noop the 'include' * parameter. 'include' differs from 'in' in that 'in' forms * an IN clause that works in conjunction with other filters * passed to the function, while 'include' is interpreted as * an exact list of items to retrieve, which skips all other * filter-related parameters. Default: false. * @type int|bool $per_page Default: 20. * @type string|bool $display_comments Default: 'threaded'. * } */ public function __construct($args) { $bp = buddypress(); // Backward compatibility with old method of passing arguments. if (!is_array($args) || func_num_args() > 1) { _deprecated_argument(__METHOD__, '1.6', sprintf(__('Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress'), __METHOD__, __FILE__)); $old_args_keys = array(0 => 'page', 1 => 'per_page', 2 => 'max', 3 => 'include', 4 => 'sort', 5 => 'filter', 6 => 'search_terms', 7 => 'display_comments', 8 => 'show_hidden', 9 => 'exclude', 10 => 'in', 11 => 'spam', 12 => 'page_arg'); $func_args = func_get_args(); $args = bp_core_parse_args_array($old_args_keys, $func_args); } $defaults = array('page' => 1, 'per_page' => 20, 'page_arg' => 'acpage', 'max' => false, 'fields' => 'all', 'count_total' => false, 'sort' => false, 'include' => false, 'exclude' => false, 'in' => false, 'filter' => false, 'scope' => false, 'search_terms' => false, 'meta_query' => false, 'date_query' => false, 'filter_query' => false, 'display_comments' => 'threaded', 'show_hidden' => false, 'spam' => 'ham_only', 'update_meta_cache' => true); $r = wp_parse_args($args, $defaults); extract($r); $this->pag_arg = sanitize_key($r['page_arg']); $this->pag_page = bp_sanitize_pagination_arg($this->pag_arg, $r['page']); $this->pag_num = bp_sanitize_pagination_arg('num', $r['per_page']); // Check if blog/forum replies are disabled. $this->disable_blogforum_replies = (bool) bp_core_get_root_option('bp-disable-blogforum-comments'); // Get an array of the logged in user's favorite activities. $this->my_favs = maybe_unserialize(bp_get_user_meta(bp_loggedin_user_id(), 'bp_favorite_activities', true)); // Fetch specific activity items based on ID's. if (!empty($include)) { $this->activities = bp_activity_get_specific(array('activity_ids' => explode(',', $include), 'max' => $max, 'count_total' => $count_total, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'sort' => $sort, 'display_comments' => $display_comments, 'show_hidden' => $show_hidden, 'spam' => $spam, 'update_meta_cache' => $update_meta_cache)); // Fetch all activity items. } else { $this->activities = bp_activity_get(array('display_comments' => $display_comments, 'max' => $max, 'count_total' => $count_total, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'sort' => $sort, 'search_terms' => $search_terms, 'meta_query' => $meta_query, 'date_query' => $date_query, 'filter_query' => $filter_query, 'filter' => $filter, 'scope' => $scope, 'show_hidden' => $show_hidden, 'exclude' => $exclude, 'in' => $in, 'spam' => $spam, 'update_meta_cache' => $update_meta_cache)); } // The total_activity_count property will be set only if a // 'count_total' query has taken place. if (!is_null($this->activities['total'])) { if (!$max || $max >= (int) $this->activities['total']) { $this->total_activity_count = (int) $this->activities['total']; } else { $this->total_activity_count = (int) $max; } } $this->has_more_items = $this->activities['has_more_items']; $this->activities = $this->activities['activities']; if ($max) { if ($max >= count($this->activities)) { $this->activity_count = count($this->activities); } else { $this->activity_count = (int) $max; } } else { $this->activity_count = count($this->activities); } $this->full_name = bp_get_displayed_user_fullname(); // Fetch parent content for activity comments so we do not have to query in the loop. foreach ((array) $this->activities as $activity) { if ('activity_comment' != $activity->type) { continue; } $parent_ids[] = $activity->item_id; } if (!empty($parent_ids)) { $activity_parents = bp_activity_get_specific(array('activity_ids' => $parent_ids)); } if (!empty($activity_parents['activities'])) { foreach ($activity_parents['activities'] as $parent) { $this->activity_parents[$parent->id] = $parent; } unset($activity_parents); } if ((int) $this->total_activity_count && (int) $this->pag_num) { $this->pag_links = paginate_links(array('base' => add_query_arg($this->pag_arg, '%#%'), 'format' => '', 'total' => ceil((int) $this->total_activity_count / (int) $this->pag_num), 'current' => (int) $this->pag_page, 'prev_text' => _x('←', 'Activity pagination previous text', 'buddypress'), 'next_text' => _x('→', 'Activity pagination next text', 'buddypress'), 'mid_size' => 1, 'add_args' => array())); } }
/** * Handle filtering of data, sorting, pagination, and any other data manipulation prior to rendering. * * @since BuddyPress (1.6.0) */ function prepare_items() { // Option defaults $filter = array(); $include_id = false; $search_terms = false; $sort = 'DESC'; $spam = 'ham_only'; // Set current page $page = $this->get_pagenum(); // Set per page from the screen options $per_page = $this->get_items_per_page(str_replace('-', '_', "{$this->screen->id}_per_page")); // Check if we're on the "Spam" view if (!empty($_REQUEST['activity_status']) && 'spam' == $_REQUEST['activity_status']) { $spam = 'spam_only'; $this->view = 'spam'; } // Sort order if (!empty($_REQUEST['order']) && 'desc' != $_REQUEST['order']) { $sort = 'ASC'; } // Order by /*if ( !empty( $_REQUEST['orderby'] ) ) { }*/ // Filter if (!empty($_REQUEST['activity_type'])) { $filter = array('action' => $_REQUEST['activity_type']); } // Are we doing a search? if (!empty($_REQUEST['s'])) { $search_terms = $_REQUEST['s']; } // Check if user has clicked on a specific activity (if so, fetch only that, and any related, activity). if (!empty($_REQUEST['aid'])) { $include_id = (int) $_REQUEST['aid']; } // Get the spam total (ignoring any search query or filter) $spams = bp_activity_get(array('display_comments' => 'stream', 'show_hidden' => true, 'spam' => 'spam_only', 'count_total' => 'count_query')); $this->spam_count = $spams['total']; unset($spams); // Get the activities from the database $activities = bp_activity_get(array('display_comments' => 'stream', 'filter' => $filter, 'in' => $include_id, 'page' => $page, 'per_page' => $per_page, 'search_terms' => $search_terms, 'show_hidden' => true, 'spam' => $spam, 'count_total' => 'count_query')); // If we're viewing a specific activity, flatten all activities into a single array. if ($include_id) { $activities['activities'] = BP_Activity_List_Table::flatten_activity_array($activities['activities']); $activities['total'] = count($activities['activities']); // Sort the array by the activity object's date_recorded value usort($activities['activities'], create_function('$a, $b', 'return $a->date_recorded > $b->date_recorded;')); } // bp_activity_get returns an array of objects; cast these to arrays for WP_List_Table. $new_activities = array(); foreach ($activities['activities'] as $activity_item) { $new_activities[] = (array) $activity_item; // Build an array of activity-to-user ID mappings for better efficiency in the In Response To column $this->activity_user_id[$activity_item->id] = $activity_item->user_id; } // Set raw data to display $this->items = $new_activities; // Store information needed for handling table pagination $this->set_pagination_args(array('per_page' => $per_page, 'total_items' => $activities['total'], 'total_pages' => ceil($activities['total'] / $per_page))); // Don't truncate activity items; bp_activity_truncate_entry() needs to be used inside a BP_Activity_Template loop. remove_filter('bp_get_activity_content_body', 'bp_activity_truncate_entry', 5); }
/** * Deletes the blog comment when the associated activity comment is deleted. * * Note: This is hooked on the 'bp_activity_delete_comment_pre' filter instead * of the 'bp_activity_delete_comment' action because we need to fetch the * activity comment children before they are deleted. * * @since BuddyPress (2.0.0) * * @param bool $retval * @param int $parent_activity_id The parent activity ID for the activity comment. * @param int $activity_id The activity ID for the pending deleted activity comment. */ function bp_blogs_sync_delete_from_activity_comment( $retval, $parent_activity_id, $activity_id ) { // check if parent activity is a blog post $parent_activity = new BP_Activity_Activity( $parent_activity_id ); if ( 'new_blog_post' != $parent_activity->type ) { return $retval; } // fetch the activity comments for the activity item $activity = bp_activity_get( array( 'in' => $activity_id, 'display_comments' => 'stream', ) ); // get all activity comment IDs for the pending deleted item $activity_ids = bp_activity_recurse_comments_activity_ids( $activity ); $activity_ids[] = $activity_id; // handle multisite // switch to the blog where the comment was made switch_to_blog( $parent_activity->item_id ); // remove associated blog comments bp_blogs_remove_associated_blog_comments( $activity_ids, current_user_can( 'moderate_comments' ) ); // multisite again! restore_current_blog(); // rebuild activity comment tree // emulate bp_activity_delete_comment() BP_Activity_Activity::rebuild_activity_comment_tree( $parent_activity_id ); // we're overriding the default bp_activity_delete_comment() functionality // so we need to return false return false; }
/** * @group friends_delete_activity */ public function test_delete_friendship_activity_on_user_delete() { $old_user = get_current_user_id(); $u1 = $this->factory->user->create(); $u2 = $this->factory->user->create(); friends_add_friend($u2, $u1); $friendship_id = friends_get_friendship_id($u2, $u1); // Set current user to u1 to accept the friendship $this->set_current_user($u1); friends_accept_friendship($friendship_id); // Reset the current user $this->set_current_user($old_user); // Delete $u1. wp_delete_user($u1); // 'friendship_created' activity item should not exist. $friendship_activity = bp_activity_get(array('component' => buddypress()->friends->id, 'filter' => array('action' => array('friendship_created'), 'primary_id' => $friendship_id))); $this->assertEmpty($friendship_activity['activities']); }
function bp_blogs_record_post($post_id, $post, $user_id = 0) { global $bp, $wpdb; $post_id = (int) $post_id; $blog_id = (int) $wpdb->blogid; if (!$user_id) { $user_id = (int) $post->post_author; } // Stop infinite loops with WordPress MU Sitewide Tags. // That plugin changed the way its settings were stored at some point. Thus the dual check. if (!empty($bp->site_options['sitewide_tags_blog'])) { $st_options = maybe_unserialize($bp->site_options['sitewide_tags_blog']); $tags_blog_id = isset($st_options['tags_blog_id']) ? $st_options['tags_blog_id'] : 0; } else { $tags_blog_id = isset($bp->site_options['tags_blog_id']) ? $bp->site_options['tags_blog_id'] : 0; } if ((int) $blog_id == $tags_blog_id && apply_filters('bp_blogs_block_sitewide_tags_activity', true)) { return false; } // Don't record this if it's not a post if (!in_array($post->post_type, apply_filters('bp_blogs_record_post_post_types', array('post')))) { return false; } $is_blog_public = apply_filters('bp_is_blog_public', (int) get_blog_option($blog_id, 'blog_public')); if ('publish' == $post->post_status && empty($post->post_password)) { if ($is_blog_public || !is_multisite()) { // Record this in activity streams $post_permalink = get_permalink($post_id); if (is_multisite()) { $activity_action = sprintf(__('%1$s wrote a new post, %2$s, on the site %3$s', 'buddypress'), bp_core_get_userlink((int) $post->post_author), '<a href="' . $post_permalink . '">' . $post->post_title . '</a>', '<a href="' . get_blog_option($blog_id, 'home') . '">' . get_blog_option($blog_id, 'blogname') . '</a>'); } else { $activity_action = sprintf(__('%1$s wrote a new post, %2$s', 'buddypress'), bp_core_get_userlink((int) $post->post_author), '<a href="' . $post_permalink . '">' . $post->post_title . '</a>'); } // Make sure there's not an existing entry for this post (prevent bumping) if (bp_is_active('activity')) { $existing = bp_activity_get(array('filter' => array('user_id' => (int) $post->post_author, 'action' => 'new_blog_post', 'primary_id' => $blog_id, 'secondary_id' => $post_id))); if (!empty($existing['activities'])) { return; } } $activity_content = $post->post_content; bp_blogs_record_activity(array('user_id' => (int) $post->post_author, 'action' => apply_filters('bp_blogs_activity_new_post_action', $activity_action, $post, $post_permalink), 'content' => apply_filters('bp_blogs_activity_new_post_content', $activity_content, $post, $post_permalink), 'primary_link' => apply_filters('bp_blogs_activity_new_post_primary_link', $post_permalink, $post_id), 'type' => 'new_blog_post', 'item_id' => $blog_id, 'secondary_item_id' => $post_id, 'recorded_time' => $post->post_modified_gmt)); } // Update the blogs last activity bp_blogs_update_blogmeta($blog_id, 'last_activity', bp_core_current_time()); } else { bp_blogs_remove_post($post_id, $blog_id, $user_id); } do_action('bp_blogs_new_blog_post', $post_id, $post, $user_id); }
function gtags_activity_for_item($args) { global $wpdb, $bp; ob_start(); $defaults = array('group_ids' => '', 'scope' => '', 'show' => 4, 'show_more' => 8, 'truncate' => 190); $args = wp_parse_args($args, $defaults); extract($args, EXTR_SKIP); if ($scope == 'my' && is_user_logged_in()) { $my_groups = BP_Groups_Member::get_group_ids($bp->loggedin_user->id); $group_ids = array_intersect($group_ids, $my_groups['groups']); $show_hidden = true; } if (empty($group_ids)) { echo '<div class="recent recent-none-found">' . __('Sorry no groups were found.', 'gtags') . '</div>'; return; } ?> <div class="recent"><?php // generate source group links foreach ($group_ids as $group_id) { $group = groups_get_group(array('group_id' => $group_id)); $avatar = bp_core_fetch_avatar('object=group&type=thumb&width=50&height=50&item_id=' . $group->id); $group_output .= $sep . '<a href="' . bp_get_group_permalink($group) . '" class="recent-group-avatar">' . $avatar . ' ' . $group->name . '</a>'; $sep = ', '; //compile group data to be used in loop below $the_groups[$group->id] = array('permalink' => bp_get_group_permalink($group), 'name' => bp_get_group_name($group), 'avatar' => $avatar); } ?> <div class="gtags-recent-groups"> <?php _e('Recent Activity From', 'gtags'); ?> <a href="#" class="gtags-more-groups"><?php _e('these groups +', 'gtags'); ?> </a> <div class="gtags-recent-groups-list"><?php echo $group_output; ?> </div> </div> <?php // fetch a whole bunch of activity so we can sort them by date below, otherwise they are sorted by group $filter = array('user_id' => false, 'object' => 'groups', 'action' => false, 'primary_id' => implode(',', (array) $group_ids)); $activity = bp_activity_get(array('max' => 1000, 'per_page' => 1000, 'filter' => $filter, 'show_hidden' => $show_hidden)); //$type_skip = apply_filters( 'gtags_type_skip', array( 'joined_group' ) ); // array of activity types to skip // generate a cleaned array of content foreach ($activity['activities'] as $item) { if (in_array($item->type, (array) $type_skip)) { continue; } $action = preg_replace('/:$/', '', $item->action); // remove trailing colon in activity $action = apply_filters('gtags_action', $action); $content = strip_tags(stripslashes($item->content)); if ($truncate && strlen($content) > $truncate) { $content = substr($content, 0, $truncate) . '... '; } if ($content) { $content .= ' <a href="' . $item->primary_link . '">view</a>'; } $activity_list[$item->date_recorded] = array('action' => $action, 'group_id' => $item->item_id, 'content' => $content, 'primary_link' => $item->primary_link, 'user_id' => $item->user_id); } if (empty($activity_list)) { echo __("Sorry, there was no activity found.", 'gtags'); echo "</div>"; //close the div return; } // sort them by date (regardless of group) ksort($activity_list); $activity_list = array_reverse($activity_list); // output pretty html for recent activity for groups foreach ((array) $activity_list as $date => $item) { $i++; $group_id = $item['group_id']; $action = $item['action']; // show only a certain amount, after that make a 'show more' link and show the rest in a hidden div if ($i == $show + 1 && $show_more) { ?> <a href="#" class="gtags-more-activity"><?php _e('show more +', 'gtags'); ?> </a> <div class="gtags-more-content"><?php $more_link = true; } if ($i > $show + $show_more + 1) { break; } // for repeating group content, remove group link and shrink group avatar if ($prev_group_id == $group_id) { $action = preg_replace('/ in the group(.*)$/i', '', $action); $dup_class = ' duplicate-group'; } else { $dup_class = ''; } $prev_group_id = $group_id; // group avatar echo '<a href="' . $the_groups[$group_id]['permalink'] . '" title="' . $the_groups[$group_id]['name'] . '" class="gtags-item-group-avatar' . $dup_class . '">' . $the_groups[$group_id]['avatar'] . '</a>'; // the actual content ?> <div class="gtags-item-recent group"> <div class="gtags-item-avatar"> <a href="<?php echo bp_core_get_user_domain($item['user_id']); ?> "> <?php echo bp_core_fetch_avatar('object=user&type=full&width=50&height=50&item_id=' . $item['user_id']); ?> </a> </div> <div class="gtags-item-action"> <?php echo $action; ?> <span class="gtags-time-ago"><?php echo bp_core_time_since($date); ?> <?php _e('ago', 'gtags'); ?> </span> </div> <div class="gtags-item-content"> <?php echo convert_smilies($item['content']); ?> </div> </div><?php } if ($more_link) { echo '<div class="gtags-recent-groups"> ' . __('Continue reading in:', 'gtags') . ' ' . $group_output . '</div>'; echo '</div>'; // close the more div } ?> </div><?php // end recent return ob_get_clean(); }
/** * Add an activity item when a user has updated his profile. * * @since 2.0.0 * * @param int $user_id ID of the user who has updated his profile. * @param array $field_ids IDs of the fields submitted. * @param bool $errors True if validation or saving errors occurred, otherwise false. * @param array $old_values Pre-save xprofile field values and visibility levels. * @param array $new_values Post-save xprofile field values and visibility levels. * * @return bool True on success, false on failure. */ function bp_xprofile_updated_profile_activity($user_id, $field_ids = array(), $errors = false, $old_values = array(), $new_values = array()) { // If there were errors, don't post. if (!empty($errors)) { return false; } // Bail if activity component is not active. if (!bp_is_active('activity')) { return false; } // Don't post if there have been no changes, or if the changes are // related solely to non-public fields. $public_changes = false; foreach ($new_values as $field_id => $new_value) { $old_value = isset($old_values[$field_id]) ? $old_values[$field_id] : ''; // Don't register changes to private fields. if (empty($new_value['visibility']) || 'public' !== $new_value['visibility']) { continue; } // Don't register if there have been no changes. if ($new_value === $old_value) { continue; } // Looks like we have public changes - no need to keep checking. $public_changes = true; break; } // Bail if no public changes. if (empty($public_changes)) { return false; } // Throttle to one activity of this type per 2 hours. $existing = bp_activity_get(array('max' => 1, 'filter' => array('user_id' => $user_id, 'object' => buddypress()->profile->id, 'action' => 'updated_profile'))); // Default throttle time is 2 hours. Filter to change (in seconds). if (!empty($existing['activities'])) { /** * Filters the throttle time, in seconds, used to prevent excessive activity posting. * * @since 2.0.0 * * @param int $value Throttle time, in seconds. */ $throttle_period = apply_filters('bp_xprofile_updated_profile_activity_throttle_time', HOUR_IN_SECONDS * 2); $then = strtotime($existing['activities'][0]->date_recorded); $now = strtotime(bp_core_current_time()); // Bail if throttled. if ($now - $then < $throttle_period) { return false; } } // If we've reached this point, assemble and post the activity item. $profile_link = trailingslashit(bp_core_get_user_domain($user_id) . bp_get_profile_slug()); return (bool) xprofile_record_activity(array('user_id' => $user_id, 'primary_link' => $profile_link, 'component' => buddypress()->profile->id, 'type' => 'updated_profile')); }
/** * Save method for our extension during edits. * * @param int $group_id The group ID. */ public function edit_screen_save($group_id = null) { if (!isset($_POST['save'])) { return false; } check_admin_referer('groups_edit_save_' . $this->slug); $existing_feeds = (array) groups_get_groupmeta(bp_get_current_group_id(), 'blogfeeds'); $unfiltered_feeds = explode(',', $_POST['blogfeeds']); $blog_feeds = array(); foreach ((array) $unfiltered_feeds as $blog_feed) { if (!empty($blog_feed)) { $blog_feeds[] = esc_url_raw(trim($blog_feed)); } } /* Loop and find any feeds that have been removed, so we can delete activity stream items */ if (!empty($existing_feeds)) { foreach ((array) $existing_feeds as $feed) { if (!in_array($feed, (array) $blog_feeds)) { $removed[] = $feed; } } } if ($removed) { foreach ((array) $removed as $feed) { $existing = bp_activity_get(array('user_id' => false, 'component' => 'groups', 'type' => 'exb', 'item_id' => bp_get_current_group_id(), 'update_meta_cache' => false, 'display_comments' => false, 'meta_query' => array(array('key' => 'exb_feedurl', 'value' => trim($feed))))); // only delete items matching the feed if (!empty($existing['activities'])) { $aids = wp_list_pluck($existing['activities'], 'id'); foreach ($aids as $aid) { bp_activity_delete(array('id' => $aid)); } // old way - delete all feed items matching the group } else { bp_activity_delete(array('item_id' => bp_get_current_group_id(), 'component' => 'groups', 'type' => 'exb')); } } } groups_update_groupmeta(bp_get_current_group_id(), 'fetchtime', $_POST['fetch-time']); groups_update_groupmeta(bp_get_current_group_id(), 'blogfeeds', $blog_feeds); groups_update_groupmeta(bp_get_current_group_id(), 'bp_groupblogs_lastupdate', gmdate("Y-m-d H:i:s")); /* Re-fetch */ bp_groupblogs_fetch_group_feeds(bp_get_current_group_id()); bp_core_add_message(__('External blog feeds updated successfully!', 'bp-groups-externalblogs')); bp_core_redirect(bp_get_group_permalink(groups_get_current_group()) . '/admin/' . $this->slug); }
/** * Add an activity item when a user has updated his profile. * * @since BuddyPress (2.0.0) * * @param int $user_id ID of the user who has updated his profile. * @param array $field_ids IDs of the fields submitted. * @param bool $errors True if validation or saving errors occurred, otherwise * false. * @param array $old_values Pre-save xprofile field values and visibility * levels. * @param array $new_values Post-save xprofile field values and visibility * levels. * @return bool True on success, false on failure. */ function bp_xprofile_updated_profile_activity($user_id, $field_ids, $errors, $old_values = array(), $new_values = array()) { // If there were errors, don't post if (!empty($errors)) { return false; } if (!bp_is_active('activity')) { return false; } // Don't post if there have been no changes, or if the changes are // related solely to non-public fields $public_changes = false; foreach ($new_values as $field_id => $new_value) { $old_value = isset($old_values[$field_id]) ? $old_values[$field_id] : ''; $old_value_value = isset($old_value['value']) ? $old_value['value'] : ''; $old_value_visibility = isset($old_value['visibility']) ? $old_value['visibility'] : ''; // Don't register changes to private fields if ('public' !== $new_value['visibility']) { continue; } // Don't register if there have been no changes if ($new_value === $old_value) { continue; } // Looks like we have public changes - no need to keep checking $public_changes = true; break; } if (!$public_changes) { return false; } // Throttle to one activity of this type per 2 hours $existing = bp_activity_get(array('max' => 1, 'filter' => array('user_id' => $user_id, 'object' => buddypress()->profile->id, 'action' => 'updated_profile'))); if (empty($existing['activities'])) { $throttle = false; } else { // Default throttle time is 2 hours. Filter to change (in seconds) $throttle_period = apply_filters('bp_xprofile_updated_profile_activity_throttle_time', 60 * 60 * 2); $then = strtotime($existing['activities'][0]->date_recorded); $now = strtotime(bp_core_current_time()); $throttle = $now - $then < $throttle_period; } if ($throttle) { return false; } // If we've reached this point, assemble and post the activity item $profile_link = trailingslashit(bp_core_get_user_domain($user_id) . buddypress()->profile->slug); $retval = xprofile_record_activity(array('user_id' => $user_id, 'primary_link' => $profile_link, 'component' => buddypress()->profile->id, 'type' => 'updated_profile')); return (bool) $retval; }
/** * @group activity_action * @group bp_groups_format_activity_action_group_details_updated */ public function test_bp_groups_format_activity_action_group_details_updated_with_updated_name_and_description() { $old_user = get_current_user_id(); $u = $this->factory->user->create(); $this->set_current_user($u); $group = $this->factory->group->create_and_get(); groups_edit_base_group_details($group->id, 'Foo', 'Bar', true); $a = bp_activity_get(array('component' => buddypress()->groups->id, 'action' => 'group_details_updated', 'item_id' => $group->id)); $this->assertNotEmpty($a['activities']); $expected = sprintf(__('%s changed the name and description of the group %s', 'buddypress'), bp_core_get_userlink($u), '<a href="' . bp_get_group_permalink($group) . '">Foo</a>'); $this->assertSame($expected, $a['activities'][0]->action); $this->set_current_user($old_user); }
/** * When a Notepad is edited, record the fact to the activity stream * * @since 1.0 * @param int $post_id * @param object $post * @return int The id of the activity item posted */ function participad_notepad_record_notepad_activity($post_id, $post) { global $bp; // Run only for participad_notebook post type if (empty($post->post_type) || participad_notepad_post_type_name() != $post->post_type) { return; } // Throttle activity updates: No duplicate posts (same user, same // notepad) within 60 minutes $already_args = array('max' => 1, 'sort' => 'DESC', 'show_hidden' => 1, 'filter' => array('user_id' => get_current_user_id(), 'action' => 'participad_notepad_edited', 'secondary_id' => $post_id)); $already_activity = bp_activity_get($already_args); // If any activity items are found, compare its date_recorded with time() to // see if it's within the allotted throttle time. If so, don't record the // activity item if (!empty($already_activity['activities'])) { $date_recorded = $already_activity['activities'][0]->date_recorded; $drunix = strtotime($date_recorded); if (time() - $drunix <= apply_filters('participad_notepad_edit_activity_throttle_time', 60 * 60)) { return; } } $post_permalink = get_permalink($post_id); $action = sprintf(__('%1$s edited a notepad %2$s on the site %3$s', 'participad'), bp_core_get_userlink(get_current_user_id()), '<a href="' . $post_permalink . '">' . esc_html($post->post_title) . '</a>', '<a href="' . get_option('siteurl') . '">' . get_option('blogname') . '</a>'); $activity_id = bp_activity_add(array('user_id' => get_current_user_id(), 'component' => bp_is_active('blogs') ? $bp->blogs->id : 'blogs', 'action' => $action, 'primary_link' => $post_permalink, 'type' => 'participad_notepad_edited', 'item_id' => get_current_blog_id(), 'secondary_item_id' => $post_id, 'recorded_time' => $post->post_modified_gmt, 'hide_sitewide' => get_option('blog_public') <= 0)); if (function_exists('bp_blogs_update_blogmeta')) { bp_blogs_update_blogmeta(get_current_blog_id(), 'last_activity', bp_core_current_time()); } return $activity_id; }