Skip to:
Content

BuddyPress.org

Changeset 7207


Ignore:
Timestamp:
06/12/2013 10:08:10 PM (7 years ago)
Author:
boonebgorges
Message:

Introduces BP_Activity_Feed class, and migrates existing feeds

RSS feeds for BP activity have historically been generated on a one-by-one
basis, with separate template files used for each theme. This resulted in a
huge amount of unnecessarily duplicated code. Moreover, it made the process
of customizing feeds, or providing new feeds, unnecessarily cumbersome.

BP_Activity_Feed abstracts the central parts of RSS feed building, allowing for
easier customization, and fewer points of failure.

This changeset also fixes our RSS implementation to match best practices with
respect to encoding content inside of the <description> element.

Fixes #5020

Props r-a-y

Location:
trunk
Files:
7 deleted
3 edited

Legend:

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

    r7193 r7207  
    422422 */
    423423function bp_activity_action_sitewide_feed() {
    424     global $bp, $wp_query;
    425 
    426     if ( !bp_is_activity_component() || !bp_is_current_action( 'feed' ) || bp_is_user() || !empty( $bp->groups->current_group ) )
    427         return false;
    428 
    429     $wp_query->is_404 = false;
    430     status_header( 200 );
    431 
    432     include_once( 'feeds/bp-activity-sitewide-feed.php' );
    433     die;
     424    global $bp;
     425
     426    if ( ! bp_is_activity_component() || ! bp_is_current_action( 'feed' ) || bp_is_user() || ! empty( $bp->groups->current_group ) )
     427        return false;
     428
     429    // setup the feed
     430    buddypress()->activity->feed = new BP_Activity_Feed( array(
     431        'id'            => 'sitewide',
     432
     433        /* translators: Sitewide activity RSS title - "[Site Name] | Site Wide Activity" */
     434        'title'         => sprintf( __( '%s | Site Wide Activity', 'buddypress' ), bp_get_site_name() ),
     435
     436        'link'          => bp_get_activity_directory_permalink(),
     437        'description'   => __( 'Activity feed for the entire site.', 'buddypress' ),
     438        'activity_args' => 'display_comments=threaded'
     439    ) );
    434440}
    435441add_action( 'bp_actions', 'bp_activity_action_sitewide_feed' );
     
    448454 */
    449455function bp_activity_action_personal_feed() {
    450     global $wp_query;
    451 
    452     if ( !bp_is_user_activity() || !bp_is_current_action( 'feed' ) )
    453         return false;
    454 
    455     $wp_query->is_404 = false;
    456     status_header( 200 );
    457 
    458     include_once( 'feeds/bp-activity-personal-feed.php' );
    459     die;
     456    if ( ! bp_is_user_activity() || ! bp_is_current_action( 'feed' ) ) {
     457        return false;
     458    }
     459
     460    // setup the feed
     461    buddypress()->activity->feed = new BP_Activity_Feed( array(
     462        'id'            => 'personal',
     463
     464        /* translators: Personal activity RSS title - "[Site Name] | [User Display Name] | Activity" */
     465        'title'         => sprintf( __( '%1$s | %2$s | Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
     466
     467        'link'          => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() ),
     468        'description'   => sprintf( __( 'Activity feed for %s.', 'buddypress' ), bp_get_displayed_user_fullname() ),
     469        'activity_args' => 'user_id=' . bp_displayed_user_id()
     470    ) );
    460471}
    461472add_action( 'bp_actions', 'bp_activity_action_personal_feed' );
     
    477488 */
    478489function bp_activity_action_friends_feed() {
    479     global $wp_query;
    480 
    481     if ( !bp_is_active( 'friends' ) || !bp_is_user_activity() || !bp_is_current_action( bp_get_friends_slug() ) || !bp_is_action_variable( 'feed', 0 ) )
    482         return false;
    483 
    484     $wp_query->is_404 = false;
    485     status_header( 200 );
    486 
    487     include_once( 'feeds/bp-activity-friends-feed.php' );
    488     die;
     490    if ( ! bp_is_active( 'friends' ) || ! bp_is_user_activity() || ! bp_is_current_action( bp_get_friends_slug() ) || ! bp_is_action_variable( 'feed', 0 ) ) {
     491        return false;
     492    }
     493
     494    // setup the feed
     495    buddypress()->activity->feed = new BP_Activity_Feed( array(
     496        'id'            => 'friends',
     497
     498        /* translators: Friends activity RSS title - "[Site Name] | [User Display Name] | Friends Activity" */
     499        'title'         => sprintf( __( '%1$s | %2$s | Friends Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
     500
     501        'link'          => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() ),
     502        'description'   => sprintf( __( "Activity feed for %s' friends.", 'buddypress' ), bp_get_displayed_user_fullname() ),
     503        'activity_args' => 'scope=friends'
     504    ) );
    489505}
    490506add_action( 'bp_actions', 'bp_activity_action_friends_feed' );
     
    506522 */
    507523function bp_activity_action_my_groups_feed() {
     524    if ( ! bp_is_active( 'groups' ) || ! bp_is_user_activity() || ! bp_is_current_action( bp_get_groups_slug() ) || ! bp_is_action_variable( 'feed', 0 ) ) {
     525        return false;
     526    }
     527
     528    // get displayed user's group IDs
     529    $groups    = groups_get_user_groups();
     530    $group_ids = implode( ',', $groups['groups'] );
     531
     532    // setup the feed
     533    buddypress()->activity->feed = new BP_Activity_Feed( array(
     534        'id'            => 'mygroups',
     535
     536        /* translators: Member groups activity RSS title - "[Site Name] | [User Display Name] | Groups Activity" */
     537        'title'         => sprintf( __( '%1$s | %2$s | Group Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
     538
     539        'link'          => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() ),
     540        'description'   => sprintf( __( "Public group activity feed of which %s is a member of.", 'buddypress' ), bp_get_displayed_user_fullname() ),
     541        'activity_args' => array(
     542            'object'           => buddypress()->groups->id,
     543            'primary_id'       => $group_ids,
     544            'display_comments' => 'threaded'
     545        )
     546    ) );
     547}
     548add_action( 'bp_actions', 'bp_activity_action_my_groups_feed' );
     549
     550/**
     551 * Load a user's @mentions feed.
     552 *
     553 * @since BuddyPress (1.2)
     554 *
     555 * @global object $wp_query
     556 * @uses bp_is_user_activity()
     557 * @uses bp_is_current_action()
     558 * @uses bp_is_action_variable()
     559 * @uses status_header()
     560 *
     561 * @return bool False on failure
     562 */
     563function bp_activity_action_mentions_feed() {
    508564    global $wp_query;
    509565
    510     if ( !bp_is_active( 'groups' ) || !bp_is_user_activity() || !bp_is_current_action( bp_get_groups_slug() ) || !bp_is_action_variable( 'feed', 0 ) )
     566    if ( ! bp_activity_do_mentions() ) {
     567        return false;
     568    }
     569
     570    if ( !bp_is_user_activity() || !bp_is_current_action( 'mentions' ) || !bp_is_action_variable( 'feed', 0 ) )
    511571        return false;
    512572
     
    514574    status_header( 200 );
    515575
    516     include_once( 'feeds/bp-activity-mygroups-feed.php' );
     576    include_once( 'feeds/bp-activity-mentions-feed.php' );
    517577    die;
    518578}
    519 add_action( 'bp_actions', 'bp_activity_action_my_groups_feed' );
    520 
    521 /**
    522  * Load a user's @mentions feed.
     579add_action( 'bp_actions', 'bp_activity_action_mentions_feed' );
     580
     581/**
     582 * Load a user's favorites feed.
    523583 *
    524584 * @since BuddyPress (1.2)
     
    532592 * @return bool False on failure
    533593 */
    534 function bp_activity_action_mentions_feed() {
    535     global $wp_query;
    536 
    537     if ( ! bp_activity_do_mentions() ) {
    538         return false;
    539     }
    540 
    541     if ( !bp_is_user_activity() || !bp_is_current_action( 'mentions' ) || !bp_is_action_variable( 'feed', 0 ) )
    542         return false;
    543 
    544     $wp_query->is_404 = false;
    545     status_header( 200 );
    546 
    547     include_once( 'feeds/bp-activity-mentions-feed.php' );
    548     die;
    549 }
    550 add_action( 'bp_actions', 'bp_activity_action_mentions_feed' );
    551 
    552 /**
    553  * Load a user's favorites feed.
    554  *
    555  * @since BuddyPress (1.2)
    556  *
    557  * @global object $wp_query
    558  * @uses bp_is_user_activity()
    559  * @uses bp_is_current_action()
    560  * @uses bp_is_action_variable()
    561  * @uses status_header()
    562  *
    563  * @return bool False on failure
    564  */
    565594function bp_activity_action_favorites_feed() {
    566     global $wp_query;
    567 
    568     if ( !bp_is_user_activity() || !bp_is_current_action( 'favorites' ) || !bp_is_action_variable( 'feed', 0 ) )
    569         return false;
    570 
    571     $wp_query->is_404 = false;
    572     status_header( 200 );
    573 
    574     include_once( 'feeds/bp-activity-favorites-feed.php' );
    575     die;
     595    if ( ! bp_is_user_activity() || ! bp_is_current_action( 'favorites' ) || ! bp_is_action_variable( 'feed', 0 ) ) {
     596        return false;
     597    }
     598
     599    // get displayed user's favorite activity IDs
     600    $favs = bp_activity_get_user_favorites( bp_displayed_user_id() );
     601    $fav_ids = implode( ',', (array) $favs );
     602
     603    // setup the feed
     604    buddypress()->activity->feed = new BP_Activity_Feed( array(
     605        'id'            => 'favorites',
     606
     607        /* translators: User activity favorites RSS title - "[Site Name] | [User Display Name] | Favorites" */
     608        'title'         => sprintf( __( '%1$s | %2$s | Favorites', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
     609
     610        'link'          => bp_displayed_user_domain() . bp_get_activity_slug() . '/favorites/',
     611        'description'   => sprintf( __( "Activity feed of %s' favorites.", 'buddypress' ), bp_get_displayed_user_fullname() ),
     612        'activity_args' => 'include=' . $fav_ids
     613    ) );
    576614}
    577615add_action( 'bp_actions', 'bp_activity_action_favorites_feed' );
  • trunk/bp-activity/bp-activity-classes.php

    r7149 r7207  
    257257            $activity_user_ids = implode( ',', wp_parse_id_list( $activity_user_ids ) );
    258258
    259             if ( !empty( $activity_user_ids ) ) {               
     259            if ( !empty( $activity_user_ids ) ) {
    260260                if ( $names = $wpdb->get_results( "SELECT user_id, value AS user_fullname FROM {$bp->profile->table_name_data} WHERE field_id = 1 AND user_id IN ({$activity_user_ids})" ) ) {
    261261                    foreach ( (array) $names as $name )
     
    731731    }
    732732}
     733
     734/**
     735 * Create a RSS feed using the activity component.
     736 *
     737 * You should only construct a new feed when you've validated that you're on
     738 * the appropriate screen.
     739 *
     740 * See {@link bp_activity_action_sitewide_feed()} as an example.
     741 *
     742 * Accepted parameters:
     743 *   id               - internal id for the feed; should be alphanumeric only
     744 *                      (required)
     745 *   title            - RSS feed title
     746 *   link             - Relevant link for the RSS feed
     747 *   description      - RSS feed description
     748 *   ttl              - Time-to-live (see inline doc in constructor)
     749 *   update_period    - Part of the syndication module (see inline doc in
     750 *                      constructor for more info)
     751 *   update_frequency - Part of the syndication module (see inline doc in
     752 *                      constructor for more info)
     753 *   max              - Number of feed items to display
     754 *   activity_args    - Arguments passed to {@link bp_has_activities()}
     755 *
     756 * @since BuddyPress (1.8)
     757 */
     758class BP_Activity_Feed {
     759    /**
     760     * Holds our custom class properties.
     761     *
     762     * These variables are stored in a protected array that is magically
     763     * updated using PHP 5.2+ methods.
     764     *
     765     * @see BP_Feed::__construct() This is where $data is added
     766     * @var array
     767     */
     768    protected $data;
     769
     770    /**
     771     * Magic method for checking the existence of a certain data variable.
     772     *
     773     * @param string $key
     774     */
     775    public function __isset( $key ) { return isset( $this->data[$key] ); }
     776
     777    /**
     778     * Magic method for getting a certain data variable.
     779     *
     780     * @param string $key
     781     */
     782    public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
     783
     784    /**
     785     * Constructor.
     786     *
     787     * @param $args Array
     788     */
     789    public function __construct( $args = array() ) {
     790        // If feeds are disabled, stop now!
     791        if ( false === (bool) apply_filters( 'bp_activity_enable_feeds', true ) ) {
     792            global $wp_query;
     793
     794            // set feed flag to false
     795            $wp_query->is_feed = false;
     796
     797            return false;
     798        }
     799
     800        // Setup data
     801        $this->data = wp_parse_args( $args, array(
     802            // Internal identifier for the RSS feed - should be alphanumeric only
     803            'id'               => '',
     804
     805            // RSS title - should be plain-text
     806            'title'            => '',
     807
     808            // relevant link for the RSS feed
     809            'link'             => '',
     810
     811            // RSS description - should be plain-text
     812            'description'      => '',
     813
     814            // Time-to-live - number of minutes to cache the data before an aggregator
     815            // requests it again.  This is only acknowledged if the RSS client supports it
     816            //
     817            // See: http://www.rssboard.org/rss-profile#element-channel-ttl
     818            //      http://www.kbcafe.com/rss/rssfeedstate.html#ttl
     819            'ttl'              => '30',
     820
     821            // Syndication module - similar to ttl, but not really supported by RSS
     822            // clients
     823            //
     824            // See: http://web.resource.org/rss/1.0/modules/syndication/#description
     825            //      http://www.kbcafe.com/rss/rssfeedstate.html#syndicationmodule
     826            'update_period'    => 'hourly',
     827            'update_frequency' => 2,
     828
     829            // Number of items to display
     830            'max'              => 50,
     831
     832            // Activity arguments passed to bp_has_activities()
     833            'activity_args'    => array()
     834        ) );
     835
     836        // Plugins can use this filter to modify the feed before it is setup
     837        do_action_ref_array( 'bp_activity_feed_prefetch', array( &$this ) );
     838
     839        // Setup class properties
     840        $this->setup_properties();
     841
     842        // Check if id is valid
     843        if ( empty( $this->id ) ) {
     844            _doing_it_wrong( 'BP_Activity_Feed', __( "RSS feed 'id' must be defined", 'buddypress' ), 'BP 1.8' );
     845            return false;
     846        }
     847
     848        // Plugins can use this filter to modify the feed after it's setup
     849        do_action_ref_array( 'bp_activity_feed_postfetch', array( &$this ) );
     850
     851        // Setup feed hooks
     852        $this->setup_hooks();
     853
     854        // Output the feed
     855        $this->output();
     856
     857        // Kill the rest of the output
     858        die();
     859    }
     860
     861    /** SETUP ****************************************************************/
     862
     863    /**
     864     * Setup and validate the class properties.
     865     */
     866    protected function setup_properties() {
     867        $this->id               = sanitize_title( $this->id );
     868        $this->title            = strip_tags( $this->title );
     869        $this->link             = esc_url_raw( $this->link );
     870        $this->description      = strip_tags( $this->description );
     871        $this->ttl              = (int) $this->ttl;
     872        $this->update_period    = strip_tags( $this->update_period );
     873        $this->update_frequency = (int) $this->update_frequency;
     874
     875        $this->activity_args    = wp_parse_args( $this->activity_args, array(
     876            'max'              => $this->max,
     877            'display_comments' => 'stream'
     878        ) );
     879
     880    }
     881
     882    /**
     883     * Setup some hooks that are used in the feed.
     884     *
     885     * Currently, these hooks are used to maintain backwards compatibility with
     886     * the RSS feeds previous to BP 1.8.
     887     */
     888    protected function setup_hooks() {
     889        add_action( 'bp_activity_feed_rss_attributes',   array( $this, 'backpat_rss_attributes' ) );
     890        add_action( 'bp_activity_feed_channel_elements', array( $this, 'backpat_channel_elements' ) );
     891        add_action( 'bp_activity_feed_item_elements',    array( $this, 'backpat_item_elements' ) );
     892    }
     893
     894    /** BACKPAT HOOKS ********************************************************/
     895
     896    public function backpat_rss_attributes() {
     897        do_action( 'bp_activity_' . $this->id . '_feed' );
     898    }
     899
     900    public function backpat_channel_elements() {
     901        do_action( 'bp_activity_' . $this->id . '_feed_head' );
     902    }
     903
     904    public function backpat_item_elements() {
     905        switch ( $this->id ) {
     906
     907            // sitewide and friends feeds use the 'personal' hook
     908            case 'sitewide' :
     909            case 'friends' :
     910                $id = 'personal';
     911
     912                break;
     913
     914            default :
     915                $id = $this->id;
     916
     917                break;
     918        }
     919
     920        do_action( 'bp_activity_' . $id . '_feed_item' );
     921    }
     922
     923    /** HELPERS **************************************************************/
     924
     925    /**
     926     * Output the feed's item content.
     927     */
     928    protected function feed_content() {
     929        bp_activity_content_body();
     930
     931        switch ( $this->id ) {
     932
     933            // also output parent activity item if we're on a specific feed
     934            case 'favorites' :
     935            case 'friends' :
     936            case 'mentions' :
     937            case 'personal' :
     938
     939                if ( 'activity_comment' == bp_get_activity_action_name() ) :
     940            ?>
     941                <strong><?php _e( 'In reply to', 'buddypress' ) ?></strong> -
     942                <?php bp_activity_parent_content() ?>
     943            <?php
     944                endif;
     945
     946                break;
     947        }
     948    }
     949
     950    /** OUTPUT ***************************************************************/
     951
     952    /**
     953     * Output the RSS feed.
     954     */
     955    protected function output() {
     956        // set up some additional headers if not on a directory page
     957        // this is done b/c BP uses pseudo-pages
     958        if ( ! bp_is_directory() ) {
     959            global $wp_query;
     960
     961            $wp_query->is_404 = false;
     962            status_header( 200 );
     963        }
     964
     965        header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
     966        echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?'.'>';
     967    ?>
     968
     969<rss version="2.0"
     970    xmlns:content="http://purl.org/rss/1.0/modules/content/"
     971    xmlns:atom="http://www.w3.org/2005/Atom"
     972    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     973    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
     974    <?php do_action( 'bp_activity_feed_rss_attributes' ); ?>
     975>
     976
     977<channel>
     978    <title><?php echo $this->title; ?></title>
     979    <link><?php echo $this->link; ?></link>
     980    <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
     981    <description><?php echo $this->description ?></description>
     982    <lastBuildDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false ); ?></lastBuildDate>
     983    <generator>http://buddypress.org/?v=<?php bp_version(); ?></generator>
     984    <language><?php bloginfo_rss( 'language' ); ?></language>
     985    <ttl><?php echo $this->ttl; ?></ttl>
     986    <sy:updatePeriod><?php echo $this->update_period; ?></sy:updatePeriod>
     987    <sy:updateFrequency><?php echo $this->update_frequency; ?></sy:updateFrequency>
     988    <?php do_action( 'bp_activity_feed_channel_elements' ); ?>
     989
     990    <?php if ( bp_has_activities( $this->activity_args ) ) : ?>
     991        <?php while ( bp_activities() ) : bp_the_activity(); ?>
     992            <item>
     993                <guid isPermaLink="false"><?php bp_activity_feed_item_guid(); ?></guid>
     994                <title><?php echo stripslashes( bp_get_activity_feed_item_title() ); ?></title>
     995                <link><?php bp_activity_thread_permalink() ?></link>
     996                <pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_get_activity_feed_item_date(), false ); ?></pubDate>
     997
     998                <?php if ( bp_get_activity_feed_item_description() ) : ?>
     999                    <content:encoded><![CDATA[<?php $this->feed_content(); ?>]]></content:encoded>
     1000                <?php endif; ?>
     1001
     1002                <?php if ( bp_activity_can_comment() ) : ?>
     1003                    <slash:comments><?php bp_activity_comment_count(); ?></slash:comments>
     1004                <?php endif; ?>
     1005
     1006                <?php do_action( 'bp_activity_feed_item_elements' ); ?>
     1007            </item>
     1008        <?php endwhile; ?>
     1009
     1010    <?php endif; ?>
     1011</channel>
     1012</rss><?php
     1013    }
     1014}
  • trunk/bp-groups/bp-groups-actions.php

    r7172 r7207  
    305305add_action( 'bp_actions', 'groups_action_redirect_to_random_group' );
    306306
     307/**
     308 * Load the activity feed for the specific group.
     309 *
     310 * @since BuddyPress (v1.2)
     311 */
    307312function groups_action_group_feed() {
    308     global $bp, $wp_query;
    309 
    310     if ( !bp_is_active( 'activity' ) || !bp_is_groups_component() || !isset( $bp->groups->current_group ) || !bp_is_current_action( 'feed' ) )
    311         return false;
    312 
    313     $wp_query->is_404 = false;
    314     status_header( 200 );
    315 
    316     if ( 'public' != $bp->groups->current_group->status ) {
    317         if ( !groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) )
    318             return false;
    319     }
    320 
    321     include_once( BP_PLUGIN_DIR . '/bp-activity/feeds/bp-activity-group-feed.php' );
    322     die;
     313
     314    // get current group
     315    $group = groups_get_current_group();
     316
     317    if ( ! bp_is_active( 'activity' ) || ! bp_is_groups_component() || ! $group || ! bp_is_current_action( 'feed' ) )
     318        return false;
     319
     320    // if group isn't public or if logged-in user is not a member of the group, do
     321    // not output the group activity feed
     322    if ( ! bp_group_is_visible( $group ) ) {
     323        return false;
     324    }
     325
     326    // setup the feed
     327    buddypress()->activity->feed = new BP_Activity_Feed( array(
     328        'id'            => 'group',
     329
     330        /* translators: Group activity RSS title - "[Site Name] | [Group Name] | Activity" */
     331        'title'         => sprintf( __( '%1$s | %2$s | Activity', 'buddypress' ), bp_get_site_name(), bp_get_current_group_name() ),
     332
     333        'link'          => bp_get_group_permalink( $group ),
     334        'description'   => sprintf( __( "Activity feed for the group, %s.", 'buddypress' ), bp_get_current_group_name() ),
     335        'activity_args' => array(
     336            'object'           => buddypress()->groups->id,
     337            'primary_id'       => bp_get_current_group_id(),
     338            'display_comments' => 'threaded'
     339        )
     340    ) );
    323341}
    324342add_action( 'bp_actions', 'groups_action_group_feed' );
Note: See TracChangeset for help on using the changeset viewer.