Index: bp-activity/bp-activity-classes.php
===================================================================
--- bp-activity/bp-activity-classes.php
+++ bp-activity/bp-activity-classes.php
@@ -161,6 +161,12 @@ class BP_Activity_Activity {
 			$this->mptt_right        = $row->mptt_right;
 			$this->is_spam           = $row->is_spam;
 		}
+
+		$action = bp_activity_generate_action_string( $this );
+
+		if ( $action ) {
+			$this->action = $action;
+		}
 	}
 
 	/**
@@ -442,6 +448,12 @@ class BP_Activity_Activity {
 		if ( $activities && $display_comments )
 			$activities = BP_Activity_Activity::append_comments( $activities, $spam );
 
+		// Pre-fetch data associated with activity users and other objects
+		BP_Activity_Activity::prefetch_object_data( $activities );
+
+		// Generate action strings
+		$activities = BP_Activity_Activity::generate_action_strings( $activities );
+
 		// If $max is set, only return up to the max results
 		if ( !empty( $max ) ) {
 			if ( (int) $total_activities > (int) $max )
@@ -559,6 +571,50 @@ class BP_Activity_Activity {
 	}
 
 	/**
+	 * Pre-fetch data for objects associated with activity items.
+	 *
+	 * Activity items are associated with users, and often with other
+	 * BuddyPress data objects. Here, we pre-fetch data about these
+	 * associated objects, so that inline lookups - done primarily when
+	 * building action strings - do not result in excess database queries.
+	 *
+	 * The only object data required for activity component activity types
+	 * (activity_update and activity_comment) is related to users, and that
+	 * info is fetched separately in BP_Activity_Activity::get_activity_data().
+	 * So this method contains nothing but a filter that allows other
+	 * components, such as bp-friends and bp-groups, to hook in and prime
+	 * their own caches at the beginning of an activity loop.
+	 *
+	 * @since BuddyPress (2.0.0)
+	 *
+	 * @param array $activities Array of activities.
+	 */
+	protected static function prefetch_object_data( $activities ) {
+		return apply_filters( 'bp_activity_prefetch_object_data', $activities );
+	}
+
+	/**
+	 * Generate action strings for the activities located in BP_Activity_Activity::get().
+	 *
+	 * @since BuddyPress (2.0.0)
+	 *
+	 * @param array $activities Array of activities.
+	 * @return array
+	 */
+	protected static function generate_action_strings( $activities ) {
+		foreach ( $activities as $key => $activity ) {
+			$generated_action = bp_activity_generate_action_string( $activity );
+			if ( false !== $generated_action ) {
+				$activity->action = $generated_action;
+			}
+
+			$activities[ $key ] = $activity;
+		}
+
+		return $activities;
+	}
+
+	/**
 	 * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get().
 	 *
 	 * We use WP_Meta_Query to do the heavy lifting of parsing the
Index: bp-activity/bp-activity-functions.php
===================================================================
--- bp-activity/bp-activity-functions.php
+++ bp-activity/bp-activity-functions.php
@@ -266,27 +266,35 @@ function bp_activity_get_userid_from_mentionname( $mentionname ) {
  * @param string $component_id The unique string ID of the component.
  * @param string $key The action key.
  * @param string $value The action value.
+ * @param callable $format_callback Callback for formatting the action string.
  * @return bool False if any param is empty, otherwise true.
  */
