Skip to:
Content

BuddyPress.org


Ignore:
Timestamp:
03/13/2014 06:34:06 PM (11 years ago)
Author:
boonebgorges
Message:

Generate activity actions dynamically, instead of using static values stored in the database

Activity actions - like 'Joe became a registered member' - have always been
stored as static strings in the activity table. This has been a perennial thorn
in the side of BP site administrators. For one thing, static strings cannot be
translated for multilingual audiences (without unreasonable workarounds).
For another, information in these static strings becomes out of date as users
change their display names, groups change their names, and so on.

This changeset makes it possible for activity types to be registered with a
new $format_callback function, passed to bp_activity_set_action(), which BP
will use to generate the action dynamically when building the activity loop.
This makes the activity stream fully localizable, continually up-to-date, and
generally the bomb dot com.

Existing plugins that do not register format_callback functions will continue
to have their actions pulled directly from the database. Likewise, since a copy
of the static string is saved in the activity table, static strings can be
served if the given component is disabled at any point (and thus the callback
is no longer available).

The original argument for caching the action strings was that generating them
inline was too resource intensive; it often requires pulling up display names,
user permalinks, group links, blog post names, and so forth. To address this
problem, each component can now prefetch required data at the beginning of an
activity loop by hooking to bp_activity_prefetch_object_data, and loading any
relevant data into the cache. The Activity, Friends, Groups, and Blogs
component now do this natively. It's likely that this prefetching will have
other performance benefits, as plugin authors will now be able to access user
data etc inline without performance penalties.

The case of the Blogs component is a special one; it's not practical to
prefetch data from multiple blogs at the beginning of a loop, due to the
resources required by switch_to_blog(). For this reason, the format_callback
functions in the blog component cache some relevant data (like the post name)
in blogmeta, where it's readily accessible within the loop.

