diff --git bp-activity/bp-activity-classes.php bp-activity/bp-activity-classes.php
index eca743a..0084a8a 100644
--- bp-activity/bp-activity-classes.php
+++ bp-activity/bp-activity-classes.php
@@ -442,6 +442,9 @@ class BP_Activity_Activity {
 		if ( $activities && $display_comments )
 			$activities = BP_Activity_Activity::append_comments( $activities, $spam );
 
+		// Generate action string
+		$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 )
@@ -569,6 +572,31 @@ class BP_Activity_Activity {
 	}
 
 	/**
+	 * 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 ) {
+			// Load action_data, the cached strings that will be
+			// used by the callback to generate the action strings
+			$activity->action_data = bp_activity_get_meta( $activity->id, 'action_data' );
+
+			$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
diff --git bp-activity/bp-activity-functions.php bp-activity/bp-activity-functions.php
index 8599d50..1beb746 100644
--- 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;
@@ -860,7 +868,13 @@ 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_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' ) );
 
 	do_action( 'bp_activity_register_activity_actions' );
@@ -870,6 +884,40 @@ 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 ) || empty( $activity->action_data ) ) {
+		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 ) {
+	$user_link = isset( $activity->action_data['user_link'] ) ? $activity->action_data['user_link'] : '';
+	return sprintf( __( '%s posted an update', 'buddypress' ), $user_link );
+}
+
 /******************************************************************************
  * Business functions are where all the magic happens in BuddyPress. They will
  * handle the actual saving or manipulation of information. Usually they will
@@ -1062,6 +1110,7 @@ function bp_activity_add( $args = '' ) {
 		'id'                => false, // Pass an existing activity ID to update an existing entry.
 
 		'action'            => '',    // The activity action - e.g. "Jon Doe posted an update"
+		'action_data'       => array(),
 		'content'           => '',    // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!"
 
 		'component'         => false, // The name/ID of the component e.g. groups, profile, mycomponent
@@ -1090,7 +1139,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;
@@ -1098,10 +1146,15 @@ function bp_activity_add( $args = '' ) {
 	$activity->date_recorded     = $recorded_time;
 	$activity->hide_sitewide     = $hide_sitewide;
 	$activity->is_spam           = $is_spam;
+	$activity->action_data       = $action_data;
+	$activity->action            = ! empty( $action ) ? $action : bp_activity_generate_action_string( $activity );
 
 	if ( !$activity->save() )
 		return false;
 
+	if ( ! empty( $action_data ) )
+		bp_activity_update_meta( $activity->id, 'action_data', $action_data );
+
 	// If this is an activity comment, rebuild the tree
 	if ( 'activity_comment' == $activity->type )
 		BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id );
@@ -1153,18 +1206,19 @@ 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',
+		'action_data'  => array(
+			'user_link' => $from_user_link,
+		),
 	) );
 
 	$activity_content = apply_filters( 'bp_activity_latest_update_content', $content, $activity_content );
diff --git bp-groups/bp-groups-activity.php bp-groups/bp-groups-activity.php
index 324064c..aefb5f1 100644
--- bp-groups/bp-groups-activity.php
+++ bp-groups/bp-groups-activity.php
@@ -24,7 +24,12 @@ function groups_register_activity_actions() {
 	}
 
 	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,
+		'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 +44,20 @@ function groups_register_activity_actions() {
 add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' );
 
 /**
+ * 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  = isset( $activity->action_data['user_link'] ) ? $activity->action_data['user_link'] : '';
+	$group_link = isset( $activity->action_data['group_link'] ) ? $activity->action_data['group_link'] : '';
+	return sprintf( __( '%1$s joined the group %2$s', 'buddypress' ), $user_link, $group_link );
+}
+
+/**
  * Record an activity item related to the Groups component.
  *
  * A wrapper for {@link bp_activity_add()} that provides some Groups-specific
diff --git bp-groups/bp-groups-functions.php bp-groups/bp-groups-functions.php
index 251ae96..3234c24 100644
--- bp-groups/bp-groups-functions.php
+++ bp-groups/bp-groups-functions.php
@@ -329,10 +329,13 @@ 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,
+		'action_data' => array(
+			'user_link' => bp_core_get_userlink( $user_id ),
+			'group_link' => '<a href="' . bp_get_group_permalink( $group ) . '">' . esc_attr( bp_get_group_name( $group ) ) . '</a>',
+		),
 	) );
 
 	// Modify group meta