-function bp_activity_set_action( $component_id, $key, $value ) {
+function bp_activity_set_action( $component_id, $key, $value, $format_callback = false ) {
 	global $bp;
 
 	// Return false if any of the above values are not set
-	if ( empty( $component_id ) || empty( $key ) || empty( $value ) )
+	if ( empty( $component_id ) || empty( $key ) || empty( $value ) ) {
 		return false;
+	}
 
 	// Set activity action
 	if ( !isset( $bp->activity->actions ) || !is_object( $bp->activity->actions ) ) {
 		$bp->activity->actions = new stdClass;
 	}
 
+	// Verify callback
+	if ( ! is_callable( $format_callback ) ) {
+		$format_callback = '';
+	}
+
 	if ( !isset( $bp->activity->actions->{$component_id} ) || !is_object( $bp->activity->actions->{$component_id} ) ) {
 		$bp->activity->actions->{$component_id} = new stdClass;
 	}
 
 	$bp->activity->actions->{$component_id}->{$key} = apply_filters( 'bp_activity_set_action', array(
-		'key'   => $key,
-		'value' => $value
+		'key'             => $key,
+		'value'           => $value,
+		'format_callback' => $format_callback,
 	), $component_id, $key, $value );
 
 	return true;
@@ -857,8 +865,19 @@ add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' );
 function bp_activity_register_activity_actions() {
 	global $bp;
 
-	bp_activity_set_action( $bp->activity->id, 'activity_update', __( 'Posted a status update', 'buddypress' ) );
-	bp_activity_set_action( $bp->activity->id, 'activity_comment', __( 'Replied to a status update', 'buddypress' ) );
+	bp_activity_set_action(
+		$bp->activity->id,
+		'activity_update',
+		__( 'Posted a status update', 'buddypress' ),
+		'bp_activity_format_activity_action_activity_update'
+	);
+
+	bp_activity_set_action(
+		$bp->activity->id,
+		'activity_comment',
+		__( 'Replied to a status update', 'buddypress' ),
+		'bp_activity_format_activity_action_activity_comment'
+	);
 
 	do_action( 'bp_activity_register_activity_actions' );
 
@@ -867,6 +886,80 @@ function bp_activity_register_activity_actions() {
 }
 add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actions' );
 
+/**
+ * Generate an activity action string for an activity item.
+ *
+ * @param object $activity Activity data object.
+ * @return string|bool Returns false if no callback is found, otherwise returns
+ *         the formatted action string.
+ */
+function bp_activity_generate_action_string( $activity ) {
+	// Check for valid input
+	if ( empty( $activity->component ) || empty( $activity->type ) ) {
+		return false;
+	}
+
+	// Check for registered format callback
+	if ( empty( buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'] ) ) {
+		return false;
+	}
+
+	return call_user_func( buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'], $activity );
+}
+
+/**
+ * Format 'activity_update' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data object.
+ * @return string
+ */
+function bp_activity_format_activity_action_activity_update( $activity ) {
+	$action = sprintf( __( '%s posted an update', 'buddypress' ), bp_activity_get_userlink( $activity ) );
+	return apply_filters( 'bp_activity_new_update_action', $action, $activity );
+}
+
+/**
+ * Format 'activity_comment' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data object.
+ * @return string
+ */
+function bp_activity_format_activity_action_activity_comment( $activity ) {
+	$action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_activity_get_userlink( $activity ) );
+	return apply_filters( 'bp_activity_comment_action', $action, $activity );
+}
+
+/**
+ * Gets the user link for activity items.
+ *
+ * During the activity loop, we have already queried all the userdata for each
+ * activity item, therefore we can reference these items directly instead of
+ * bp_core_get_userlink(), which can lead to unnecessary queries.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data object.
+ * @return string
+ */
+function bp_activity_get_userlink( $activity ) {
+	// $activity->user_nicename is only populated during an activity loop
+	// not during a new BP_Activity_Activity object
+	//
+	// in these cases, fetch userlink as always
+	if ( empty( $activity->user_nicename ) ) {
+		return bp_core_get_userlink( $activity->user_id );
+	}
+
+	$url = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login );
+
+	// apply 'bp_core_get_userlink' just in case
+	return apply_filters( 'bp_core_get_userlink', '<a href="' . $url . '" title="' . $activity->user_fullname . '">' . $activity->user_fullname . '</a>', $activity->user_id );
+}
+
 /******************************************************************************
  * Business functions are where all the magic happens in BuddyPress. They will
  * handle the actual saving or manipulation of information. Usually they will
@@ -1087,7 +1180,6 @@ function bp_activity_add( $args = '' ) {
 	$activity->user_id           = $user_id;
 	$activity->component         = $component;
 	$activity->type              = $type;
-	$activity->action            = $action;
 	$activity->content           = $content;
 	$activity->primary_link      = $primary_link;
 	$activity->item_id           = $item_id;
@@ -1095,6 +1187,7 @@ function bp_activity_add( $args = '' ) {
 	$activity->date_recorded     = $recorded_time;
 	$activity->hide_sitewide     = $hide_sitewide;
 	$activity->is_spam           = $is_spam;
+	$activity->action            = ! empty( $action ) ? $action : bp_activity_generate_action_string( $activity );
 
 	if ( !$activity->save() )
 		return false;
@@ -1150,18 +1243,16 @@ function bp_activity_post_update( $args = '' ) {
 
 	// Record this on the user's profile
 	$from_user_link   = bp_core_get_userlink( $user_id );
-	$activity_action  = sprintf( __( '%s posted an update', 'buddypress' ), $from_user_link );
 	$activity_content = $content;
 	$primary_link     = bp_core_get_userlink( $user_id, false, true );
 
 	// Now write the values
 	$activity_id = bp_activity_add( array(
 		'user_id'      => $user_id,
-		'action'       => apply_filters( 'bp_activity_new_update_action', $activity_action ),
 		'content'      => apply_filters( 'bp_activity_new_update_content', $activity_content ),
 		'primary_link' => apply_filters( 'bp_activity_new_update_primary_link', $primary_link ),
 		'component'    => $bp->activity->id,
-		'type'         => 'activity_update'
+		'type'         => 'activity_update',
 	) );
 
 	$activity_content = apply_filters( 'bp_activity_latest_update_content', $content, $activity_content );
@@ -1230,7 +1321,6 @@ function bp_activity_new_comment( $args = '' ) {
 	// Insert the activity comment
 	$comment_id = bp_activity_add( array(
 		'id'                => $id,
-		'action'            => apply_filters( 'bp_activity_comment_action', sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $user_id ) ) ),
 		'content'           => apply_filters( 'bp_activity_comment_content', $content ),
 		'component'         => buddypress()->activity->id,
 		'type'              => 'activity_comment',
Index: bp-blogs/bp-blogs-activity.php
===================================================================
--- bp-blogs/bp-blogs-activity.php
+++ bp-blogs/bp-blogs-activity.php
@@ -28,17 +28,217 @@ function bp_blogs_register_activity_actions() {
 	}
 
 	if ( is_multisite() ) {
-		bp_activity_set_action( $bp->blogs->id, 'new_blog', __( 'New site created',        'buddypress' ) );
+		bp_activity_set_action(
+			$bp->blogs->id,
+			'new_blog',
+			__( 'New site created', 'buddypress' ),
+			'bp_blogs_format_activity_action_new_blog'
+		);
 	}
 
-	bp_activity_set_action( $bp->blogs->id, 'new_blog_post',    __( 'New post published',      'buddypress' ) );
-	bp_activity_set_action( $bp->blogs->id, 'new_blog_comment', __( 'New post comment posted', 'buddypress' ) );
+	bp_activity_set_action(
+		$bp->blogs->id,
+		'new_blog_post',
+		__( 'New post published', 'buddypress' ),
+		'bp_blogs_format_activity_action_new_blog_post'
+	);
+
+	bp_activity_set_action(
+		$bp->blogs->id,
+		'new_blog_comment',
+		__( 'New post comment posted', 'buddypress' ),
+		'bp_blogs_format_activity_action_new_blog_comment'
+	);
 
 	do_action( 'bp_blogs_register_activity_actions' );
 }
 add_action( 'bp_register_activity_actions', 'bp_blogs_register_activity_actions' );
 
 /**
+ * Format 'new_blog' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param obj $activity Activity data object.
+ */
+function bp_blogs_format_activity_action_new_blog( $activity ) {
+	$blog_url  = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
+	$blog_name = bp_blogs_get_blogmeta( $activity->item_id, 'name' );
+
+	$action = sprintf( __( '%s created the site %s', 'buddypress' ), bp_activity_get_userlink( $activity ), '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
+
+	// Legacy filter - requires the BP_Blogs_Blog object
+	if ( has_filter( 'bp_blogs_activity_created_blog_action' ) ) {
+		$user_blog = BP_Blogs_Blog::get_user_blog( $activity->user_id, $activity->item_id );
+		if ( $user_blog ) {
+			$recorded_blog = new BP_Blogs_Blog( $user_blog );
+		}
+
+		if ( isset( $recorded_blog ) ) {
+			$action = apply_filters( 'bp_blogs_activity_created_blog_action', $action, $recorded_blog, $blog_name, bp_blogs_get_blogmeta( $activity->item_id, 'description' ) );
+		}
+	}
+
+	return apply_filters( 'bp_blogs_format_activity_action_new_blog', $action, $activity );
+}
+
+/**
+ * Format 'new_blog_post' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param obj $activity Activity data object.
+ */
+function bp_blogs_format_activity_action_new_blog_post( $activity ) {
+	$blog_url  = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
+	$blog_name = bp_blogs_get_blogmeta( $activity->item_id, 'name' );
+
+	if ( empty( $blog_url ) || empty( $blog_name ) ) {
+		$blog_url  = get_home_url( $activity->item_id );
+		$blog_name = get_blog_option( $activity->item_id, 'blogname' );
+
+		bp_blogs_update_blogmeta( $activity->item_id, 'url', $blog_url );
+		bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
+	}
+
+	$post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
+
+	$post_title = bp_activity_get_meta( $activity->id, 'post_title' );
+
+	// Should only be empty at the time of post creation
+	if ( empty( $post_title ) ) {
+		switch_to_blog( $activity->item_id );
+
+		$post = get_post( $activity->secondary_item_id );
+		if ( is_a( $post, 'WP_Post' ) ) {
+			$post_title = $post->post_title;
+			bp_activity_update_meta( $activity->id, 'post_title', $post_title );
+		}
+
+		restore_current_blog();
+	}
+
+	$post_link  = '<a href="' . $post_url . '">' . $post_title . '</a>';
+
+	$user_link = bp_activity_get_userlink( $activity );
+
+	if ( is_multisite() ) {
+		$action  = sprintf( __( '%1$s wrote a new post, %2$s, on the site %3$s', 'buddypress' ), $user_link, $post_link, '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
+	} else {
+		$action  = sprintf( __( '%1$s wrote a new post, %2$s', 'buddypress' ), $user_link, $post_link );
+	}
+
+	// Legacy filter - requires the post object
+	if ( has_filter( 'bp_blogs_activity_new_post_action' ) ) {
+		switch_to_blog( $activity->item_id );
+		$post = get_post( $activity->secondary_item_id );
+		restore_current_blog();
+
+		if ( ! empty( $post ) && ! is_wp_error( $post ) ) {
+			$action = apply_filters( 'bp_blogs_activity_new_post_action', $action, $post, $post_url );
+		}
+	}
+
+	return apply_filters( 'bp_blogs_format_activity_action_new_blog_post', $action, $activity );
+}
+
+/**
+ * Format 'new_blog_comment' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param obj $activity Activity data object.
+ */
+function bp_blogs_format_activity_action_new_blog_comment( $activity ) {
+	$blog_url  = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
+	$blog_name = bp_blogs_get_blogmeta( $activity->item_id, 'name' );
+
+	if ( empty( $blog_url ) || empty( $blog_name ) ) {
+		$blog_url  = get_home_url( $activity->item_id );
+		$blog_name = get_blog_option( $activity->item_id, 'blogname' );
+
+		bp_blogs_update_blogmeta( $activity->item_id, 'url', $blog_url );
+		bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
+	}
+
+	$post_url   = bp_activity_get_meta( $activity->id, 'post_url' );
+	$post_title = bp_activity_get_meta( $activity->id, 'post_title' );
+
+	// Should only be empty at the time of post creation
+	if ( empty( $post_url ) || empty( $post_title ) ) {
+		switch_to_blog( $activity->item_id );
+
+		$comment = get_comment( $activity->secondary_item_id );
+
+		if ( ! empty( $comment->comment_post_ID ) ) {
+			$post_url = add_query_arg( 'p', $comment->comment_post_ID, trailingslashit( $blog_url ) );
+			bp_activity_update_meta( $activity->id, 'post_url', $post_url );
+
+			$post = get_post( $comment->comment_post_ID );
+
+			if ( is_a( $post, 'WP_Post' ) ) {
+				$post_title = $post->post_title;
+				bp_activity_update_meta( $activity->id, 'post_title', $post_title );
+			}
+		}
+
+		restore_current_blog();
+	}
+
+	$post_link = '<a href="' . $post_url . '">' . $post_title . '</a>';
+	$user_link = bp_activity_get_userlink( $activity );
+
+	if ( is_multisite() ) {
+		$action  = sprintf( __( '%1$s commented on the post, %2$s, on the site %3$s', 'buddypress' ), $user_link, $post_link, '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
+	} else {
+		$action  = sprintf( __( '%1$s commented on the post, %2$s', 'buddypress' ), $user_link, $post_link );
+	}
+
+	// Legacy filter - requires the comment object
+	if ( has_filter( 'bp_blogs_activity_new_comment_action' ) ) {
+		switch_to_blog( $activity->item_id );
+		$comment = get_comment( $activity->secondary_item_id );
+		restore_current_blog();
+
+		if ( ! empty( $comment ) && ! is_wp_error( $comment ) ) {
+			$action = apply_filters( 'bp_blogs_activity_new_comment_action', $action, $comment, $post_url . '#' . $activity->secondary_item_id );
+		}
+	}
+
+	return apply_filters( 'bp_blogs_format_activity_action_new_blog_comment', $action, $activity );
+}
+
+/**
+ * Fetch data related to blogs at the beginning of an activity loop.
+ *
+ * This reduces database overhead during the activity loop.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param array $activities Array of activity items.
+ * @return array
+ */
+function bp_blogs_prefetch_activity_object_data( $activities ) {
+	if ( empty( $activities ) ) {
+		return $activities;
+	}
+
+	$blog_ids = array();
+
+	foreach ( $activities as $activity ) {
+		if ( buddypress()->blogs->id !== $activity->component ) {
+			continue;
+		}
+
+		$blog_ids[] = $activity->item_id;
+	}
+
+	if ( ! empty( $blog_ids ) ) {
+		bp_blogs_update_meta_cache( $blog_ids );
+	}
+}
+add_filter( 'bp_activity_prefetch_object_data', 'bp_blogs_prefetch_activity_object_data' );
+/**
  * Record blog-related activity to the activity stream.
  *
  * @since BuddyPress (1.0.0)
Index: bp-blogs/bp-blogs-classes.php
===================================================================
--- bp-blogs/bp-blogs-classes.php
+++ bp-blogs/bp-blogs-classes.php
@@ -503,4 +503,25 @@ class BP_Blogs_Blog {
 
 		return false;
 	}
+
+	/**
+	 * Get ID of user-blog link.
+	 *
+	 * @param int $user_id ID of user.
+	 * @param int $blog_id ID of blog.
+	 * @return int|bool ID of user-blog link, or false if not found.
+	 */
+	public static function get_user_blog( $user_id, $blog_id ) {
+		global $bp, $wpdb;
+
+		$user_blog = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->blogs->table_name} WHERE user_id = %d AND blog_id = %d", $user_id, $blog_id ) );
+
+		if ( empty( $user_blog ) ) {
+			$user_blog = false;
+		} else {
+			$user_blog = intval( $user_blog );
+		}
+
+		return $user_blog;
+	}
 }
Index: bp-blogs/bp-blogs-functions.php
===================================================================
--- bp-blogs/bp-blogs-functions.php
+++ bp-blogs/bp-blogs-functions.php
@@ -182,6 +182,7 @@ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
 	if ( !bp_blogs_is_blog_recordable( $blog_id, $user_id ) )
 		return false;
 
+	$url         = get_home_url( $blog_id );
 	$name        = get_blog_option( $blog_id, 'blogname' );
 	$description = get_blog_option( $blog_id, 'blogdescription' );
 
@@ -194,6 +195,7 @@ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
 	$recorded_blog_id       = $recorded_blog->save();
 	$is_recorded            = !empty( $recorded_blog_id ) ? true : false;
 
+	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'url', $url );
 	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'name', $name );
 	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'description', $description );
 	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'last_activity', bp_core_current_time() );
