Ticket #6870: 6870.diff
File 6870.diff, 261.0 KB (added by , 9 years ago) |
---|
-
src/bp-activity/bp-activity-admin.php
16 16 // Include WP's list table class. 17 17 if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); 18 18 19 require dirname( __FILE__ ) . '/classes/class-bp-activity-list-table.php'; 20 19 21 // Per_page screen option. Has to be hooked in extremely early. 20 22 if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-activity' == $_REQUEST['page'] ) 21 23 add_filter( 'set-screen-option', 'bp_activity_admin_screen_options', 10, 3 ); … … 1038 1040 1039 1041 <?php 1040 1042 } 1041 1042 /**1043 * List table class for the Activity component admin page.1044 *1045 * @since 1.6.01046 */1047 class BP_Activity_List_Table extends WP_List_Table {1048 1049 /**1050 * What type of view is being displayed?1051 *1052 * E.g. "all", "pending", "approved", "spam"...1053 *1054 * @since 1.6.01055 * @var string $view1056 */1057 public $view = 'all';1058 1059 /**1060 * How many activity items have been marked as spam.1061 *1062 * @since 1.6.01063 * @var int $spam_count1064 */1065 public $spam_count = 0;1066 1067 /**1068 * Store activity-to-user-ID mappings for use in the In Response To column.1069 *1070 * @since 1.6.01071 * @var array $activity_user_id1072 */1073 protected $activity_user_id = array();1074 1075 /**1076 * If users can comment on blog & forum activity items.1077 *1078 * @link https://buddypress.trac.wordpress.org/ticket/62771079 *1080 * @since 2.2.21081 * @var bool $disable_blogforum_comments1082 */1083 public $disable_blogforum_comments = false;1084 1085 /**1086 * Constructor.1087 *1088 * @since 1.6.01089 */1090 public function __construct() {1091 1092 // See if activity commenting is enabled for blog / forum activity items.1093 $this->disable_blogforum_comments = bp_disable_blogforum_comments();1094 1095 // Define singular and plural labels, as well as whether we support AJAX.1096 parent::__construct( array(1097 'ajax' => false,1098 'plural' => 'activities',1099 'singular' => 'activity',1100 'screen' => get_current_screen(),1101 ) );1102 }1103 1104 /**1105 * Handle filtering of data, sorting, pagination, and any other data manipulation prior to rendering.1106 *1107 * @since 1.6.01108 */1109 function prepare_items() {1110 1111 // Option defaults.1112 $filter = array();1113 $include_id = false;1114 $search_terms = false;1115 $sort = 'DESC';1116 $spam = 'ham_only';1117 1118 // Set current page.1119 $page = $this->get_pagenum();1120 1121 // Set per page from the screen options.1122 $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );1123 1124 // Check if we're on the "Spam" view.1125 if ( !empty( $_REQUEST['activity_status'] ) && 'spam' == $_REQUEST['activity_status'] ) {1126 $spam = 'spam_only';1127 $this->view = 'spam';1128 }1129 1130 // Sort order.1131 if ( !empty( $_REQUEST['order'] ) && 'desc' != $_REQUEST['order'] )1132 $sort = 'ASC';1133 1134 // Order by.1135 /*if ( !empty( $_REQUEST['orderby'] ) ) {1136 }*/1137 1138 // Filter.1139 if ( !empty( $_REQUEST['activity_type'] ) )1140 $filter = array( 'action' => $_REQUEST['activity_type'] );1141 1142 // Are we doing a search?1143 if ( !empty( $_REQUEST['s'] ) )1144 $search_terms = $_REQUEST['s'];1145 1146 // Check if user has clicked on a specific activity (if so, fetch only that, and any related, activity).1147 if ( !empty( $_REQUEST['aid'] ) )1148 $include_id = (int) $_REQUEST['aid'];1149 1150 // Get the spam total (ignoring any search query or filter).1151 $spams = bp_activity_get( array(1152 'display_comments' => 'stream',1153 'show_hidden' => true,1154 'spam' => 'spam_only',1155 'count_total' => 'count_query',1156 ) );1157 $this->spam_count = $spams['total'];1158 unset( $spams );1159 1160 // Get the activities from the database.1161 $activities = bp_activity_get( array(1162 'display_comments' => 'stream',1163 'filter' => $filter,1164 'in' => $include_id,1165 'page' => $page,1166 'per_page' => $per_page,1167 'search_terms' => $search_terms,1168 'show_hidden' => true,1169 // 'sort' => $sort,1170 'spam' => $spam,1171 'count_total' => 'count_query',1172 ) );1173 1174 // If we're viewing a specific activity, flatten all activities into a single array.1175 if ( $include_id ) {1176 $activities['activities'] = BP_Activity_List_Table::flatten_activity_array( $activities['activities'] );1177 $activities['total'] = count( $activities['activities'] );1178 1179 // Sort the array by the activity object's date_recorded value.1180 usort( $activities['activities'], create_function( '$a, $b', 'return $a->date_recorded > $b->date_recorded;' ) );1181 }1182 1183 // The bp_activity_get function returns an array of objects; cast these to arrays for WP_List_Table.1184 $new_activities = array();1185 foreach ( $activities['activities'] as $activity_item ) {1186 $new_activities[] = (array) $activity_item;1187 1188 // Build an array of activity-to-user ID mappings for better efficiency in the In Response To column.1189 $this->activity_user_id[$activity_item->id] = $activity_item->user_id;1190 }1191 1192 // Set raw data to display.1193 $this->items = $new_activities;1194 1195 // Store information needed for handling table pagination.1196 $this->set_pagination_args( array(1197 'per_page' => $per_page,1198 'total_items' => $activities['total'],1199 'total_pages' => ceil( $activities['total'] / $per_page )1200 ) );1201 1202 // Don't truncate activity items; bp_activity_truncate_entry() needs to be used inside a BP_Activity_Template loop.1203 remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );1204 }1205 1206 /**1207 * Get an array of all the columns on the page.1208 *1209 * @since 1.6.01210 *1211 * @return array Column headers.1212 */1213 function get_column_info() {1214 $this->_column_headers = array(1215 $this->get_columns(),1216 array(),1217 $this->get_sortable_columns(),1218 $this->get_default_primary_column_name(),1219 );1220 1221 return $this->_column_headers;1222 }1223 1224 /**1225 * Get name of default primary column1226 *1227 * @since 2.3.31228 *1229 * @return string1230 */1231 protected function get_default_primary_column_name() {1232 return 'author';1233 }1234 1235 /**1236 * Display a message on screen when no items are found (e.g. no search matches).1237 *1238 * @since 1.6.01239 */1240 function no_items() {1241 _e( 'No activities found.', 'buddypress' );1242 }1243 1244 /**1245 * Output the Activity data table.1246 *1247 * @since 1.6.01248 */1249 function display() {1250 $this->display_tablenav( 'top' ); ?>1251 1252 <h2 class="screen-reader-text"><?php _e( 'Activities list', 'buddypress' ); ?></h2>1253 1254 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">1255 <thead>1256 <tr>1257 <?php $this->print_column_headers(); ?>1258 </tr>1259 </thead>1260 1261 <tfoot>1262 <tr>1263 <?php $this->print_column_headers( false ); ?>1264 </tr>1265 </tfoot>1266 1267 <tbody id="the-comment-list">1268 <?php $this->display_rows_or_placeholder(); ?>1269 </tbody>1270 </table>1271 <?php1272 1273 $this->display_tablenav( 'bottom' );1274 }1275 1276 /**1277 * Generate content for a single row of the table.1278 *1279 * @since 1.6.01280 *1281 * @param object $item The current item.1282 */1283 function single_row( $item ) {1284 static $even = false;1285 1286 if ( $even ) {1287 $row_class = ' class="even"';1288 } else {1289 $row_class = ' class="alternate odd"';1290 }1291 1292 if ( 'activity_comment' === $item['type'] ) {1293 $root_id = $item['item_id'];1294 } else {1295 $root_id = $item['id'];1296 }1297 1298 echo '<tr' . $row_class . ' id="activity-' . esc_attr( $item['id'] ) . '" data-parent_id="' . esc_attr( $item['id'] ) . '" data-root_id="' . esc_attr( $root_id ) . '">';1299 echo $this->single_row_columns( $item );1300 echo '</tr>';1301 1302 $even = ! $even;1303 }1304 1305 /**1306 * Get the list of views available on this table (e.g. "all", "spam").1307 *1308 * @since 1.6.01309 */1310 function get_views() {1311 $url_base = add_query_arg( array( 'page' => 'bp-activity' ), bp_get_admin_url( 'admin.php' ) ); ?>1312 1313 <h2 class="screen-reader-text"><?php _e( 'Filter activities list', 'buddypress' ); ?></h2>1314 1315 <ul class="subsubsub">1316 <li class="all"><a href="<?php echo esc_url( $url_base ); ?>" class="<?php if ( 'spam' != $this->view ) echo 'current'; ?>"><?php _e( 'All', 'buddypress' ); ?></a> |</li>1317 <li class="spam"><a href="<?php echo esc_url( add_query_arg( array( 'activity_status' => 'spam' ), $url_base ) ); ?>" class="<?php if ( 'spam' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Spam <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->spam_count ) ); ?></a></li>1318 1319 <?php1320 1321 /**1322 * Fires inside listing of views so plugins can add their own.1323 *1324 * @since 1.6.01325 *1326 * @param string $url_base Current URL base for view.1327 * @param string $view Current view being displayed.1328 */1329 do_action( 'bp_activity_list_table_get_views', $url_base, $this->view ); ?>1330 </ul>1331 <?php1332 }1333 1334 /**1335 * Get bulk actions.1336 *1337 * @since 1.6.01338 *1339 * @return array Key/value pairs for the bulk actions dropdown.1340 */1341 function get_bulk_actions() {1342 $actions = array();1343 $actions['bulk_spam'] = __( 'Mark as Spam', 'buddypress' );1344 $actions['bulk_ham'] = __( 'Not Spam', 'buddypress' );1345 $actions['bulk_delete'] = __( 'Delete Permanently', 'buddypress' );1346 1347 /**1348 * Filters the default bulk actions so plugins can add custom actions.1349 *1350 * @since 1.6.01351 *1352 * @param array $actions Default available actions for bulk operations.1353 */1354 return apply_filters( 'bp_activity_list_table_get_bulk_actions', $actions );1355 }1356 1357 /**1358 * Get the table column titles.1359 *1360 * @since 1.6.01361 *1362 * @see WP_List_Table::single_row_columns()1363 *1364 * @return array The columns to appear in the Activity list table.1365 */1366 function get_columns() {1367 /**1368 * Filters the titles for the columns for the activity list table.1369 *1370 * @since 2.4.01371 *1372 * @param array $value Array of slugs and titles for the columns.1373 */1374 return apply_filters( 'bp_activity_list_table_get_columns', array(1375 'cb' => '<input name type="checkbox" />',1376 'author' => _x('Author', 'Admin SWA column header', 'buddypress' ),1377 'comment' => _x( 'Activity', 'Admin SWA column header', 'buddypress' ),1378 'action' => _x( 'Action', 'Admin SWA column header', 'buddypress' ),1379 'response' => _x( 'In Response To', 'Admin SWA column header', 'buddypress' ),1380 ) );1381 }1382 1383 /**1384 * Get the column names for sortable columns.1385 *1386 * Currently, returns an empty array (no columns are sortable).1387 *1388 * @since 1.6.01389 * @todo For this to work, BP_Activity_Activity::get() needs updating1390 * to support ordering by specific fields.1391 *1392 * @return array The columns that can be sorted on the Activity screen.1393 */1394 function get_sortable_columns() {1395 return array();1396 1397 /*return array(1398 'author' => array( 'activity_author', false ), // Intentionally not using "=>"1399 );*/1400 }1401 1402 /**1403 * Markup for the "filter" part of the form (i.e. which activity type to display).1404 *1405 * @since 1.6.01406 *1407 * @param string $which 'top' or 'bottom'.1408 */1409 function extra_tablenav( $which ) {1410 1411 // Bail on bottom table nav.1412 if ( 'bottom' === $which ) {1413 return;1414 }1415 1416 // Is any filter currently selected?1417 $selected = ( ! empty( $_REQUEST['activity_type'] ) ) ? $_REQUEST['activity_type'] : '';1418 1419 // Get the actions.1420 $activity_actions = bp_activity_get_actions(); ?>1421 1422 <div class="alignleft actions">1423 <label for="activity-type" class="screen-reader-text"><?php _e( 'Filter by activity type', 'buddypress' ); ?></label>1424 <select name="activity_type" id="activity-type">1425 <option value="" <?php selected( ! $selected ); ?>><?php _e( 'View all actions', 'buddypress' ); ?></option>1426 1427 <?php foreach ( $activity_actions as $component => $actions ) : ?>1428 1429 <optgroup label="<?php echo ucfirst( $component ); ?>">1430 1431 <?php foreach ( $actions as $action_key => $action_values ) : ?>1432 1433 <?php1434 1435 // Skip the incorrectly named pre-1.6 action.1436 if ( 'friends_register_activity_action' !== $action_key ) : ?>1437 1438 <option value="<?php echo esc_attr( $action_key ); ?>" <?php selected( $action_key, $selected ); ?>><?php echo esc_html( $action_values[ 'value' ] ); ?></option>1439 1440 <?php endif; ?>1441 1442 <?php endforeach; ?>1443 1444 </optgroup>1445 1446 <?php endforeach; ?>1447 1448 </select>1449 1450 <?php submit_button( __( 'Filter', 'buddypress' ), 'secondary', false, false, array( 'id' => 'post-query-submit' ) ); ?>1451 </div>1452 1453 <?php1454 }1455 1456 /**1457 * Override WP_List_Table::row_actions().1458 *1459 * Basically a duplicate of the row_actions() method, but removes the1460 * unnecessary <button> addition.1461 *1462 * @since 2.3.31463 * @since 2.3.4 Visibility set to public for compatibility with WP < 4.0.0.1464 *1465 * @param array $actions The list of actions.1466 * @param bool $always_visible Whether the actions should be always visible.1467 * @return string1468 */1469 public function row_actions( $actions, $always_visible = false ) {1470 $action_count = count( $actions );1471 $i = 0;1472 1473 if ( !$action_count )1474 return '';1475 1476 $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';1477 foreach ( $actions as $action => $link ) {1478 ++$i;1479 ( $i == $action_count ) ? $sep = '' : $sep = ' | ';1480 $out .= "<span class='$action'>$link$sep</span>";1481 }1482 $out .= '</div>';1483 1484 return $out;1485 }1486 1487 /**1488 * Checkbox column markup.1489 *1490 * @since 1.6.01491 *1492 * @see WP_List_Table::single_row_columns()1493 *1494 * @param array $item A singular item (one full row).1495 */1496 function column_cb( $item ) {1497 printf( '<label class="screen-reader-text" for="aid-%1$d">' . __( 'Select activity item %1$d', 'buddypress' ) . '</label><input type="checkbox" name="aid[]" value="%1$d" id="aid-%1$d" />', $item['id'] );1498 }1499 1500 /**1501 * Author column markup.1502 *1503 * @since 1.6.01504 *1505 * @see WP_List_Table::single_row_columns()1506 *1507 * @param array $item A singular item (one full row).1508 */1509 function column_author( $item ) {1510 echo '<strong>' . get_avatar( $item['user_id'], '32' ) . ' ' . bp_core_get_userlink( $item['user_id'] ) . '</strong>';1511 }1512 1513 /**1514 * Action column markup.1515 *1516 * @since 2.0.01517 *1518 * @see WP_List_Table::single_row_columns()1519 *1520 * @param array $item A singular item (one full row).1521 */1522 function column_action( $item ) {1523 $actions = bp_activity_admin_get_activity_actions();1524 1525 if ( isset( $actions[ $item['type'] ] ) ) {1526 echo $actions[ $item['type'] ];1527 } else {1528 printf( __( 'Unregistered action - %s', 'buddypress' ), $item['type'] );1529 }1530 }1531 1532 /**1533 * Content column, and "quick admin" rollover actions.1534 *1535 * Called "comment" in the CSS so we can re-use some WP core CSS.1536 *1537 * @since 1.6.01538 *1539 * @see WP_List_Table::single_row_columns()1540 *1541 * @param array $item A singular item (one full row).1542 */1543 function column_comment( $item ) {1544 // Determine what type of item (row) we're dealing with.1545 if ( $item['is_spam'] )1546 $item_status = 'spam';1547 else1548 $item_status = 'all';1549 1550 // Preorder items: Reply | Edit | Spam | Delete Permanently.1551 $actions = array(1552 'reply' => '',1553 'edit' => '',1554 'spam' => '', 'unspam' => '',1555 'delete' => '',1556 );1557 1558 // Build actions URLs.1559 $base_url = bp_get_admin_url( 'admin.php?page=bp-activity&aid=' . $item['id'] );1560 $spam_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'spam-activity_' . $item['id'] ) );1561 1562 $delete_url = $base_url . "&action=delete&$spam_nonce";1563 $edit_url = $base_url . '&action=edit';1564 $ham_url = $base_url . "&action=ham&$spam_nonce";1565 $spam_url = $base_url . "&action=spam&$spam_nonce";1566 1567 // Rollover actions.1568 // Reply - JavaScript only; implemented by AJAX.1569 if ( 'spam' != $item_status ) {1570 if ( $this->can_comment( $item ) ) {1571 $actions['reply'] = sprintf( '<a href="#" class="reply hide-if-no-js">%s</a>', __( 'Reply', 'buddypress' ) );1572 } else {1573 $actions['reply'] = sprintf( '<span class="form-input-tip" title="%s">%s</span>', __( 'Replies are disabled for this activity item', 'buddypress' ), __( 'Replies disabled', 'buddypress' ) );1574 }1575 1576 // Edit.1577 $actions['edit'] = sprintf( '<a href="%s">%s</a>', $edit_url, __( 'Edit', 'buddypress' ) );1578 }1579 1580 // Spam/unspam.1581 if ( 'spam' == $item_status )1582 $actions['unspam'] = sprintf( '<a href="%s">%s</a>', $ham_url, __( 'Not Spam', 'buddypress' ) );1583 else1584 $actions['spam'] = sprintf( '<a href="%s">%s</a>', $spam_url, __( 'Spam', 'buddypress' ) );1585 1586 // Delete.1587 $actions['delete'] = sprintf( '<a href="%s" onclick="%s">%s</a>', $delete_url, "javascript:return confirm('" . esc_js( __( 'Are you sure?', 'buddypress' ) ) . "'); ", __( 'Delete Permanently', 'buddypress' ) );1588 1589 // Start timestamp.1590 echo '<div class="submitted-on">';1591 1592 /**1593 * Filters available actions for plugins to alter.1594 *1595 * @since 1.6.01596 *1597 * @param array $actions Array of available actions user could use.1598 * @param array $item Current item being added to page.1599 */1600 $actions = apply_filters( 'bp_activity_admin_comment_row_actions', array_filter( $actions ), $item );1601 1602 /* translators: 2: activity admin ui date/time */1603 printf(1604 __( 'Submitted on <a href="%1$s">%2$s at %3$s</a>', 'buddypress' ),1605 bp_activity_get_permalink( $item['id'] ),1606 date_i18n( bp_get_option( 'date_format' ), strtotime( $item['date_recorded'] ) ),1607 get_date_from_gmt( $item['date_recorded'], bp_get_option( 'time_format' ) )1608 );1609 1610 // End timestamp.1611 echo '</div>';1612 1613 // Get activity content - if not set, use the action.1614 if ( ! empty( $item['content'] ) ) {1615 1616 /**1617 * Filters current activity item content.1618 *1619 * @since 1.2.01620 *1621 * @param array $item Array index holding current activity item content.1622 */1623 $content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $item['content'] ) );1624 } else {1625 /**1626 * Filters current activity item action.1627 *1628 * @since 1.2.01629 *1630 * @var array $item Array index holding current activity item action.1631 */1632 $content = apply_filters_ref_array( 'bp_get_activity_action', array( $item['action'] ) );1633 }1634 1635 /**1636 * Filter here to add extra output to the activity content into the Administration.1637 *1638 * @since 2.4.01639 *1640 * @param string $content The activity content.1641 * @param array $item The activity object converted into an array.1642 */1643 echo apply_filters( 'bp_activity_admin_comment_content', $content, $item ) . ' ' . $this->row_actions( $actions );1644 }1645 1646 /**1647 * "In response to" column markup.1648 *1649 * @since 1.6.01650 *1651 * @see WP_List_Table::single_row_columns()1652 *1653 * @param array $item A singular item (one full row).1654 */1655 function column_response( $item ) {1656 1657 // Is $item is a root activity?1658 ?>1659 1660 <div class="response-links">1661 1662 <?php1663 // Activity permalink.1664 $activity_permalink = '';1665 if ( ! $item['is_spam'] ) {1666 $activity_permalink = '<a href="' . bp_activity_get_permalink( $item['id'], (object) $item ) . '" class="comments-view-item-link">' . __( 'View Activity', 'buddypress' ) . '</a>';1667 }1668 1669 /**1670 * Filters default list of default root activity types.1671 *1672 * @since 1.6.01673 *1674 * @param array $value Array of default activity types.1675 * @param array $item Current item being displayed.1676 */1677 if ( empty( $item['item_id'] ) || ! in_array( $item['type'], apply_filters( 'bp_activity_admin_root_activity_types', array( 'activity_comment' ), $item ) ) ) {1678 echo $activity_permalink;1679 1680 $comment_count = !empty( $item['children'] ) ? bp_activity_recurse_comment_count( (object) $item ) : 0;1681 $root_activity_url = bp_get_admin_url( 'admin.php?page=bp-activity&aid=' . $item['id'] );1682 1683 // If the activity has comments, display a link to the activity's permalink, with its comment count in a speech bubble.1684 if ( $comment_count ) {1685 $title_attr = sprintf( _n( '%s related activity', '%s related activities', $comment_count, 'buddypress' ), number_format_i18n( $comment_count ) );1686 printf( '<a href="%1$s" title="%2$s" class="post-com-count post-com-count-approved"><span class="comment-count comment-count-approved">%3$s</span></a>', esc_url( $root_activity_url ), esc_attr( $title_attr ), number_format_i18n( $comment_count ) );1687 }1688 1689 // For non-root activities, display a link to the replied-to activity's author's profile.1690 } else {1691 echo '<strong>' . get_avatar( $this->get_activity_user_id( $item['item_id'] ), '32' ) . ' ' . bp_core_get_userlink( $this->get_activity_user_id( $item['item_id'] ) ) . '</strong><br />';1692 echo $activity_permalink;1693 }1694 ?>1695 1696 </div>1697 1698 <?php1699 }1700 1701 /**1702 * Allow plugins to add their custom column.1703 *1704 * @since 2.4.01705 *1706 * @param array $item Information about the current row.1707 * @param string $column_name The column name.1708 * @return string1709 */1710 public function column_default( $item = array(), $column_name = '' ) {1711 1712 /**1713 * Filters a string to allow plugins to add custom column content.1714 *1715 * @since 2.4.01716 *1717 * @param string $value Empty string.1718 * @param string $column_name Name of the column being rendered.1719 * @param array $item The current activity item in the loop.1720 */1721 return apply_filters( 'bp_activity_admin_get_custom_column', '', $column_name, $item );1722 }1723 1724 /**1725 * Get the user id associated with a given activity item.1726 *1727 * Wraps bp_activity_get_specific(), with some additional logic for1728 * avoiding duplicate queries.1729 *1730 * @since 1.6.01731 *1732 * @param int $activity_id Activity ID to retrieve User ID for.1733 * @return int User ID of the activity item in question.1734 */1735 protected function get_activity_user_id( $activity_id ) {1736 // If there is an existing activity/user ID mapping, just return the user ID.1737 if ( ! empty( $this->activity_user_id[$activity_id] ) ) {1738 return $this->activity_user_id[$activity_id];1739 1740 /*1741 * We don't have a mapping. This means the $activity_id is not on the current1742 * page of results, so fetch its details from the database.1743 */1744 } else {1745 $activity = bp_activity_get_specific( array( 'activity_ids' => $activity_id, 'show_hidden' => true, 'spam' => 'all', ) );1746 1747 /*1748 * If, somehow, the referenced activity has been deleted, leaving its associated1749 * activities as orphans, use the logged in user's ID to avoid errors.1750 */1751 if ( empty( $activity['activities'] ) )1752 return bp_loggedin_user_id();1753 1754 // Store the new activity/user ID mapping for any later re-use.1755 $this->activity_user_id[ $activity['activities'][0]->id ] = $activity['activities'][0]->user_id;1756 1757 // Return the user ID.1758 return $activity['activities'][0]->user_id;1759 }1760 }1761 1762 /**1763 * Checks if an activity item can be replied to.1764 *1765 * This method merges functionality from {@link bp_activity_can_comment()} and1766 * {@link bp_blogs_disable_activity_commenting()}. This is done because the activity1767 * list table doesn't use a BuddyPress activity loop, which prevents those1768 * functions from working as intended.1769 *1770 * @since 2.0.01771 *1772 * @param array $item An array version of the BP_Activity_Activity object.1773 * @return bool $can_comment1774 */1775 protected function can_comment( $item ) {1776 $can_comment = true;1777 1778 if ( $this->disable_blogforum_comments ) {1779 switch ( $item['type'] ) {1780 case 'new_blog_post' :1781 case 'new_blog_comment' :1782 case 'new_forum_topic' :1783 case 'new_forum_post' :1784 $can_comment = false;1785 break;1786 }1787 1788 // Activity comments supported.1789 } else {1790 // Activity comment.1791 if ( 'activity_comment' == $item['type'] ) {1792 // Blogs.1793 if ( bp_is_active( 'blogs' ) ) {1794 // Grab the parent activity entry.1795 $parent_activity = new BP_Activity_Activity( $item['item_id'] );1796 1797 // Fetch blog post comment depth and if the blog post's comments are open.1798 bp_blogs_setup_activity_loop_globals( $parent_activity );1799 1800 // Check if the activity item can be replied to.1801 if ( false === bp_blogs_can_comment_reply( true, $item ) ) {1802 $can_comment = false;1803 }1804 }1805 1806 // Blog post.1807 } elseif ( 'new_blog_post' == $item['type'] ) {1808 if ( bp_is_active( 'blogs' ) ) {1809 bp_blogs_setup_activity_loop_globals( (object) $item );1810 1811 if ( empty( buddypress()->blogs->allow_comments[$item['id']] ) ) {1812 $can_comment = false;1813 }1814 }1815 }1816 }1817 1818 /**1819 * Filters if an activity item can be commented on or not.1820 *1821 * @since 2.0.01822 *1823 * @param bool $can_comment Whether an activity item can be commented on or not.1824 */1825 return apply_filters( 'bp_activity_list_table_can_comment', $can_comment );1826 }1827 1828 /**1829 * Flatten the activity array.1830 *1831 * In some cases, BuddyPress gives us a structured tree of activity1832 * items plus their comments. This method converts it to a flat array.1833 *1834 * @since 1.6.01835 *1836 * @param array $tree Source array.1837 * @return array Flattened array.1838 */1839 public static function flatten_activity_array( $tree ){1840 foreach ( (array) $tree as $node ) {1841 if ( isset( $node->children ) ) {1842 1843 foreach ( BP_Activity_List_Table::flatten_activity_array( $node->children ) as $child ) {1844 $tree[] = $child;1845 }1846 1847 unset( $node->children );1848 }1849 }1850 1851 return $tree;1852 }1853 } -
src/bp-activity/bp-activity-akismet.php
10 10 // Exit if accessed directly. 11 11 defined( 'ABSPATH' ) || exit; 12 12 13 /** 14 * Akismet support for the Activity component. 15 * 16 * @since 1.6.0 17 * @since 2.3.0 We only support Akismet 3+. 18 */ 19 class BP_Akismet { 13 require dirname( __FILE__ ) . '/classes/class-bp-akismet.php'; 20 14 21 /**22 * The activity last marked as spam.23 *24 * @since 1.6.025 * @var BP_Activity_Activity26 */27 protected $last_activity = null;28 29 /**30 * Constructor.31 *32 * @since 1.6.033 */34 public function __construct() {35 $this->setup_actions();36 }37 38 /**39 * Hook Akismet into the activity stream.40 *41 * @since 1.6.042 */43 protected function setup_actions() {44 // Add nonces to activity stream lists.45 add_action( 'bp_after_activity_post_form', array( $this, 'add_activity_stream_nonce' ) );46 add_action( 'bp_activity_entry_comments', array( $this, 'add_activity_stream_nonce' ) );47 48 // Add a "mark as spam" button to individual activity items.49 add_action( 'bp_activity_entry_meta', array( $this, 'add_activity_spam_button' ) );50 add_action( 'bp_activity_comment_options', array( $this, 'add_activity_comment_spam_button' ) );51 52 // Check activity for spam.53 add_action( 'bp_activity_before_save', array( $this, 'check_activity' ), 4, 1 );54 55 // Tidy up member's latest (activity) update.56 add_action( 'bp_activity_posted_update', array( $this, 'check_member_activity_update' ), 1, 3 );57 58 // Hooks to extend Activity core spam/ham functions for Akismet.59 add_action( 'bp_activity_mark_as_spam', array( $this, 'mark_as_spam' ), 10, 2 );60 add_action( 'bp_activity_mark_as_ham', array( $this, 'mark_as_ham' ), 10, 2 );61 62 // Hook into the Activity wp-admin screen.63 add_action( 'bp_activity_admin_comment_row_actions', array( $this, 'comment_row_action' ), 10, 2 );64 add_action( 'bp_activity_admin_load', array( $this, 'add_history_metabox' ) );65 }66 67 /**68 * Add a history item to the hover links in an activity's row.69 *70 * This function lifted with love from the Akismet WordPress plugin's71 * akismet_comment_row_action() function. Thanks!72 *73 * @since 1.6.074 *75 * @param array $actions The hover links.76 * @param array $activity The activity for the current row being processed.77 * @return array The hover links.78 */79 function comment_row_action( $actions, $activity ) {80 $akismet_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_result' );81 $user_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_user_result' );82 $desc = '';83 84 if ( !$user_result || $user_result == $akismet_result ) {85 // Show the original Akismet result if the user hasn't overridden it, or if their decision was the same.86 if ( 'true' == $akismet_result && $activity['is_spam'] )87 $desc = __( 'Flagged as spam by Akismet', 'buddypress' );88 89 elseif ( 'false' == $akismet_result && !$activity['is_spam'] )90 $desc = __( 'Cleared by Akismet', 'buddypress' );91 92 } else {93 $who = bp_activity_get_meta( $activity['id'], '_bp_akismet_user' );94 95 if ( 'true' == $user_result )96 $desc = sprintf( __( 'Flagged as spam by %s', 'buddypress' ), $who );97 else98 $desc = sprintf( __( 'Un-spammed by %s', 'buddypress' ), $who );99 }100 101 // Add a History item to the hover links, just after Edit.102 if ( $akismet_result ) {103 $b = array();104 foreach ( $actions as $k => $item ) {105 $b[ $k ] = $item;106 if ( $k == 'edit' )107 $b['history'] = '<a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history"> '. __( 'History', 'buddypress' ) . '</a>';108 }109 110 $actions = $b;111 }112 113 if ( $desc )114 echo '<span class="akismet-status"><a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history">' . htmlspecialchars( $desc ) . '</a></span>';115 116 /**117 * Filters the list of actions for the current activity's row.118 *119 * @since 1.6.0120 *121 * @param array $actions Array of available actions for the current activity item's row.122 */123 return apply_filters( 'bp_akismet_comment_row_action', $actions );124 }125 126 /**127 * Generate nonces for activity forms.128 *129 * These nonces appear in the member profile status form, as well as in130 * the reply form of each activity item. The nonces are, in turn, used131 * by Akismet to help detect spam activity.132 *133 * @since 1.6.0134 *135 * @see https://plugins.trac.wordpress.org/ticket/1232136 */137 public function add_activity_stream_nonce() {138 $form_id = '_bp_as_nonce';139 $value = '_bp_as_nonce_' . bp_loggedin_user_id();140 141 // If we're in the activity stream loop, we can use the current item's ID to make the nonce unique.142 if ( 'bp_activity_entry_comments' == current_filter() ) {143 $form_id .= '_' . bp_get_activity_id();144 $value .= '_' . bp_get_activity_id();145 }146 147 wp_nonce_field( $value, $form_id, false );148 }149 150 /**151 * Clean up the bp_latest_update usermeta in case of spamming.152 *153 * Run just after an update is posted, this method check to see whether154 * the newly created update has been marked as spam by Akismet. If so,155 * the cached update is cleared from the user's 'bp_latest_update'156 * usermeta, ensuring that it won't appear in the member header and157 * elsewhere in the theme.158 *159 * This can't be done in BP_Akismet::check_activity() due to the160 * default AJAX implementation; see bp_dtheme_post_update().161 *162 * @since 1.6.0163 *164 * @see bp_dtheme_post_update()165 *166 * @param string $content Activity update text.167 * @param int $user_id User ID.168 * @param int $activity_id Activity ID.169 */170 public function check_member_activity_update( $content, $user_id, $activity_id ) {171 // By default, only handle activity updates and activity comments.172 if ( empty( $this->last_activity ) || !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )173 return;174 175 // Was this $activity_id just marked as spam? If not, bail out.176 if ( !$this->last_activity->id || $activity_id != $this->last_activity->id || 'false' == $this->last_activity->akismet_submission['bp_as_result'] )177 return;178 179 // It was, so delete the member's latest activity update.180 bp_delete_user_meta( $user_id, 'bp_latest_update' );181 }182 183 /**184 * Adds a "mark as spam" button to each activity item for site admins.185 *186 * This function is intended to be used inside the activity stream loop.187 *188 * @since 1.6.0189 */190 public function add_activity_spam_button() {191 if ( !bp_activity_user_can_mark_spam() )192 return;193 194 // By default, only handle activity updates and activity comments.195 if ( !in_array( bp_get_activity_type(), BP_Akismet::get_activity_types() ) )196 return;197 198 bp_button(199 array(200 'block_self' => false,201 'component' => 'activity',202 'id' => 'activity_make_spam_' . bp_get_activity_id(),203 'link_class' => 'bp-secondary-action spam-activity confirm button item-button',204 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_id() . '/', 'bp_activity_akismet_spam_' . bp_get_activity_id() ),205 'link_text' => __( 'Spam', 'buddypress' ),206 'wrapper' => false,207 )208 );209 }210 211 /**212 * Adds a "mark as spam" button to each activity COMMENT item for site admins.213 *214 * This function is intended to be used inside the activity stream loop.215 *216 * @since 1.6.0217 */218 public function add_activity_comment_spam_button() {219 if ( !bp_activity_user_can_mark_spam() )220 return;221 222 // By default, only handle activity updates and activity comments.223 $current_comment = bp_activity_current_comment();224 if ( empty( $current_comment ) || !in_array( $current_comment->type, BP_Akismet::get_activity_types() ) )225 return;226 227 bp_button(228 array(229 'block_self' => false,230 'component' => 'activity',231 'id' => 'activity_make_spam_' . bp_get_activity_comment_id(),232 'link_class' => 'bp-secondary-action spam-activity-comment confirm',233 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_comment_id() . '/?cid=' . bp_get_activity_comment_id(), 'bp_activity_akismet_spam_' . bp_get_activity_comment_id() ),234 'link_text' => __( 'Spam', 'buddypress' ),235 'wrapper' => false,236 )237 );238 }239 240 /**241 * Get a filterable list of activity types that Akismet should automatically check for spam.242 *243 * @since 1.6.0244 *245 * @static246 *247 * @return array $value List of activity types.248 */249 public static function get_activity_types() {250 251 /**252 * Filters the list of activity types that Akismet should automatically check for spam.253 *254 * @since 1.6.0255 *256 * @param array $value Array of default activity types for Akismet to check.257 */258 return apply_filters( 'bp_akismet_get_activity_types', array( 'activity_comment', 'activity_update' ) );259 }260 261 /**262 * Mark activity item as spam.263 *264 * @since 1.6.0265 *266 * @param BP_Activity_Activity $activity Activity item being spammed.267 * @param string $source Either "by_a_person" (e.g. a person has268 * manually marked the activity as spam) or269 * "by_akismet" (automatically spammed).270 */271 public function mark_as_spam( $activity, $source ) {272 // Record this item so we can do some tidyup in BP_Akismet::check_member_activity_update().273 $this->last_activity = $activity;274 275 /**276 * Fires after marking an activity item has been marked as spam.277 *278 * @since 1.6.0279 *280 * @param BP_Activity_Activity $activity Activity object being marked as spam.281 * @param string $source Source of the whom marked as spam.282 * Either "by_a_person" (e.g. a person has283 * manually marked the activity as spam)284 * or "by_akismet".285 */286 do_action( 'bp_activity_akismet_mark_as_spam', $activity, $source );287 }288 289 /**290 * Mark activity item as ham.291 *292 * @since 1.6.0293 *294 * @param BP_Activity_Activity $activity Activity item being hammed.295 * @param string $source Either "by_a_person" (e.g. a person has296 * manually marked the activity as ham) or297 * "by_akismet" (automatically hammed).298 */299 public function mark_as_ham( $activity, $source ) {300 // If the activity was, originally, automatically marked as spam by Akismet, run the @mentions filter as it would have been skipped.301 if ( 'true' == bp_activity_get_meta( $activity->id, '_bp_akismet_result' ) && !bp_activity_get_meta( $activity->id, '_bp_akismet_user_result' ) )302 $activity->content = bp_activity_at_name_filter( $activity->content, $activity->id );303 304 /**305 * Fires after marking an activity item has been marked as ham.306 *307 * @since 1.6.0308 *309 * @param BP_Activity_Activity $activity Activity object being marked as ham.310 * @param string $source Source of the whom marked as ham.311 * Either "by_a_person" (e.g. a person has312 * manually marked the activity as ham) or313 * "by_akismet" (automatically hammed).314 */315 do_action( 'bp_activity_akismet_mark_as_ham', $activity, $source );316 }317 318 /**319 * Build a data package for the Akismet service to inspect.320 *321 * @since 1.6.0322 *323 * @see http://akismet.com/development/api/#comment-check324 * @static325 *326 * @param BP_Activity_Activity $activity Activity item data.327 * @return array $activity_data328 */329 public static function build_akismet_data_package( $activity ) {330 $userdata = get_userdata( $activity->user_id );331 332 $activity_data = array();333 $activity_data['akismet_comment_nonce'] = 'inactive';334 $activity_data['comment_author'] = $userdata->display_name;335 $activity_data['comment_author_email'] = $userdata->user_email;336 $activity_data['comment_author_url'] = bp_core_get_userlink( $userdata->ID, false, true);337 $activity_data['comment_content'] = $activity->content;338 $activity_data['comment_type'] = $activity->type;339 $activity_data['permalink'] = bp_activity_get_permalink( $activity->id, $activity );340 $activity_data['user_ID'] = $userdata->ID;341 $activity_data['user_role'] = Akismet::get_user_roles( $userdata->ID );342 343 /**344 * Get the nonce if the new activity was submitted through the "what's up, Paul?" form.345 * This helps Akismet ensure that the update was a valid form submission.346 */347 if ( !empty( $_POST['_bp_as_nonce'] ) )348 $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST['_bp_as_nonce'], "_bp_as_nonce_{$userdata->ID}" ) ? 'passed' : 'failed';349 350 /**351 * If the new activity was a reply to an existing item, check the nonce with the activity parent ID.352 * This helps Akismet ensure that the update was a valid form submission.353 */354 elseif ( !empty( $activity->secondary_item_id ) && !empty( $_POST['_bp_as_nonce_' . $activity->secondary_item_id] ) )355 $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST["_bp_as_nonce_{$activity->secondary_item_id}"], "_bp_as_nonce_{$userdata->ID}_{$activity->secondary_item_id}" ) ? 'passed' : 'failed';356 357 /**358 * Filters activity data before being sent to Akismet to inspect.359 *360 * @since 1.6.0361 *362 * @param array $activity_data Array of activity data for Akismet to inspect.363 * @param BP_Activity_Activity $activity Activity item data.364 */365 return apply_filters( 'bp_akismet_build_akismet_data_package', $activity_data, $activity );366 }367 368 /**369 * Check if the activity item is spam or ham.370 *371 * @since 1.6.0372 *373 * @see http://akismet.com/development/api/374 * @todo Spam counter?375 * @todo Auto-delete old spam?376 *377 * @param BP_Activity_Activity $activity The activity item to check.378 */379 public function check_activity( $activity ) {380 // By default, only handle activity updates and activity comments.381 if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )382 return;383 384 // Make sure last_activity is clear to avoid any confusion.385 $this->last_activity = null;386 387 // Build data package for Akismet.388 $activity_data = BP_Akismet::build_akismet_data_package( $activity );389 390 // Check with Akismet to see if this is spam.391 $activity_data = $this->send_akismet_request( $activity_data, 'check', 'spam' );392 393 // Record this item.394 $this->last_activity = $activity;395 396 // Store a copy of the data that was submitted to Akismet.397 $this->last_activity->akismet_submission = $activity_data;398 399 // Spam.400 if ( 'true' == $activity_data['bp_as_result'] ) {401 /**402 * Fires after an activity item has been proven to be spam, but before officially being marked as spam.403 *404 * @since 1.6.0405 *406 * @param BP_Activity_Activity $activity The activity item proven to be spam.407 * @param array $activity_data Array of activity data for item including408 * Akismet check results data.409 */410 do_action_ref_array( 'bp_activity_akismet_spam_caught', array( &$activity, $activity_data ) );411 412 // Mark as spam.413 bp_activity_mark_as_spam( $activity, 'by_akismet' );414 }415 416 // Update activity meta after a spam check.417 add_action( 'bp_activity_after_save', array( $this, 'update_activity_akismet_meta' ), 1, 1 );418 }419 420 /**421 * Update activity meta after a manual spam change (user-initiated).422 *423 * @since 1.6.0424 *425 * @param BP_Activity_Activity $activity The activity to check.426 */427 public function update_activity_spam_meta( $activity ) {428 // By default, only handle activity updates and activity comments.429 if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )430 return;431 432 $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-spam' );433 bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'true' );434 bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );435 }436 437 /**438 * Update activity meta after a manual ham change (user-initiated).439 *440 * @since 1.6.0441 *442 * @param BP_Activity_Activity $activity The activity to check.443 */444 public function update_activity_ham_meta( $activity ) {445 // By default, only handle activity updates and activity comments.446 if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )447 return;448 449 $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as not spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-ham' );450 bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'false' );451 bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );452 }453 454 /**455 * Update activity meta after an automatic spam check (not user-initiated).456 *457 * @since 1.6.0458 *459 * @param BP_Activity_Activity $activity The activity to check.460 */461 public function update_activity_akismet_meta( $activity ) {462 // Check we're dealing with what was last updated by Akismet.463 if ( empty( $this->last_activity ) || !empty( $this->last_activity ) && $activity->id != $this->last_activity->id )464 return;465 466 // By default, only handle activity updates and activity comments.467 if ( !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )468 return;469 470 // Spam.471 if ( 'true' == $this->last_activity->akismet_submission['bp_as_result'] ) {472 bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'true' );473 $this->update_activity_history( $activity->id, __( 'Akismet caught this item as spam', 'buddypress' ), 'check-spam' );474 475 // Not spam.476 } elseif ( 'false' == $this->last_activity->akismet_submission['bp_as_result'] ) {477 bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'false' );478 $this->update_activity_history( $activity->id, __( 'Akismet cleared this item', 'buddypress' ), 'check-ham' );479 480 // Uh oh, something's gone horribly wrong. Unexpected result.481 } else {482 bp_activity_update_meta( $activity->id, '_bp_akismet_error', bp_core_current_time() );483 $this->update_activity_history( $activity->id, sprintf( __( 'Akismet was unable to check this item (response: %s), will automatically retry again later.', 'buddypress' ), $this->last_activity->akismet_submission['bp_as_result'] ), 'check-error' );484 }485 486 // Record the original data which was submitted to Akismet for checking.487 bp_activity_update_meta( $activity->id, '_bp_akismet_submission', $this->last_activity->akismet_submission );488 }489 490 /**491 * Contact Akismet to check if this is spam or ham.492 *493 * Props to WordPress core Akismet plugin for a lot of this.494 *495 * @since 1.6.0496 *497 * @param array $activity_data Packet of information to submit to Akismet.498 * @param string $check "check" or "submit".499 * @param string $spam "spam" or "ham".500 * @return array $activity_data Activity data, with Akismet data added.501 */502 public function send_akismet_request( $activity_data, $check = 'check', $spam = 'spam' ) {503 $query_string = $path = '';504 505 $activity_data['blog'] = bp_get_option( 'home' );506 $activity_data['blog_charset'] = bp_get_option( 'blog_charset' );507 $activity_data['blog_lang'] = get_locale();508 $activity_data['referrer'] = $_SERVER['HTTP_REFERER'];509 $activity_data['user_agent'] = bp_core_current_user_ua();510 $activity_data['user_ip'] = bp_core_current_user_ip();511 512 if ( Akismet::is_test_mode() )513 $activity_data['is_test'] = 'true';514 515 // Loop through _POST args and rekey strings.516 foreach ( $_POST as $key => $value )517 if ( is_string( $value ) && 'cookie' != $key )518 $activity_data['POST_' . $key] = $value;519 520 // Keys to ignore.521 $ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );522 523 // Loop through _SERVER args and remove whitelisted keys.524 foreach ( $_SERVER as $key => $value ) {525 526 // Key should not be ignored.527 if ( !in_array( $key, $ignore ) && is_string( $value ) ) {528 $activity_data[$key] = $value;529 530 // Key should be ignored.531 } else {532 $activity_data[$key] = '';533 }534 }535 536 foreach ( $activity_data as $key => $data )537 $query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';538 539 if ( 'check' == $check )540 $path = 'comment-check';541 elseif ( 'submit' == $check )542 $path = 'submit-' . $spam;543 544 // Send to Akismet.545 add_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );546 $response = Akismet::http_post( $query_string, $path );547 remove_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );548 549 // Get the response.550 if ( ! empty( $response[1] ) && ! is_wp_error( $response[1] ) )551 $activity_data['bp_as_result'] = $response[1];552 else553 $activity_data['bp_as_result'] = false;554 555 // Perform a daily tidy up.556 if ( ! wp_next_scheduled( 'bp_activity_akismet_delete_old_metadata' ) )557 wp_schedule_event( time(), 'daily', 'bp_activity_akismet_delete_old_metadata' );558 559 return $activity_data;560 }561 562 /**563 * Filters user agent when sending to Akismet to add BuddyPress info.564 *565 * @since 1.6.0566 *567 * @param string $user_agent User agent string, as generated by Akismet.568 * @return string $user_agent Modified user agent string.569 */570 public function buddypress_ua( $user_agent ) {571 $user_agent = 'BuddyPress/' . bp_get_version() . ' | Akismet/'. constant( 'AKISMET_VERSION' );572 return $user_agent;573 }574 575 /**576 * Adds a "History" meta box to the activity edit screen.577 *578 * @since 1.6.0579 *580 * @param string $screen_action The type of screen that has been requested.581 */582 function add_history_metabox( $screen_action ) {583 // Only proceed if we're on the edit screen.584 if ( 'edit' != $screen_action )585 return;586 587 // Display meta box with a low priority (low position on screen by default).588 add_meta_box( 'bp_activity_history', __( 'Activity History', 'buddypress' ), array( $this, 'history_metabox' ), get_current_screen()->id, 'normal', 'low' );589 }590 591 /**592 * History meta box for the Activity admin edit screen.593 *594 * @since 1.6.0595 *596 * @see https://buddypress.trac.wordpress.org/ticket/3907597 * @todo Update activity meta to allow >1 record with the same key (iterate through $history).598 *599 * @param object $item Activity item.600 */601 function history_metabox( $item ) {602 $history = BP_Akismet::get_activity_history( $item->id );603 604 if ( empty( $history ) )605 return;606 607 echo '<div class="akismet-history"><div>';608 printf( _x( '%1$s — %2$s', 'x hours ago - akismet cleared this item', 'buddypress' ), '<span>' . bp_core_time_since( $history[2] ) . '</span>', esc_html( $history[1] ) );609 echo '</div></div>';610 }611 612 /**613 * Update an activity item's Akismet history.614 *615 * @since 1.6.0616 *617 * @param int $activity_id Activity item ID.618 * @param string $message Human-readable description of what's changed.619 * @param string $event The type of check we were carrying out.620 */621 public function update_activity_history( $activity_id = 0, $message = '', $event = '' ) {622 $event = array(623 'event' => $event,624 'message' => $message,625 'time' => Akismet::_get_microtime(),626 'user' => bp_loggedin_user_id(),627 );628 629 // Save the history data.630 bp_activity_update_meta( $activity_id, '_bp_akismet_history', $event );631 }632 633 /**634 * Get an activity item's Akismet history.635 *636 * @since 1.6.0637 *638 * @param int $activity_id Activity item ID.639 * @return array The activity item's Akismet history.640 */641 public function get_activity_history( $activity_id = 0 ) {642 $history = bp_activity_get_meta( $activity_id, '_bp_akismet_history' );643 if ( $history === false )644 $history = array();645 646 // Sort it by the time recorded.647 usort( $history, 'akismet_cmp_time' );648 649 return $history;650 }651 }652 653 15 /** 654 16 * Delete old spam activity meta data. 655 17 * -
src/bp-activity/bp-activity-loader.php
12 12 // Exit if accessed directly. 13 13 defined( 'ABSPATH' ) || exit; 14 14 15 /** 16 * Main Activity Class. 17 * 18 * @since 1.5.0 19 */ 20 class BP_Activity_Component extends BP_Component { 15 require dirname( __FILE__ ) . '/classes/class-bp-activity-loader.php'; 21 16 22 /**23 * Start the activity component setup process.24 *25 * @since 1.5.026 */27 public function __construct() {28 parent::start(29 'activity',30 __( 'Activity Streams', 'buddypress' ),31 buddypress()->plugin_dir,32 array(33 'adminbar_myaccount_order' => 10,34 'search_query_arg' => 'activity_search',35 )36 );37 }38 39 /**40 * Include component files.41 *42 * @since 1.5.043 *44 * @see BP_Component::includes() for a description of arguments.45 *46 * @param array $includes See BP_Component::includes() for a description.47 */48 public function includes( $includes = array() ) {49 50 // Files to include.51 $includes = array(52 'cssjs',53 'actions',54 'screens',55 'filters',56 'classes',57 'template',58 'functions',59 'notifications',60 'cache'61 );62 63 // Load Akismet support if Akismet is configured.64 $akismet_key = bp_get_option( 'wordpress_api_key' );65 66 /** This filter is documented in bp-activity/bp-activity-actions.php */67 if ( defined( 'AKISMET_VERSION' ) && class_exists( 'Akismet' ) && ( ! empty( $akismet_key ) || defined( 'WPCOM_API_KEY' ) ) && apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {68 $includes[] = 'akismet';69 }70 71 if ( is_admin() ) {72 $includes[] = 'admin';73 }74 75 parent::includes( $includes );76 }77 78 /**79 * Set up component global variables.80 *81 * The BP_ACTIVITY_SLUG constant is deprecated, and only used here for82 * backwards compatibility.83 *84 * @since 1.5.085 *86 * @see BP_Component::setup_globals() for a description of arguments.87 *88 * @param array $args See BP_Component::setup_globals() for a description.89 */90 public function setup_globals( $args = array() ) {91 $bp = buddypress();92 93 // Define a slug, if necessary.94 if ( ! defined( 'BP_ACTIVITY_SLUG' ) ) {95 define( 'BP_ACTIVITY_SLUG', $this->id );96 }97 98 // Global tables for activity component.99 $global_tables = array(100 'table_name' => $bp->table_prefix . 'bp_activity',101 'table_name_meta' => $bp->table_prefix . 'bp_activity_meta',102 );103 104 // Metadata tables for groups component.105 $meta_tables = array(106 'activity' => $bp->table_prefix . 'bp_activity_meta',107 );108 109 // All globals for activity component.110 // Note that global_tables is included in this array.111 $args = array(112 'slug' => BP_ACTIVITY_SLUG,113 'root_slug' => isset( $bp->pages->activity->slug ) ? $bp->pages->activity->slug : BP_ACTIVITY_SLUG,114 'has_directory' => true,115 'directory_title' => _x( 'Site-Wide Activity', 'component directory title', 'buddypress' ),116 'notification_callback' => 'bp_activity_format_notifications',117 'search_string' => __( 'Search Activity...', 'buddypress' ),118 'global_tables' => $global_tables,119 'meta_tables' => $meta_tables,120 );121 122 parent::setup_globals( $args );123 }124 125 /**126 * Set up component navigation.127 *128 * @since 1.5.0129 *130 * @see BP_Component::setup_nav() for a description of arguments.131 * @uses bp_is_active()132 * @uses is_user_logged_in()133 * @uses bp_get_friends_slug()134 * @uses bp_get_groups_slug()135 *136 * @param array $main_nav Optional. See BP_Component::setup_nav() for description.137 * @param array $sub_nav Optional. See BP_Component::setup_nav() for description.138 */139 public function setup_nav( $main_nav = array(), $sub_nav = array() ) {140 141 // Stop if there is no user displayed or logged in.142 if ( ! is_user_logged_in() && ! bp_displayed_user_id() ) {143 return;144 }145 146 // Determine user to use.147 if ( bp_displayed_user_domain() ) {148 $user_domain = bp_displayed_user_domain();149 } elseif ( bp_loggedin_user_domain() ) {150 $user_domain = bp_loggedin_user_domain();151 } else {152 return;153 }154 155 $slug = bp_get_activity_slug();156 $activity_link = trailingslashit( $user_domain . $slug );157 158 // Add 'Activity' to the main navigation.159 $main_nav = array(160 'name' => _x( 'Activity', 'Profile activity screen nav', 'buddypress' ),161 'slug' => $slug,162 'position' => 10,163 'screen_function' => 'bp_activity_screen_my_activity',164 'default_subnav_slug' => 'just-me',165 'item_css_id' => $this->id166 );167 168 // Add the subnav items to the activity nav item if we are using a theme that supports this.169 $sub_nav[] = array(170 'name' => _x( 'Personal', 'Profile activity screen sub nav', 'buddypress' ),171 'slug' => 'just-me',172 'parent_url' => $activity_link,173 'parent_slug' => $slug,174 'screen_function' => 'bp_activity_screen_my_activity',175 'position' => 10176 );177 178 // Check @mentions.179 if ( bp_activity_do_mentions() ) {180 $sub_nav[] = array(181 'name' => _x( 'Mentions', 'Profile activity screen sub nav', 'buddypress' ),182 'slug' => 'mentions',183 'parent_url' => $activity_link,184 'parent_slug' => $slug,185 'screen_function' => 'bp_activity_screen_mentions',186 'position' => 20,187 'item_css_id' => 'activity-mentions'188 );189 }190 191 // Favorite activity items.192 if ( bp_activity_can_favorite() ) {193 $sub_nav[] = array(194 'name' => _x( 'Favorites', 'Profile activity screen sub nav', 'buddypress' ),195 'slug' => 'favorites',196 'parent_url' => $activity_link,197 'parent_slug' => $slug,198 'screen_function' => 'bp_activity_screen_favorites',199 'position' => 30,200 'item_css_id' => 'activity-favs'201 );202 }203 204 // Additional menu if friends is active.205 if ( bp_is_active( 'friends' ) ) {206 $sub_nav[] = array(207 'name' => _x( 'Friends', 'Profile activity screen sub nav', 'buddypress' ),208 'slug' => bp_get_friends_slug(),209 'parent_url' => $activity_link,210 'parent_slug' => $slug,211 'screen_function' => 'bp_activity_screen_friends',212 'position' => 40,213 'item_css_id' => 'activity-friends'214 ) ;215 }216 217 // Additional menu if groups is active.218 if ( bp_is_active( 'groups' ) ) {219 $sub_nav[] = array(220 'name' => _x( 'Groups', 'Profile activity screen sub nav', 'buddypress' ),221 'slug' => bp_get_groups_slug(),222 'parent_url' => $activity_link,223 'parent_slug' => $slug,224 'screen_function' => 'bp_activity_screen_groups',225 'position' => 50,226 'item_css_id' => 'activity-groups'227 );228 }229 230 parent::setup_nav( $main_nav, $sub_nav );231 }232 233 /**234 * Set up the component entries in the WordPress Admin Bar.235 *236 * @since 1.5.0237 *238 * @see BP_Component::setup_nav() for a description of the $wp_admin_nav239 * parameter array.240 * @uses is_user_logged_in()241 * @uses trailingslashit()242 * @uses bp_get_total_mention_count_for_user()243 * @uses bp_loggedin_user_id()244 * @uses bp_is_active()245 * @uses bp_get_friends_slug()246 * @uses bp_get_groups_slug()247 *248 * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a249 * description.250 */251 public function setup_admin_bar( $wp_admin_nav = array() ) {252 253 // Menus for logged in user.254 if ( is_user_logged_in() ) {255 256 // Setup the logged in user variables.257 $activity_link = trailingslashit( bp_loggedin_user_domain() . bp_get_activity_slug() );258 259 // Unread message count.260 if ( bp_activity_do_mentions() ) {261 $count = bp_get_total_mention_count_for_user( bp_loggedin_user_id() );262 if ( !empty( $count ) ) {263 $title = sprintf( _x( 'Mentions <span class="count">%s</span>', 'Toolbar Mention logged in user', 'buddypress' ), bp_core_number_format( $count ) );264 } else {265 $title = _x( 'Mentions', 'Toolbar Mention logged in user', 'buddypress' );266 }267 }268 269 // Add the "Activity" sub menu.270 $wp_admin_nav[] = array(271 'parent' => buddypress()->my_account_menu_id,272 'id' => 'my-account-' . $this->id,273 'title' => _x( 'Activity', 'My Account Activity sub nav', 'buddypress' ),274 'href' => $activity_link275 );276 277 // Personal.278 $wp_admin_nav[] = array(279 'parent' => 'my-account-' . $this->id,280 'id' => 'my-account-' . $this->id . '-personal',281 'title' => _x( 'Personal', 'My Account Activity sub nav', 'buddypress' ),282 'href' => $activity_link283 );284 285 // Mentions.286 if ( bp_activity_do_mentions() ) {287 $wp_admin_nav[] = array(288 'parent' => 'my-account-' . $this->id,289 'id' => 'my-account-' . $this->id . '-mentions',290 'title' => $title,291 'href' => trailingslashit( $activity_link . 'mentions' )292 );293 }294 295 // Favorite activity items.296 if ( bp_activity_can_favorite() ) {297 $wp_admin_nav[] = array(298 'parent' => 'my-account-' . $this->id,299 'id' => 'my-account-' . $this->id . '-favorites',300 'title' => _x( 'Favorites', 'My Account Activity sub nav', 'buddypress' ),301 'href' => trailingslashit( $activity_link . 'favorites' )302 );303 }304 305 // Friends?306 if ( bp_is_active( 'friends' ) ) {307 $wp_admin_nav[] = array(308 'parent' => 'my-account-' . $this->id,309 'id' => 'my-account-' . $this->id . '-friends',310 'title' => _x( 'Friends', 'My Account Activity sub nav', 'buddypress' ),311 'href' => trailingslashit( $activity_link . bp_get_friends_slug() )312 );313 }314 315 // Groups?316 if ( bp_is_active( 'groups' ) ) {317 $wp_admin_nav[] = array(318 'parent' => 'my-account-' . $this->id,319 'id' => 'my-account-' . $this->id . '-groups',320 'title' => _x( 'Groups', 'My Account Activity sub nav', 'buddypress' ),321 'href' => trailingslashit( $activity_link . bp_get_groups_slug() )322 );323 }324 }325 326 parent::setup_admin_bar( $wp_admin_nav );327 }328 329 /**330 * Set up the title for pages and <title>.331 *332 * @since 1.5.0333 *334 * @uses bp_is_activity_component()335 * @uses bp_is_my_profile()336 * @uses bp_core_fetch_avatar()337 */338 public function setup_title() {339 340 // Adjust title based on view.341 if ( bp_is_activity_component() ) {342 $bp = buddypress();343 344 if ( bp_is_my_profile() ) {345 $bp->bp_options_title = _x( 'My Activity', 'Page and <title>', 'buddypress' );346 } else {347 $bp->bp_options_avatar = bp_core_fetch_avatar( array(348 'item_id' => bp_displayed_user_id(),349 'type' => 'thumb',350 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )351 ) );352 $bp->bp_options_title = bp_get_displayed_user_fullname();353 }354 }355 356 parent::setup_title();357 }358 359 /**360 * Set up actions necessary for the component.361 *362 * @since 1.6.0363 */364 public function setup_actions() {365 366 // Spam prevention.367 add_action( 'bp_include', 'bp_activity_setup_akismet' );368 369 parent::setup_actions();370 }371 372 /**373 * Setup cache groups.374 *375 * @since 2.2.0376 */377 public function setup_cache_groups() {378 379 // Global groups.380 wp_cache_add_global_groups( array(381 'bp_activity',382 'bp_activity_comments',383 'activity_meta'384 ) );385 386 parent::setup_cache_groups();387 }388 }389 390 17 /** 391 18 * Bootstrap the Activity component. 392 19 * -
src/bp-activity/bp-activity-screens.php
14 14 // Exit if accessed directly. 15 15 defined( 'ABSPATH' ) || exit; 16 16 17 require dirname( __FILE__ ) . '/classes/class-bp-activity-theme-compat.php'; 18 17 19 /** 18 20 * Load the Activity directory. 19 21 * … … 416 418 417 419 /** Theme Compatibility *******************************************************/ 418 420 419 /**420 * The main theme compat class for BuddyPress Activity.421 *422 * This class sets up the necessary theme compatibility actions to safely output423 * activity template parts to the_title and the_content areas of a theme.424 *425 * @since 1.7.0426 */427 class BP_Activity_Theme_Compat {428 429 /**430 * Set up the activity component theme compatibility.431 *432 * @since 1.7.0433 */434 public function __construct() {435 add_action( 'bp_setup_theme_compat', array( $this, 'is_activity' ) );436 }437 438 /**439 * Set up the theme compatibility hooks, if we're looking at an activity page.440 *441 * @since 1.7.0442 */443 public function is_activity() {444 445 // Bail if not looking at a group.446 if ( ! bp_is_activity_component() )447 return;448 449 // Activity Directory.450 if ( ! bp_displayed_user_id() && ! bp_current_action() ) {451 bp_update_is_directory( true, 'activity' );452 453 /** This action is documented in bp-activity/bp-activity-screens.php */454 do_action( 'bp_activity_screen_index' );455 456 add_filter( 'bp_get_buddypress_template', array( $this, 'directory_template_hierarchy' ) );457 add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );458 add_filter( 'bp_replace_the_content', array( $this, 'directory_content' ) );459 460 // Single activity.461 } elseif ( bp_is_single_activity() ) {462 add_filter( 'bp_get_buddypress_template', array( $this, 'single_template_hierarchy' ) );463 add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'single_dummy_post' ) );464 add_filter( 'bp_replace_the_content', array( $this, 'single_dummy_content' ) );465 }466 }467 468 /** Directory *************************************************************/469 470 /**471 * Add template hierarchy to theme compat for the activity directory page.472 *473 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.474 *475 * @since 1.8.0476 *477 * @param string $templates The templates from bp_get_theme_compat_templates().478 * @return array $templates Array of custom templates to look for.479 */480 public function directory_template_hierarchy( $templates ) {481 482 /**483 * Filters the template hierarchy for the activity directory page.484 *485 * @since 1.8.0486 *487 * @param array $index-directory Array holding template names to be merged into template list.488 */489 $new_templates = apply_filters( 'bp_template_hierarchy_activity_directory', array(490 'activity/index-directory.php'491 ) );492 493 // Merge new templates with existing stack494 // @see bp_get_theme_compat_templates().495 $templates = array_merge( (array) $new_templates, $templates );496 497 return $templates;498 }499 500 /**501 * Update the global $post with directory data.502 *503 * @since 1.7.0504 */505 public function directory_dummy_post() {506 bp_theme_compat_reset_post( array(507 'ID' => 0,508 'post_title' => bp_get_directory_title( 'activity' ),509 'post_author' => 0,510 'post_date' => 0,511 'post_content' => '',512 'post_type' => 'page',513 'post_status' => 'publish',514 'is_page' => true,515 'comment_status' => 'closed'516 ) );517 }518 519 /**520 * Filter the_content with the groups index template part.521 *522 * @since 1.7.0523 */524 public function directory_content() {525 return bp_buffer_template_part( 'activity/index', null, false );526 }527 528 /** Single ****************************************************************/529 530 /**531 * Add custom template hierarchy to theme compat for activity permalink pages.532 *533 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.534 *535 * @since 1.8.0536 *537 * @param string $templates The templates from bp_get_theme_compat_templates().538 * @return array $templates Array of custom templates to look for.539 */540 public function single_template_hierarchy( $templates ) {541 542 /**543 * Filters the template hierarchy for the activity permalink pages.544 *545 * @since 1.8.0546 *547 * @param array $index Array holding template names to be merged into template list.548 */549 $new_templates = apply_filters( 'bp_template_hierarchy_activity_single_item', array(550 'activity/single/index.php'551 ) );552 553 // Merge new templates with existing stack554 // @see bp_get_theme_compat_templates().555 $templates = array_merge( (array) $new_templates, $templates );556 557 return $templates;558 }559 560 /**561 * Update the global $post with the displayed user's data.562 *563 * @since 1.7.0564 */565 public function single_dummy_post() {566 bp_theme_compat_reset_post( array(567 'ID' => 0,568 'post_title' => __( 'Activity', 'buddypress' ),569 'post_author' => 0,570 'post_date' => 0,571 'post_content' => '',572 'post_type' => 'page',573 'post_status' => 'publish',574 'is_page' => true,575 'comment_status' => 'closed'576 ) );577 }578 579 /**580 * Filter the_content with the members' activity permalink template part.581 *582 * @since 1.7.0583 */584 public function single_dummy_content() {585 return bp_buffer_template_part( 'activity/single/home', null, false );586 }587 }588 421 new BP_Activity_Theme_Compat(); -
src/bp-activity/bp-activity-template.php
10 10 // Exit if accessed directly. 11 11 defined( 'ABSPATH' ) || exit; 12 12 13 require dirname( __FILE__ ) . '/classes/class-bp-activity-template.php'; 14 13 15 /** 14 16 * Output the activity component slug. 15 17 * … … 107 109 } 108 110 109 111 /** 110 * The main activity template loop class.111 *112 * This is responsible for loading a group of activity items and displaying them.113 *114 * @since 1.0.0115 */116 class BP_Activity_Template {117 118 /**119 * The loop iterator.120 *121 * @since 1.0.0122 * @var int123 */124 public $current_activity = -1;125 126 /**127 * The activity count.128 *129 * @since 1.0.0130 * @var int131 */132 public $activity_count;133 134 /**135 * The total activity count.136 *137 * @since 1.0.0138 * @var int139 */140 public $total_activity_count;141 142 /**143 * Array of activities located by the query.144 *145 * @since 1.0.0146 * @var array147 */148 public $activities;149 150 /**151 * The activity object currently being iterated on.152 *153 * @since 1.0.0154 * @var object155 */156 public $activity;157 158 /**159 * A flag for whether the loop is currently being iterated.160 *161 * @since 1.0.0162 * @var bool163 */164 public $in_the_loop;165 166 /**167 * URL parameter key for activity pagination. Default: 'acpage'.168 *169 * @since 2.1.0170 * @var string171 */172 public $pag_arg;173 174 /**175 * The page number being requested.176 *177 * @since 1.0.0178 * @var int179 */180 public $pag_page;181 182 /**183 * The number of items being requested per page.184 *185 * @since 1.0.0186 * @var int187 */188 public $pag_num;189 190 /**191 * An HTML string containing pagination links.192 *193 * @since 1.0.0194 * @var string195 */196 public $pag_links;197 198 /**199 * The displayed user's full name.200 *201 * @since 1.0.0202 * @var string203 */204 public $full_name;205 206 /**207 * Constructor method.208 *209 * The arguments passed to this class constructor are of the same210 * format as {@link BP_Activity_Activity::get()}.211 *212 * @since 1.5.0213 *214 * @see BP_Activity_Activity::get() for a description of the argument215 * structure, as well as default values.216 *217 * @param array $args {218 * Array of arguments. Supports all arguments from219 * BP_Activity_Activity::get(), as well as 'page_arg' and220 * 'include'. Default values for 'per_page' and 'display_comments'221 * differ from the originating function, and are described below.222 * @type string $page_arg The string used as a query parameter in223 * pagination links. Default: 'acpage'.224 * @type array|bool $include Pass an array of activity IDs to225 * retrieve only those items, or false to noop the 'include'226 * parameter. 'include' differs from 'in' in that 'in' forms227 * an IN clause that works in conjunction with other filters228 * passed to the function, while 'include' is interpreted as229 * an exact list of items to retrieve, which skips all other230 * filter-related parameters. Default: false.231 * @type int|bool $per_page Default: 20.232 * @type string|bool $display_comments Default: 'threaded'.233 * }234 */235 public function __construct( $args ) {236 $bp = buddypress();237 238 // Backward compatibility with old method of passing arguments.239 if ( !is_array( $args ) || func_num_args() > 1 ) {240 _deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );241 242 $old_args_keys = array(243 0 => 'page',244 1 => 'per_page',245 2 => 'max',246 3 => 'include',247 4 => 'sort',248 5 => 'filter',249 6 => 'search_terms',250 7 => 'display_comments',251 8 => 'show_hidden',252 9 => 'exclude',253 10 => 'in',254 11 => 'spam',255 12 => 'page_arg'256 );257 258 $func_args = func_get_args();259 $args = bp_core_parse_args_array( $old_args_keys, $func_args );260 }261 262 $defaults = array(263 'page' => 1,264 'per_page' => 20,265 'page_arg' => 'acpage',266 'max' => false,267 'fields' => 'all',268 'count_total' => false,269 'sort' => false,270 'include' => false,271 'exclude' => false,272 'in' => false,273 'filter' => false,274 'scope' => false,275 'search_terms' => false,276 'meta_query' => false,277 'date_query' => false,278 'filter_query' => false,279 'display_comments' => 'threaded',280 'show_hidden' => false,281 'spam' => 'ham_only',282 'update_meta_cache' => true,283 );284 $r = wp_parse_args( $args, $defaults );285 extract( $r );286 287 $this->pag_arg = sanitize_key( $r['page_arg'] );288 $this->pag_page = bp_sanitize_pagination_arg( $this->pag_arg, $r['page'] );289 $this->pag_num = bp_sanitize_pagination_arg( 'num', $r['per_page'] );290 291 // Check if blog/forum replies are disabled.292 $this->disable_blogforum_replies = (bool) bp_core_get_root_option( 'bp-disable-blogforum-comments' );293 294 // Get an array of the logged in user's favorite activities.295 $this->my_favs = maybe_unserialize( bp_get_user_meta( bp_loggedin_user_id(), 'bp_favorite_activities', true ) );296 297 // Fetch specific activity items based on ID's.298 if ( !empty( $include ) ) {299 $this->activities = bp_activity_get_specific( array(300 'activity_ids' => explode( ',', $include ),301 'max' => $max,302 'count_total' => $count_total,303 'page' => $this->pag_page,304 'per_page' => $this->pag_num,305 'sort' => $sort,306 'display_comments' => $display_comments,307 'show_hidden' => $show_hidden,308 'spam' => $spam,309 'update_meta_cache' => $update_meta_cache,310 ) );311 312 // Fetch all activity items.313 } else {314 $this->activities = bp_activity_get( array(315 'display_comments' => $display_comments,316 'max' => $max,317 'count_total' => $count_total,318 'per_page' => $this->pag_num,319 'page' => $this->pag_page,320 'sort' => $sort,321 'search_terms' => $search_terms,322 'meta_query' => $meta_query,323 'date_query' => $date_query,324 'filter_query' => $filter_query,325 'filter' => $filter,326 'scope' => $scope,327 'show_hidden' => $show_hidden,328 'exclude' => $exclude,329 'in' => $in,330 'spam' => $spam,331 'update_meta_cache' => $update_meta_cache,332 ) );333 }334 335 // The total_activity_count property will be set only if a336 // 'count_total' query has taken place.337 if ( ! is_null( $this->activities['total'] ) ) {338 if ( ! $max || $max >= (int) $this->activities['total'] ) {339 $this->total_activity_count = (int) $this->activities['total'];340 } else {341 $this->total_activity_count = (int) $max;342 }343 }344 345 $this->has_more_items = $this->activities['has_more_items'];346 347 $this->activities = $this->activities['activities'];348 349 if ( $max ) {350 if ( $max >= count($this->activities) ) {351 $this->activity_count = count( $this->activities );352 } else {353 $this->activity_count = (int) $max;354 }355 } else {356 $this->activity_count = count( $this->activities );357 }358 359 $this->full_name = bp_get_displayed_user_fullname();360 361 // Fetch parent content for activity comments so we do not have to query in the loop.362 foreach ( (array) $this->activities as $activity ) {363 if ( 'activity_comment' != $activity->type ) {364 continue;365 }366 367 $parent_ids[] = $activity->item_id;368 }369 370 if ( !empty( $parent_ids ) ) {371 $activity_parents = bp_activity_get_specific( array( 'activity_ids' => $parent_ids ) );372 }373 374 if ( !empty( $activity_parents['activities'] ) ) {375 foreach( $activity_parents['activities'] as $parent ) {376 $this->activity_parents[$parent->id] = $parent;377 }378 379 unset( $activity_parents );380 }381 382 if ( (int) $this->total_activity_count && (int) $this->pag_num ) {383 $this->pag_links = paginate_links( array(384 'base' => add_query_arg( $this->pag_arg, '%#%' ),385 'format' => '',386 'total' => ceil( (int) $this->total_activity_count / (int) $this->pag_num ),387 'current' => (int) $this->pag_page,388 'prev_text' => _x( '←', 'Activity pagination previous text', 'buddypress' ),389 'next_text' => _x( '→', 'Activity pagination next text', 'buddypress' ),390 'mid_size' => 1,391 'add_args' => array(),392 ) );393 }394 }395 396 /**397 * Whether there are activity items available in the loop.398 *399 * @since 1.0.0400 *401 * @see bp_has_activities()402 *403 * @return bool True if there are items in the loop, otherwise false.404 */405 function has_activities() {406 if ( $this->activity_count ) {407 return true;408 }409 410 return false;411 }412 413 /**414 * Set up the next activity item and iterate index.415 *416 * @since 1.0.0417 *418 * @return object The next activity item to iterate over.419 */420 public function next_activity() {421 $this->current_activity++;422 $this->activity = $this->activities[ $this->current_activity ];423 424 return $this->activity;425 }426 427 /**428 * Rewind the posts and reset post index.429 *430 * @since 1.0.0431 */432 public function rewind_activities() {433 $this->current_activity = -1;434 if ( $this->activity_count > 0 ) {435 $this->activity = $this->activities[0];436 }437 }438 439 /**440 * Whether there are activity items left in the loop to iterate over.441 *442 * This method is used by {@link bp_activities()} as part of the while loop443 * that controls iteration inside the activities loop, eg:444 * while ( bp_activities() ) { ...445 *446 * @since 1.0.0447 *448 * @see bp_activities()449 *450 * @return bool True if there are more activity items to show,451 * otherwise false.452 */453 public function user_activities() {454 if ( ( $this->current_activity + 1 ) < $this->activity_count ) {455 return true;456 } elseif ( ( $this->current_activity + 1 ) == $this->activity_count ) {457 458 /**459 * Fires right before the rewinding of activity posts.460 *461 * @since 1.1.0462 */463 do_action( 'activity_loop_end' );464 465 // Do some cleaning up after the loop.466 $this->rewind_activities();467 }468 469 $this->in_the_loop = false;470 471 return false;472 }473 474 /**475 * Set up the current activity item inside the loop.476 *477 * Used by {@link bp_the_activity()} to set up the current activity item478 * data while looping, so that template tags used during that iteration479 * make reference to the current activity item.480 *481 * @since 1.0.0482 *483 * @see bp_the_activity()484 */485 public function the_activity() {486 487 $this->in_the_loop = true;488 $this->activity = $this->next_activity();489 490 if ( is_array( $this->activity ) ) {491 $this->activity = (object) $this->activity;492 }493 494 // Loop has just started.495 if ( $this->current_activity == 0 ) {496 497 /**498 * Fires if the current activity item is the first in the activity loop.499 *500 * @since 1.1.0501 */502 do_action('activity_loop_start');503 }504 }505 }506 507 /**508 112 * Initialize the activity loop. 509 113 * 510 114 * Based on the $args passed, bp_has_activities() populates the -
src/bp-activity/classes/class-bp-activity-list-table.php
1 1 <?php 2 /**3 * BuddyPress Activity component admin screen.4 *5 * Props to WordPress core for the Comments admin screen, and its contextual6 * help text, on which this implementation is heavily based.7 *8 * @package BuddyPress9 * @subpackage ActivityAdmin10 * @since 1.6.011 */12 2 13 // Exit if accessed directly.14 defined( 'ABSPATH' ) || exit;15 16 // Include WP's list table class.17 if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );18 19 // Per_page screen option. Has to be hooked in extremely early.20 if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-activity' == $_REQUEST['page'] )21 add_filter( 'set-screen-option', 'bp_activity_admin_screen_options', 10, 3 );22 23 3 /** 24 * Register the Activity component admin screen.25 *26 * @since 1.6.027 */28 function bp_activity_add_admin_menu() {29 30 // Add our screen.31 $hook = add_menu_page(32 _x( 'Activity', 'Admin Dashbord SWA page title', 'buddypress' ),33 _x( 'Activity', 'Admin Dashbord SWA menu', 'buddypress' ),34 'bp_moderate',35 'bp-activity',36 'bp_activity_admin',37 'div'38 );39 40 // Hook into early actions to load custom CSS and our init handler.41 add_action( "load-$hook", 'bp_activity_admin_load' );42 }43 add_action( bp_core_admin_hook(), 'bp_activity_add_admin_menu' );44 45 /**46 * Add activity component to custom menus array.47 *48 * Several BuddyPress components have top-level menu items in the Dashboard,49 * which all appear together in the middle of the Dashboard menu. This function50 * adds the Activity page to the array of these menu items.51 *52 * @since 1.7.053 *54 * @param array $custom_menus The list of top-level BP menu items.55 * @return array $custom_menus List of top-level BP menu items, with Activity added.56 */57 function bp_activity_admin_menu_order( $custom_menus = array() ) {58 array_push( $custom_menus, 'bp-activity' );59 return $custom_menus;60 }61 add_filter( 'bp_admin_menu_order', 'bp_activity_admin_menu_order' );62 63 /**64 * AJAX receiver for Activity replies via the admin screen.65 *66 * Processes requests to add new activity comments, and echoes HTML for a new67 * table row.68 *69 * @since 1.6.070 */71 function bp_activity_admin_reply() {72 // Check nonce.73 check_ajax_referer( 'bp-activity-admin-reply', '_ajax_nonce-bp-activity-admin-reply' );74 75 $parent_id = ! empty( $_REQUEST['parent_id'] ) ? (int) $_REQUEST['parent_id'] : 0;76 $root_id = ! empty( $_REQUEST['root_id'] ) ? (int) $_REQUEST['root_id'] : 0;77 78 // $parent_id is required79 if ( empty( $parent_id ) )80 die( '-1' );81 82 // If $root_id not set (e.g. for root items), use $parent_id.83 if ( empty( $root_id ) )84 $root_id = $parent_id;85 86 // Check that a reply has been entered.87 if ( empty( $_REQUEST['content'] ) )88 die( __( 'ERROR: Please type a reply.', 'buddypress' ) );89 90 // Check parent activity exists.91 $parent_activity = new BP_Activity_Activity( $parent_id );92 if ( empty( $parent_activity->component ) )93 die( __( 'ERROR: The item you are trying to reply to cannot be found, or it has been deleted.', 'buddypress' ) );94 95 // @todo: Check if user is allowed to create new activity items96 // if ( ! current_user_can( 'bp_new_activity' ) )97 if ( ! current_user_can( 'bp_moderate' ) )98 die( '-1' );99 100 // Add new activity comment.101 $new_activity_id = bp_activity_new_comment( array(102 'activity_id' => $root_id, // ID of the root activity item.103 'content' => $_REQUEST['content'],104 'parent_id' => $parent_id, // ID of a parent comment.105 ) );106 107 // Fetch the new activity item, as we need it to create table markup to return.108 $new_activity = new BP_Activity_Activity( $new_activity_id );109 110 // This needs to be set for the BP_Activity_List_Table constructor to work.111 set_current_screen( 'toplevel_page_bp-activity' );112 113 // Set up an output buffer.114 ob_start();115 $list_table = new BP_Activity_List_Table();116 $list_table->single_row( (array) $new_activity );117 118 // Get table markup.119 $response = array(120 'data' => ob_get_contents(),121 'id' => $new_activity_id,122 'position' => -1,123 'what' => 'bp_activity',124 );125 ob_end_clean();126 127 // Send response.128 $r = new WP_Ajax_Response();129 $r->add( $response );130 $r->send();131 132 exit();133 }134 add_action( 'wp_ajax_bp-activity-admin-reply', 'bp_activity_admin_reply' );135 136 /**137 * Handle save/update of screen options for the Activity component admin screen.138 *139 * @since 1.6.0140 *141 * @param string $value Will always be false unless another plugin filters it first.142 * @param string $option Screen option name.143 * @param string $new_value Screen option form value.144 * @return string Option value. False to abandon update.145 */146 function bp_activity_admin_screen_options( $value, $option, $new_value ) {147 if ( 'toplevel_page_bp_activity_per_page' != $option && 'toplevel_page_bp_activity_network_per_page' != $option )148 return $value;149 150 // Per page.151 $new_value = (int) $new_value;152 if ( $new_value < 1 || $new_value > 999 )153 return $value;154 155 return $new_value;156 }157 158 /**159 * Hide the advanced edit meta boxes by default, so we don't clutter the screen.160 *161 * @since 1.6.0162 *163 * @param array $hidden Array of items to hide.164 * @param WP_Screen $screen Screen identifier.165 * @return array Hidden Meta Boxes.166 */167 function bp_activity_admin_edit_hidden_metaboxes( $hidden, $screen ) {168 if ( empty( $screen->id ) || 'toplevel_page_bp-activity' != $screen->id && 'toplevel_page_bp-activity_network' != $screen->id )169 return $hidden;170 171 // Hide the primary link meta box by default.172 $hidden = array_merge( (array) $hidden, array( 'bp_activity_itemids', 'bp_activity_link', 'bp_activity_type', 'bp_activity_userid', ) );173 174 /**175 * Filters default hidden metaboxes so plugins can alter list.176 *177 * @since 1.6.0178 *179 * @param array $hidden Default metaboxes to hide.180 * @param WP_Screen $screen Screen identifier.181 */182 return apply_filters( 'bp_hide_meta_boxes', array_unique( $hidden ), $screen );183 }184 add_filter( 'default_hidden_meta_boxes', 'bp_activity_admin_edit_hidden_metaboxes', 10, 2 );185 186 /**187 * Set up the Activity admin page.188 *189 * Does the following:190 * - Register contextual help and screen options for this admin page.191 * - Enqueues scripts and styles.192 * - Catches POST and GET requests related to Activity.193 *194 * @since 1.6.0195 *196 * @global object $bp BuddyPress global settings.197 * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list table.198 */199 function bp_activity_admin_load() {200 global $bp_activity_list_table;201 202 $bp = buddypress();203 204 // Decide whether to load the dev version of the CSS and JavaScript.205 $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : 'min.';206 207 $doaction = bp_admin_list_table_current_bulk_action();208 209 /**210 * Fires at top of Activity admin page.211 *212 * @since 1.6.0213 *214 * @param string $doaction Current $_GET action being performed in admin screen.215 */216 do_action( 'bp_activity_admin_load', $doaction );217 218 // Edit screen.219 if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) ) {220 // Columns screen option.221 add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) );222 223 get_current_screen()->add_help_tab( array(224 'id' => 'bp-activity-edit-overview',225 'title' => __( 'Overview', 'buddypress' ),226 'content' =>227 '<p>' . __( 'You edit activities made on your site similar to the way you edit a comment. This is useful if you need to change which page the activity links to, or when you notice that the author has made a typographical error.', 'buddypress' ) . '</p>' .228 '<p>' . __( 'The two big editing areas for the activity title and content are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Primary Item/Secondary Item, Link, Type, Author ID) or to choose a 1- or 2-column layout for this screen.', 'buddypress' ) . '</p>' .229 '<p>' . __( 'You can also moderate the activity from this screen using the Status box, where you can also change the timestamp of the activity.', 'buddypress' ) . '</p>'230 ) );231 232 get_current_screen()->add_help_tab( array(233 'id' => 'bp-activity-edit-advanced',234 'title' => __( 'Item, Link, Type', 'buddypress' ),235 'content' =>236 '<p>' . __( '<strong>Primary Item/Secondary Item</strong> - These identify the object that created the activity. For example, the fields could reference a comment left on a specific site. Some types of activity may only use one, or none, of these fields.', 'buddypress' ) . '</p>' .237 '<p>' . __( '<strong>Link</strong> - Used by some types of activity (e.g blog posts and comments, and forum topics and replies) to store a link back to the original content.', 'buddypress' ) . '</p>' .238 '<p>' . __( '<strong>Type</strong> - Each distinct kind of activity has its own type. For example, <code>created_group</code> is used when a group is created and <code>joined_group</code> is used when a user joins a group.', 'buddypress' ) . '</p>' .239 '<p>' . __( 'For information about when and how BuddyPress uses all of these settings, see the Managing Activity link in the panel to the side.', 'buddypress' ) . '</p>'240 ) );241 242 // Help panel - sidebar links.243 get_current_screen()->set_help_sidebar(244 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .245 '<p>' . __( '<a href="https://codex.buddypress.org/administrator-guide/activity-stream-management-panels/">Managing Activity</a>', 'buddypress' ) . '</p>' .246 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'247 );248 249 // Register metaboxes for the edit screen.250 add_meta_box( 'submitdiv', _x( 'Status', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_status', get_current_screen()->id, 'side', 'core' );251 add_meta_box( 'bp_activity_itemids', _x( 'Primary Item/Secondary Item', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_itemids', get_current_screen()->id, 'normal', 'core' );252 add_meta_box( 'bp_activity_link', _x( 'Link', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_link', get_current_screen()->id, 'normal', 'core' );253 add_meta_box( 'bp_activity_type', _x( 'Type', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_type', get_current_screen()->id, 'normal', 'core' );254 add_meta_box( 'bp_activity_userid', _x( 'Author ID', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_userid', get_current_screen()->id, 'normal', 'core' );255 256 /**257 * Fires after the registration of all of the default activity meta boxes.258 *259 * @since 2.4.0260 */261 do_action( 'bp_activity_admin_meta_boxes' );262 263 // Enqueue JavaScript files.264 wp_enqueue_script( 'postbox' );265 wp_enqueue_script( 'dashboard' );266 wp_enqueue_script( 'comment' );267 268 // Index screen.269 } else {270 // Create the Activity screen list table.271 $bp_activity_list_table = new BP_Activity_List_Table();272 273 // The per_page screen option.274 add_screen_option( 'per_page', array( 'label' => _x( 'Activity', 'Activity items per page (screen options)', 'buddypress' )) );275 276 // Help panel - overview text.277 get_current_screen()->add_help_tab( array(278 'id' => 'bp-activity-overview',279 'title' => __( 'Overview', 'buddypress' ),280 'content' =>281 '<p>' . __( 'You can manage activities made on your site similar to the way you manage comments and other content. This screen is customizable in the same ways as other management screens, and you can act on activities using the on-hover action links or the Bulk Actions.', 'buddypress' ) . '</p>' .282 '<p>' . __( 'There are many different types of activities. Some are generated automatically by BuddyPress and other plugins, and some are entered directly by a user in the form of status update. To help manage the different activity types, use the filter dropdown box to switch between them.', 'buddypress' ) . '</p>'283 ) );284 285 // Help panel - moderation text.286 get_current_screen()->add_help_tab( array(287 'id' => 'bp-activity-moderating',288 'title' => __( 'Moderating Activity', 'buddypress' ),289 'content' =>290 '<p>' . __( 'In the <strong>Activity</strong> column, above each activity it says “Submitted on,” followed by the date and time the activity item was generated on your site. Clicking on the date/time link will take you to that activity on your live site. Hovering over any activity gives you options to reply, edit, spam mark, or delete that activity.', 'buddypress' ) . '</p>' .291 '<p>' . __( "In the <strong>In Response To</strong> column, if the activity was in reply to another activity, it shows that activity's author's picture and name, and a link to that activity on your live site. If there is a small bubble, the number in it shows how many other activities are related to this one; these are usually comments. Clicking the bubble will filter the activity screen to show only related activity items.", 'buddypress' ) . '</p>'292 ) );293 294 // Help panel - sidebar links.295 get_current_screen()->set_help_sidebar(296 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .297 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'298 );299 300 // Add accessible hidden heading and text for Activity screen pagination.301 if ( bp_get_major_wp_version() >= 4.4 ) {302 get_current_screen()->set_screen_reader_content( array(303 'heading_pagination' => __( 'Activity list navigation', 'buddypress' ),304 ) );305 }306 }307 308 // Enqueue CSS and JavaScript.309 wp_enqueue_script( 'bp_activity_admin_js', $bp->plugin_url . "bp-activity/admin/js/admin.{$min}js", array( 'jquery', 'wp-ajax-response' ), bp_get_version(), true );310 wp_localize_script( 'bp_activity_admin_js', 'bp_activity_admin_vars', array(311 'page' => get_current_screen()->id312 ) );313 wp_enqueue_style( 'bp_activity_admin_css', $bp->plugin_url . "bp-activity/admin/css/admin.{$min}css", array(), bp_get_version() );314 315 wp_style_add_data( 'bp_activity_admin_css', 'rtl', true );316 if ( $min ) {317 wp_style_add_data( 'bp_activity_admin_css', 'suffix', $min );318 }319 320 /**321 * Fires after the activity js and style has been enqueued.322 *323 * @since 2.4.0324 */325 do_action( 'bp_activity_admin_enqueue_scripts' );326 327 // Handle spam/un-spam/delete of activities.328 if ( !empty( $doaction ) && ! in_array( $doaction, array( '-1', 'edit', 'save', ) ) ) {329 330 // Build redirection URL.331 $redirect_to = remove_query_arg( array( 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), wp_get_referer() );332 $redirect_to = add_query_arg( 'paged', $bp_activity_list_table->get_pagenum(), $redirect_to );333 334 // Get activity IDs.335 $activity_ids = array_map( 'absint', (array) $_REQUEST['aid'] );336 337 /**338 * Filters list of IDs being spammed/un-spammed/deleted.339 *340 * @since 1.6.0341 *342 * @param array $activity_ids Activity IDs to spam/un-spam/delete.343 */344 $activity_ids = apply_filters( 'bp_activity_admin_action_activity_ids', $activity_ids );345 346 // Is this a bulk request?347 if ( 'bulk_' == substr( $doaction, 0, 5 ) && ! empty( $_REQUEST['aid'] ) ) {348 // Check this is a valid form submission.349 check_admin_referer( 'bulk-activities' );350 351 // Trim 'bulk_' off the action name to avoid duplicating a ton of code.352 $doaction = substr( $doaction, 5 );353 354 // This is a request to delete, spam, or un-spam, a single item.355 } elseif ( !empty( $_REQUEST['aid'] ) ) {356 357 // Check this is a valid form submission.358 check_admin_referer( 'spam-activity_' . $activity_ids[0] );359 }360 361 // Initialise counters for how many of each type of item we perform an action on.362 $deleted = $spammed = $unspammed = 0;363 364 // Store any errors that occurs when updating the database items.365 $errors = array();366 367 // "We'd like to shoot the monster, could you move, please?"368 foreach ( $activity_ids as $activity_id ) {369 // @todo: Check the permissions on each370 // if ( ! current_user_can( 'bp_edit_activity', $activity_id ) )371 // continue;372 // Get the activity from the database.373 $activity = new BP_Activity_Activity( $activity_id );374 if ( empty( $activity->component ) ) {375 $errors[] = $activity_id;376 continue;377 }378 379 switch ( $doaction ) {380 case 'delete' :381 if ( 'activity_comment' == $activity->type )382 bp_activity_delete_comment( $activity->item_id, $activity->id );383 else384 bp_activity_delete( array( 'id' => $activity->id ) );385 386 $deleted++;387 break;388 389 case 'ham' :390 /**391 * Remove moderation and blacklist checks in case we want to ham an activity392 * which contains one of these listed keys.393 */394 remove_action( 'bp_activity_before_save', 'bp_activity_check_moderation_keys', 2, 1 );395 remove_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys', 2, 1 );396 397 bp_activity_mark_as_ham( $activity );398 $result = $activity->save();399 400 // Check for any error during activity save.401 if ( ! $result )402 $errors[] = $activity->id;403 else404 $unspammed++;405 break;406 407 case 'spam' :408 bp_activity_mark_as_spam( $activity );409 $result = $activity->save();410 411 // Check for any error during activity save.412 if ( ! $result )413 $errors[] = $activity->id;414 else415 $spammed++;416 break;417 418 default:419 break;420 }421 422 // Release memory.423 unset( $activity );424 }425 426 /**427 * Fires before redirect for plugins to do something with activity.428 *429 * Passes an activity array counts how many were spam, not spam, deleted, and IDs that were errors.430 *431 * @since 1.6.0432 *433 * @param array $value Array holding spam, not spam, deleted counts, error IDs.434 * @param string $redirect_to URL to redirect to.435 * @param array $activity_ids Original array of activity IDs.436 */437 do_action( 'bp_activity_admin_action_after', array( $spammed, $unspammed, $deleted, $errors ), $redirect_to, $activity_ids );438 439 // Add arguments to the redirect URL so that on page reload, we can easily display what we've just done.440 if ( $spammed )441 $redirect_to = add_query_arg( 'spammed', $spammed, $redirect_to );442 443 if ( $unspammed )444 $redirect_to = add_query_arg( 'unspammed', $unspammed, $redirect_to );445 446 if ( $deleted )447 $redirect_to = add_query_arg( 'deleted', $deleted, $redirect_to );448 449 // If an error occurred, pass back the activity ID that failed.450 if ( ! empty( $errors ) )451 $redirect_to = add_query_arg( 'error', implode ( ',', array_map( 'absint', $errors ) ), $redirect_to );452 453 /**454 * Filters redirect URL after activity spamming/un-spamming/deletion occurs.455 *456 * @since 1.6.0457 *458 * @param string $redirect_to URL to redirect to.459 */460 wp_redirect( apply_filters( 'bp_activity_admin_action_redirect', $redirect_to ) );461 exit;462 463 464 // Save the edit.465 } elseif ( $doaction && 'save' == $doaction ) {466 // Build redirection URL.467 $redirect_to = remove_query_arg( array( 'action', 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );468 469 // Get activity ID.470 $activity_id = (int) $_REQUEST['aid'];471 472 // Check this is a valid form submission.473 check_admin_referer( 'edit-activity_' . $activity_id );474 475 // Get the activity from the database.476 $activity = new BP_Activity_Activity( $activity_id );477 478 // If the activity doesn't exist, just redirect back to the index.479 if ( empty( $activity->component ) ) {480 wp_redirect( $redirect_to );481 exit;482 }483 484 // Check the form for the updated properties.485 // Store any error that occurs when updating the database item.486 $error = 0;487 488 // Activity spam status.489 $prev_spam_status = $new_spam_status = false;490 if ( ! empty( $_POST['activity_status'] ) ) {491 $prev_spam_status = $activity->is_spam;492 $new_spam_status = ( 'spam' == $_POST['activity_status'] ) ? true : false;493 }494 495 // Activity action.496 if ( isset( $_POST['bp-activities-action'] ) )497 $activity->action = $_POST['bp-activities-action'];498 499 // Activity content.500 if ( isset( $_POST['bp-activities-content'] ) )501 $activity->content = $_POST['bp-activities-content'];502 503 // Activity primary link.504 if ( ! empty( $_POST['bp-activities-link'] ) )505 $activity->primary_link = $_POST['bp-activities-link'];506 507 // Activity user ID.508 if ( ! empty( $_POST['bp-activities-userid'] ) )509 $activity->user_id = (int) $_POST['bp-activities-userid'];510 511 // Activity item primary ID.512 if ( isset( $_POST['bp-activities-primaryid'] ) )513 $activity->item_id = (int) $_POST['bp-activities-primaryid'];514 515 // Activity item secondary ID.516 if ( isset( $_POST['bp-activities-secondaryid'] ) )517 $activity->secondary_item_id = (int) $_POST['bp-activities-secondaryid'];518 519 // Activity type.520 if ( ! empty( $_POST['bp-activities-type'] ) ) {521 $actions = bp_activity_admin_get_activity_actions();522 523 // Check that the new type is a registered activity type.524 if ( in_array( $_POST['bp-activities-type'], $actions ) ) {525 $activity->type = $_POST['bp-activities-type'];526 }527 }528 529 // Activity timestamp.530 if ( ! empty( $_POST['aa'] ) && ! empty( $_POST['mm'] ) && ! empty( $_POST['jj'] ) && ! empty( $_POST['hh'] ) && ! empty( $_POST['mn'] ) && ! empty( $_POST['ss'] ) ) {531 $aa = $_POST['aa'];532 $mm = $_POST['mm'];533 $jj = $_POST['jj'];534 $hh = $_POST['hh'];535 $mn = $_POST['mn'];536 $ss = $_POST['ss'];537 $aa = ( $aa <= 0 ) ? date( 'Y' ) : $aa;538 $mm = ( $mm <= 0 ) ? date( 'n' ) : $mm;539 $jj = ( $jj > 31 ) ? 31 : $jj;540 $jj = ( $jj <= 0 ) ? date( 'j' ) : $jj;541 $hh = ( $hh > 23 ) ? $hh -24 : $hh;542 $mn = ( $mn > 59 ) ? $mn -60 : $mn;543 $ss = ( $ss > 59 ) ? $ss -60 : $ss;544 545 // Reconstruct the date into a timestamp.546 $gmt_date = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );547 548 $activity->date_recorded = $gmt_date;549 }550 551 // Has the spam status has changed?552 if ( $new_spam_status != $prev_spam_status ) {553 if ( $new_spam_status )554 bp_activity_mark_as_spam( $activity );555 else556 bp_activity_mark_as_ham( $activity );557 }558 559 // Save.560 $result = $activity->save();561 562 // Clear the activity stream first page cache, in case this activity's timestamp was changed.563 wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );564 565 // Check for any error during activity save.566 if ( false === $result )567 $error = $activity->id;568 569 /**570 * Fires before redirect so plugins can do something first on save action.571 *572 * @since 1.6.0573 *574 * @param array $value Array holding activity object and ID that holds error.575 */576 do_action_ref_array( 'bp_activity_admin_edit_after', array( &$activity, $error ) );577 578 // If an error occurred, pass back the activity ID that failed.579 if ( $error )580 $redirect_to = add_query_arg( 'error', (int) $error, $redirect_to );581 else582 $redirect_to = add_query_arg( 'updated', (int) $activity->id, $redirect_to );583 584 /**585 * Filters URL to redirect to after saving.586 *587 * @since 1.6.0588 *589 * @param string $redirect_to URL to redirect to.590 */591 wp_redirect( apply_filters( 'bp_activity_admin_edit_redirect', $redirect_to ) );592 exit;593 594 595 // If a referrer and a nonce is supplied, but no action, redirect back.596 } elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {597 wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), stripslashes( $_SERVER['REQUEST_URI'] ) ) );598 exit;599 }600 }601 602 /**603 * Output the Activity component admin screens.604 *605 * @since 1.6.0606 */607 function bp_activity_admin() {608 // Decide whether to load the index or edit screen.609 $doaction = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';610 611 // Display the single activity edit screen.612 if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) )613 bp_activity_admin_edit();614 615 // Otherwise, display the Activity index screen.616 else617 bp_activity_admin_index();618 }619 620 /**621 * Display the single activity edit screen.622 *623 * @since 1.6.0624 */625 function bp_activity_admin_edit() {626 627 // @todo: Check if user is allowed to edit activity items628 // if ( ! current_user_can( 'bp_edit_activity' ) )629 if ( ! is_super_admin() )630 die( '-1' );631 632 // Get the activity from the database.633 $activity = bp_activity_get( array(634 'in' => ! empty( $_REQUEST['aid'] ) ? (int) $_REQUEST['aid'] : 0,635 'max' => 1,636 'show_hidden' => true,637 'spam' => 'all',638 'display_comments' => 0639 ) );640 641 if ( ! empty( $activity['activities'][0] ) ) {642 $activity = $activity['activities'][0];643 644 // Workaround to use WP's touch_time() without duplicating that function.645 $GLOBALS['comment'] = new stdClass;646 $GLOBALS['comment']->comment_date = $activity->date_recorded;647 } else {648 $activity = '';649 }650 651 // Construct URL for form.652 $form_url = remove_query_arg( array( 'action', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );653 $form_url = add_query_arg( 'action', 'save', $form_url );654 655 /**656 * Fires before activity edit form is displays so plugins can modify the activity.657 *658 * @since 1.6.0659 *660 * @param array $value Array holding single activity object that was passed by reference.661 */662 do_action_ref_array( 'bp_activity_admin_edit', array( &$activity ) ); ?>663 664 <div class="wrap">665 <h1><?php printf( __( 'Editing Activity (ID #%s)', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?></h1>666 667 <?php if ( ! empty( $activity ) ) : ?>668 669 <form action="<?php echo esc_url( $form_url ); ?>" id="bp-activities-edit-form" method="post">670 <div id="poststuff">671 672 <div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">673 <div id="post-body-content">674 <div id="postdiv">675 <div id="bp_activity_action" class="postbox">676 <h2><?php _e( 'Action', 'buddypress' ); ?></h2>677 <div class="inside">678 <?php wp_editor( stripslashes( $activity->action ), 'bp-activities-action', array( 'media_buttons' => false, 'textarea_rows' => 7, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>679 </div>680 </div>681 682 <div id="bp_activity_content" class="postbox">683 <h2><?php _e( 'Content', 'buddypress' ); ?></h2>684 <div class="inside">685 <?php wp_editor( stripslashes( $activity->content ), 'bp-activities-content', array( 'media_buttons' => false, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>686 </div>687 </div>688 </div>689 </div><!-- #post-body-content -->690 691 <div id="postbox-container-1" class="postbox-container">692 <?php do_meta_boxes( get_current_screen()->id, 'side', $activity ); ?>693 </div>694 695 <div id="postbox-container-2" class="postbox-container">696 <?php do_meta_boxes( get_current_screen()->id, 'normal', $activity ); ?>697 <?php do_meta_boxes( get_current_screen()->id, 'advanced', $activity ); ?>698 </div>699 </div><!-- #post-body -->700 701 </div><!-- #poststuff -->702 <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>703 <?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>704 <?php wp_nonce_field( 'edit-activity_' . $activity->id ); ?>705 </form>706 707 <?php else : ?>708 <p>709 <?php _e( 'No activity found with this ID.', 'buddypress' ); ?>710 <a href="<?php echo esc_url( bp_get_admin_url( 'admin.php?page=bp-activity' ) ); ?>"><?php _e( 'Go back and try again.', 'buddypress' ); ?></a>711 </p>712 <?php endif; ?>713 714 </div><!-- .wrap -->715 716 <?php717 }718 719 /**720 * Status metabox for the Activity admin edit screen.721 *722 * @since 1.6.0723 *724 * @param object $item Activity item.725 */726 function bp_activity_admin_edit_metabox_status( $item ) {727 ?>728 729 <div class="submitbox" id="submitcomment">730 731 <div id="minor-publishing">732 <div id="minor-publishing-actions">733 <div id="preview-action">734 <a class="button preview" href="<?php echo esc_attr( bp_activity_get_permalink( $item->id, $item ) ); ?>" target="_blank"><?php _e( 'View Activity', 'buddypress' ); ?></a>735 </div>736 737 <div class="clear"></div>738 </div><!-- #minor-publishing-actions -->739 740 <div id="misc-publishing-actions">741 <div class="misc-pub-section" id="comment-status-radio">742 <label class="approved" for="activity-status-approved"><input type="radio" name="activity_status" id="activity-status-approved" value="ham" <?php checked( $item->is_spam, 0 ); ?>><?php _e( 'Approved', 'buddypress' ); ?></label><br />743 <label class="spam" for="activity-status-spam"><input type="radio" name="activity_status" id="activity-status-spam" value="spam" <?php checked( $item->is_spam, 1 ); ?>><?php _e( 'Spam', 'buddypress' ); ?></label>744 </div>745 746 <div class="misc-pub-section curtime misc-pub-section-last">747 <?php748 // Translators: Publish box date format, see http://php.net/date.749 $datef = __( 'M j, Y @ G:i', 'buddypress' );750 $date = date_i18n( $datef, strtotime( $item->date_recorded ) );751 ?>752 <span id="timestamp"><?php printf( __( 'Submitted on: %s', 'buddypress' ), '<strong>' . $date . '</strong>' ); ?></span> <a href="#edit_timestamp" class="edit-timestamp hide-if-no-js" tabindex='4'><?php _e( 'Edit', 'buddypress' ); ?></a>753 754 <div id='timestampdiv' class='hide-if-js'>755 <?php touch_time( 1, 0, 5 ); ?>756 </div><!-- #timestampdiv -->757 </div>758 </div> <!-- #misc-publishing-actions -->759 760 <div class="clear"></div>761 </div><!-- #minor-publishing -->762 763 <div id="major-publishing-actions">764 <div id="publishing-action">765 <?php submit_button( __( 'Update', 'buddypress' ), 'primary', 'save', false ); ?>766 </div>767 <div class="clear"></div>768 </div><!-- #major-publishing-actions -->769 770 </div><!-- #submitcomment -->771 772 <?php773 }774 775 /**776 * Primary link metabox for the Activity admin edit screen.777 *778 * @since 1.6.0779 *780 * @param object $item Activity item.781 */782 function bp_activity_admin_edit_metabox_link( $item ) {783 ?>784 785 <label class="screen-reader-text" for="bp-activities-link"><?php _e( 'Link', 'buddypress' ); ?></label>786 <input type="url" name="bp-activities-link" id="bp-activities-link" value="<?php echo esc_url( $item->primary_link ); ?>" aria-describedby="bp-activities-link-description" />787 <p id="bp-activities-link-description"><?php _e( 'Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item.', 'buddypress' ); ?></p>788 789 <?php790 }791 792 /**793 * User ID metabox for the Activity admin edit screen.794 *795 * @since 1.6.0796 *797 * @param object $item Activity item.798 */799 function bp_activity_admin_edit_metabox_userid( $item ) {800 ?>801 802 <label class="screen-reader-text" for="bp-activities-userid"><?php _e( 'Author ID', 'buddypress' ); ?></label>803 <input type="number" name="bp-activities-userid" id="bp-activities-userid" value="<?php echo esc_attr( $item->user_id ); ?>" min="1" />804 805 <?php806 }807 808 /**809 * Get flattened array of all registered activity actions.810 *811 * Format is [activity_type] => Pretty name for activity type.812 *813 * @since 2.0.0814 *815 * @return array $actions816 */817 function bp_activity_admin_get_activity_actions() {818 $actions = array();819 820 // Walk through the registered actions, and build an array of actions/values.821 foreach ( bp_activity_get_actions() as $action ) {822 $action = array_values( (array) $action );823 824 for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {825 $actions[ $action[$i]['key'] ] = $action[$i]['value'];826 }827 }828 829 // This was a mis-named activity type from before BP 1.6.830 unset( $actions['friends_register_activity_action'] );831 832 // Sort array by the human-readable value.833 natsort( $actions );834 835 return $actions;836 }837 838 /**839 * Activity type metabox for the Activity admin edit screen.840 *841 * @since 1.6.0842 *843 * @param object $item Activity item.844 */845 function bp_activity_admin_edit_metabox_type( $item ) {846 $bp = buddypress();847 848 $actions = array();849 $selected = $item->type;850 851 // Walk through the registered actions, and build an array of actions/values.852 foreach ( bp_activity_get_actions() as $action ) {853 $action = array_values( (array) $action );854 855 for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )856 $actions[ $action[$i]['key'] ] = $action[$i]['value'];857 }858 859 // This was a mis-named activity type from before BP 1.6.860 unset( $actions['friends_register_activity_action'] );861 862 // Sort array by the human-readable value.863 natsort( $actions );864 865 /*866 * If the activity type is not registered properly (eg, a plugin has867 * not called bp_activity_set_action()), add the raw type to the end868 * of the list.869 */870 if ( ! isset( $actions[ $selected ] ) ) {871 _doing_it_wrong( __FUNCTION__, sprintf( __( 'This activity item has a type (%s) that is not registered using bp_activity_set_action(), so no label is available.', 'buddypress' ), $selected ), '2.0.0' );872 $actions[ $selected ] = $selected;873 }874 875 ?>876 877 <label for="bp-activities-type" class="screen-reader-text"><?php esc_html_e( 'Select activity type', 'buddypress' ); ?></label>878 <select name="bp-activities-type" id="bp-activities-type">879 <?php foreach ( $actions as $k => $v ) : ?>880 <option value="<?php echo esc_attr( $k ); ?>" <?php selected( $k, $selected ); ?>><?php echo esc_html( $v ); ?></option>881 <?php endforeach; ?>882 </select>883 884 <?php885 }886 887 /**888 * Primary item ID/Secondary item ID metabox for the Activity admin edit screen.889 *890 * @since 1.6.0891 *892 * @param object $item Activity item.893 */894 function bp_activity_admin_edit_metabox_itemids( $item ) {895 ?>896 897 <label for="bp-activities-primaryid"><?php _e( 'Primary Item ID', 'buddypress' ); ?></label>898 <input type="number" name="bp-activities-primaryid" id="bp-activities-primaryid" value="<?php echo esc_attr( $item->item_id ); ?>" min="0" />899 <br />900 901 <label for="bp-activities-secondaryid"><?php _e( 'Secondary Item ID', 'buddypress' ); ?></label>902 <input type="number" name="bp-activities-secondaryid" id="bp-activities-secondaryid" value="<?php echo esc_attr( $item->secondary_item_id ); ?>" min="0" />903 904 <p><?php _e( 'These identify the object that created this activity. For example, the fields could reference a pair of site and comment IDs.', 'buddypress' ); ?></p>905 906 <?php907 }908 909 /**910 * Display the Activity admin index screen, which contains a list of all the activities.911 *912 * @since 1.6.0913 *914 * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list table.915 * @global string $plugin_page The current plugin page.916 */917 function bp_activity_admin_index() {918 global $bp_activity_list_table, $plugin_page;919 920 $messages = array();921 922 // If the user has just made a change to an activity item, build status messages.923 if ( ! empty( $_REQUEST['deleted'] ) || ! empty( $_REQUEST['spammed'] ) || ! empty( $_REQUEST['unspammed'] ) || ! empty( $_REQUEST['error'] ) || ! empty( $_REQUEST['updated'] ) ) {924 $deleted = ! empty( $_REQUEST['deleted'] ) ? (int) $_REQUEST['deleted'] : 0;925 $errors = ! empty( $_REQUEST['error'] ) ? $_REQUEST['error'] : '';926 $spammed = ! empty( $_REQUEST['spammed'] ) ? (int) $_REQUEST['spammed'] : 0;927 $unspammed = ! empty( $_REQUEST['unspammed'] ) ? (int) $_REQUEST['unspammed'] : 0;928 $updated = ! empty( $_REQUEST['updated'] ) ? (int) $_REQUEST['updated'] : 0;929 930 $errors = array_map( 'absint', explode( ',', $errors ) );931 932 // Make sure we don't get any empty values in $errors.933 for ( $i = 0, $errors_count = count( $errors ); $i < $errors_count; $i++ ) {934 if ( 0 === $errors[$i] ) {935 unset( $errors[$i] );936 }937 }938 939 // Reindex array.940 $errors = array_values( $errors );941 942 if ( $deleted > 0 )943 $messages[] = sprintf( _n( '%s activity item has been permanently deleted.', '%s activity items have been permanently deleted.', $deleted, 'buddypress' ), number_format_i18n( $deleted ) );944 945 if ( ! empty( $errors ) ) {946 if ( 1 == count( $errors ) ) {947 $messages[] = sprintf( __( 'An error occurred when trying to update activity ID #%s.', 'buddypress' ), number_format_i18n( $errors[0] ) );948 949 } else {950 $error_msg = __( 'Errors occurred when trying to update these activity items:', 'buddypress' );951 $error_msg .= '<ul class="activity-errors">';952 953 // Display each error as a list item.954 foreach ( $errors as $error ) {955 // Translators: This is a bulleted list of item IDs.956 $error_msg .= '<li>' . sprintf( __( '#%s', 'buddypress' ), number_format_i18n( $error ) ) . '</li>';957 }958 959 $error_msg .= '</ul>';960 $messages[] = $error_msg;961 }962 }963 964 if ( $spammed > 0 )965 $messages[] = sprintf( _n( '%s activity item has been successfully spammed.', '%s activity items have been successfully spammed.', $spammed, 'buddypress' ), number_format_i18n( $spammed ) );966 967 if ( $unspammed > 0 )968 $messages[] = sprintf( _n( '%s activity item has been successfully unspammed.', '%s activity items have been successfully unspammed.', $unspammed, 'buddypress' ), number_format_i18n( $unspammed ) );969 970 if ( $updated > 0 )971 $messages[] = __( 'The activity item has been updated successfully.', 'buddypress' );972 }973 974 // Prepare the activity items for display.975 $bp_activity_list_table->prepare_items();976 977 /**978 * Fires before edit form is displayed so plugins can modify the activity messages.979 *980 * @since 1.6.0981 *982 * @param array $messages Array of messages to display at top of page.983 */984 do_action( 'bp_activity_admin_index', $messages ); ?>985 986 <div class="wrap">987 <h1>988 <?php if ( !empty( $_REQUEST['aid'] ) ) : ?>989 <?php printf( __( 'Activity related to ID #%s', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?>990 <?php else : ?>991 <?php _ex( 'Activity', 'Admin SWA page', 'buddypress' ); ?>992 <?php endif; ?>993 994 <?php if ( !empty( $_REQUEST['s'] ) ) : ?>995 <span class="subtitle"><?php printf( __( 'Search results for “%s”', 'buddypress' ), wp_html_excerpt( esc_html( stripslashes( $_REQUEST['s'] ) ), 50 ) ); ?></span>996 <?php endif; ?>997 </h1>998 999 <?php // If the user has just made a change to an activity item, display the status messages. ?>1000 <?php if ( !empty( $messages ) ) : ?>1001 <div id="moderated" class="<?php echo ( ! empty( $_REQUEST['error'] ) ) ? 'error' : 'updated'; ?>"><p><?php echo implode( "<br/>\n", $messages ); ?></p></div>1002 <?php endif; ?>1003 1004 <?php // Display each activity on its own row. ?>1005 <?php $bp_activity_list_table->views(); ?>1006 1007 <form id="bp-activities-form" action="" method="get">1008 <?php $bp_activity_list_table->search_box( __( 'Search all Activity', 'buddypress' ), 'bp-activity' ); ?>1009 <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" />1010 <?php $bp_activity_list_table->display(); ?>1011 </form>1012 1013 <?php // This markup is used for the reply form. ?>1014 <table style="display: none;">1015 <tr id="bp-activities-container" style="display: none;">1016 <td colspan="4">1017 <form method="get" action="">1018 1019 <h3 id="bp-replyhead"><?php _e( 'Reply to Activity', 'buddypress' ); ?></h3>1020 <?php wp_editor( '', 'bp-activities', array( 'dfw' => false, 'media_buttons' => false, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ), 'tinymce' => false, ) ); ?>1021 1022 <p id="bp-replysubmit" class="submit">1023 <a href="#" class="cancel button-secondary alignleft"><?php _e( 'Cancel', 'buddypress' ); ?></a>1024 <a href="#" class="save button-primary alignright"><?php _e( 'Reply', 'buddypress' ); ?></a>1025 1026 <img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />1027 <span class="error" style="display:none;"></span>1028 <br class="clear" />1029 </p>1030 1031 <?php wp_nonce_field( 'bp-activity-admin-reply', '_ajax_nonce-bp-activity-admin-reply', false ); ?>1032 1033 </form>1034 </td>1035 </tr>1036 </table>1037 </div>1038 1039 <?php1040 }1041 1042 /**1043 4 * List table class for the Activity component admin page. 1044 5 * 1045 6 * @since 1.6.0 -
src/bp-activity/classes/class-bp-activity-loader.php
1 1 <?php 2 2 /** 3 * BuddyPress Activity Streams Loader.3 * Activity component class. 4 4 * 5 * An activity stream component, for users, groups, and site tracking.6 *7 5 * @package BuddyPress 8 6 * @subpackage ActivityCore 9 7 * @since 1.5.0 … … 386 384 parent::setup_cache_groups(); 387 385 } 388 386 } 389 390 /**391 * Bootstrap the Activity component.392 *393 * @since 1.6.0394 */395 function bp_setup_activity() {396 buddypress()->activity = new BP_Activity_Component();397 }398 add_action( 'bp_setup_components', 'bp_setup_activity', 6 ); -
src/bp-activity/classes/class-bp-activity-template.php
11 11 defined( 'ABSPATH' ) || exit; 12 12 13 13 /** 14 * Output the activity component slug.15 *16 * @since 1.5.017 *18 * @uses bp_get_activity_slug()19 */20 function bp_activity_slug() {21 echo bp_get_activity_slug();22 }23 /**24 * Return the activity component slug.25 *26 * @since 1.5.027 *28 * @uses apply_filters() To call the 'bp_get_activity_slug' hook.29 *30 * @return string The activity component slug.31 */32 function bp_get_activity_slug() {33 34 /**35 * Filters the activity component slug.36 *37 * @since 1.5.038 *39 * @param string $slug Activity component slug.40 */41 return apply_filters( 'bp_get_activity_slug', buddypress()->activity->slug );42 }43 44 /**45 * Output the activity component root slug.46 *47 * @since 1.5.048 *49 * @uses bp_get_activity_root_slug()50 */51 function bp_activity_root_slug() {52 echo bp_get_activity_root_slug();53 }54 /**55 * Return the activity component root slug.56 *57 * @since 1.5.058 *59 * @uses apply_filters() To call the 'bp_get_activity_root_slug' hook.60 *61 * @return string The activity component root slug.62 */63 function bp_get_activity_root_slug() {64 65 /**66 * Filters the activity component root slug.67 *68 * @since 1.5.069 *70 * @param string $root_slug Activity component root slug.71 */72 return apply_filters( 'bp_get_activity_root_slug', buddypress()->activity->root_slug );73 }74 75 /**76 * Output activity directory permalink.77 *78 * @since 1.5.079 *80 * @uses bp_get_activity_directory_permalink()81 */82 function bp_activity_directory_permalink() {83 echo esc_url( bp_get_activity_directory_permalink() );84 }85 /**86 * Return activity directory permalink.87 *88 * @since 1.5.089 *90 * @uses trailingslashit()91 * @uses bp_get_root_domain()92 * @uses bp_get_activity_root_slug()93 * @uses apply_filters() To call the 'bp_get_activity_directory_permalink' hook.94 *95 * @return string Activity directory permalink.96 */97 function bp_get_activity_directory_permalink() {98 99 /**100 * Filters the activity directory permalink.101 *102 * @since 1.5.0103 *104 * @param string $url Permalink url for the activity directory.105 */106 return apply_filters( 'bp_get_activity_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_activity_root_slug() ) );107 }108 109 /**110 14 * The main activity template loop class. 111 15 * 112 16 * This is responsible for loading a group of activity items and displaying them. … … 503 407 } 504 408 } 505 409 } 506 507 /**508 * Initialize the activity loop.509 *510 * Based on the $args passed, bp_has_activities() populates the511 * $activities_template global, enabling the use of BuddyPress templates and512 * template functions to display a list of activity items.513 *514 * @since 1.0.0515 * @since 2.4.0 Introduced the `$fields` parameter.516 *517 * @global object $activities_template {@link BP_Activity_Template}518 * @uses groups_is_user_member()519 * @uses bp_current_action()520 * @uses bp_is_current_action()521 * @uses bp_get_activity_slug()522 * @uses bp_action_variable()523 * @uses wp_parse_args()524 * @uses bp_is_active()525 * @uses friends_get_friend_user_ids()526 * @uses groups_get_user_groups()527 * @uses bp_activity_get_user_favorites()528 * @uses apply_filters() To call the 'bp_has_activities' hook.529 *530 * @param array|string $args {531 * Arguments for limiting the contents of the activity loop. Most arguments532 * are in the same format as {@link BP_Activity_Activity::get()}. However,533 * because the format of the arguments accepted here differs in a number of534 * ways, and because bp_has_activities() determines some default arguments in535 * a dynamic fashion, we list all accepted arguments here as well.536 *537 * Arguments can be passed as an associative array, or as a URL querystring538 * (eg, 'user_id=4&display_comments=threaded').539 *540 * @type int $page Which page of results to fetch. Using page=1 without per_page will result541 * in no pagination. Default: 1.542 * @type int|bool $per_page Number of results per page. Default: 20.543 * @type string $page_arg String used as a query parameter in pagination links. Default: 'acpage'.544 * @type int|bool $max Maximum number of results to return. Default: false (unlimited).545 * @type string $fields Activity fields to retrieve. 'all' to fetch entire activity objects,546 * 'ids' to get only the activity IDs. Default 'all'.547 * @type string|bool $count_total If true, an additional DB query is run to count the total activity items548 * for the query. Default: false.549 * @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.550 * @type array|bool $exclude Array of activity IDs to exclude. Default: false.551 * @type array|bool $in Array of IDs to limit query by (IN). 'in' is intended to be used in552 * conjunction with other filter parameters. Default: false.553 * @type array|bool $include Array of exact activity IDs to query. Providing an 'include' array will554 * override all other filters passed in the argument array. When viewing the555 * permalink page for a single activity item, this value defaults to the ID of556 * that item. Otherwise the default is false.557 * @type array $meta_query Limit by activitymeta by passing an array of meta_query conditions. See558 * {@link WP_Meta_Query::queries} for a description of the syntax.559 * @type array $date_query Limit by date by passing an array of date_query conditions. See first560 * parameter of {@link WP_Date_Query::__construct()} for syntax.561 * @type array $filter_query Advanced activity filtering. See {@link BP_Activity_Query::__construct()}.562 * @type string $search_terms Limit results by a search term. Default: false.563 * @type string $scope Use a BuddyPress pre-built filter.564 * - 'just-me' retrieves items belonging only to a user; this is equivalent565 * to passing a 'user_id' argument.566 * - 'friends' retrieves items belonging to the friends of a user.567 * - 'groups' retrieves items belonging to groups to which a user belongs to.568 * - 'favorites' retrieves a user's favorited activity items.569 * - 'mentions' retrieves items where a user has received an @-mention.570 * The default value of 'scope' is set to one of the above if that value571 * appears in the appropriate place in the URL; eg, 'scope' will be 'groups'572 * when visiting http://example.com/members/joe/activity/groups/. Otherwise573 * defaults to false.574 * @type int|array|bool $user_id The ID(s) of user(s) whose activity should be fetched. Pass a single ID or575 * an array of IDs. When viewing a user profile page (but not that user's576 * activity subpages, ie My Friends, My Groups, etc), 'user_id' defaults to577 * the ID of the displayed user. Otherwise the default is false.578 * @type string|array|bool $object Filters by the `component` column in the database, which is generally the579 * component ID in the case of BuddyPress components, or the plugin slug in580 * the case of plugins. For example, 'groups' will limit results to those that581 * are associated with the BP Groups component. Accepts a single component582 * string, or an array of multiple components. Defaults to 'groups' when583 * viewing the page of a single group, the My Groups activity filter, or the584 * Activity > Groups filter of a user profile. Otherwise defaults to false.585 * @type string|array|bool $action Filters by the `type` column in the database, which is a string586 * categorizing the activity item (eg, 'new_blog_post', 'created_group').587 * Accepts a comma-delimited string or an array of types. Default: false.588 * @type int|array|bool $primary_id Filters by the `item_id` column in the database. The meaning of589 * 'primary_id' differs between components/types; for example, in the case of590 * 'created_group', 'primary_id' is the ID of the group. Accepts a single ID,591 * or an array of multiple IDs. When viewing a single group, defaults to the592 * current group ID. When viewing a user's Groups stream page, defaults to the593 * IDs of the user's groups. Otherwise defaults to false.594 * @type int|array|bool $secondary_id Filters by the `secondary_item_id` column in the database. The meaning of595 * 'secondary_id' differs between components/types. Accepts a single ID, or an596 * array of multiple IDs. Defaults to false.597 * @type int $offset Return only activity items with an ID greater than or equal to this one.598 * Note that providing an offset will disable pagination. Default: false.599 * @type string|bool $display_comments How to handle activity comments. Possible values:600 * - 'threaded' - comments appear in a threaded tree, under their parent601 * items.602 * - 'stream' - the activity stream is presented in a flat manner, with603 * comments sorted in chronological order alongside other activity items.604 * - false - don't fetch activity comments at all.605 * Default: 'threaded'.606 * @type bool $show_hidden Whether to show items marked hide_sitewide. Defaults to false, except in607 * the following cases:608 * - User is viewing his own activity stream.609 * - User is viewing the activity stream of a non-public group of which he610 * is a member.611 * @type string|bool $spam Spam status. 'ham_only', 'spam_only', or false to show all activity612 * regardless of spam status. Default: 'ham_only'.613 * @type bool $populate_extras Whether to pre-fetch the activity metadata for the queried items.614 * Default: true.615 * }616 * @return bool Returns true when activities are found, otherwise false.617 */618 function bp_has_activities( $args = '' ) {619 global $activities_template;620 621 // Get BuddyPress.622 $bp = buddypress();623 624 /*625 * Smart Defaults.626 */627 628 // User filtering.629 $user_id = bp_displayed_user_id()630 ? bp_displayed_user_id()631 : false;632 633 // Group filtering.634 if ( bp_is_group() ) {635 $object = $bp->groups->id;636 $primary_id = bp_get_current_group_id();637 $show_hidden = (bool) ( groups_is_user_member( bp_loggedin_user_id(), $primary_id ) || bp_current_user_can( 'bp_moderate' ) );638 } else {639 $object = false;640 $primary_id = false;641 $show_hidden = false;642 }643 644 // The default scope should recognize custom slugs.645 $scope = array_key_exists( bp_current_action(), (array) $bp->loaded_components )646 ? $bp->loaded_components[ bp_current_action() ]647 : bp_current_action();648 649 // Support for permalinks on single item pages: /groups/my-group/activity/124/.650 $include = bp_is_current_action( bp_get_activity_slug() )651 ? bp_action_variable( 0 )652 : false;653 654 $search_terms_default = false;655 $search_query_arg = bp_core_get_component_search_query_arg( 'activity' );656 if ( ! empty( $_REQUEST[ $search_query_arg ] ) ) {657 $search_terms_default = stripslashes( $_REQUEST[ $search_query_arg ] );658 }659 660 /*661 * Parse Args.662 */663 664 // Note: any params used for filtering can be a single value, or multiple665 // values comma separated.666 $r = bp_parse_args( $args, array(667 'display_comments' => 'threaded', // False for none, stream/threaded - show comments in the stream or threaded under items.668 'include' => $include, // Pass an activity_id or string of IDs comma-separated.669 'exclude' => false, // Pass an activity_id or string of IDs comma-separated.670 'in' => false, // Comma-separated list or array of activity IDs among which to search.671 'sort' => 'DESC', // Sort DESC or ASC.672 'page' => 1, // Which page to load.673 'per_page' => 20, // Number of items per page.674 'page_arg' => 'acpage', // See https://buddypress.trac.wordpress.org/ticket/3679.675 'max' => false, // Max number to return.676 'fields' => 'all',677 'count_total' => false,678 'show_hidden' => $show_hidden, // Show activity items that are hidden site-wide?679 'spam' => 'ham_only', // Hide spammed items.680 681 // Scope - pre-built activity filters for a user (friends/groups/favorites/mentions).682 'scope' => $scope,683 684 // Filtering685 'user_id' => $user_id, // user_id to filter on.686 'object' => $object, // Object to filter on e.g. groups, profile, status, friends.687 'action' => false, // Action to filter on e.g. activity_update, new_forum_post, profile_updated.688 'primary_id' => $primary_id, // Object ID to filter on e.g. a group_id or forum_id or blog_id etc.689 'secondary_id' => false, // Secondary object ID to filter on e.g. a post_id.690 'offset' => false, // Return only items >= this ID.691 'since' => false, // Return only items recorded since this Y-m-d H:i:s date.692 693 'meta_query' => false, // Filter on activity meta. See WP_Meta_Query for format.694 'date_query' => false, // Filter by date. See first parameter of WP_Date_Query for format.695 'filter_query' => false, // Advanced filtering. See BP_Activity_Query for format.696 697 // Searching.698 'search_terms' => $search_terms_default,699 'update_meta_cache' => true,700 ), 'has_activities' );701 702 /*703 * Smart Overrides.704 */705 706 // Translate various values for 'display_comments'707 // This allows disabling comments via ?display_comments=0708 // or =none or =false. Final true is a strict type check. See #5029.709 if ( in_array( $r['display_comments'], array( 0, '0', 'none', 'false' ), true ) ) {710 $r['display_comments'] = false;711 }712 713 // Ignore pagination if an offset is passed.714 if ( ! empty( $r['offset'] ) ) {715 $r['page'] = 0;716 }717 718 // Search terms.719 if ( ! empty( $_REQUEST['s'] ) && empty( $r['search_terms'] ) ) {720 $r['search_terms'] = $_REQUEST['s'];721 }722 723 // Do not exceed the maximum per page.724 if ( ! empty( $r['max'] ) && ( (int) $r['per_page'] > (int) $r['max'] ) ) {725 $r['per_page'] = $r['max'];726 }727 728 /**729 * Filters whether BuddyPress should enable afilter support.730 *731 * Support for basic filters in earlier BP versions is disabled by default.732 * To enable, put add_filter( 'bp_activity_enable_afilter_support', '__return_true' );733 * into bp-custom.php or your theme's functions.php.734 *735 * @since 1.6.0736 *737 * @param bool $value True if BuddyPress should enable afilter support.738 */739 if ( isset( $_GET['afilter'] ) && apply_filters( 'bp_activity_enable_afilter_support', false ) ) {740 $r['filter'] = array(741 'object' => $_GET['afilter']742 );743 } elseif ( ! empty( $r['user_id'] ) || ! empty( $r['object'] ) || ! empty( $r['action'] ) || ! empty( $r['primary_id'] ) || ! empty( $r['secondary_id'] ) || ! empty( $r['offset'] ) || ! empty( $r['since'] ) ) {744 $r['filter'] = array(745 'user_id' => $r['user_id'],746 'object' => $r['object'],747 'action' => $r['action'],748 'primary_id' => $r['primary_id'],749 'secondary_id' => $r['secondary_id'],750 'offset' => $r['offset'],751 'since' => $r['since']752 );753 } else {754 $r['filter'] = false;755 }756 757 // If specific activity items have been requested, override the $hide_spam758 // argument. This prevents backpat errors with AJAX.759 if ( ! empty( $r['include'] ) && ( 'ham_only' === $r['spam'] ) ) {760 $r['spam'] = 'all';761 }762 763 /*764 * Query765 */766 767 $activities_template = new BP_Activity_Template( $r );768 769 /**770 * Filters whether or not there are activity items to display.771 *772 * @since 1.1.0773 *774 * @param bool $value Whether or not there are activity items to display.775 * @param string $activities_template Current activities template being used.776 * @param array $r Array of arguments passed into the BP_Activity_Template class.777 */778 return apply_filters( 'bp_has_activities', $activities_template->has_activities(), $activities_template, $r );779 }780 781 /**782 * Determine if there are still activities left in the loop.783 *784 * @since 1.0.0785 *786 * @global object $activities_template {@link BP_Activity_Template}787 * @uses BP_Activity_Template::user_activities() {@link BP_Activity_Template::user_activities()}788 *789 * @return bool Returns true when activities are found.790 */791 function bp_activities() {792 global $activities_template;793 return $activities_template->user_activities();794 }795 796 /**797 * Get the current activity object in the loop.798 *799 * @since 1.0.0800 *801 * @global object $activities_template {@link BP_Activity_Template}802 * @uses BP_Activity_Template::the_activity() {@link BP_Activity_Template::the_activity()}803 *804 * @return object The current activity within the loop.805 */806 function bp_the_activity() {807 global $activities_template;808 return $activities_template->the_activity();809 }810 811 /**812 * Output the URL for the Load More link.813 *814 * @since 2.1.0815 */816 function bp_activity_load_more_link() {817 echo esc_url( bp_get_activity_load_more_link() );818 }819 /**820 * Get the URL for the Load More link.821 *822 * @since 2.1.0823 *824 * @return string $link825 */826 function bp_get_activity_load_more_link() {827 global $activities_template;828 829 $url = bp_get_requested_url();830 $link = add_query_arg( $activities_template->pag_arg, $activities_template->pag_page + 1, $url );831 832 /**833 * Filters the Load More link URL.834 *835 * @since 2.1.0836 *837 * @param string $link The "Load More" link URL with appropriate query args.838 * @param string $url The original URL.839 * @param object $activities_template The activity template loop global.840 */841 return apply_filters( 'bp_get_activity_load_more_link', $link, $url, $activities_template );842 }843 844 /**845 * Output the activity pagination count.846 *847 * @since 1.0.0848 *849 * @global object $activities_template {@link BP_Activity_Template}850 * @uses BP_Activity_Template::the_activity() {@link BP_Activity_Template::the_activity()}851 */852 function bp_activity_pagination_count() {853 echo bp_get_activity_pagination_count();854 }855 856 /**857 * Return the activity pagination count.858 *859 * @since 1.2.0860 *861 * @global object $activities_template {@link BP_Activity_Template}862 * @uses bp_core_number_format()863 *864 * @return string The pagination text.865 */866 function bp_get_activity_pagination_count() {867 global $activities_template;868 869 $start_num = intval( ( $activities_template->pag_page - 1 ) * $activities_template->pag_num ) + 1;870 $from_num = bp_core_number_format( $start_num );871 $to_num = bp_core_number_format( ( $start_num + ( $activities_template->pag_num - 1 ) > $activities_template->total_activity_count ) ? $activities_template->total_activity_count : $start_num + ( $activities_template->pag_num - 1 ) );872 $total = bp_core_number_format( $activities_template->total_activity_count );873 874 if ( 1 == $activities_template->total_activity_count ) {875 $message = __( 'Viewing 1 item', 'buddypress' );876 } else {877 $message = sprintf( _n( 'Viewing %1$s - %2$s of %3$s item', 'Viewing %1$s - %2$s of %3$s items', $activities_template->total_activity_count, 'buddypress' ), $from_num, $to_num, $total );878 }879 880 return $message;881 }882 883 /**884 * Output the activity pagination links.885 *886 * @since 1.0.0887 *888 * @uses bp_get_activity_pagination_links()889 */890 function bp_activity_pagination_links() {891 echo bp_get_activity_pagination_links();892 }893 894 /**895 * Return the activity pagination links.896 *897 * @since 1.0.0898 *899 * @global object $activities_template {@link BP_Activity_Template}900 * @uses apply_filters() To call the 'bp_get_activity_pagination_links' hook.901 *902 * @return string The pagination links.903 */904 function bp_get_activity_pagination_links() {905 global $activities_template;906 907 /**908 * Filters the activity pagination link output.909 *910 * @since 1.0.0911 *912 * @param string $pag_links Output for the activity pagination links.913 */914 return apply_filters( 'bp_get_activity_pagination_links', $activities_template->pag_links );915 }916 917 /**918 * Return true when there are more activity items to be shown than currently appear.919 *920 * @since 1.5.0921 *922 * @global object $activities_template {@link BP_Activity_Template}923 * @uses apply_filters() To call the 'bp_activity_has_more_items' hook.924 *925 * @return bool $has_more_items True if more items, false if not.926 */927 function bp_activity_has_more_items() {928 global $activities_template;929 930 if ( ! empty( $activities_template->has_more_items ) ) {931 $has_more_items = true;932 } else {933 $remaining_pages = 0;934 935 if ( ! empty( $activities_template->pag_page ) ) {936 $remaining_pages = floor( ( $activities_template->total_activity_count - 1 ) / ( $activities_template->pag_num * $activities_template->pag_page ) );937 }938 939 $has_more_items = (int) $remaining_pages > 0;940 }941 942 /**943 * Filters whether there are more activity items to display.944 *945 * @since 1.5.0946 *947 * @param bool $has_more_items Whether or not there are more activity items to display.948 */949 return apply_filters( 'bp_activity_has_more_items', $has_more_items );950 }951 952 /**953 * Output the activity count.954 *955 * @since 1.2.0956 *957 * @uses bp_get_activity_count()958 */959 function bp_activity_count() {960 echo bp_get_activity_count();961 }962 963 /**964 * Return the activity count.965 *966 * @since 1.2.0967 *968 * @global object $activities_template {@link BP_Activity_Template}969 * @uses apply_filters() To call the 'bp_get_activity_count' hook.970 *971 * @return int The activity count.972 */973 function bp_get_activity_count() {974 global $activities_template;975 976 /**977 * Filters the activity count for the activity template.978 *979 * @since 1.2.0980 *981 * @param int $activity_count The count for total activity.982 */983 return apply_filters( 'bp_get_activity_count', (int) $activities_template->activity_count );984 }985 986 /**987 * Output the number of activities per page.988 *989 * @since 1.2.0990 *991 * @uses bp_get_activity_per_page()992 */993 function bp_activity_per_page() {994 echo bp_get_activity_per_page();995 }996 997 /**998 * Return the number of activities per page.999 *1000 * @since 1.2.01001 *1002 * @global object $activities_template {@link BP_Activity_Template}1003 * @uses apply_filters() To call the 'bp_get_activity_per_page' hook.1004 *1005 * @return int The activities per page.1006 */1007 function bp_get_activity_per_page() {1008 global $activities_template;1009 1010 /**1011 * Filters the activity posts per page value.1012 *1013 * @since 1.2.01014 *1015 * @param int $pag_num How many post should be displayed for pagination.1016 */1017 return apply_filters( 'bp_get_activity_per_page', (int) $activities_template->pag_num );1018 }1019 1020 /**1021 * Output the activities title.1022 *1023 * @since 1.0.01024 *1025 * @uses bp_get_activities_title()1026 * @todo Deprecate.1027 */1028 function bp_activities_title() {1029 echo bp_get_activities_title();1030 }1031 1032 /**1033 * Return the activities title.1034 *1035 * @since 1.0.01036 *1037 * @global string $bp_activity_title1038 * @uses apply_filters() To call the 'bp_get_activities_title' hook.1039 * @todo Deprecate.1040 *1041 * @return string The activities title.1042 */1043 function bp_get_activities_title() {1044 global $bp_activity_title;1045 1046 /**1047 * Filters the activities title for the activity template.1048 *1049 * @since 1.0.01050 *1051 * @param string $bp_activity_title The title to be displayed.1052 */1053 return apply_filters( 'bp_get_activities_title', $bp_activity_title );1054 }1055 1056 /**1057 * {@internal Missing Description}1058 *1059 * @since 1.0.01060 *1061 * @uses bp_get_activities_no_activity()1062 * @todo Deprecate.1063 */1064 function bp_activities_no_activity() {1065 echo bp_get_activities_no_activity();1066 }1067 1068 /**1069 * {@internal Missing Description}1070 *1071 * @since 1.0.01072 *1073 * @global string $bp_activity_no_activity1074 * @uses apply_filters() To call the 'bp_get_activities_no_activity' hook.1075 * @todo Deprecate.1076 *1077 * @return string1078 */1079 function bp_get_activities_no_activity() {1080 global $bp_activity_no_activity;1081 1082 /**1083 * Filters the text used when there is no activity to display.1084 *1085 * @since 1.0.01086 *1087 * @param string $bp_activity_no_activity Text to display for no activity.1088 */1089 return apply_filters( 'bp_get_activities_no_activity', $bp_activity_no_activity );1090 }1091 1092 /**1093 * Output the activity ID.1094 *1095 * @since 1.2.01096 *1097 * @uses bp_get_activity_id()1098 */1099 function bp_activity_id() {1100 echo bp_get_activity_id();1101 }1102 1103 /**1104 * Return the activity ID.1105 *1106 * @since 1.2.01107 *1108 * @global object $activities_template {@link BP_Activity_Template}1109 * @uses apply_filters() To call the 'bp_get_activity_id' hook.1110 *1111 * @return int The activity ID.1112 */1113 function bp_get_activity_id() {1114 global $activities_template;1115 1116 /**1117 * Filters the activity ID being displayed.1118 *1119 * @since 1.2.01120 *1121 * @param int $id The activity ID.1122 */1123 return apply_filters( 'bp_get_activity_id', $activities_template->activity->id );1124 }1125 1126 /**1127 * Output the activity item ID.1128 *1129 * @since 1.2.01130 *1131 * @uses bp_get_activity_item_id()1132 */1133 function bp_activity_item_id() {1134 echo bp_get_activity_item_id();1135 }1136 1137 /**1138 * Return the activity item ID.1139 *1140 * @since 1.2.01141 *1142 * @global object $activities_template {@link BP_Activity_Template}1143 * @uses apply_filters() To call the 'bp_get_activity_item_id' hook.1144 *1145 * @return int The activity item ID.1146 */1147 function bp_get_activity_item_id() {1148 global $activities_template;1149 1150 /**1151 * Filters the activity item ID being displayed.1152 *1153 * @since 1.2.01154 *1155 * @param int $item_id The activity item ID.1156 */1157 return apply_filters( 'bp_get_activity_item_id', $activities_template->activity->item_id );1158 }1159 1160 /**1161 * Output the activity secondary item ID.1162 *1163 * @since 1.2.01164 *1165 * @uses bp_get_activity_secondary_item_id()1166 */1167 function bp_activity_secondary_item_id() {1168 echo bp_get_activity_secondary_item_id();1169 }1170 1171 /**1172 * Return the activity secondary item ID.1173 *1174 * @since 1.2.01175 *1176 * @global object $activities_template {@link BP_Activity_Template}1177 * @uses apply_filters() To call the 'bp_get_activity_secondary_item_id' hook.1178 *1179 * @return int The activity secondary item ID.1180 */1181 function bp_get_activity_secondary_item_id() {1182 global $activities_template;1183 1184 /**1185 * Filters the activity secondary item ID being displayed.1186 *1187 * @since 1.2.01188 *1189 * @param int $secondary_item_id The activity secondary item ID.1190 */1191 return apply_filters( 'bp_get_activity_secondary_item_id', $activities_template->activity->secondary_item_id );1192 }1193 1194 /**1195 * Output the date the activity was recorded.1196 *1197 * @since 1.2.01198 *1199 * @uses bp_get_activity_date_recorded()1200 */1201 function bp_activity_date_recorded() {1202 echo bp_get_activity_date_recorded();1203 }1204 1205 /**1206 * Return the date the activity was recorded.1207 *1208 * @since 1.2.01209 *1210 * @global object $activities_template {@link BP_Activity_Template}1211 * @uses apply_filters() To call the 'bp_get_activity_date_recorded' hook.1212 *1213 * @return string The date the activity was recorded.1214 */1215 function bp_get_activity_date_recorded() {1216 global $activities_template;1217 1218 /**1219 * Filters the date the activity was recorded.1220 *1221 * @since 1.2.01222 *1223 * @param int $date_recorded The activity's date.1224 */1225 return apply_filters( 'bp_get_activity_date_recorded', $activities_template->activity->date_recorded );1226 }1227 1228 /**1229 * Output the display name of the member who posted the activity.1230 *1231 * @since 2.1.01232 *1233 * @uses bp_get_activity_member_display_name()1234 */1235 function bp_activity_member_display_name() {1236 echo bp_get_activity_member_display_name();1237 }1238 1239 /**1240 * Return the display name of the member who posted the activity.1241 *1242 * @since 2.1.01243 *1244 * @global object $activities_template {@link BP_Activity_Template}1245 * @uses apply_filters() To call the 'bp_get_activity_member_display_name' hook.1246 *1247 * @return string The date the activity was recorded.1248 */1249 function bp_get_activity_member_display_name() {1250 global $activities_template;1251 1252 $retval = isset( $activities_template->activity->display_name )1253 ? $activities_template->activity->display_name1254 : '';1255 1256 /**1257 * Filters the display name of the member who posted the activity.1258 *1259 * @since 2.1.01260 *1261 * @param int $retval Display name for the member who posted.1262 */1263 return apply_filters( 'bp_get_activity_member_display_name', $retval );1264 }1265 1266 /**1267 * Output the activity object name.1268 *1269 * @since 1.2.01270 *1271 * @uses bp_get_activity_object_name()1272 */1273 function bp_activity_object_name() {1274 echo bp_get_activity_object_name();1275 }1276 1277 /**1278 * Return the activity object name.1279 *1280 * @since 1.2.01281 *1282 * @global object $activities_template {@link BP_Activity_Template}1283 * @uses apply_filters() To call the 'bp_get_activity_object_name' hook.1284 *1285 * @return string The activity object name.1286 */1287 function bp_get_activity_object_name() {1288 global $activities_template;1289 1290 /**1291 * Filters the activity object name.1292 *1293 * @since 1.2.01294 *1295 * @param string $activity_component The activity object name.1296 */1297 return apply_filters( 'bp_get_activity_object_name', $activities_template->activity->component );1298 }1299 1300 /**1301 * Output the activity type.1302 *1303 * @since 1.2.01304 *1305 * @uses bp_get_activity_type()1306 */1307 function bp_activity_type() {1308 echo bp_get_activity_type();1309 }1310 1311 /**1312 * Return the activity type.1313 *1314 * @since 1.2.01315 *1316 * @global object $activities_template {@link BP_Activity_Template}1317 * @uses apply_filters() To call the 'bp_get_activity_type' hook.1318 *1319 * @return string The activity type.1320 */1321 function bp_get_activity_type() {1322 global $activities_template;1323 1324 /**1325 * Filters the activity type.1326 *1327 * @since 1.2.01328 *1329 * @param string $activity_type The activity type.1330 */1331 return apply_filters( 'bp_get_activity_type', $activities_template->activity->type );1332 }1333 1334 /**1335 * Output the activity action name.1336 *1337 * Just a wrapper for bp_activity_type().1338 *1339 * @since 1.2.01340 * @deprecated 1.5.01341 *1342 * @todo Properly deprecate in favor of bp_activity_type() and1343 * remove redundant echo1344 *1345 * @uses bp_activity_type()1346 */1347 function bp_activity_action_name() { echo bp_activity_type(); }1348 1349 /**1350 * Return the activity type.1351 *1352 * Just a wrapper for bp_get_activity_type().1353 *1354 * @since 1.2.01355 * @deprecated 1.5.01356 *1357 * @todo Properly deprecate in favor of bp_get_activity_type().1358 *1359 * @uses bp_get_activity_type()1360 *1361 * @return string The activity type.1362 */1363 function bp_get_activity_action_name() { return bp_get_activity_type(); }1364 1365 /**1366 * Output the activity user ID.1367 *1368 * @since 1.1.01369 *1370 * @uses bp_get_activity_user_id()1371 */1372 function bp_activity_user_id() {1373 echo bp_get_activity_user_id();1374 }1375 1376 /**1377 * Return the activity user ID.1378 *1379 * @since 1.1.01380 *1381 * @global object $activities_template {@link BP_Activity_Template}1382 * @uses apply_filters() To call the 'bp_get_activity_user_id' hook.1383 *1384 * @return int The activity user ID.1385 */1386 function bp_get_activity_user_id() {1387 global $activities_template;1388 1389 /**1390 * Filters the activity user ID.1391 *1392 * @since 1.1.01393 *1394 * @param int $user_id The activity user ID.1395 */1396 return apply_filters( 'bp_get_activity_user_id', $activities_template->activity->user_id );1397 }1398 1399 /**1400 * Output the activity user link.1401 *1402 * @since 1.2.01403 *1404 * @uses bp_get_activity_user_link()1405 */1406 function bp_activity_user_link() {1407 echo bp_get_activity_user_link();1408 }1409 1410 /**1411 * Return the activity user link.1412 *1413 * @since 1.2.01414 *1415 * @global object $activities_template {@link BP_Activity_Template}1416 * @uses bp_core_get_user_domain()1417 * @uses apply_filters() To call the 'bp_get_activity_user_link' hook.1418 *1419 * @return string $link The activity user link.1420 */1421 function bp_get_activity_user_link() {1422 global $activities_template;1423 1424 if ( empty( $activities_template->activity->user_id ) || empty( $activities_template->activity->user_nicename ) || empty( $activities_template->activity->user_login ) ) {1425 $link = $activities_template->activity->primary_link;1426 } else {1427 $link = bp_core_get_user_domain( $activities_template->activity->user_id, $activities_template->activity->user_nicename, $activities_template->activity->user_login );1428 }1429 1430 /**1431 * Filters the activity user link.1432 *1433 * @since 1.2.01434 *1435 * @param string $link The activity user link.1436 */1437 return apply_filters( 'bp_get_activity_user_link', $link );1438 }1439 1440 /**1441 * Output the avatar of the user that performed the action.1442 *1443 * @since 1.1.01444 *1445 * @see bp_get_activity_avatar() for description of arguments.1446 * @uses bp_get_activity_avatar()1447 *1448 * @param array|string $args See {@link bp_get_activity_avatar()} for description.1449 */1450 function bp_activity_avatar( $args = '' ) {1451 echo bp_get_activity_avatar( $args );1452 }1453 /**1454 * Return the avatar of the user that performed the action.1455 *1456 * @since 1.1.01457 *1458 * @see bp_core_fetch_avatar() For a description of the arguments.1459 * @global object $activities_template {@link BP_Activity_Template}1460 * @uses bp_is_single_activity()1461 * @uses wp_parse_args()1462 * @uses apply_filters() To call the 'bp_get_activity_avatar_object_' . $current_activity_item->component hook.1463 * @uses apply_filters() To call the 'bp_get_activity_avatar_item_id' hook.1464 * @uses bp_core_fetch_avatar()1465 * @uses apply_filters() To call the 'bp_get_activity_avatar' hook.1466 *1467 * @param array|string $args {1468 * Arguments are listed here with an explanation of their defaults.1469 * For more information about the arguments, see1470 * {@link bp_core_fetch_avatar()}.1471 * @type string $alt Default: 'Profile picture of [user name]' if1472 * activity user name is available, otherwise 'Profile picture'.1473 * @type string $class Default: 'avatar'.1474 * @type string|bool $email Default: Email of the activity's1475 * associated user, if available. Otherwise false.1476 * @type string $type Default: 'full' when viewing a single activity1477 * permalink page, otherwise 'thumb'.1478 * @type int|bool $user_id Default: ID of the activity's user.1479 * }1480 * @return string User avatar string.1481 */1482 function bp_get_activity_avatar( $args = '' ) {1483 global $activities_template;1484 1485 $bp = buddypress();1486 1487 // On activity permalink pages, default to the full-size avatar.1488 $type_default = bp_is_single_activity() ? 'full' : 'thumb';1489 1490 // Within the activity comment loop, the current activity should be set1491 // to current_comment. Otherwise, just use activity.1492 $current_activity_item = isset( $activities_template->activity->current_comment ) ? $activities_template->activity->current_comment : $activities_template->activity;1493 1494 // Activity user display name.1495 $dn_default = isset( $current_activity_item->display_name ) ? $current_activity_item->display_name : '';1496 1497 // Prepend some descriptive text to alt.1498 $alt_default = !empty( $dn_default ) ? sprintf( __( 'Profile picture of %s', 'buddypress' ), $dn_default ) : __( 'Profile picture', 'buddypress' );1499 1500 $defaults = array(1501 'alt' => $alt_default,1502 'class' => 'avatar',1503 'email' => false,1504 'type' => $type_default,1505 'user_id' => false1506 );1507 1508 $r = wp_parse_args( $args, $defaults );1509 extract( $r, EXTR_SKIP );1510 1511 if ( !isset( $height ) && !isset( $width ) ) {1512 1513 // Backpat.1514 if ( isset( $bp->avatar->full->height ) || isset( $bp->avatar->thumb->height ) ) {1515 $height = ( 'full' == $type ) ? $bp->avatar->full->height : $bp->avatar->thumb->height;1516 } else {1517 $height = 20;1518 }1519 1520 // Backpat.1521 if ( isset( $bp->avatar->full->width ) || isset( $bp->avatar->thumb->width ) ) {1522 $width = ( 'full' == $type ) ? $bp->avatar->full->width : $bp->avatar->thumb->width;1523 } else {1524 $width = 20;1525 }1526 }1527 1528 /**1529 * Filters the activity avatar object based on current activity item component.1530 *1531 * This is a variable filter dependent on the component used.1532 * Possible hooks are bp_get_activity_avatar_object_blog,1533 * bp_get_activity_avatar_object_group, and bp_get_activity_avatar_object_user.1534 *1535 * @since 1.1.01536 *1537 * @param string $component Component being displayed.1538 */1539 $object = apply_filters( 'bp_get_activity_avatar_object_' . $current_activity_item->component, 'user' );1540 $item_id = !empty( $user_id ) ? $user_id : $current_activity_item->user_id;1541 1542 /**1543 * Filters the activity avatar item ID.1544 *1545 * @since 1.2.101546 *1547 * @param int $item_id Item ID for the activity avatar.1548 */1549 $item_id = apply_filters( 'bp_get_activity_avatar_item_id', $item_id );1550 1551 // If this is a user object pass the users' email address for Gravatar so we don't have to prefetch it.1552 if ( 'user' == $object && empty( $user_id ) && empty( $email ) && isset( $current_activity_item->user_email ) ) {1553 $email = $current_activity_item->user_email;1554 }1555 1556 /**1557 * Filters the value returned by bp_core_fetch_avatar.1558 *1559 * @since 1.1.31560 *1561 * @param array $value Array of arguments calculated for use with bp_core_fetch_avatar.1562 */1563 return apply_filters( 'bp_get_activity_avatar', bp_core_fetch_avatar( array(1564 'item_id' => $item_id,1565 'object' => $object,1566 'type' => $type,1567 'alt' => $alt,1568 'class' => $class,1569 'width' => $width,1570 'height' => $height,1571 'email' => $email1572 ) ) );1573 }1574 1575 /**1576 * Output the avatar of the object that action was performed on.1577 *1578 * @since 1.2.01579 *1580 * @see bp_get_activity_secondary_avatar() for description of arguments.1581 * @uses bp_get_activity_secondary_avatar()1582 *1583 * @param array|string $args See {@link bp_get_activity_secondary_avatar} for description.1584 */1585 function bp_activity_secondary_avatar( $args = '' ) {1586 echo bp_get_activity_secondary_avatar( $args );1587 }1588 1589 /**1590 * Return the avatar of the object that action was performed on.1591 *1592 * @since 1.2.01593 *1594 * @see bp_core_fetch_avatar() for description of arguments.1595 * @global object $activities_template {@link BP_Activity_Template}1596 * @uses wp_parse_args()1597 * @uses get_blog_option()1598 * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component hook.1599 * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar_item_id' hook.1600 * @uses bp_core_fetch_avatar()1601 * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar' hook.1602 *1603 * @param array|string $args {1604 * For a complete description of arguments, see {@link bp_core_fetch_avatar()}.1605 * @type string $alt Default value varies based on current activity1606 * item component.1607 * @type string $type Default: 'full' when viewing a single activity1608 * permalink page, otherwise 'thumb'.1609 * @type string $class Default: 'avatar'.1610 * @type string|bool $email Default: email of the activity's user.1611 * @type int|bool $user_id Default: ID of the activity's user.1612 * }1613 * @return string The secondary avatar.1614 */1615 function bp_get_activity_secondary_avatar( $args = '' ) {1616 global $activities_template;1617 1618 $r = wp_parse_args( $args, array(1619 'alt' => '',1620 'type' => 'thumb',1621 'width' => 20,1622 'height' => 20,1623 'class' => 'avatar',1624 'link_class' => '',1625 'linked' => true,1626 'email' => false1627 ) );1628 extract( $r, EXTR_SKIP );1629 1630 // Set item_id and object (default to user).1631 switch ( $activities_template->activity->component ) {1632 case 'groups' :1633 if ( bp_disable_group_avatar_uploads() ) {1634 return false;1635 }1636 1637 $object = 'group';1638 $item_id = $activities_template->activity->item_id;1639 $link = '';1640 $name = '';1641 1642 // Only if groups is active.1643 if ( bp_is_active( 'groups' ) ) {1644 $group = groups_get_group( array(1645 'group_id' => $item_id,1646 'populate_extras' => false,1647 'update_meta_cache' => false,1648 ) );1649 $link = bp_get_group_permalink( $group );1650 $name = $group->name;1651 }1652 1653 if ( empty( $alt ) ) {1654 $alt = __( 'Group logo', 'buddypress' );1655 1656 if ( ! empty( $name ) ) {1657 $alt = sprintf( __( 'Group logo of %s', 'buddypress' ), $name );1658 }1659 }1660 1661 break;1662 case 'blogs' :1663 $object = 'blog';1664 $item_id = $activities_template->activity->item_id;1665 $link = home_url();1666 1667 if ( empty( $alt ) ) {1668 $alt = sprintf( __( 'Profile picture of the author of the site %s', 'buddypress' ), get_blog_option( $item_id, 'blogname' ) );1669 }1670 1671 break;1672 case 'friends' :1673 $object = 'user';1674 $item_id = $activities_template->activity->secondary_item_id;1675 $link = bp_core_get_userlink( $item_id, false, true );1676 1677 if ( empty( $alt ) ) {1678 $alt = sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $activities_template->activity->secondary_item_id ) );1679 }1680 1681 break;1682 default :1683 $object = 'user';1684 $item_id = $activities_template->activity->user_id;1685 $email = $activities_template->activity->user_email;1686 $link = bp_core_get_userlink( $item_id, false, true );1687 1688 if ( empty( $alt ) ) {1689 $alt = sprintf( __( 'Profile picture of %s', 'buddypress' ), $activities_template->activity->display_name );1690 }1691 1692 break;1693 }1694 1695 /**1696 * Filters the activity secondary avatar object based on current activity item component.1697 *1698 * This is a variable filter dependent on the component used. Possible hooks are1699 * bp_get_activity_secondary_avatar_object_blog, bp_get_activity_secondary_avatar_object_group,1700 * and bp_get_activity_secondary_avatar_object_user.1701 *1702 * @since 1.2.101703 *1704 * @param string $object Component being displayed.1705 */1706 $object = apply_filters( 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component, $object );1707 1708 /**1709 * Filters the activity secondary avatar item ID.1710 *1711 * @since 1.2.101712 *1713 * @param int $item_id ID for the secondary avatar item.1714 */1715 $item_id = apply_filters( 'bp_get_activity_secondary_avatar_item_id', $item_id );1716 1717 // If we have no item_id or object, there is no avatar to display.1718 if ( empty( $item_id ) || empty( $object ) ) {1719 return false;1720 }1721 1722 // Get the avatar.1723 $avatar = bp_core_fetch_avatar( array(1724 'item_id' => $item_id,1725 'object' => $object,1726 'type' => $type,1727 'alt' => $alt,1728 'class' => $class,1729 'width' => $width,1730 'height' => $height,1731 'email' => $email1732 ) );1733 1734 if ( !empty( $linked ) ) {1735 1736 /**1737 * Filters the secondary avatar link for current activity.1738 *1739 * @since 1.7.01740 *1741 * @param string $link Link to wrap the avatar image in.1742 * @param string $component Activity component being acted on.1743 */1744 $link = apply_filters( 'bp_get_activity_secondary_avatar_link', $link, $activities_template->activity->component );1745 1746 /**1747 * Filters the determined avatar for the secondary activity item.1748 *1749 * @since 1.2.101750 *1751 * @param string $avatar Formatted HTML <img> element, or raw avatar URL.1752 */1753 $avatar = apply_filters( 'bp_get_activity_secondary_avatar', $avatar );1754 1755 return sprintf( '<a href="%s" class="%s">%s</a>',1756 $link,1757 $link_class,1758 $avatar1759 );1760 }1761 1762 /** This filter is documented in bp-activity/bp-activity-template.php */1763 return apply_filters( 'bp_get_activity_secondary_avatar', $avatar );1764 }1765 1766 /**1767 * Output the activity action.1768 *1769 * @since 1.2.01770 *1771 * @param array $args See bp_get_activity_action().1772 * @uses bp_get_activity_action()1773 */1774 function bp_activity_action( $args = array() ) {1775 echo bp_get_activity_action( $args );1776 }1777 1778 /**1779 * Return the activity action.1780 *1781 * @since 1.2.01782 *1783 * @global object $activities_template {@link BP_Activity_Template}1784 * @uses apply_filters_ref_array() To call the 'bp_get_activity_action_pre_meta' hook.1785 * @uses bp_insert_activity_meta()1786 * @uses apply_filters_ref_array() To call the 'bp_get_activity_action' hook.1787 *1788 * @param array $args {1789 * @type bool $no_timestamp Whether to exclude the timestamp.1790 * }1791 *1792 * @return string The activity action.1793 */1794 function bp_get_activity_action( $args = array() ) {1795 global $activities_template;1796 1797 $r = wp_parse_args( $args, array(1798 'no_timestamp' => false,1799 ) );1800 1801 /**1802 * Filters the activity action before the action is inserted as meta.1803 *1804 * @since 1.2.101805 *1806 * @param array $value Array containing the current action, the current activity, and the $args array passed into the function.1807 */1808 $action = apply_filters_ref_array( 'bp_get_activity_action_pre_meta', array(1809 $activities_template->activity->action,1810 &$activities_template->activity,1811 $r1812 ) );1813 1814 // Prepend the activity action meta (link, time since, etc...).1815 if ( ! empty( $action ) && empty( $r['no_timestamp'] ) ) {1816 $action = bp_insert_activity_meta( $action );1817 }1818 1819 /**1820 * Filters the activity action after the action has been inserted as meta.1821 *1822 * @since 1.2.01823 *1824 * @param array $value Array containing the current action, the current activity, and the $args array passed into the function.1825 */1826 return apply_filters_ref_array( 'bp_get_activity_action', array(1827 $action,1828 &$activities_template->activity,1829 $r1830 ) );1831 }1832 1833 /**1834 * Output the activity content body.1835 *1836 * @since 1.2.01837 *1838 * @uses bp_get_activity_content_body()1839 */1840 function bp_activity_content_body() {1841 echo bp_get_activity_content_body();1842 }1843 1844 /**1845 * Return the activity content body.1846 *1847 * @since 1.2.01848 *1849 * @global object $activities_template {@link BP_Activity_Template}1850 * @uses bp_insert_activity_meta()1851 * @uses apply_filters_ref_array() To call the 'bp_get_activity_content_body' hook.1852 *1853 * @return string The activity content body.1854 */1855 function bp_get_activity_content_body() {1856 global $activities_template;1857 1858 // Backwards compatibility if action is not being used.1859 if ( empty( $activities_template->activity->action ) && ! empty( $activities_template->activity->content ) ) {1860 $activities_template->activity->content = bp_insert_activity_meta( $activities_template->activity->content );1861 }1862 1863 /**1864 * Filters the activity content body.1865 *1866 * @since 1.2.01867 *1868 * @param array $value Array containing the current activity content body and the current activity.1869 */1870 return apply_filters_ref_array( 'bp_get_activity_content_body', array( $activities_template->activity->content, &$activities_template->activity ) );1871 }1872 1873 /**1874 * Does the activity have content?1875 *1876 * @since 1.2.01877 *1878 * @global object $activities_template {@link BP_Activity_Template}1879 *1880 * @return bool True if activity has content, false otherwise.1881 */1882 function bp_activity_has_content() {1883 global $activities_template;1884 1885 if ( ! empty( $activities_template->activity->content ) ) {1886 return true;1887 }1888 1889 return false;1890 }1891 1892 /**1893 * Output the activity content.1894 *1895 * @since 1.0.01896 * @deprecated 1.5.01897 *1898 * @todo properly deprecate this function.1899 *1900 * @uses bp_get_activity_content()1901 */1902 function bp_activity_content() {1903 echo bp_get_activity_content();1904 }1905 1906 /**1907 * Return the activity content.1908 *1909 * @since 1.0.01910 * @deprecated 1.5.01911 *1912 * @todo properly deprecate this function.1913 *1914 * @uses bp_get_activity_action()1915 * @uses bp_get_activity_content_body()1916 * @uses apply_filters() To call the 'bp_get_activity_content' hook.1917 *1918 * @return string The activity content.1919 */1920 function bp_get_activity_content() {1921 1922 /**1923 * If you want to filter activity update content, please use1924 * the filter 'bp_get_activity_content_body'.1925 *1926 * This function is mainly for backwards compatibility.1927 */1928 $content = bp_get_activity_action() . ' ' . bp_get_activity_content_body();1929 return apply_filters( 'bp_get_activity_content', $content );1930 }1931 1932 /**1933 * Attach metadata about an activity item to the activity content.1934 *1935 * This metadata includes the time since the item was posted (which will appear1936 * as a link to the item's permalink).1937 *1938 * @since 1.2.01939 *1940 * @global object $activities_template {@link BP_Activity_Template}1941 * @uses bp_core_time_since()1942 * @uses apply_filters_ref_array() To call the 'bp_activity_time_since' hook.1943 * @uses bp_is_single_activity()1944 * @uses bp_activity_get_permalink()1945 * @uses esc_attr__()1946 * @uses apply_filters_ref_array() To call the 'bp_activity_permalink' hook.1947 * @uses apply_filters() To call the 'bp_insert_activity_meta' hook.1948 *1949 * @param string $content The activity content.1950 * @return string The activity content with the metadata string attached.1951 */1952 function bp_insert_activity_meta( $content = '' ) {1953 global $activities_template;1954 1955 // Strip any legacy time since placeholders from BP 1.0-1.1.1956 $new_content = str_replace( '<span class="time-since">%s</span>', '', $content );1957 1958 // Get the time since this activity was recorded.1959 $date_recorded = bp_core_time_since( $activities_template->activity->date_recorded );1960 1961 /**1962 * Filters the activity item time since markup.1963 *1964 * @since 1.2.01965 *1966 * @param array $value Array containing the time since markup and the current activity component.1967 */1968 $time_since = apply_filters_ref_array( 'bp_activity_time_since', array(1969 '<span class="time-since">' . $date_recorded . '</span>',1970 &$activities_template->activity1971 ) );1972 1973 // Insert the permalink.1974 if ( ! bp_is_single_activity() ) {1975 1976 // Setup variables for activity meta.1977 $activity_permalink = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity );1978 $activity_meta = sprintf( '%1$s <a href="%2$s" class="view activity-time-since" title="%3$s">%4$s</a>',1979 $new_content,1980 $activity_permalink,1981 esc_attr__( 'View Discussion', 'buddypress' ),1982 $time_since1983 );1984 1985 /**1986 * Filters the activity permalink to be added to the activity content.1987 *1988 * @since 1.2.01989 *1990 * @param array $value Array containing the html markup for the activity permalink, after being parsed by1991 * sprintf and current activity component.1992 */1993 $new_content = apply_filters_ref_array( 'bp_activity_permalink', array(1994 $activity_meta,1995 &$activities_template->activity1996 ) );1997 } else {1998 $new_content .= str_pad( $time_since, strlen( $time_since ) + 2, ' ', STR_PAD_BOTH );1999 }2000 2001 /**2002 * Filters the activity content after activity metadata has been attached.2003 *2004 * @since 1.2.02005 *2006 * @param string $content Activity content with the activity metadata added.2007 */2008 return apply_filters( 'bp_insert_activity_meta', $new_content, $content );2009 }2010 2011 /**2012 * Determine if the current user can delete an activity item.2013 *2014 * @since 1.2.02015 *2016 * @global object $activities_template {@link BP_Activity_Template}2017 * @uses apply_filters() To call the 'bp_activity_user_can_delete' hook.2018 *2019 * @param object|bool $activity Optional. Falls back on the current item in the loop.2020 * @return bool True if can delete, false otherwise.2021 */2022 function bp_activity_user_can_delete( $activity = false ) {2023 global $activities_template;2024 2025 // Try to use current activity if none was passed.2026 if ( empty( $activity ) && ! empty( $activities_template->activity ) ) {2027 $activity = $activities_template->activity;2028 }2029 2030 // If current_comment is set, we'll use that in place of the main activity.2031 if ( isset( $activity->current_comment ) ) {2032 $activity = $activity->current_comment;2033 }2034 2035 // Assume the user cannot delete the activity item.2036 $can_delete = false;2037 2038 // Only logged in users can delete activity.2039 if ( is_user_logged_in() ) {2040 2041 // Community moderators can always delete activity (at least for now).2042 if ( bp_current_user_can( 'bp_moderate' ) ) {2043 $can_delete = true;2044 }2045 2046 // Users are allowed to delete their own activity. This is actually2047 // quite powerful, because doing so also deletes all comments to that2048 // activity item. We should revisit this eventually.2049 if ( isset( $activity->user_id ) && ( (int) $activity->user_id === bp_loggedin_user_id() ) ) {2050 $can_delete = true;2051 }2052 2053 // Viewing a single item, and this user is an admin of that item.2054 if ( bp_is_single_item() && bp_is_item_admin() ) {2055 $can_delete = true;2056 }2057 }2058 2059 /**2060 * Filters whether the current user can delete an activity item.2061 *2062 * @since 1.5.02063 *2064 * @param bool $can_delete Whether the user can delete the item.2065 * @param object $activity Current activity item object.2066 */2067 return (bool) apply_filters( 'bp_activity_user_can_delete', $can_delete, $activity );2068 }2069 2070 /**2071 * Output the activity parent content.2072 *2073 * @since 1.2.02074 *2075 * @see bp_get_activity_parent_content() for a description of arguments.2076 * @uses bp_get_activity_parent_content()2077 *2078 * @param array|string $args See {@link bp_get_activity_parent_content} for description.2079 */2080 function bp_activity_parent_content( $args = '' ) {2081 echo bp_get_activity_parent_content($args);2082 }2083 2084 /**2085 * Return the activity content.2086 *2087 * @since 1.2.02088 *2089 * @global object $activities_template {@link BP_Activity_Template}2090 * @uses apply_filters() To call the 'bp_get_activity_parent_content' hook.2091 *2092 * @param string $args Unused. Left over from an earlier implementation.2093 * @return mixed False on failure, otherwise the activity parent content.2094 */2095 function bp_get_activity_parent_content( $args = '' ) {2096 global $activities_template;2097 2098 // Bail if no activity on no item ID.2099 if ( empty( $activities_template->activity ) || empty( $activities_template->activity->item_id ) ) {2100 return false;2101 }2102 2103 // Get the ID of the parent activity content.2104 $parent_id = (int) $activities_template->activity->item_id;2105 2106 // Bail if no parent content.2107 if ( empty( $activities_template->activity_parents[ $parent_id ] ) ) {2108 return false;2109 }2110 2111 // Bail if no action.2112 if ( empty( $activities_template->activity_parents[ $parent_id ]->action ) ) {2113 return false;2114 }2115 2116 // Content always includes action.2117 $content = $activities_template->activity_parents[ $parent_id ]->action;2118 2119 // Maybe append activity content, if it exists.2120 if ( ! empty( $activities_template->activity_parents[ $parent_id ]->content ) ) {2121 $content .= ' ' . $activities_template->activity_parents[ $parent_id ]->content;2122 }2123 2124 // Remove the time since content for backwards compatibility.2125 $content = str_replace( '<span class="time-since">%s</span>', '', $content );2126 2127 // Remove images.2128 $content = preg_replace( '/<img[^>]*>/Ui', '', $content );2129 2130 /**2131 * Filters the activity parent content.2132 *2133 * @since 1.2.02134 *2135 * @param string $content Content set to be displayed as parent content.2136 */2137 return apply_filters( 'bp_get_activity_parent_content', $content );2138 }2139 2140 /**2141 * Output the parent activity's user ID.2142 *2143 * @since 1.7.02144 */2145 function bp_activity_parent_user_id() {2146 echo bp_get_activity_parent_user_id();2147 }2148 2149 /**2150 * Return the parent activity's user ID.2151 *2152 * @since 1.7.02153 *2154 * @global BP_Activity_Template $activities_template2155 *2156 * @return bool|int False if parent activity can't be found, otherwise2157 * the parent activity's user ID.2158 */2159 function bp_get_activity_parent_user_id() {2160 global $activities_template;2161 2162 // Bail if no activity on no item ID.2163 if ( empty( $activities_template->activity ) || empty( $activities_template->activity->item_id ) ) {2164 return false;2165 }2166 2167 // Get the ID of the parent activity content.2168 $parent_id = (int) $activities_template->activity->item_id;2169 2170 // Bail if no parent item.2171 if ( empty( $activities_template->activity_parents[ $parent_id ] ) ) {2172 return false;2173 }2174 2175 // Bail if no parent user ID.2176 if ( empty( $activities_template->activity_parents[ $parent_id ]->user_id ) ) {2177 return false;2178 }2179 2180 $retval = $activities_template->activity_parents[ $parent_id ]->user_id;2181 2182 /**2183 * Filters the activity parent item's user ID.2184 *2185 * @since 1.7.02186 *2187 * @param int $retval ID for the activity parent's user.2188 */2189 return (int) apply_filters( 'bp_get_activity_parent_user_id', $retval );2190 }2191 2192 /**2193 * Output whether or not the current activity is in a current user's favorites.2194 *2195 * @since 1.2.02196 *2197 * @uses bp_get_activity_is_favorite()2198 */2199 function bp_activity_is_favorite() {2200 echo bp_get_activity_is_favorite();2201 }2202 2203 /**2204 * Return whether the current activity is in a current user's favorites.2205 *2206 * @since 1.2.02207 *2208 * @global object $activities_template {@link BP_Activity_Template}2209 * @uses apply_filters() To call the 'bp_get_activity_is_favorite' hook.2210 *2211 * @return bool True if user favorite, false otherwise.2212 */2213 function bp_get_activity_is_favorite() {2214 global $activities_template;2215 2216 /**2217 * Filters whether the current activity item is in the current user's favorites.2218 *2219 * @since 1.2.02220 *2221 * @param bool $value Whether or not the current activity item is in the current user's favorites.2222 */2223 return (bool) apply_filters( 'bp_get_activity_is_favorite', in_array( $activities_template->activity->id, (array) $activities_template->my_favs ) );2224 }2225 2226 /**2227 * Output the comment markup for an activity item.2228 *2229 * @since 1.2.02230 *2231 * @todo deprecate $args param2232 *2233 * @param array|string $args See {@link bp_activity_get_comments} for description.2234 */2235 function bp_activity_comments( $args = '' ) {2236 echo bp_activity_get_comments( $args );2237 }2238 2239 /**2240 * Get the comment markup for an activity item.2241 *2242 * @since 1.2.02243 *2244 * @todo deprecate $args param2245 * @todo Given that checks for children already happen in bp_activity_recurse_comments(),2246 * this function can probably be streamlined or removed.2247 *2248 * @global object $activities_template {@link BP_Activity_Template}2249 * @uses bp_activity_recurse_comments()2250 *2251 * @param string $args Unused. Left over from an earlier implementation.2252 * @return bool2253 */2254 function bp_activity_get_comments( $args = '' ) {2255 global $activities_template;2256 2257 if ( empty( $activities_template->activity->children ) ) {2258 return false;2259 }2260 2261 bp_activity_recurse_comments( $activities_template->activity );2262 }2263 2264 /**2265 * Loops through a level of activity comments and loads the template for each.2266 *2267 * Note: The recursion itself used to happen entirely in this function. Now it is2268 * split between here and the comment.php template.2269 *2270 * @since 1.2.02271 *2272 * @global object $activities_template {@link BP_Activity_Template}2273 * @uses locate_template()2274 *2275 * @param object $comment The activity object currently being recursed.2276 * @return bool|string2277 */2278 function bp_activity_recurse_comments( $comment ) {2279 global $activities_template;2280 2281 if ( empty( $comment ) ) {2282 return false;2283 }2284 2285 if ( empty( $comment->children ) ) {2286 return false;2287 }2288 2289 /**2290 * Filters the opening tag for the template that lists activity comments.2291 *2292 * @since 1.6.02293 *2294 * @param string $value Opening tag for the HTML markup to use.2295 */2296 echo apply_filters( 'bp_activity_recurse_comments_start_ul', '<ul>' );2297 foreach ( (array) $comment->children as $comment_child ) {2298 2299 // Put the comment into the global so it's available to filters.2300 $activities_template->activity->current_comment = $comment_child;2301 2302 $template = bp_locate_template( 'activity/comment.php', false, false );2303 2304 // Backward compatibility. In older versions of BP, the markup was2305 // generated in the PHP instead of a template. This ensures that2306 // older themes (which are not children of bp-default and won't2307 // have the new template) will still work.2308 if ( !$template ) {2309 $template = buddypress()->plugin_dir . '/bp-themes/bp-default/activity/comment.php';2310 }2311 2312 load_template( $template, false );2313 2314 unset( $activities_template->activity->current_comment );2315 }2316 2317 /**2318 * Filters the closing tag for the template that list activity comments.2319 *2320 * @since 1.6.02321 *2322 * @param string $value Closing tag for the HTML markup to use.2323 */2324 echo apply_filters( 'bp_activity_recurse_comments_end_ul', '</ul>' );2325 }2326 2327 /**2328 * Utility function that returns the comment currently being recursed.2329 *2330 * @since 1.5.02331 *2332 * @global object $activities_template {@link BP_Activity_Template}2333 * @uses apply_filters() To call the 'bp_activity_current_comment' hook.2334 *2335 * @return object|bool $current_comment The activity comment currently being2336 * displayed. False on failure.2337 */2338 function bp_activity_current_comment() {2339 global $activities_template;2340 2341 $current_comment = !empty( $activities_template->activity->current_comment )2342 ? $activities_template->activity->current_comment2343 : false;2344 2345 /**2346 * Filters the current comment being recursed.2347 *2348 * @since 1.5.02349 *2350 * @param object|bool $current_comment The activity comment currently being displayed. False on failure.2351 */2352 return apply_filters( 'bp_activity_current_comment', $current_comment );2353 }2354 2355 2356 /**2357 * Output the ID of the activity comment currently being displayed.2358 *2359 * @since 1.5.02360 *2361 * @uses bp_get_activity_comment_id()2362 */2363 function bp_activity_comment_id() {2364 echo bp_get_activity_comment_id();2365 }2366 2367 /**2368 * Return the ID of the activity comment currently being displayed.2369 *2370 * @since 1.5.02371 *2372 * @global object $activities_template {@link BP_Activity_Template}2373 * @uses apply_filters() To call the 'bp_activity_comment_id' hook.2374 *2375 * @return int|bool $comment_id The ID of the activity comment currently2376 * being displayed, false if none is found.2377 */2378 function bp_get_activity_comment_id() {2379 global $activities_template;2380 2381 $comment_id = isset( $activities_template->activity->current_comment->id ) ? $activities_template->activity->current_comment->id : false;2382 2383 /**2384 * Filters the ID of the activity comment currently being displayed.2385 *2386 * @since 1.5.02387 *2388 * @param int|bool $comment_id ID for the comment currently being displayed.2389 */2390 return apply_filters( 'bp_activity_comment_id', $comment_id );2391 }2392 2393 /**2394 * Output the ID of the author of the activity comment currently being displayed.2395 *2396 * @since 1.5.02397 *2398 * @uses bp_get_activity_comment_user_id()2399 */2400 function bp_activity_comment_user_id() {2401 echo bp_get_activity_comment_user_id();2402 }2403 2404 /**2405 * Return the ID of the author of the activity comment currently being displayed.2406 *2407 * @since 1.5.02408 *2409 * @global object $activities_template {@link BP_Activity_Template}2410 * @uses apply_filters() To call the 'bp_activity_comment_user_id' hook.2411 *2412 * @return int|bool $user_id The user_id of the author of the displayed2413 * activity comment. False on failure.2414 */2415 function bp_get_activity_comment_user_id() {2416 global $activities_template;2417 2418 $user_id = isset( $activities_template->activity->current_comment->user_id ) ? $activities_template->activity->current_comment->user_id : false;2419 2420 /**2421 * Filters the ID of the author of the activity comment currently being displayed.2422 *2423 * @since 1.5.02424 *2425 * @param int|bool $user_id ID for the author of the comment currently being displayed.2426 */2427 return apply_filters( 'bp_activity_comment_user_id', $user_id );2428 }2429 2430 /**2431 * Output the author link for the activity comment currently being displayed.2432 *2433 * @since 1.5.02434 *2435 * @uses bp_get_activity_comment_user_link()2436 */2437 function bp_activity_comment_user_link() {2438 echo bp_get_activity_comment_user_link();2439 }2440 2441 /**2442 * Return the author link for the activity comment currently being displayed.2443 &n