diff --git src/bp-activity/bp-activity-actions.php src/bp-activity/bp-activity-actions.php
index 2a04601..17f23e6 100644
--- src/bp-activity/bp-activity-actions.php
+++ src/bp-activity/bp-activity-actions.php
@@ -766,3 +766,47 @@ function bp_ajax_get_suggestions() {
 	wp_send_json_success( $results );
 }
 add_action( 'wp_ajax_bp_get_suggestions', 'bp_ajax_get_suggestions' );
+
+/**
+ * Detect a change in post type status, and initiate an activity update if necessary.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @todo Support untrashing better.
+ *
+ * @param string $new_status New status for the post.
+ * @param string $old_status Old status for the post.
+ * @param object $post       Post data.
+ */
+function bp_activity_catch_transition_post_type_status( $new_status, $old_status, $post ) {
+	if ( ! post_type_supports( $post->post_type, 'buddypress-activity' ) ) {
+		return;
+	}
+
+	// This is an edit.
+	if ( $new_status === $old_status ) {
+		// An edit of an existing post should update the existing activity item.
+		if ( $new_status == 'publish' ) {
+			bp_activity_post_type_update( $post );
+		}
+
+		return;
+	}
+
+	// Publishing a previously unpublished post.
+	if ( 'publish' === $new_status ) {
+		// Untrashing the post type - nothing here yet.
+		if ( 'trash' == $old_status ) {
+			do_action( 'bp_activity_post_type_untrash_' . $post->post_type, $post );
+		} else {
+			// Record the post.
+			bp_activity_post_type_publish( $post->ID, $post );
+		}
+
+	// Unpublishing a previously published post.
+	} else if ( 'publish' === $old_status ) {
+		// Some form of pending status - only remove the activity entry
+		bp_activity_post_type_unpublish( $post->ID, $post );
+	}
+}
+add_action( 'transition_post_status', 'bp_activity_catch_transition_post_type_status', 10, 3 );
diff --git src/bp-activity/bp-activity-admin.php src/bp-activity/bp-activity-admin.php
index 5eb6c48..4386b28 100644
--- src/bp-activity/bp-activity-admin.php
+++ src/bp-activity/bp-activity-admin.php
@@ -798,7 +798,7 @@ function bp_activity_admin_get_activity_actions() {
 	$actions  = array();
 
 	// Walk through the registered actions, and build an array of actions/values.
-	foreach ( buddypress()->activity->actions as $action ) {
+	foreach ( bp_activity_get_actions() as $action ) {
 		$action = array_values( (array) $action );
 
 		for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
@@ -831,7 +831,7 @@ function bp_activity_admin_edit_metabox_type( $item ) {
 	$selected = $item->type;
 
 	// Walk through the registered actions, and build an array of actions/values.
-	foreach ( $bp->activity->actions as $action ) {
+	foreach ( bp_activity_get_actions() as $action ) {
 		$action = array_values( (array) $action );
 
 		for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
@@ -1365,7 +1365,7 @@ class BP_Activity_List_Table extends WP_List_Table {
 		$selected = ( ! empty( $_REQUEST['activity_type'] ) ) ? $_REQUEST['activity_type'] : '';
 
 		// Get the actions
-		$activity_actions = buddypress()->activity->actions; ?>
+		$activity_actions = bp_activity_get_actions(); ?>
 
 		<div class="alignleft actions">
 			<select name="activity_type">
diff --git src/bp-activity/bp-activity-functions.php src/bp-activity/bp-activity-functions.php
index fcbbc07..05231fc 100644
--- src/bp-activity/bp-activity-functions.php
+++ src/bp-activity/bp-activity-functions.php
@@ -316,17 +316,17 @@ function bp_activity_get_userid_from_mentionname( $mentionname ) {
  *
  * @since BuddyPress (1.1.0)
  *
- * @param string $component_id The unique string ID of the component.
- * @param string $type The action type.
- * @param string $description The action description.
- * @param callable $format_callback Callback for formatting the action string.
- * @param string $label String to describe this action in the activity stream
- *        filter dropdown.
- * @param array $context Activity stream contexts where the filter should appear.
- *        'activity', 'member', 'member_groups', 'group'
+ * @param  string   $component_id    The unique string ID of the component.
+ * @param  string   $type            The action type.
+ * @param  string   $description     The action description.
+ * @param  callable $format_callback Callback for formatting the action string.
+ * @param  string   $label           String to describe this action in the activity stream filter dropdown.
+ * @param  array    $context         Optional. Activity stream contexts where the filter should appear.
+ *                                   Values: 'activity', 'member', 'member_groups', 'group'
+ * @param  int      $position        Optional. The position of the action when listed in dropdowns.
  * @return bool False if any param is empty, otherwise true.
  */
-function bp_activity_set_action( $component_id, $type, $description, $format_callback = false, $label = false, $context = array() ) {
+function bp_activity_set_action( $component_id, $type, $description, $format_callback = false, $label = false, $context = array(), $position = 0 ) {
 	$bp = buddypress();
 
 	// Return false if any of the above values are not set
@@ -368,12 +368,198 @@ function bp_activity_set_action( $component_id, $type, $description, $format_cal
 		'format_callback' => $format_callback,
 		'label'           => $label,
 		'context'         => $context,
+		'position'        => $position,
 	), $component_id, $type, $description, $format_callback, $label, $context );
 
 	return true;
 }
 
 /**
+ * Set tracking arguments for a given post type.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @global $wp_post_types
+ *
+ * @param string $post_type The name of the post type, as registered with WordPress. Eg 'post' or 'page'.
+ * @param array  $args {
+ *     An associative array of tracking parameters. All items are optional.
+ *
+ *     @type string   $bp_activity_admin_filter String to use in the Dashboard > Activity dropdown.
+ *     @type string   $bp_activity_front_filter String to use in frontend dropdown.
+ *     @type string   $bp_activity_new_post     String format to use for generating the activity action. Should be a
+ *                                              translatable string where %1$s is replaced by a user link and %2$s is
+ *                                              the URL of the newly created post.
+ *     @type string   $bp_activity_new_post_ms  String format to use for generating the activity action on Multisite.
+ *                                              Should be a translatable string where %1$s is replaced by a user link,
+ *                                              %2$s is the URL of the newly created post, and %3$s is a link to
+ *                                              the site.
+ *     @type string   $component_id             ID of the BuddyPress component to associate the activity item.
+ *     @type string   $action_id                Value for the 'type' param of the new activity item.
+ *     @type callable $format_callback          Callback for formatting the activity action string.
+ *                                              Default: 'bp_activity_format_activity_action_custom_post_type_post'.
+ *     @type array    $contexts                 The directory contexts in which the filter will show.
+ *                                              Default: array( 'activity' ),
+ *     @type array    $position                 Position of the item in filter dropdowns.
+ *     @type string   $singular                 Singular, translatable name of the post type item. If no value is
+ *                                              provided, it's pulled from the 'singular_name' of the post type.
+ *     @type bool     $activity_comment         Whether to allow comments on the activity items. Defaults to true if
+ *                                              the post type does not natively support comments, otherwise false.
+ * }
+ */
+function bp_activity_set_post_type_tracking_args( $post_type = '', $args = array() ) {
+	global $wp_post_types;
+	$bp = buddypress();
+
+	if ( empty( $wp_post_types[ $post_type ] ) || ! post_type_supports( $post_type, 'buddypress-activity' ) || ! is_array( $args ) ) {
+		return false;
+	}
+
+	// Labels are loaded into the post type object.
+	foreach ( array( 'bp_activity_admin_filter', 'bp_activity_front_filter', 'bp_activity_new_post', 'bp_activity_new_post_ms' ) as $label_type ) {
+		if ( ! empty( $args[ $label_type ] ) ) {
+			$wp_post_types[ $post_type ]->labels->{$label_type} = $args[ $label_type ];
+			unset( $args[ $post_type ] );
+		}
+	}
+
+	// If there are any additional args, put them in the bp_activity attribute of the post type.
+	if ( ! empty( $args ) ) {
+		$wp_post_types[ $post_type ]->bp_activity = $args;
+	}
+}
+
+/**
+ * Get tracking arguments for a specific post type.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @param  string $post_type Name of the post type
+ * @return object The tracking arguments of the post type.
+ */
+function bp_activity_get_post_type_tracking_args( $post_type ) {
+	if ( ! post_type_supports( $post_type, 'buddypress-activity' ) ) {
+		return false;
+	}
+
+	$post_type_object = get_post_type_object( $post_type );
+
+	$post_type_activity = array(
+		'component_id'      => buddypress()->activity->id,
+		'action_id'         => 'new_' . $post_type,
+		'format_callback'   => 'bp_activity_format_activity_action_custom_post_type_post',
+		'front_filter'      => $post_type_object->labels->name,
+		'contexts'          => array( 'activity' ),
+		'position'          => 0,
+		'singular'          => strtolower( $post_type_object->labels->singular_name ),
+		'activity_commment' => ! post_type_supports( $post_type, 'comments' ),
+	);
+
+	if ( ! empty( $post_type_object->bp_activity ) ) {
+		$post_type_activity = bp_parse_args( (array) $post_type_object->bp_activity, $post_type_activity, $post_type . '_tracking_args' );
+	}
+
+	$post_type_activity = (object) $post_type_activity;
+
+	// Try to get the admin filter from the post type labels.
+	if ( ! empty( $post_type_object->labels->bp_activity_admin_filter ) ) {
+		$post_type_activity->admin_filter = $post_type_object->labels->bp_activity_admin_filter;
+
+	// Fall back to a generic name.
+	} else {
+		$post_type_activity->admin_filter = _x( 'New item published', 'Post Type generic activity post admin filter', 'buddypress' );
+	}
+
+	// Check for the front filter in the post type labels.
+	if ( ! empty( $post_type_object->labels->bp_activity_front_filter ) ) {
+		$post_type_activity->front_filter = $post_type_object->labels->bp_activity_front_filter;
+	}
+
+	// Try to get the action for new post type action on non-multisite installations.
+	if ( ! empty( $post_type_object->labels->bp_activity_new_post ) ) {
+		$post_type_activity->new_post_type_action = $post_type_object->labels->bp_activity_new_post;
+	}
+
+	// Try to get the action for new post type action on multisite installations.
+	if ( ! empty( $post_type_object->labels->bp_activity_new_post_ms ) ) {
+		$post_type_activity->new_post_type_action_ms = $post_type_object->labels->bp_activity_new_post_ms;
+	}
+
+	return apply_filters( 'bp_activity_get_post_type_tracking_args', $post_type_activity, $post_type );
+}
+
+/**
+ * Get tracking arguments for all post types.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @return array List of post types with their tracking arguments.
+ */
+function bp_activity_get_post_types_tracking_args() {
+	// Fetch all public post types
+	$post_types = get_post_types( array( 'public' => true ), 'names' );
+
+	$post_types_tracking_args = array();
+
+	foreach ( $post_types as $post_type ) {
+		$track_post_type = bp_activity_get_post_type_tracking_args( $post_type );
+
+		if ( ! empty( $track_post_type ) ) {
+			$post_types_tracking_args[ $track_post_type->action_id ] = $track_post_type;
+		}
+
+	}
+
+	return apply_filters( 'bp_activity_get_post_types_tracking_args', $post_types_tracking_args );
+}
+
+/**
+ * Get all components' activity actions, sorted by their position attribute.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @return object actions ordered by their position
+ */
+function bp_activity_get_actions() {
+	$bp = buddypress();
+
+	$post_types = bp_activity_get_post_types_tracking_args();
+
+	// Create the actions for the post types, if they haven't already been created.
+	if ( ! empty( $post_types ) ) {
+		foreach ( $post_types as $post_type ) {
+			if ( isset( $bp->activity->actions->{$post_type->component_id}->{$post_type->action_id} ) ) {
+				continue;
+			}
+
+			bp_activity_set_action(
+				$post_type->component_id,
+				$post_type->action_id,
+				$post_type->admin_filter,
+				$post_type->format_callback,
+				$post_type->front_filter,
+				$post_type->contexts,
+				$post_type->position
+			);
+		}
+	}
+
+	// Sort the actions by their position within each component.
+	foreach ( $bp->activity->actions as $component => $actions ) {
+		$actions = (array) $actions;
+		$temp = bp_sort_by_key( $actions, 'position', 'num' );
+
+		// Restore keys.
+		$bp->activity->actions->{$component} = new stdClass;
+		foreach ( $temp as $key_ordered ) {
+			$bp->activity->actions->{$component}->{$key_ordered['key']} = $key_ordered;
+		}
+	}
+
+	return $bp->activity->actions;
+}
+
+/**
  * Retreive the current action from a component and key.
  *
  * @since BuddyPress (1.1.0)
@@ -391,19 +577,22 @@ function bp_activity_get_action( $component_id, $key ) {
 		return false;
 	}
 
-	$bp     = buddypress();
-	$retval = isset( $bp->activity->actions->{$component_id}->{$key} )
-		? $bp->activity->actions->{$component_id}->{$key}
-		: false;
+	$bp      = buddypress();
+	$actions = bp_activity_get_actions();
+
+	$retval = false;
+	if ( isset( $actions->{$component_id}->{$key} ) ) {
+		$retval = $actions->{$component_id}->{$key};
+	}
 
 	/**
 	 * Filters the current action by component and key.
 	 *
 	 * @since BuddyPress (1.1.0)
 	 *
-	 * @param string|bool $retval The action key.
+	 * @param string|bool $retval       The action key.
 	 * @param string      $component_id The unique string ID of the component.
-	 * @param string      $key The action key.
+	 * @param string      $key          The action key.
 	 */
 	return apply_filters( 'bp_activity_get_action', $retval, $component_id, $key );
 }
@@ -419,7 +608,7 @@ function bp_activity_get_types() {
 	$actions  = array();
 
 	// Walk through the registered actions, and build an array of actions/values.
-	foreach ( buddypress()->activity->actions as $action ) {
+	foreach ( bp_activity_get_actions() as $action ) {
 		$action = array_values( (array) $action );
 
 		for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
@@ -1130,6 +1319,63 @@ function bp_activity_format_activity_action_activity_comment( $action, $activity
 	return apply_filters( 'bp_activity_comment_action', $action, $activity );
 }
 
+/**
+ * Format activity action strings for custom post types.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @param string $action   Static activity action.
+ * @param object $activity Activity data object.
+ * @return string
+ */
+function bp_activity_format_activity_action_custom_post_type_post( $action, $activity ) {
+	$bp = buddypress();
+
+	// Fetch all the tracked post types once.
+	if ( empty( $bp->activity->track ) ) {
+		$bp->activity->track = bp_activity_get_post_types_tracking_args();
+	}
+
+	if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) {
+		return $action;
+	}
+
+	$user_link = bp_core_get_userlink( $activity->user_id );
+	$blog_url  = get_home_url( $activity->item_id );
+
+	if ( empty( $activity->post_url ) ) {
+		$post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
+	} else {
+		$post_url = $activity->post_url;
+	}
+
+	if ( is_multisite() ) {
+		$blog_link = '<a href="' . $blog_url . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>';
+
+		if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action_ms ) ) {
+			$action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action_ms, $user_link, $post_url, $blog_link );
+		} else {
+			$action = sprintf( _x( '%1$s wrote a new <a href="%2$s">item</a>, on the site %3$s', 'Activity Custom Post Type post action', 'buddypress' ), $user_link, $post_url, $blog_link );
+		}
+	} else {
+		if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action ) ) {
+			$action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action, $user_link, $post_url );
+		} else {
+			$action = sprintf( _x( '%1$s wrote a new <a href="%2$s">item</a>', 'Activity Custom Post Type post action', 'buddypress' ), $user_link, $post_url );
+		}
+	}
+
+	/**
+	 * Filters the formatted custom post type activity post action string.
+	 *
+	 * @since BuddyPress (2.2.0)
+	 *
+	 * @param string               $action Activity action string value.
+	 * @param BP_Activity_Activity $activity Activity item object.
+	 */
+	return apply_filters( 'bp_activity_custom_post_type_post_action', $action, $activity );
+}
+
 /******************************************************************************
  * Business functions are where all the magic happens in BuddyPress. They will
  * handle the actual saving or manipulation of information. Usually they will
@@ -1513,6 +1759,235 @@ function bp_activity_post_update( $args = '' ) {
 }
 
 /**
+ * Create an activity item for a newly published post type post.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @param  int      $post_id ID of the new post.
+ * @param  WP_Post  $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 ) {
+	$bp = buddypress();
+
+	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;
+	}
+
+	// Let components/plugins bail before the activity is posted.
+	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,
+	);
+
+	// Remove large images and replace them with just one image thumbnail.
+	if ( ! empty( $activity_args['content'] ) ) {
+		$activity_args['content'] = bp_activity_thumbnail_content_images( $activity_args['content'], $activity_args['primary_link'], $activity_args );
+	}
+
+	if ( ! empty( $activity_args['content'] ) ) {
+		// Create the excerpt.
+		$activity_excerpt = bp_create_excerpt( $activity_args['content'] );
+
+		// Backward compatibility filter for blog posts.
+		if ( 'blogs' == $activity_post_object->component_id )  {
+			$activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_excerpt, $activity_args['content'], $activity_args, $post->post_type );
+		} else {
+			$activity_args['content'] = $activity_excerpt;
+		}
+	}
+
+	// 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 );
+
+	do_action( 'bp_activity_post_type_published', $activity_id, $post, $activity_args );
+
+	return $activity_id;
+}
+
+/**
+ * Update the activity item for a custom post type entry.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @param  WP_Post $post Post item.
+ * @return bool    True on success, false on failure.
+ */
+function bp_activity_post_type_update( $post = null ) {
+	$bp = buddypress();
+
+	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 ( empty( $activity_post_object->action_id ) ) {
+		return;
+	}
+
+	$activity_id = bp_activity_get_activity_id( array(
+		'component'         => $activity_post_object->component_id,
+		'item_id'           => get_current_blog_id(),
+		'secondary_item_id' => $post->ID,
+		'type'              => $activity_post_object->action_id,
+	) );
+
+	// Activity ID doesn't exist, so stop!
+	if ( empty( $activity_id ) ) {
+		return;
+	}
+
+	// Delete the activity if the post was updated with a password.
+	if ( ! empty( $post->post_password ) ) {
+		bp_activity_delete( array( 'id' => $activity_id ) );
+	}
+
+	// Update the activity entry.
+	$activity = new BP_Activity_Activity( $activity_id );
+
+	if ( ! empty( $post->post_content ) ) {
+		// Make sure to update the thumbnail image.
+		$post_content = bp_activity_thumbnail_content_images( $post->post_content, $activity->primary_link, (array) $activity );
+
+		// Generate an excerpt.
+		$activity_excerpt = bp_create_excerpt( $post_content );
+
+		// Backward compatibility filter for the blogs component.
+		if ( 'blogs' == $activity_post_object->component_id ) {
+			$activity->content = apply_filters( 'bp_blogs_record_activity_content', $activity_excerpt, $post_content, (array) $activity, $post->post_type );
+		} else {
+			$activity->content = $activity_excerpt;
+		}
+	}
+
+	// Save the updated activity.
+	$updated = $activity->save();
+
+	do_action( 'bp_activity_post_type_updated', $post, $activity );
+
+	return $updated;
+}
+
+/**
+ * Unpublish an activity for the custom post type.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @param  int     $post_id ID of the post being unpublished.
+ * @param  WP_Post $post    Post object.
+ * @return bool    True on success, false on failure.
+ */
+function bp_activity_post_type_unpublish( $post_id = 0, $post = null ) {
+	$bp = buddypress();
+
+	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 ( empty( $activity_post_object->action_id ) ) {
+		return;
+	}
+
+	if ( empty( $post_id ) ) {
+		$post_id = $post->ID;
+	}
+
+	$delete_activity_args = array(
+		'item_id'           => get_current_blog_id(),
+		'secondary_item_id' => $post_id,
+		'component'         => $activity_post_object->component_id,
+		'type'              => $activity_post_object->action_id,
+		'user_id'           => false,
+	);
+
+	$deleted = bp_activity_delete_by_item_id( $delete_activity_args );
+
+	do_action( 'bp_activity_post_type_unpublished', $delete_activity_args, $post, $deleted );
+
+	return $deleted;
+}
+
+/**
  * Add an activity comment.
  *
  * @since BuddyPress (1.2.0)
@@ -1988,6 +2463,7 @@ function bp_activity_delete_comment( $activity_id, $comment_id ) {
  * @return string $link Permalink for the activity item.
  */
 function bp_activity_get_permalink( $activity_id, $activity_obj = false ) {
+	$bp = buddypress();
 
 	if ( empty( $activity_obj ) ) {
 		$activity_obj = new BP_Activity_Activity( $activity_id );
@@ -1997,7 +2473,18 @@ function bp_activity_get_permalink( $activity_id, $activity_obj = false ) {
 		$activity_obj = $activity_obj->current_comment;
 	}
 
-	if ( 'new_blog_post' == $activity_obj->type || 'new_blog_comment' == $activity_obj->type || 'new_forum_topic' == $activity_obj->type || 'new_forum_post' == $activity_obj->type ) {
+	$use_primary_links = array(
+		'new_blog_post',
+		'new_blog_comment',
+		'new_forum_topic',
+		'new_forum_post',
+	);
+
+	if ( ! empty( $bp->activity->track ) ) {
+		$use_primary_links = array_merge( $use_primary_links, array_keys( $bp->activity->track ) );
+	}
+
+	if ( false !== array_search( $activity_obj->type, $use_primary_links ) ) {
 		$link = $activity_obj->primary_link;
 	} else {
 		if ( 'activity_comment' == $activity_obj->type ) {
diff --git src/bp-activity/bp-activity-template.php src/bp-activity/bp-activity-template.php
index d51c2f3..9035a86 100644
--- src/bp-activity/bp-activity-template.php
+++ src/bp-activity/bp-activity-template.php
@@ -3315,30 +3315,38 @@ function bp_activity_filter_links( $args = false ) {
  */
 function bp_activity_can_comment() {
 	global $activities_template;
+	$bp = buddypress();
 
 	// Assume activity can be commented on
 	$can_comment = true;
 
 	// Determine ability to comment based on activity action name
 	$activity_action = bp_get_activity_action_name();
-	switch ( $activity_action ) {
-
-		// Maybe turn off for blog and forum updates
-		case 'new_blog_post'    :
-		case 'new_blog_comment' :
-		case 'new_forum_topic'  :
-		case 'new_forum_post'   :
-			if ( ! empty( $activities_template->disable_blogforum_replies ) ) {
-				$can_comment = false;
-			}
-			break;
 
-		// Turn off for activity comments
-		case 'activity_comment' :
-			$can_comment = false;
-			break;
+	$turn_off = 0;
+	if ( ! empty( $activities_template->disable_blogforum_replies ) ) {
+		$turn_off = 1;
 	}
 
+	$maybe_turn_off = array_fill_keys( array(
+		'new_blog_post',
+		'new_blog_comment',
+		'new_forum_topic',
+		'new_forum_post',
+	), $turn_off );
+
+	$maybe_turn_off['activity_comment'] = 1;
+
+	if ( ! empty( $bp->activity->track ) ) {
+		foreach ( array_keys( $bp->activity->track ) as $action  ) {
+			if ( empty( $bp->activity->track[ $action ]['activity_commment'] ) ) {
+				$maybe_turn_off[ $action ] = $turn_off;
+			}
+		}
+	}
+
+	$can_comment = empty( $maybe_turn_off[ $activity_action ] );
+
 	/**
 	 * Filters whether a comment can be made on an activity item.
 	 *
@@ -4367,7 +4375,7 @@ function bp_activity_show_filters( $context = '' ) {
 
 		// Walk through the registered actions, and prepare an the
 		// select box options.
-		foreach ( buddypress()->activity->actions as $actions ) {
+		foreach ( bp_activity_get_actions() as $actions ) {
 			foreach ( $actions as $action ) {
 				if ( ! in_array( $context, (array) $action['context'] ) ) {
 					continue;
diff --git src/bp-blogs/bp-blogs-activity.php src/bp-blogs/bp-blogs-activity.php
index 8b67a16..0a43935 100644
--- src/bp-blogs/bp-blogs-activity.php
+++ src/bp-blogs/bp-blogs-activity.php
@@ -33,27 +33,23 @@ function bp_blogs_register_activity_actions() {
 			'new_blog',
 			__( 'New site created', 'buddypress' ),
 			'bp_blogs_format_activity_action_new_blog',
-			__( 'New Sites', 'buddypress' )
+			__( 'New Sites', 'buddypress' ),
+			0
 		);
 	}
 
-	bp_activity_set_action(
-		$bp->blogs->id,
-		'new_blog_post',
-		__( 'New post published', 'buddypress' ),
-		'bp_blogs_format_activity_action_new_blog_post',
-		__( 'Posts', 'buddypress' ),
-		array( 'activity', 'member' )
-	);
-
-	bp_activity_set_action(
-		$bp->blogs->id,
-		'new_blog_comment',
-		__( 'New post comment posted', 'buddypress' ),
-		'bp_blogs_format_activity_action_new_blog_comment',
-		__( 'Comments', 'buddypress' ),
-		array( 'activity', 'member' )
-	);
+	// Only add the comment type if the 'post' post type is trackable
+	if ( post_type_supports( 'post', 'buddypress-activity' ) ) {
+		bp_activity_set_action(
+			$bp->blogs->id,
+			'new_blog_comment',
+			__( 'New post comment posted', 'buddypress' ),
+			'bp_blogs_format_activity_action_new_blog_comment',
+			__( 'Comments', 'buddypress' ),
+			array( 'activity', 'member' ),
+			10
+		);
+	}
 
 	do_action( 'bp_blogs_register_activity_actions' );
 }
@@ -108,9 +104,17 @@ function bp_blogs_format_activity_action_new_blog_post( $action, $activity ) {
 		bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
 	}
 
-	$post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
+	if ( empty( $activity->post_url ) ) {
+		$post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
+	} else {
+		$post_url = $activity->post_url;
+	}
 
-	$post_title = bp_activity_get_meta( $activity->id, 'post_title' );
+	if ( empty( $activity->post_title ) ) {
+		$post_title = bp_activity_get_meta( $activity->id, 'post_title' );
+	} else {
+		$post_title = $activity->post_title;
+	}
 
 	// Should only be empty at the time of post creation
 	if ( empty( $post_title ) ) {
diff --git src/bp-blogs/bp-blogs-filters.php src/bp-blogs/bp-blogs-filters.php
index 9cf0c92..ab3b60e 100644
--- src/bp-blogs/bp-blogs-filters.php
+++ src/bp-blogs/bp-blogs-filters.php
@@ -42,13 +42,59 @@ add_filter( 'wp_signup_location', 'bp_blogs_creation_location' );
  *
  * @since BuddyPress (2.1.0)
  *
- * @see bp_blogs_update_post()
+ * @see bp_blogs_update_post_activity_meta()
  *
  * @param array Current SQL clauses in array format
  * @return array
  */
 function bp_blogs_comments_clauses_select_by_id( $retval ) {
 	$retval['fields'] = 'comment_ID';
-	
+
 	return $retval;
-}
\ No newline at end of file
+}
+
+/**
+ * Check whether the current post can be published.
+ *
+ * Abstracted from the deprecated `bp_blogs_record_post()`.
+ *
+ * @since BuddyPress (2.2.0)
+ *
+ * @param  bool $return  Whether the post should be published.
+ * @param  int  $blog_id ID of the blog.
+ * @param  int  $post_id ID of the post.
+ * @param  int  $user_id ID of the post author.
+ * @return bool True to authorize the post to be published, otherwise false.
+ */
+function bp_blogs_post_pre_publish( $return = true, $blog_id = 0, $post_id = 0, $user_id = 0 ) {
+	$bp = buddypress();
+
+	// If blog is not trackable, do not record the activity.
+	if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) ) {
+		return false;
+	}
+
+	/*
+	 * 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;
+	}
+
+	$is_blog_public = apply_filters( 'bp_is_blog_public', (int) get_blog_option( $blog_id, 'blog_public' ) );
+
+	if ( 0 === $is_blog_public && is_multisite() ) {
+		return false;
+	}
+
+	return $return;
+}
+add_filter( 'bp_activity_post_pre_publish', 'bp_blogs_post_pre_publish', 10, 4 );
diff --git src/bp-blogs/bp-blogs-functions.php src/bp-blogs/bp-blogs-functions.php
index 41f62f6..caffa1e 100644
--- src/bp-blogs/bp-blogs-functions.php
+++ src/bp-blogs/bp-blogs-functions.php
@@ -402,199 +402,54 @@ function bp_blogs_update_option_thread_comments_depth( $oldvalue, $newvalue ) {
 add_action( 'update_option_thread_comments_depth', 'bp_blogs_update_option_thread_comments_depth', 10, 2 );
 
 /**
- * Detect a change in post status, and initiate an activity update if necessary.
+ * Record activity metadata about a published blog post.
  *
- * Posts get new activity updates when (a) they are being published, and (b)
- * they have not already been published. This enables proper posting for
- * regular posts as well as scheduled posts, while preventing post bumping.
+ * @since BuddyPress (2.2.0)
  *
- * See #4090, #3746, #2546 for background.
- *
- * @since BuddyPress (2.0.0)
- *
- * @todo Support untrashing better
- *
- * @param string $new_status New status for the post.
- * @param string $old_status Old status for the post.
- * @param object $post Post data.
+ * @param  int     $activity_id ID of the acitvity item.
+ * @param  WP_Post $post        Post object.
  */
-function bp_blogs_catch_transition_post_status( $new_status, $old_status, $post ) {
-
-	// This is an edit
-	if ( $new_status === $old_status ) {
-		if ( $new_status == 'publish' ) {
-			bp_blogs_update_post( $post );
-			return;
-		}
-	}
-
-	// Publishing a previously unpublished post
-	if ( 'publish' === $new_status ) {
-		// Untrashing the post
-		// Nothing here yet
-		if ( 'trash' == $old_status ) {}
-
-		// Record the post
-		bp_blogs_record_post( $post->ID, $post );
-
-	// Unpublishing a previously published post
-	} else if ( 'publish' === $old_status ) {
-		// Some form of pending status
-		// Only remove the activity entry
-		bp_blogs_delete_activity( array(
-			'item_id'           => get_current_blog_id(),
-			'secondary_item_id' => $post->ID,
-			'component'         => buddypress()->blogs->id,
-			'type'              => 'new_blog_post'
-		) );
+function bp_blogs_publish_post_activity_meta( $activity_id, $post, $args ) {
+	if ( empty( $activity_id ) || 'post' != $post->post_type ) {
+		return;
 	}
-}
-add_action( 'transition_post_status', 'bp_blogs_catch_transition_post_status', 10, 3 );
-
-/**
- * Record a new blog post in the BuddyPress activity stream.
- *
- * @param int $post_id ID of the post being recorded.
- * @param object $post The WP post object passed to the 'save_post' action.
- * @param int $user_id Optional. The user to whom the activity item will be
- *        associated. Defaults to the post_author.
- * @return bool|null Returns false on failure.
- */
-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 blog is not trackable, do not record the activity.
-	if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) )
-		return false;
 
-	if ( !$user_id )
-		$user_id = (int) $post->post_author;
+	bp_activity_update_meta( $activity_id, 'post_title', $post->post_title );
 
-	// 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;
+	if ( ! empty( $args['post_url'] ) ) {
+		$post_permalink = $args['post_url'];
 	} else {
-		$tags_blog_id = isset( $bp->site_options['tags_blog_id'] ) ? $bp->site_options['tags_blog_id'] : 0;
+		$post_permalink = $post->guid;
 	}
 
-	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() ) {
+	bp_activity_update_meta( $activity_id, 'post_url',   $post_permalink );
 
-			// Record this in activity streams
-			$post_permalink = add_query_arg(
-				'p',
-				$post_id,
-				trailingslashit( get_home_url( $blog_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(
-						'action'       => 'new_blog_post',
-						'primary_id'   => $blog_id,
-						'secondary_id' => $post_id,
-					)
-				) );
-
-				if ( !empty( $existing['activities'] ) ) {
-					return;
-				}
-			}
-
-			$activity_content = $post->post_content;
-
-			$activity_id = bp_blogs_record_activity( array(
-				'user_id'           => (int) $post->post_author,
-				'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_date_gmt,
-			) );
-
-			// save post title in activity meta
-			if ( bp_is_active( 'activity' ) ) {
-				bp_activity_update_meta( $activity_id, 'post_title', $post->post_title );
-				bp_activity_update_meta( $activity_id, 'post_url',   $post_permalink );
-			}
-		}
-
-		// 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 );
-	}
+	// Update the blog's last activity.
+	bp_blogs_update_blogmeta( $args['item_id'], 'last_activity', bp_core_current_time() );
 
-	do_action( 'bp_blogs_new_blog_post', $post_id, $post, $user_id );
+	do_action( 'bp_blogs_new_blog_post', $post->ID, $post, $args['user_id'] );
 }
+add_action( 'bp_activity_post_type_published', 'bp_blogs_publish_post_activity_meta', 10, 3 );
 
 /**
- * Updates a blog post's corresponding activity entry during a post edit.
+ * Updates a blog post's activity meta entry during a post edit.
  *
- * @since BuddyPress (2.0.0)
- *
- * @see bp_blogs_catch_transition_post_status()
+ * @since BuddyPress (2.2.0)
  *
- * @param WP_Post $post
+ * @param WP_Post              $post     Post object.
+ * @param BP_Actitivy_Activity $activity Activity object.
  */
-function bp_blogs_update_post( $post ) {
-	if ( ! bp_is_active( 'activity' ) ) {
-		return;
-	}
-
-	$activity_id = bp_activity_get_activity_id( array(
-		'component'         => buddypress()->blogs->id,
-		'item_id'           => get_current_blog_id(),
-		'secondary_item_id' => $post->ID,
-		'type'              => 'new_blog_post',
-	 ) );
-
-	// activity ID doesn't exist, so stop!
-	if ( empty( $activity_id ) ) {
+function bp_blogs_update_post_activity_meta( $post, $activity ) {
+	if ( empty( $activity->id ) || 'post' != $post->post_type ) {
 		return;
 	}
 
-	// update the activity entry
-	$activity = new BP_Activity_Activity( $activity_id );
-
-	if ( ! empty( $post->post_content ) ) {
-		// Make sure to update the thumbnail image
-		$post_content = bp_activity_thumbnail_content_images( $post->post_content, $activity->primary_link, (array) $activity );
-
-		// Make sure to apply the blop post excerpt
-		$activity->content = apply_filters( 'bp_blogs_record_activity_content', bp_create_excerpt( $post_content ), $post_content, (array) $activity );
-	}
-
-	// Save the updated activity
-	$activity->save();
-
-	// update post title in activity meta
-	$existing_title = bp_activity_get_meta( $activity_id, 'post_title' );
+	// Update post title in activity meta.
+	$existing_title = bp_activity_get_meta( $activity->id, 'post_title' );
 	if ( $post->post_title !== $existing_title ) {
-		bp_activity_update_meta( $activity_id, 'post_title', $post->post_title );
+		bp_activity_update_meta( $activity->id, 'post_title', $post->post_title );
 
-		// now update activity meta for post comments... sigh
+		// Now update activity meta for post comments... sigh.
 		add_filter( 'comments_clauses', 'bp_blogs_comments_clauses_select_by_id' );
 		$comments = get_comments( array( 'post_id' => $post->ID ) );
 		remove_filter( 'comments_clauses', 'bp_blogs_comments_clauses_select_by_id' );
@@ -603,14 +458,14 @@ function bp_blogs_update_post( $post ) {
 			$activity_ids = array();
 			$comment_ids  = wp_list_pluck( $comments, 'comment_ID' );
 
-			// setup activity args
+			// Set up activity args.
 			$args = array(
 				'update_meta_cache' => false,
 				'show_hidden'       => true,
 				'per_page'          => 99999,
 			);
 
-			// query for old-style "new_blog_comment" activity items
+			// Query for old-style "new_blog_comment" activity items.
 			$args['filter'] = array(
 				'object'       => buddypress()->blogs->id,
 				'action'       => 'new_blog_comment',
@@ -622,7 +477,7 @@ function bp_blogs_update_post( $post ) {
 				$activity_ids = (array) wp_list_pluck( $activities['activities'], 'id' );
 			}
 
-			// query for activity comments connected to a blog post
+			// Query for activity comments connected to a blog post.
 			unset( $args['filter'] );
 			$args['meta_query'] = array( array(
 				'key'     => 'bp_blogs_post_comment_id',
@@ -637,7 +492,7 @@ function bp_blogs_update_post( $post ) {
 				$activity_ids = array_merge( $activity_ids, (array) wp_list_pluck( $activities['activities'], 'id' ) );
 			}
 
-			// update activity meta for all found activity items
+			// Update activity meta for all found activity items.
 			if ( ! empty( $activity_ids ) ) {
 				foreach ( $activity_ids as $aid ) {
 					bp_activity_update_meta( $aid, 'post_title', $post->post_title );
@@ -648,13 +503,14 @@ function bp_blogs_update_post( $post ) {
 		}
 	}
 
-	// add post comment status to activity meta if closed
+	// Add post comment status to activity meta if closed.
 	if( 'closed' == $post->comment_status ) {
-		bp_activity_update_meta( $activity_id, 'post_comment_status', $post->comment_status );
+		bp_activity_update_meta( $activity->id, 'post_comment_status', $post->comment_status );
 	} else {
-		bp_activity_delete_meta( $activity_id, 'post_comment_status' );
+		bp_activity_delete_meta( $activity->id, 'post_comment_status' );
 	}
 }
+add_action( 'bp_activity_post_type_updated', 'bp_blogs_update_post_activity_meta', 10, 2 );
 
 /**
  * Record a new blog comment in the BuddyPress activity stream.
diff --git src/bp-blogs/bp-blogs-loader.php src/bp-blogs/bp-blogs-loader.php
index 112cc80..989ac1c 100644
--- src/bp-blogs/bp-blogs-loader.php
+++ src/bp-blogs/bp-blogs-loader.php
@@ -75,6 +75,23 @@ class BP_Blogs_Component extends BP_Component {
 
 		// Setup the globals
 		parent::setup_globals( $args );
+
+		/*
+		 * Set up the post post type to track.
+		 *
+		 * In case the config is not multisite, the blog_public option is ignored.
+		 */
+		if ( 0 !== (int) get_option( 'blog_public' ) || ! is_multisite() ) {
+			// Get all posts to track.
+			$post_types = apply_filters( 'bp_blogs_record_post_post_types', array( 'post' ) );
+
+			foreach ( $post_types as $post_type ) {
+				add_post_type_support( $post_type, 'buddypress-activity' );
+			}
+		}
+
+		// Filter the generic track parameters for the 'post' post type.
+		add_filter( 'bp_activity_get_post_type_tracking_args', array( $this, 'post_tracking_args' ), 10, 2 );
 	}
 
 	/**
@@ -246,6 +263,30 @@ class BP_Blogs_Component extends BP_Component {
 
 		parent::setup_title();
 	}
+
+	/**
+	 * Set up the tracking arguments for the 'post' post type.
+	 *
+	 * @since BuddyPress (2.2.0)
+	 *
+	 * @see bp_activity_get_post_type_tracking_args() for information on parameters.
+	 */
+	public function post_tracking_args( $params = array(), $post_type = 0 ) {
+		if ( 'post' != $post_type ) {
+			return $params;
+		}
+
+		// Set specific params for the 'post' post type.
+		$params->component_id    = $this->id;
+		$params->action_id       = 'new_blog_post';
+		$params->admin_filter    = __( 'New post published', 'buddypress' );
+		$params->format_callback = 'bp_blogs_format_activity_action_new_blog_post';
+		$params->front_filter    = __( 'Posts', 'buddypress' );
+		$params->contexts        = array( 'activity', 'member' );
+		$params->position        = 5;
+
+		return $params;
+	}
 }
 
 /**
diff --git tests/phpunit/testcases/activity/functions.php tests/phpunit/testcases/activity/functions.php
index 6cea6bd..4f8cad6 100644
--- tests/phpunit/testcases/activity/functions.php
+++ tests/phpunit/testcases/activity/functions.php
@@ -576,6 +576,340 @@ Bar!';
 	}
 
 	/**
+	 * @group activity_action
+	 * @group bp_activity_format_activity_action_custom_post_type_post
+	 * @group activity_tracking
+	 */
+	public function test_bp_activity_format_activity_action_custom_post_type_post_nonms() {
+		if ( is_multisite() ) {
+			return;
+		}
+
+		$bp = buddypress();
+
+		register_post_type( 'foo', array(
+			'label'   => 'foo',
+			'public'   => true,
+			'supports' => array( 'buddypress-activity' ),
+		) );
+
+		// Build the actions to fetch the tracking args
+		bp_activity_get_actions();
+
+		$u = $this->factory->user->create();
+		$p = $this->factory->post->create( array(
+			'post_author' => $u,
+			'post_type'   => 'foo',
+		) );
+
+		$a = $this->factory->activity->create( array(
+			'component'         => 'activity',
+			'type'              => 'new_foo',
+			'user_id'           => $u,
+			'item_id'           => 1,
+			'secondary_item_id' => $p,
+		) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$user_link = bp_core_get_userlink( $u );
+		$blog_url = get_home_url();
+		$post_url = add_query_arg( 'p', $p, trailingslashit( $blog_url ) );
+		$post_link = '<a href="' . $post_url . '">item</a>';
+
+		$expected = sprintf( '%s wrote a new %s', $user_link, $post_link );
+
+		$this->assertSame( $expected, $a_obj->action );
+
+		_unregister_post_type( 'foo' );
+
+		// Reset globals
+		unset( $bp->activity->actions->activity->new_foo );
+		$bp->activity->track = array();
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_activity_format_activity_action_custom_post_type_post_ms
+	 * @group activity_tracking
+	 */
+	public function test_bp_activity_format_activity_action_custom_post_type_post_ms() {
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		$bp = buddypress();
+
+		$b = $this->factory->blog->create();
+		$u = $this->factory->user->create();
+
+		switch_to_blog( $b );
+
+		register_post_type( 'foo', array(
+			'label'   => 'foo',
+			'public'   => true,
+			'supports' => array( 'buddypress-activity' ),
+		) );
+
+		// Build the actions to fetch the tracking args
+		bp_activity_get_actions();
+
+		$p = $this->factory->post->create( array(
+			'post_author' => $u,
+			'post_type'   => 'foo',
+		) );
+
+		$activity_args = array(
+			'component'         => 'activity',
+			'type'              => 'new_foo',
+			'user_id'           => $u,
+			'item_id'           => $b,
+			'secondary_item_id' => $p,
+		);
+
+		_unregister_post_type( 'foo' );
+		bp_activity_get_actions();
+
+		restore_current_blog();
+
+		$a = $this->factory->activity->create( $activity_args );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$user_link = bp_core_get_userlink( $u );
+		$blog_url = get_blog_option( $a_obj->item_id, 'home' );
+		$post_url = add_query_arg( 'p', $p, trailingslashit( $blog_url ) );
+
+		$post_link = '<a href="' . $post_url . '">item</a>';
+
+		$expected = sprintf( '%s wrote a new %s, on the site %s', $user_link, $post_link, '<a href="' . $blog_url . '">' . get_blog_option( $a_obj->item_id, 'blogname' ) . '</a>' );
+
+		$this->assertSame( $expected, $a_obj->action );
+
+		// Reset globals
+		unset( $bp->activity->actions->activity->new_foo );
+		$bp->activity->track = array();
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_activity_get_actions
+	 */
+	public function test_bp_activity_get_actions_should_sort_by_position() {
+		$old_actions = bp_activity_get_actions();
+		buddypress()->activity->actions = new stdClass;
+
+		register_post_type( 'foo5', array(
+			'public'      => true,
+			'supports'    => array( 'buddypress-activity' ),
+			'bp_activity' => array(
+				'component_id' => 'foo',
+				'action_id' => 'foo_bar_5',
+				'position' => 5,
+			),
+		) );
+
+		register_post_type( 'foo50', array(
+			'public'      => true,
+			'supports'    => array( 'buddypress-activity' ),
+			'bp_activity' => array(
+				'component_id' => 'foo',
+				'action_id' => 'foo_bar_50',
+				'position' => 50,
+			),
+		) );
+
+		register_post_type( 'foo25', array(
+			'public'      => true,
+			'supports'    => array( 'buddypress-activity' ),
+			'bp_activity' => array(
+				'component_id' => 'foo',
+				'action_id' => 'foo_bar_25',
+				'position' => 25,
+			),
+		) );
+
+		$actions = bp_activity_get_actions();
+
+		$expected = array(
+			'foo_bar_5',
+			'foo_bar_25',
+			'foo_bar_50',
+		);
+		$foo_actions = (array) $actions->foo;
+		$this->assertEquals( $expected, array_values( wp_list_pluck( $foo_actions, 'key' ) ) );
+
+		buddypress()->activity->actions = $old_actions;
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_activity_format_activity_action_custom_post_type_post
+	 */
+	public function test_bp_activity_format_activity_action_custom_string_post_type_post_nonms() {
+		if ( is_multisite() ) {
+			return;
+		}
+
+		$bp = buddypress();
+
+		$labels = array(
+			'name'                 => 'bars',
+			'singular_name'        => 'bar',
+			'bp_activity_new_post' => '%1$s shared a new <a href="%2$s">bar</a>',
+		);
+
+		register_post_type( 'foo', array(
+			'labels'      => $labels,
+			'public'      => true,
+			'supports'    => array( 'buddypress-activity' ),
+			'bp_activity' => array(
+				'action_id' => 'foo_bar',
+			),
+		) );
+
+		// Build the actions to fetch the tracking args
+		bp_activity_get_actions();
+
+		$u = $this->factory->user->create();
+		$p = $this->factory->post->create( array(
+			'post_author' => $u,
+			'post_type'   => 'foo',
+		) );
+
+		$a = $this->factory->activity->create( array(
+			'component'         => 'activity',
+			'type'              => 'foo_bar',
+			'user_id'           => $u,
+			'item_id'           => 1,
+			'secondary_item_id' => $p,
+		) );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$user_link = bp_core_get_userlink( $u );
+		$blog_url = get_home_url();
+		$post_url = add_query_arg( 'p', $p, trailingslashit( $blog_url ) );
+
+		$expected = sprintf( '%1$s shared a new <a href="%2$s">bar</a>', $user_link, $post_url );
+
+		$this->assertSame( $expected, $a_obj->action );
+
+		_unregister_post_type( 'foo' );
+
+		// Reset globals
+		unset( $bp->activity->actions->activity->foo_bar );
+		$bp->activity->track = array();
+	}
+
+	/**
+	 * @group activity_action
+	 * @group bp_activity_format_activity_action_custom_post_type_post_ms
+	 * @group activity_tracking
+	 */
+	public function test_bp_activity_format_activity_action_custom_string_post_type_post_ms() {
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		$bp = buddypress();
+		$reset = $bp->activity->actions;
+
+		$b = $this->factory->blog->create();
+		$u = $this->factory->user->create();
+
+		switch_to_blog( $b );
+
+		$labels = array(
+			'name'                    => 'bars',
+			'singular_name'           => 'bar',
+			'bp_activity_new_post_ms' => '%1$s shared a new <a href="%2$s">bar</a>, on the site %3$s',
+		);
+
+		register_post_type( 'foo', array(
+			'labels'   => $labels,
+			'public'   => true,
+			'supports' => array( 'buddypress-activity' ),
+		) );
+
+		// Build the actions to fetch the tracking args
+		bp_activity_get_actions();
+
+		$p = $this->factory->post->create( array(
+			'post_author' => $u,
+			'post_type'   => 'foo',
+		) );
+
+		$activity_args = array(
+			'component'         => 'activity',
+			'type'              => 'new_foo',
+			'user_id'           => $u,
+			'item_id'           => $b,
+			'secondary_item_id' => $p,
+		);
+
+		_unregister_post_type( 'foo' );
+
+		restore_current_blog();
+
+		$a = $this->factory->activity->create( $activity_args );
+
+		$a_obj = new BP_Activity_Activity( $a );
+
+		$user_link = bp_core_get_userlink( $u );
+		$blog_url = get_blog_option( $a_obj->item_id, 'home' );
+		$post_url = add_query_arg( 'p', $p, trailingslashit( $blog_url ) );
+
+		$expected = sprintf( '%1$s shared a new <a href="%2$s">bar</a>, on the site %3$s', $user_link, $post_url, '<a href="' . $blog_url . '">' . get_blog_option( $a_obj->item_id, 'blogname' ) . '</a>' );
+
+		$this->assertSame( $expected, $a_obj->action );
+
+		// Reset globals
+		unset( $bp->activity->actions->activity->new_foo );
+		$bp->activity->track = array();
+	}
+
+	/**
+	 * @group bp_activity_set_post_type_tracking_args
+	 * @group activity_tracking
+	 */
+	public function test_bp_activity_set_post_type_tracking_args() {
+		$bp = buddypress();
+
+		add_post_type_support( 'page', 'buddypress-activity' );
+
+		bp_activity_set_post_type_tracking_args( 'page', array(
+			'component_id' => $bp->blogs->id,
+			'dummy'        => 'dummy value',
+		) );
+
+		// Build the actions to fetch the tracking args
+		bp_activity_get_actions();
+
+		$u = $this->factory->user->create();
+
+		$post_id = $this->factory->post->create( array(
+			'post_author' => $u,
+			'post_status' => 'publish',
+			'post_type'   => 'page',
+		) );
+
+		$a = bp_activity_get( array(
+			'action'            => 'new_page',
+			'item_id'           => get_current_blog_id(),
+			'secondary_item_id' => $post_id,
+		) );
+
+		$this->assertSame( $bp->blogs->id, $a['activities'][0]->component );
+
+		remove_post_type_support( 'page', 'buddypress-activity' );
+
+		// Reset globals
+		unset( $bp->activity->actions->blogs->new_page );
+		$bp->activity->track = array();
+	}
+
+	/**
 	 * @group bp_activity_new_comment
 	 * @group cache
 	 */
diff --git tests/phpunit/testcases/blogs/activity.php tests/phpunit/testcases/blogs/activity.php
index cc16b1f..e67adab 100644
--- tests/phpunit/testcases/blogs/activity.php
+++ tests/phpunit/testcases/blogs/activity.php
@@ -2,6 +2,25 @@
 
 class BP_Tests_Blogs_Activity extends BP_UnitTestCase {
 	/**
+	 * @group bp_blogs_register_activity_actions
+	 * @group activity_tracking
+	 */
+	public function test_bp_blogs_loader_post_tracking_args_filter() {
+		$bp = buddypress();
+
+		$expected = array( 'new_blog_post', 'new_blog_comment' );
+
+		if ( is_multisite() ) {
+			$expected = array_merge( array( 'new_blog' ), $expected );
+		}
+
+		$actions = bp_activity_get_actions();
+		$actions = array_keys( (array) $actions->blogs );
+
+		$this->assertEquals( $expected, $actions );
+	}
+
+	/**
 	 * @group activity_action
 	 * @group bp_blogs_format_activity_action_new_blog
 	 */
diff --git tests/phpunit/testcases/blogs/functions.php tests/phpunit/testcases/blogs/functions.php
index 6e03d5c..b2ee4eb 100644
--- tests/phpunit/testcases/blogs/functions.php
+++ tests/phpunit/testcases/blogs/functions.php
@@ -303,6 +303,84 @@ class BP_Tests_Blogs_Functions extends BP_UnitTestCase {
 	/**
 	 * @group bp_blogs_catch_transition_post_status
 	 */
+	public function test_transition_post_status_password_publish() {
+		$post_id = $this->factory->post->create( array(
+			'post_status'   => 'publish',
+			'post_type'     => 'post',
+			'post_password' => 'pass',
+		) );
+		$post = get_post( $post_id );
+
+		// 'new' => 'publish with password'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Published with password post should not have activity' );
+	}
+
+	/**
+	 * @group bp_blogs_catch_transition_post_status
+	 */
+	public function test_transition_post_status_publish_update_password() {
+		$post_id = $this->factory->post->create( array(
+			'post_status'   => 'publish',
+			'post_type'     => 'post',
+		) );
+		$post = get_post( $post_id );
+
+		// 'publish' => 'publish'
+		$this->assertTrue( $this->activity_exists_for_post( $post_id ), 'Published post should have activity' );
+
+		$post->post_content .= ' foo';
+		$post->post_password = 'pass';
+
+		wp_update_post( $post );
+
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Updated with password post should not have activity' );
+	}
+
+	/**
+	 * @group bp_blogs_catch_transition_post_status
+	 */
+	public function test_transition_post_status_private_publish() {
+		$post_id = $this->factory->post->create( array(
+			'post_status'   => 'private',
+			'post_type'     => 'post',
+		) );
+		$post = get_post( $post_id );
+
+		// 'new' => 'private'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Private post should not have activity' );
+
+		$post->post_status = 'publish';
+
+		wp_update_post( $post );
+
+		// 'private' => 'publish'
+		$this->assertTrue( $this->activity_exists_for_post( $post_id ), 'Published post should have activity' );
+	}
+
+	/**
+	 * @group bp_blogs_catch_transition_post_status
+	 */
+	public function test_transition_post_status_publish_private() {
+		$post_id = $this->factory->post->create( array(
+			'post_status'   => 'publish',
+			'post_type'     => 'post',
+		) );
+		$post = get_post( $post_id );
+
+		// 'new' => 'publish'
+		$this->assertTrue( $this->activity_exists_for_post( $post_id ), 'Published post should have activity' );
+
+		$post->post_status = 'private';
+
+		wp_update_post( $post );
+
+		// 'publish' => 'private'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Private post should not have activity' );
+	}
+
+	/**
+	 * @group bp_blogs_catch_transition_post_status
+	 */
 	public function test_transition_post_status_draft_to_draft() {
 		$post_id = $this->factory->post->create( array(
 			'post_status' => 'draft',
@@ -477,6 +555,60 @@ class BP_Tests_Blogs_Functions extends BP_UnitTestCase {
 		$this->set_current_user( $old_user );
 	}
 
+	/**
+	 * @group bp_blogs_catch_transition_post_status
+	 */
+	public function test_bp_blogs_is_blog_trackable_false_publish_post() {
+		add_filter( 'bp_blogs_is_blog_trackable', '__return_false' );
+
+		$post_id = $this->factory->post->create( array(
+			'post_status'   => 'publish',
+			'post_type'     => 'post',
+		) );
+		$post = get_post( $post_id );
+
+		// 'new' => 'publish'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Not trackable blog post should not have activity' );
+
+		$post->post_content .= ' foo';
+
+		wp_update_post( $post );
+
+		// 'publish' => 'publish'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Not trackable blog post should not have activity' );
+
+		remove_filter( 'bp_blogs_is_blog_trackable', '__return_false' );
+	}
+
+	/**
+	 * @group bp_blogs_catch_transition_post_status
+	 */
+	public function test_bp_is_blog_public_zero_publish_post() {
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		add_filter( 'bp_is_blog_public', '__return_zero' );
+
+		$post_id = $this->factory->post->create( array(
+			'post_status'   => 'publish',
+			'post_type'     => 'post',
+		) );
+		$post = get_post( $post_id );
+
+		// 'new' => 'publish'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Not public blog post should not have activity' );
+
+		$post->post_content .= ' foo';
+
+		wp_update_post( $post );
+
+		// 'publish' => 'publish'
+		$this->assertFalse( $this->activity_exists_for_post( $post_id ), 'Not public blog post should not have activity' );
+
+		remove_filter( 'bp_is_blog_public', '__return_zero' );
+	}
+
 	protected function activity_exists_for_post( $post_id ) {
 		$a = bp_activity_get( array(
 			'component' => buddypress()->blogs->id,