Fixes #3856

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-activity/bp-activity-functions.php

    r8076 r8125  
    257257
    258258/**
    259  * Set the current action for a given activity stream location.
    260  *
    261  * @since BuddyPress (1.1)
    262  *
    263  * @global object $bp BuddyPress global settings
    264  * @uses apply_filters() To call the 'bp_activity_set_action' hook
     259 * Register an activity 'type' and its action description/callback.
     260 *
     261 * Activity actions are strings used to describe items in the activity stream,
     262 * such as 'Joe became a registered member' or 'Bill and Susie are now
     263 * friends'. Each activity type (such as 'new_member' or 'friendship_created')
     264 * used by a component should be registered using this function.
     265 *
     266 * While it's possible to post items to the activity stream whose types are
     267 * not registered using bp_activity_set_action(), it is not recommended;
     268 * unregistered types will not be displayed properly in the activity admin
     269 * panel, and dynamic action generation (which is essential for multilingual
     270 * sites, etc) will not work.
     271 *
     272 * @since BuddyPress (1.1.0)
    265273 *
    266274 * @param string $component_id The unique string ID of the component.
    267  * @param string $key The action key.
    268  * @param string $value The action value.
     275 * @param string $type The action type.
     276 * @param string $description The action description.
     277 * @param callable $format_callback Callback for formatting the action string.
    269278 * @return bool False if any param is empty, otherwise true.
    270279 */
    271 function bp_activity_set_action( $component_id, $key, $value ) {
    272     global $bp;
     280function bp_activity_set_action( $component_id, $type, $description, $format_callback = false ) {
     281    $bp = buddypress();
    273282
    274283    // Return false if any of the above values are not set
    275     if ( empty( $component_id ) || empty( $key ) || empty( $value ) )
    276         return false;
     284    if ( empty( $component_id ) || empty( $type ) || empty( $description ) ) {
     285        return false;
     286    }
    277287
    278288    // Set activity action
    279     if ( !isset( $bp->activity->actions ) || !is_object( $bp->activity->actions ) ) {
     289    if ( ! isset( $bp->activity->actions ) || ! is_object( $bp->activity->actions ) ) {
    280290        $bp->activity->actions = new stdClass;
    281291    }
    282292
    283     if ( !isset( $bp->activity->actions->{$component_id} ) || !is_object( $bp->activity->actions->{$component_id} ) ) {
     293    // Verify callback
     294    if ( ! is_callable( $format_callback ) ) {
     295        $format_callback = '';
     296    }
     297
     298    if ( ! isset( $bp->activity->actions->{$component_id} ) || ! is_object( $bp->activity->actions->{$component_id} ) ) {
    284299        $bp->activity->actions->{$component_id} = new stdClass;
    285300    }
    286301
    287     $bp->activity->actions->{$component_id}->{$key} = apply_filters( 'bp_activity_set_action', array(
    288         'key'   => $key,
    289         'value' => $value
    290     ), $component_id, $key, $value );
     302    $bp->activity->actions->{$component_id}->{$type} = apply_filters( 'bp_activity_set_action', array(
     303        'key'             => $type,
     304        'value'           => $description,
     305        'format_callback' => $format_callback,
     306    ), $component_id, $type, $description, $format_callback );
    291307
    292308    return true;
     
    858874    global $bp;
    859875
    860     bp_activity_set_action( $bp->activity->id, 'activity_update', __( 'Posted a status update', 'buddypress' ) );
    861     bp_activity_set_action( $bp->activity->id, 'activity_comment', __( 'Replied to a status update', 'buddypress' ) );
     876    bp_activity_set_action(
     877        $bp->activity->id,
     878        'activity_update',
     879        __( 'Posted a status update', 'buddypress' ),
     880        'bp_activity_format_activity_action_activity_update'
     881    );
     882
     883    bp_activity_set_action(
     884        $bp->activity->id,
     885        'activity_comment',
     886        __( 'Replied to a status update', 'buddypress' ),
     887        'bp_activity_format_activity_action_activity_comment'
     888    );
    862889
    863890    do_action( 'bp_activity_register_activity_actions' );
     
    867894}
    868895add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actions' );
     896
     897/**
     898 * Generate an activity action string for an activity item.
     899 *
     900 * @param object $activity Activity data object.
     901 * @return string|bool Returns false if no callback is found, otherwise returns
     902 *         the formatted action string.
     903 */
     904function bp_activity_generate_action_string( $activity ) {
     905    // Check for valid input
     906    if ( empty( $activity->component ) || empty( $activity->type ) ) {
     907        return false;
     908    }
     909
     910    // Check for registered format callback
     911    if ( empty( buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'] ) ) {
     912        return false;
     913    }
     914
     915    return call_user_func( buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'], $activity );
     916}
     917
     918/**
     919 * Format 'activity_update' activity actions.
     920 *
     921 * @since BuddyPress (2.0.0)
     922 *
     923 * @param object $activity Activity data object.
     924 * @return string
     925 */
     926function bp_activity_format_activity_action_activity_update( $activity ) {
     927    $action = sprintf( __( '%s posted an update', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
     928    return apply_filters( 'bp_activity_new_update_action', $action, $activity );
     929}
     930
     931/**
     932 * Format 'activity_comment' activity actions.
     933 *
     934 * @since BuddyPress (2.0.0)
     935 *
     936 * @param object $activity Activity data object.
     937 * @return string
     938 */
     939function bp_activity_format_activity_action_activity_comment( $activity ) {
     940    $action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
     941    return apply_filters( 'bp_activity_comment_action', $action, $activity );
     942}
    869943
    870944/******************************************************************************
     
    10321106 *           false to create a new item. Default: false.
    10331107 *     @type string $action Optional. The activity action/description, typically
    1034  *           something like "Joe posted an update".
     1108 *           something like "Joe posted an update". Values passed to this param
     1109 *           will be stored in the database and used as a fallback for when the
     1110 *           activity item's format_callback cannot be found (eg, when the
     1111 *           component is disabled). As long as you have registered a
     1112 *           format_callback for your $type, it is unnecessary to include this
     1113 *           argument - BP will generate it automatically.
     1114 *           See {@link bp_activity_set_action()}.
    10351115 *     @type string $content Optional. The content of the activity item.
    10361116 *     @type string $component The unique name of the component associated with
     
    10881168    $activity->component         = $component;
    10891169    $activity->type              = $type;
    1090     $activity->action            = $action;
    10911170    $activity->content           = $content;
    10921171    $activity->primary_link      = $primary_link;
     
    10961175    $activity->hide_sitewide     = $hide_sitewide;
    10971176    $activity->is_spam           = $is_spam;
     1177    $activity->action            = ! empty( $action ) ? $action : bp_activity_generate_action_string( $activity );
    10981178
    10991179    if ( !$activity->save() )
     
    11511231    // Record this on the user's profile
    11521232    $from_user_link   = bp_core_get_userlink( $user_id );
    1153     $activity_action  = sprintf( __( '%s posted an update', 'buddypress' ), $from_user_link );
    11541233    $activity_content = $content;
    11551234    $primary_link     = bp_core_get_userlink( $user_id, false, true );
     
    11581237    $activity_id = bp_activity_add( array(
    11591238        'user_id'      => $user_id,
    1160         'action'       => apply_filters( 'bp_activity_new_update_action', $activity_action ),
    11611239        'content'      => apply_filters( 'bp_activity_new_update_content', $activity_content ),
    11621240        'primary_link' => apply_filters( 'bp_activity_new_update_primary_link', $primary_link ),
    11631241        'component'    => $bp->activity->id,
    1164         'type'         => 'activity_update'
     1242        'type'         => 'activity_update',
    11651243    ) );
    11661244
     
    12311309    $comment_id = bp_activity_add( array(
    12321310        'id'                => $id,
    1233         'action'            => apply_filters( 'bp_activity_comment_action', sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $user_id ) ) ),
    12341311        'content'           => apply_filters( 'bp_activity_comment_content', $content ),
    12351312        'component'         => buddypress()->activity->id,
Note: See TracChangeset for help on using the changeset viewer.