disable_blogforum_comments = bp_disable_blogforum_comments();
// Define singular and plural labels, as well as whether we support AJAX.
parent::__construct(
array(
'ajax' => false,
'plural' => 'activities',
'singular' => 'activity',
'screen' => get_current_screen(),
)
);
}
/**
* Handle filtering of data, sorting, pagination, and any other data manipulation prior to rendering.
*
* @since 1.6.0
*/
public function prepare_items() {
// Option defaults.
$filter = array();
$filter_query = false;
$include_id = false;
$search_terms = false;
$spam = 'ham_only';
// Set current page.
$page = $this->get_pagenum();
// Set per page from the screen options.
$per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );
// Check if we're on the "Spam" view.
if ( ! empty( $_REQUEST['activity_status'] ) && 'spam' === $_REQUEST['activity_status'] ) {
$spam = 'spam_only';
$this->view = 'spam';
}
// Filter.
if ( ! empty( $_REQUEST['activity_type'] ) ) {
$filter = array( 'action' => $_REQUEST['activity_type'] );
// Set the view as a filtered one.
$this->view = 'filtered';
/**
* Filter here to override the filter with a filter query
*
* @since 2.5.0
*
* @param array $filter Current activity filter parameters.
*/
$has_filter_query = apply_filters( 'bp_activity_list_table_filter_activity_type_items', $filter );
if ( ! empty( $has_filter_query['filter_query'] ) ) {
// Reset the filter.
$filter = array();
// And use the filter query instead.
$filter_query = $has_filter_query['filter_query'];
}
}
// Are we doing a search?
if ( ! empty( $_REQUEST['s'] ) && is_string( $_REQUEST['s'] ) ) {
$search_terms = wp_unslash( $_REQUEST['s'] );
// Set the view as a search request.
$this->view = 'search';
}
// Check if user has clicked on a specific activity (if so, fetch only that, and any related, activity).
if ( ! empty( $_REQUEST['aid'] ) ) {
$include_id = (int) $_REQUEST['aid'];
// Set the view as a single activity.
$this->view = 'single';
}
// Get the spam total (ignoring any search query or filter).
$spams = bp_activity_get(
array(
'display_comments' => 'stream',
'show_hidden' => true,
'spam' => 'spam_only',
'count_total_only' => true,
)
);
$this->spam_count = $spams['total'];
unset( $spams );
// Get the activities from the database.
$activities = bp_activity_get(
array(
'display_comments' => 'stream',
'filter' => $filter,
'in' => $include_id,
'page' => $page,
'per_page' => $per_page,
'search_terms' => $search_terms,
'filter_query' => $filter_query,
'show_hidden' => true,
'spam' => $spam,
'count_total' => 'count_query',
)
);
// If we're viewing a specific activity, flatten all activities into a single array.
if ( $include_id ) {
$activities['activities'] = self::flatten_activity_array( $activities['activities'] );
$activities['total'] = count( $activities['activities'] );
// Sort the array by the activity object's date_recorded value.
usort(
$activities['activities'],
function ( $a, $b ) {
return $a->date_recorded > $b->date_recorded;
}
);
}
// The bp_activity_get function returns an array of objects; cast these to arrays for WP_List_Table.
$new_activities = array();
foreach ( $activities['activities'] as $activity_item ) {
$new_activities[] = (array) $activity_item;
// Build an array of activity-to-user ID mappings for better efficiency in the In Response To column.
$this->activity_user_id[ $activity_item->id ] = $activity_item->user_id;
}
// Set raw data to display.
$this->items = $new_activities;
// Store information needed for handling table pagination.
$this->set_pagination_args(
array(
'per_page' => $per_page,
'total_items' => $activities['total'],
'total_pages' => ceil( $activities['total'] / $per_page ),
)
);
// Don't truncate activity items; bp_activity_truncate_entry() needs to be used inside a BP_Activity_Template loop.
remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
// Set the Total number of activities.
if ( 'all' === $this->view ) {
$this->all_count = (int) $activities['total'];
// Only perform a query if not on the main list view.
} elseif ( 'single' !== $this->view ) {
$count_activities = bp_activity_get(
array(
'fields' => 'ids',
'show_hidden' => true,
'count_total_only' => true,
)
);
if ( $count_activities['total'] ) {
$this->all_count = (int) $count_activities['total'];
}
}
}
/**
* Get an array of all the columns on the page.
*
* @since 1.6.0
*
* @return array Column headers.
*/
public function get_column_info() {
$this->_column_headers = array(
$this->get_columns(),
array(),
$this->get_sortable_columns(),
$this->get_default_primary_column_name(),
);
return $this->_column_headers;
}
/**
* Get name of default primary column
*
* @since 2.3.3
*
* @return string
*/
protected function get_default_primary_column_name() {
return 'author';
}
/**
* Display a message on screen when no items are found (e.g. no search matches).
*
* @since 1.6.0
*/
public function no_items() {
esc_html_e( 'No activities found.', 'buddypress' );
}
/**
* Output the Activity data table.
*
* @since 1.6.0
*/
public function display() {
$this->display_tablenav( 'top' ); ?>
print_column_headers(); ?>
display_rows_or_placeholder(); ?>
print_column_headers( false ); ?>
display_tablenav( 'bottom' );
}
/**
* Generate content for a single row of the table.
*
* @since 1.6.0
*
* @param object $item The current item.
*/
public function single_row( $item ) {
static $even = false;
$row_classes = array();
if ( $even ) {
$row_classes = array( 'even' );
} else {
$row_classes = array( 'alternate', 'odd' );
}
if ( 'activity_comment' === $item['type'] ) {
$root_id = $item['item_id'];
} else {
$root_id = $item['id'];
}
echo '
';
// Escapes are made into `self::single_row_columns()`.
// phpcs:ignore WordPress.Security.EscapeOutput
echo $this->single_row_columns( $item );
echo '
';
$even = ! $even;
}
/**
* Get the list of views available on this table (e.g. "all", "spam").
*
* @since 1.6.0
*/
public function get_views() {
$url_base = add_query_arg( array( 'page' => 'bp-activity' ), bp_get_admin_url( 'admin.php' ) );
$all_class = 'all' === $this->view ? 'current' : '';
$spam_class = 'spam' === $this->view ? 'current' : '';
?>
';
/**
* Filters available actions for plugins to alter.
*
* @since 1.6.0
*
* @param array $actions Array of available actions user could use.
* @param array $item Current item being added to page.
*/
$actions = apply_filters( 'bp_activity_admin_comment_row_actions', array_filter( $actions ), $item );
printf(
/* translators: %s: activity date and time */
esc_html__( 'Submitted on %s', 'buddypress' ),
sprintf(
'%2$s',
esc_url( bp_activity_get_permalink( $item['id'] ) ),
sprintf(
/* translators: 1: activity date, 2: activity time */
esc_html__( '%1$s at %2$s', 'buddypress' ),
esc_html( date_i18n( bp_get_option( 'date_format' ), strtotime( $item['date_recorded'] ) ) ),
esc_html( get_date_from_gmt( $item['date_recorded'], bp_get_option( 'time_format' ) ) )
)
)
);
// End timestamp.
echo '
';
$activity = new BP_Activity_Activity( $item['id'] );
// Get activity content - if not set, use the action.
if ( ! empty( $item['content'] ) ) {
/** This filter is documented in bp-activity/bp-activity-template.php */
$content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $item['content'], &$activity ) );
} else {
// Emulate bp_get_activity_action().
$r = array(
'no_timestamp' => false,
);
/** This filter is documented in bp-activity/bp-activity-template.php */
$content = apply_filters_ref_array( 'bp_get_activity_action', array( $item['action'], &$activity, $r ) );
}
// phpcs:disable WordPress.Security.EscapeOutput
echo apply_filters(
/**
* Filter here to add extra output to the activity content into the Administration.
*
* @since 2.4.0
*
* @param string $content The activity content.
* @param array $item The activity object converted into an array.
*/
'bp_activity_admin_comment_content',
$content,
$item
);
echo ' ' . $this->row_actions( $actions );
// phpcs:enable
}
/**
* "In response to" column markup.
*
* @since 1.6.0
*
* @see WP_List_Table::single_row_columns()
*
* @param array $item A singular item (one full row).
*/
public function column_response( $item ) {
// Is $item is a root activity?
?>
' . esc_html__( 'View Activity', 'buddypress' ) . '';
}
/**
* Filters default list of default root activity types.
*
* @since 1.6.0
*
* @param array $value Array of default activity types.
* @param array $item Current item being displayed.
*/
if ( empty( $item['item_id'] ) || ! in_array( $item['type'], apply_filters( 'bp_activity_admin_root_activity_types', array( 'activity_comment' ), $item ), true ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput
echo $activity_permalink;
$comment_count = ! empty( $item['children'] ) ? bp_activity_recurse_comment_count( (object) $item ) : 0;
$root_activity_url = bp_get_admin_url( 'admin.php?page=bp-activity&aid=' . $item['id'] );
// If the activity has comments, display a link to the activity's permalink, with its comment count in a speech bubble.
if ( $comment_count ) {
printf( '%2$s', esc_url( $root_activity_url ), esc_html( number_format_i18n( $comment_count ) ) );
}
// For non-root activities, display a link to the replied-to activity's author's profile.
} else {
$avatar = get_avatar( $this->get_activity_user_id( $item['item_id'] ), '32' );
printf(
'%1$s %2$s ',
wp_kses(
$avatar,
array(
'img' => array(
'alt' => true,
'src' => true,
'srcset' => true,
'class' => true,
'height' => true,
'width' => true,
),
)
),
// phpcs:ignore WordPress.Security.EscapeOutput
bp_core_get_userlink( $this->get_activity_user_id( $item['item_id'] ) )
);
// phpcs:ignore WordPress.Security.EscapeOutput
echo $activity_permalink;
}
?>
activity_user_id[ $activity_id ] ) ) {
return $this->activity_user_id[ $activity_id ];
/*
* We don't have a mapping. This means the $activity_id is not on the current
* page of results, so fetch its details from the database.
*/
} else {
$activity = bp_activity_get_specific(
array(
'activity_ids' => $activity_id,
'show_hidden' => true,
'spam' => 'all',
)
);
/*
* If, somehow, the referenced activity has been deleted, leaving its associated
* activities as orphans, use the logged in user's ID to avoid errors.
*/
if ( empty( $activity['activities'] ) ) {
return bp_loggedin_user_id();
}
// Store the new activity/user ID mapping for any later re-use.
$this->activity_user_id[ $activity['activities'][0]->id ] = $activity['activities'][0]->user_id;
// Return the user ID.
return $activity['activities'][0]->user_id;
}
}
/**
* Checks if an activity item can be replied to.
*
* This method merges functionality from {@link bp_activity_can_comment()} and
* {@link bp_blogs_disable_activity_commenting()}. This is done because the activity
* list table doesn't use a BuddyPress activity loop, which prevents those
* functions from working as intended.
*
* @since 2.0.0
* @since 2.5.0 Include Post type activities types
*
* @param array $item An array version of the BP_Activity_Activity object.
* @return bool
*/
protected function can_comment( $item ) {
$can_comment = bp_activity_type_supports( $item['type'], 'comment-reply' );
if ( ! $this->disable_blogforum_comments && bp_is_active( 'blogs' ) ) {
$parent_activity = false;
if ( bp_activity_type_supports( $item['type'], 'post-type-comment-tracking' ) ) {
$parent_activity = (object) $item;
} elseif ( 'activity_comment' === $item['type'] ) {
$parent_activity = new BP_Activity_Activity( $item['item_id'] );
$can_comment = bp_activity_can_comment_reply( (object) $item );
}
if ( isset( $parent_activity->type ) && bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' ) ) {
// Fetch blog post comment depth and if the blog post's comments are open.
bp_blogs_setup_activity_loop_globals( $parent_activity );
$can_comment = bp_blogs_can_comment_reply( true, $item );
}
}
/**
* Filters if an activity item can be commented on or not.
*
* @since 2.0.0
* @since 2.5.0 Add a second parameter to include the activity item into the filter.
*
* @param bool $can_comment Whether an activity item can be commented on or not.
* @param array $item An array version of the BP_Activity_Activity object.
*/
return apply_filters( 'bp_activity_list_table_can_comment', $can_comment, $item );
}
/**
* Flatten the activity array.
*
* In some cases, BuddyPress gives us a structured tree of activity
* items plus their comments. This method converts it to a flat array.
*
* @since 1.6.0
*
* @param array $tree Source array.
* @return array Flattened array.
*/
public static function flatten_activity_array( $tree ) {
foreach ( (array) $tree as $node ) {
if ( isset( $node->children ) ) {
foreach ( self::flatten_activity_array( $node->children ) as $child ) {
$tree[] = $child;
}
unset( $node->children );
}
}
return $tree;
}
}