@@ -207,8 +209,7 @@ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
 		// Record this in activity streams
 		bp_blogs_record_activity( array(
 			'user_id'      => $recorded_blog->user_id,
-			'action'       => apply_filters( 'bp_blogs_activity_created_blog_action', sprintf( __( '%s created the site %s', 'buddypress'), bp_core_get_userlink( $recorded_blog->user_id ), '<a href="' . get_home_url( $recorded_blog->blog_id ) . '">' . esc_attr( $name ) . '</a>' ), $recorded_blog, $name, $description ),
-			'primary_link' => apply_filters( 'bp_blogs_activity_created_blog_primary_link', get_home_url( $recorded_blog->blog_id ), $recorded_blog->blog_id ),
+			'primary_link' => apply_filters( 'bp_blogs_activity_created_blog_primary_link', $url, $recorded_blog->blog_id ),
 			'type'         => 'new_blog',
 			'item_id'      => $recorded_blog->blog_id
 		) );
@@ -355,7 +356,6 @@ function bp_blogs_record_post( $post_id, $post, $user_id = 0 ) {
 
 			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',
@@ -450,7 +450,6 @@ function bp_blogs_record_comment( $comment_id, $is_approved = true ) {
 		// Record in activity streams
 		bp_blogs_record_activity( array(
 			'user_id'           => $user_id,
-			'action'            => apply_filters_ref_array( 'bp_blogs_activity_new_comment_action',       array( $activity_action,  &$recorded_comment, $comment_link ) ),
 			'content'           => apply_filters_ref_array( 'bp_blogs_activity_new_comment_content',      array( $activity_content, &$recorded_comment, $comment_link ) ),
 			'primary_link'      => apply_filters_ref_array( 'bp_blogs_activity_new_comment_primary_link', array( $comment_link,     &$recorded_comment                ) ),
 			'type'              => 'new_blog_comment',
Index: bp-friends/bp-friends-activity.php
===================================================================
--- bp-friends/bp-friends-activity.php
+++ bp-friends/bp-friends-activity.php
@@ -92,8 +92,19 @@ function friends_register_activity_actions() {
 	$bp = buddypress();
 
 	// These two added in BP 1.6
-	bp_activity_set_action( $bp->friends->id, 'friendship_accepted', __( 'Friendships accepted', 'buddypress' ) );
-	bp_activity_set_action( $bp->friends->id, 'friendship_created',  __( 'New friendships',      'buddypress' ) );
+	bp_activity_set_action(
+		$bp->friends->id,
+		'friendship_accepted',
+		__( 'Friendships accepted', 'buddypress' ),
+		'bp_friends_format_activity_action_friendship_accepted'
+	);
+
+	bp_activity_set_action(
+		$bp->friends->id,
+		'friendship_created',
+		__( 'New friendships', 'buddypress' ),
+		'bp_friends_format_activity_action_friendship_created'
+	);
 
 	// < BP 1.6 backpat
 	bp_activity_set_action( $bp->friends->id, 'friends_register_activity_action', __( 'New friendship created', 'buddypress' ) );
@@ -103,6 +114,92 @@ function friends_register_activity_actions() {
 add_action( 'bp_register_activity_actions', 'friends_register_activity_actions' );
 
 /**
+ * Format 'friendship_accepted' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data.
+ * @return string $action Formatted activity action.
+ */
+function bp_friends_format_activity_action_friendship_accepted( $activity ) {
+	$initiator_link = bp_activity_get_userlink( $activity );
+	$friend_link    = bp_core_get_userlink( $activity->secondary_item_id );
+
+	$action = sprintf( __( '%1$s and %2$s are now friends', 'buddypress' ), $initiator_link, $friend_link );
+
+	// Backward compatibility for legacy filter
+	// The old filter has the $friendship object passed to it. We want to
+	// avoid having to build this object if it's not necessary
+	if ( has_filter( 'friends_activity_friendship_accepted_action' ) ) {
+		$friendship = new BP_Friends_Friendship( $activity->item_id );
+		$action     = apply_filters( 'friends_activity_friendsip_accepted_action', $action, $friendship );
+	}
+
+	return apply_filters( 'bp_friends_format_activity_action_friendship_accepted', $action, $activity );
+}
+
+/**
+ * Format 'friendship_created' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data.
+ * @return string $action Formatted activity action.
+ */
+function bp_friends_format_activity_action_friendship_created( $activity ) {
+	$initiator_link = bp_activity_get_userlink( $activity );
+	$friend_link    = bp_core_get_userlink( $activity->secondary_item_id );
+
+	$action = sprintf( __( '%1$s and %2$s are now friends', 'buddypress' ), $initiator_link, $friend_link );
+
+	// Backward compatibility for legacy filter
+	// The old filter has the $friendship object passed to it. We want to
+	// avoid having to build this object if it's not necessary
+	if ( has_filter( 'friends_activity_friendship_accepted_action' ) ) {
+		$friendship = new BP_Friends_Friendship( $activity->item_id );
+		$action     = apply_filters( 'friends_activity_friendsip_accepted_action', $action, $friendship );
+	}
+
+	return apply_filters( 'bp_friends_format_activity_action_friendship_created', $action, $activity );
+}
+
+/**
+ * Fetch data related to friended users at the beginning of an activity loop.
+ *
+ * This reduces database overhead during the activity loop.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param array $activities Array of activity items.
+ * @return array
+ */
+function bp_friends_prefetch_activity_object_data( $activities ) {
+	if ( empty( $activities ) ) {
+		return $activities;
+	}
+
+	$friend_ids = array();
+
+	foreach ( $activities as $activity ) {
+		if ( buddypress()->friends->id !== $activity->component ) {
+			continue;
+		}
+
+		$friend_ids[] = $activity->secondary_item_id;
+	}
+
+	if ( ! empty( $friend_ids ) ) {
+		// Fire a user query to prime user caches
+		new BP_User_Query( array(
+			'user_ids'          => $friend_ids,
+			'populate_extras'   => false,
+			'update_meta_cache' => false,
+		) );
+	}
+}
+add_filter( 'bp_activity_prefetch_object_data', 'bp_friends_prefetch_activity_object_data' );
+
+/**
  * Add activity stream items when one members accepts another members request
  * for virtual friendship.
  *
@@ -128,7 +225,6 @@ function bp_friends_friendship_accepted_activity( $friendship_id, $initiator_use
 	friends_record_activity( array(
 		'user_id'           => $initiator_user_id,
 		'type'              => 'friendship_created',
-		'action'            => apply_filters( 'friends_activity_friendship_accepted_action', sprintf( __( '%1$s and %2$s are now friends', 'buddypress' ), $initiator_link, $friend_link ), $friendship ),
 		'item_id'           => $friendship_id,
 		'secondary_item_id' => $friend_user_id
 	) );
@@ -137,7 +233,6 @@ function bp_friends_friendship_accepted_activity( $friendship_id, $initiator_use
 	friends_record_activity( array(
 		'user_id'           => $friend_user_id,
 		'type'              => 'friendship_created',
-		'action'            => apply_filters( 'friends_activity_friendship_accepted_action', sprintf( __( '%1$s and %2$s are now friends', 'buddypress' ), $friend_link, $initiator_link ), $friendship ),
 		'item_id'           => $friendship_id,
 		'secondary_item_id' => $initiator_user_id,
 		'hide_sitewide'     => true // We've already got the first entry site wide
Index: bp-groups/bp-groups-actions.php
===================================================================
--- bp-groups/bp-groups-actions.php
+++ bp-groups/bp-groups-actions.php
@@ -150,7 +150,6 @@ function groups_action_create_group() {
 
 			// Once we compelete all steps, record the group creation in the activity stream.
 			groups_record_activity( array(
-				'action' => apply_filters( 'groups_activity_created_group_action', sprintf( __( '%1$s created the group %2$s', 'buddypress'), bp_core_get_userlink( bp_loggedin_user_id() ), '<a href="' . bp_get_group_permalink( $bp->groups->current_group ) . '">' . esc_attr( $bp->groups->current_group->name ) . '</a>' ) ),
 				'type' => 'created_group',
 				'item_id' => $bp->groups->new_group_id
 			) );
Index: bp-groups/bp-groups-activity.php
===================================================================
--- bp-groups/bp-groups-activity.php
+++ bp-groups/bp-groups-activity.php
@@ -23,8 +23,19 @@ function groups_register_activity_actions() {
 		return false;
 	}
 
-	bp_activity_set_action( $bp->groups->id, 'created_group',   __( 'Created a group',       'buddypress' ) );
-	bp_activity_set_action( $bp->groups->id, 'joined_group',    __( 'Joined a group',        'buddypress' ) );
+	bp_activity_set_action(
+		$bp->groups->id,
+		'created_group',
+		__( 'Created a group', 'buddypress' ),
+		'bp_groups_format_activity_action_created_group'
+	);
+
+	bp_activity_set_action(
+		$bp->groups->id,
+		'joined_group',
+		__( 'Joined a group', 'buddypress' ),
+		'bp_groups_format_activity_action_joined_group'
+	);
 
 	// These actions are for the legacy forums
 	// Since the bbPress plugin also shares the same 'forums' identifier, we also
@@ -39,6 +50,108 @@ function groups_register_activity_actions() {
 add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' );
 
 /**
+ * Format 'created_group' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data object.
+ * @return string
+ */
+function bp_groups_format_activity_action_created_group( $activity ) {
+	$user_link = bp_activity_get_userlink( $activity );
+
+	$group = groups_get_group( array(
+		'group_id'        => $activity->item_id,
+		'populate_extras' => false,
+	) );
+	$group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
+
+	$action = sprintf( __( '%1$s created the group %2$s', 'buddypress'), $user_link, $group_link );
+
+	return apply_filters( 'groups_activity_created_group_action', $action, $activity );
+}
+
+/**
+ * Format 'joined_group' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity data object.
+ * @return string
+ */
+function bp_groups_format_activity_action_joined_group( $activity ) {
+	$user_link = bp_activity_get_userlink( $activity );
+
+	$group = groups_get_group( array(
+		'group_id'        => $activity->item_id,
+		'populate_extras' => false,
+	) );
+	$group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
+
+	$action = sprintf( __( '%1$s joined the group %2$s', 'buddypress' ), $user_link, $group_link );
+
+	// Legacy filters (do not follow parameter patterns of other activity
+	// action filters, and requires apply_filters_ref_array())
+	if ( has_filter( 'groups_activity_membership_accepted_action' ) ) {
+		$action = apply_filters_ref_array( 'groups_activity_membership_accepted_action', array( $action, $user_link, &$group ) );
+	}
+
+	// Another legacy filter
+	if ( has_filter( 'groups_activity_accepted_invite_action' ) ) {
+		$action = apply_filters_ref_array( 'groups_activity_accepted_invite_action', array( $action, $activity->user_id, &$group ) );
+	}
+
+	return apply_filters( 'bp_groups_format_activity_action_joined_group', $action, $activity );
+}
+
+/**
+ * Fetch data related to groups at the beginning of an activity loop.
+ *
+ * This reduces database overhead during the activity loop.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param array $activities Array of activity items.
+ * @return array
+ */
+function bp_groups_prefetch_activity_object_data( $activities ) {
+	$group_ids = array();
+
+	if ( empty( $activities ) ) {
+		return $activities;
+	}
+
+	foreach ( $activities as $activity ) {
+		if ( buddypress()->groups->id !== $activity->component ) {
+			continue;
+		}
+
+		$group_ids[] = $activity->item_id;
+	}
+
+	if ( ! empty( $group_ids ) ) {
+
+		// TEMPORARY - Once the 'populate_extras' issue is solved
+		// in the groups component, we can do this with groups_get_groups()
+		// rather than manually
+		$uncached_ids = array();
+		foreach ( $group_ids as $group_id ) {
+			if ( false === wp_cache_get( $group_id, 'bp_groups' ) ) {
+				$uncached_ids[] = $group_id;
+			}
+		}
+
+		global $wpdb, $bp;
+		$uncached_ids_sql = implode( ',', wp_parse_id_list( $uncached_ids ) );
+		$groups = $wpdb->get_results( "SELECT * FROM {$bp->groups->table_name} WHERE id IN ({$uncached_ids_sql})" );
+		foreach ( $groups as $group ) {
+			wp_cache_set( $group->id, $group, 'bp_groups' );
+		}
+	}
+}
+add_filter( 'bp_activity_prefetch_object_data', 'bp_groups_prefetch_activity_object_data' );
+
+/**
  * Record an activity item related to the Groups component.
  *
  * A wrapper for {@link bp_activity_add()} that provides some Groups-specific
@@ -141,7 +254,7 @@ function bp_groups_membership_accepted_add_activity( $user_id, $group_id ) {
 		'type'    => 'joined_group',
 		'item_id' => $group_id,
 		'user_id' => $user_id
-	) );	
+	) );
 }
 add_action( 'groups_membership_accepted', 'bp_groups_membership_accepted_add_activity', 10, 2 );
 
@@ -192,4 +305,4 @@ function bp_groups_leave_group_delete_recent_activity( $group_id, $user_id ) {
 }
 add_action( 'groups_leave_group',   'bp_groups_leave_group_delete_recent_activity', 10, 2 );
 add_action( 'groups_remove_member', 'bp_groups_leave_group_delete_recent_activity', 10, 2 );
-add_action( 'groups_ban_member',    'bp_groups_leave_group_delete_recent_activity', 10, 2 );
\ No newline at end of file
+add_action( 'groups_ban_member',    'bp_groups_leave_group_delete_recent_activity', 10, 2 );
Index: bp-groups/bp-groups-functions.php
===================================================================
--- bp-groups/bp-groups-functions.php
+++ bp-groups/bp-groups-functions.php
@@ -329,10 +329,9 @@ function groups_join_group( $group_id, $user_id = 0 ) {
 
 	// Record this in activity streams
 	groups_record_activity( array(
-		'action'  => apply_filters( 'groups_activity_joined_group', sprintf( __( '%1$s joined the group %2$s', 'buddypress'), bp_core_get_userlink( $user_id ), '<a href="' . bp_get_group_permalink( $group ) . '">' . esc_attr( bp_get_group_name( $group ) ) . '</a>' ) ),
 		'type'    => 'joined_group',
 		'item_id' => $group_id,
-		'user_id' => $user_id
+		'user_id' => $user_id,
 	) );
 
 	// Modify group meta
Index: bp-groups/bp-groups-screens.php
===================================================================
--- bp-groups/bp-groups-screens.php
+++ bp-groups/bp-groups-screens.php
@@ -49,7 +49,6 @@ function groups_screen_group_invites() {
 			$group = groups_get_group( array( 'group_id' => $group_id ) );
 
 			groups_record_activity( array(
-				'action'  => apply_filters_ref_array( 'groups_activity_accepted_invite_action', array( sprintf( __( '%1$s joined the group %2$s', 'buddypress'), bp_core_get_userlink( bp_loggedin_user_id() ), '<a href="' . bp_get_group_permalink( $group ) . '">' . esc_attr( $group->name ) . '</a>' ), bp_loggedin_user_id(), &$group ) ),
 				'type'    => 'joined_group',
 				'item_id' => $group->id
 			) );
Index: bp-members/bp-members-functions.php
===================================================================
--- bp-members/bp-members-functions.php
+++ bp-members/bp-members-functions.php
@@ -1553,7 +1553,6 @@ function bp_core_new_user_activity( $user ) {
 
 	bp_activity_add( array(
 		'user_id'   => $user_id,
-		'action'    => apply_filters( 'bp_core_activity_registered_member_action', sprintf( __( '%s became a registered member', 'buddypress' ), $userlink ), $user_id ),
 		'component' => 'xprofile',
 		'type'      => 'new_member'
 	) );
Index: bp-xprofile/bp-xprofile-activity.php
===================================================================
--- bp-xprofile/bp-xprofile-activity.php
+++ bp-xprofile/bp-xprofile-activity.php
@@ -17,15 +17,91 @@ function xprofile_register_activity_actions() {
 	global $bp;
 
 	// Register the activity stream actions for this component
-	bp_activity_set_action( $bp->profile->id, 'new_avatar',      __( 'Member changed profile picture', 'buddypress' ) );
-	bp_activity_set_action( $bp->profile->id, 'new_member',      __( 'New member registered', 'buddypress' ) );
-	bp_activity_set_action( $bp->profile->id, 'updated_profile', __( 'Updated Profile', 'buddypress' ) );
+	bp_activity_set_action(
+		$bp->profile->id,
+		'new_avatar',
+		__( 'Member changed profile picture', 'buddypress' ),
+		'bp_xprofile_format_activity_action_new_avatar'
+	);
+
+	bp_activity_set_action(
+		$bp->profile->id,
+		'new_member',
+		__( 'New member registered', 'buddypress' ),
+		'bp_xprofile_format_activity_action_new_member'
+	);
+
+	bp_activity_set_action(
+		$bp->profile->id,
+		'updated_profile',
+		__( 'Updated Profile', 'buddypress' ),
+		'bp_xprofile_format_activity_action_updated_profile'
+	);
 
 	do_action( 'xprofile_register_activity_actions' );
 }
 add_action( 'bp_register_activity_actions', 'xprofile_register_activity_actions' );
 
 /**
+ * Format 'new_avatar' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity object.
+ * @return string
+ */
+function bp_xprofile_format_activity_action_new_avatar( $activity ) {
+	$userlink = bp_activity_get_userlink( $activity );
+	$action   = sprintf( __( '%s changed their profile picture', 'buddypress' ), $userlink );
+
+	// Legacy filter - pass $user_id instead of $activity
+	if ( has_filter( 'bp_xprofile_new_avatar_action' ) ) {
+		$action = apply_filters( 'bp_xprofile_new_avatar_action', $action, $activity->user_id );
+	}
+
+	return apply_filters( 'bp_xprofile_format_activity_action_new_avatar', $action, $activity );
+}
+
+/**
+ * Format 'new_member' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity object.
+ * @return string
+ */
+function bp_xprofile_format_activity_action_new_member( $activity ) {
+	$userlink = bp_activity_get_userlink( $activity );
+	$action   = sprintf( __( '%s became a registered member', 'buddypress' ), $userlink );
+
+	// Legacy filter - pass $user_id instead of $activity
+	if ( has_filter( 'bp_core_activity_registered_member_action' ) ) {
+		$action = apply_filters( 'bp_core_activity_registered_member_action', $action, $activity->user_id );
+	}
+
+	return apply_filters( 'bp_xprofile_format_activity_action_new_member', $action, $activity );
+}
+
+/**
+ * Format 'updated_profile' activity actions.
+ *
+ * @since BuddyPress (2.0.0)
+ *
+ * @param object $activity Activity object.
+ * @return string
+ */
+function bp_xprofile_format_activity_action_updated_profile( $activity ) {
+	// Note for translators: The natural phrasing in English, "Joe updated
+	// his profile", requires that we know Joe's gender, which we don't. If
+	// your language doesn't have this restriction, feel free to use a more
+	// natural translation.
+	$profile_link = trailingslashit( bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . buddypress()->profile->slug );
+	$action	      = sprintf( __( '%1$s&#8217;s profile was updated', 'buddypress' ), '<a href="' . $profile_link . '">' . bp_core_get_user_displayname( $activity->user_id ) . '</a>' );
+
+	return apply_filters( 'bp_xprofile_format_activity_action_updated_profile', $action, $activity );
+}
+
+/**
  * Records activity for the logged in user within the profile component so that
  * it will show in the users activity stream (if installed)
  *
@@ -126,7 +202,6 @@ function bp_xprofile_new_avatar_activity() {
 
 	bp_activity_add( array(
 		'user_id' => $user_id,
-		'action' => apply_filters( 'bp_xprofile_new_avatar_action', sprintf( __( '%s changed their profile picture', 'buddypress' ), $userlink ), $user_id ),
 		'component' => 'profile',
 		'type' => 'new_avatar'
 	) );
@@ -207,17 +282,10 @@ function bp_xprofile_updated_profile_activity( $user_id, $field_ids, $errors, $o
 	}
 
 	// If we've reached this point, assemble and post the activity item
-
-	// Note for translators: The natural phrasing in English, "Joe updated
-	// his profile", requires that we know Joe's gender, which we don't. If
-	// your language doesn't have this restriction, feel free to use a more
-	// natural translation.
 	$profile_link = trailingslashit( bp_core_get_user_domain( $user_id ) . buddypress()->profile->slug );
-	$action = sprintf( __( '%1$s&#8217;s profile was updated', 'buddypress' ), '<a href="' . $profile_link . '">' . bp_core_get_user_displayname( $user_id ) . '</a>' );
 
 	$retval = xprofile_record_activity( array(
 		'user_id'      => $user_id,
-		'action'       => $action,
 		'primary_link' => $profile_link,
 		'component'    => buddypress()->profile->id,
 		'type'         => 'updated_profile',
Index: tests/includes/factory.php
===================================================================
--- tests/includes/factory.php
+++ tests/includes/factory.php
@@ -19,7 +19,6 @@ class BP_UnitTest_Factory_For_Activity extends WP_UnitTest_Factory_For_Thing {
 		parent::__construct( $factory );
 
 		$this->default_generation_definitions = array(
-			'action'       => new WP_UnitTest_Generator_Sequence( 'Activity action %s' ),
 			'component'    => buddypress()->activity->id,
 			'content'      => new WP_UnitTest_Generator_Sequence( 'Activity content %s' ),
 			'primary_link' => 'http://example.com',
Index: tests/testcases/activity/functions.php
===================================================================
--- tests/testcases/activity/functions.php
+++ tests/testcases/activity/functions.php
@@ -540,4 +540,42 @@ Bar!';
 		remove_filter( 'bp_is_username_compatibility_mode', '__return_true' );
 	}
 
+	/**
+	 * @group activity_action
+	 * @group bp_activity_format_activity_action_activity_update
+	 */
+	public function test_bp_activity_format_activity_action_activity_update() {
+		$u = $this->create_user();
+		$a = $this->factory->activity->create( array(
+			'component' => buddypress()->activity->id,
+			'type' => 'activity_update',
+			'user_id' => $u,
+		) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$expected = sprintf( '%s posted an update', bp_core_get_userlink( $u ) );
+
+		$this->assertSame( $expected, $a_obj->action );
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_activity_format_activity_action_activity_comment
+	 */
+	public function test_bp_activity_format_activity_action_activity_comment() {
+		$u = $this->create_user();
+		$a = $this->factory->activity->create( array(
+			'component' => buddypress()->activity->id,
+			'type' => 'activity_comment',
+			'user_id' => $u,
+		) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$expected = sprintf( '%s posted a new activity comment', bp_core_get_userlink( $u ) );
+
+		$this->assertSame( $expected, $a_obj->action );
+	}
+
 }
Index: tests/testcases/xprofile/activity.php
===================================================================
--- tests/testcases/xprofile/activity.php
+++ tests/testcases/xprofile/activity.php
@@ -270,6 +270,95 @@ class BP_Tests_XProfile_Activity extends BP_UnitTestCase {
 		$this->assertTrue( bp_xprofile_updated_profile_activity( $d['u'], array( $d['f'] ), false, $old_values, $new_values ) );
 	}
 
+	/**
+	 * @group activity_action
+	 * @group bp_xprofile_format_activity_action_new_avatar
+	 */
+	public function test_bp_xprofile_format_activity_action_new_avatar() {
+		$u = $this->create_user();
+		$a = $this->factory->activity->create( array(
+			'component' => buddypress()->profile->id,
+			'type' => 'new_avatar',
+			'user_id' => $u,
+		) );
+
+		$expected = sprintf( __( '%s changed their profile picture', 'buddypress' ), bp_core_get_userlink( $u ) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$this->assertSame( $expected, $a_obj->action );
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_xprofile_format_activity_action_new_member
+	 */
+	public function test_bp_xprofile_format_activity_action_new_member_xprofile_on() {
+		$active = bp_is_active( 'xprofile' );
+		buddypress()->active_components['xprofile'] = '1';
+
+		$u = $this->create_user();
+		$a = $this->factory->activity->create( array(
+			'component' => buddypress()->profile->id,
+			'type' => 'new_member',
+			'user_id' => $u,
+		) );
+
+		$expected = sprintf( __( '%s became a registered member', 'buddypress' ), bp_core_get_userlink( $u ) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$this->assertSame( $expected, $a_obj->action );
+
+		if ( ! $active ) {
+			unset( buddypress()->active_components['xprofile'] );
+		}
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_xprofile_format_activity_action_new_member
+	 */
+	public function test_bp_xprofile_format_activity_action_new_member_xprofile_off() {
+		$active = bp_is_active( 'xprofile' );
+		unset( buddypress()->active_components['xprofile'] );
+
+		$u = $this->create_user();
+		$a = $this->factory->activity->create( array(
+			'component' => buddypress()->profile->id,
+			'type' => 'new_member',
+			'user_id' => $u,
+		) );
+
+		$expected = sprintf( __( '%s became a registered member', 'buddypress' ), bp_core_get_userlink( $u ) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$this->assertSame( $expected, $a_obj->action );
+
+		if ( $active ) {
+			buddypress()->active_components['xprofile'] = '1';
+		}
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_xprofile_format_activity_action_updated_profile
+	 */
+	public function test_bp_xprofile_format_activity_action_updated_profile() {
+		$u = $this->create_user();
+		$a = $this->factory->activity->create( array(
+			'component' => buddypress()->profile->id,
+			'type' => 'updated_profile',
+			'user_id' => $u,
+		) );
+
+		$expected = sprintf( __( '%s&#8217;s profile was updated', 'buddypress' ), '<a href="' . bp_core_get_user_domain( $u ) . buddypress()->profile->slug . '/">' . bp_core_get_user_displayname( $u ) . '</a>' );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$this->assertSame( $expected, $a_obj->action );
+	}
 
 	protected function setup_updated_profile_data() {
 		$this->updated_profile_data['u'] = $this->create_user();
