Skip to:
Content

BuddyPress.org

Ticket #6772: 6772.04.patch

File 6772.04.patch, 32.8 KB (added by r-a-y, 9 years ago)
  • src/bp-activity/bp-activity-actions.php

    diff --git src/bp-activity/bp-activity-actions.php src/bp-activity/bp-activity-actions.php
    index f648b41..18ee4c1 100644
    function bp_activity_setup_akismet() { 
    744744        $bp->activity->akismet = new BP_Akismet();
    745745}
    746746
     747
     748/**
     749 * Loads our activity oEmbed component.
     750 *
     751 * @since 2.5.0
     752 */
     753function bp_activity_setup_oembed() {
     754        if ( bp_get_major_wp_version() >= 4.4 && bp_is_active( 'activity', 'embeds' ) ) {
     755                buddypress()->activity->oembed = new BP_Activity_oEmbed_Component;
     756        }
     757}
     758
    747759/**
    748760 * AJAX endpoint for Suggestions API lookups.
    749761 *
  • src/bp-activity/bp-activity-functions.php

    diff --git src/bp-activity/bp-activity-functions.php src/bp-activity/bp-activity-functions.php
    index e6c101d..a65c0dd 100644
    function bp_activity_thumbnail_content_images( $content, $link = false, $args = 
    26532653}
    26542654
    26552655/**
     2656 * Generate a text excerpt for an activity item (and remove any oEmbeds URLs).
     2657 *
     2658 * @since 2.5.0
     2659 *
     2660 * @param  string $content The content to generate an excerpt for.
     2661 * @return string
     2662 */
     2663function bp_activity_create_excerpt( $content = '' ) {
     2664        // Use the existing content in the activity loop.
     2665        if ( empty( $content ) && ! empty( $GLOBALS['activities_template']->in_the_loop ) ) {
     2666                $content = $GLOBALS['activities_template']->activity->content;
     2667        }
     2668
     2669        $content = strip_shortcodes( html_entity_decode( strip_tags( $content ) ) );
     2670        return bp_create_excerpt( preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $content ) );
     2671}
     2672
     2673/**
    26562674 * Create a rich summary of an activity item for the activity stream.
    26572675 *
    26582676 * More than just a simple excerpt, the summary could contain oEmbeds and other types of media.
    function bp_activity_create_summary( $content, $activity ) { 
    27892807        }
    27902808
    27912809        // Generate a text excerpt for this activity item (and remove any oEmbeds URLs).
    2792         $summary = strip_shortcodes( html_entity_decode( strip_tags( $content ) ) );
    2793         $summary = bp_create_excerpt( preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $summary ) );
     2810        $summary = bp_activity_create_excerpt( $content );
    27942811
    27952812        if ( $use_media_type === 'embeds' ) {
    27962813                $summary .= PHP_EOL . PHP_EOL . $extracted_media['url'];
  • src/bp-activity/bp-activity-loader.php

    diff --git src/bp-activity/bp-activity-loader.php src/bp-activity/bp-activity-loader.php
    index dfdf325..ff8dd0f 100644
    class BP_Activity_Component extends BP_Component { 
    3131                        array(
    3232                                'adminbar_myaccount_order' => 10,
    3333                                'search_query_arg' => 'activity_search',
     34                                'features' => array( 'embeds' )
    3435                        )
    3536                );
    3637        }
    class BP_Activity_Component extends BP_Component { 
    6768                        $includes[] = 'akismet';
    6869                }
    6970
     71                // Embeds - only applicable for WP 4.4+
     72                if ( bp_get_major_wp_version() >= 4.4 && bp_is_active( $this->id, 'embeds' ) ) {
     73                        $includes[] = 'classes/class-bp-activity-oembed-component';
     74                }
     75
    7076                if ( is_admin() ) {
    7177                        $includes[] = 'admin';
    7278                }
    class BP_Activity_Component extends BP_Component { 
    365371                // Spam prevention.
    366372                add_action( 'bp_include', 'bp_activity_setup_akismet' );
    367373
     374                // oEmbed handler.
     375                add_action( 'bp_loaded', 'bp_activity_setup_oembed' );
     376
    368377                parent::setup_actions();
    369378        }
    370379
  • new file src/bp-activity/classes/class-bp-activity-oembed-component.php

    diff --git src/bp-activity/classes/class-bp-activity-oembed-component.php src/bp-activity/classes/class-bp-activity-oembed-component.php
    new file mode 100644
    index 0000000..d1b9312
    - +  
     1<?php
     2/**
     3 * BuddyPress Activity Classes.
     4 *
     5 * @package BuddyPress
     6 * @subpackage Embeds
     7 */
     8
     9// Exit if accessed directly.
     10defined( 'ABSPATH' ) || exit;
     11
     12require_once( buddypress()->plugin_dir . '/bp-core/classes/class-bp-oembed-component.php' );
     13
     14/**
     15 * oEmbed handler to respond and render single activity items.
     16 *
     17 * @since 2.5.0
     18 */
     19class BP_Activity_oEmbed_Component extends BP_oEmbed_Component {
     20        /**
     21         * Custom oEmbed slug endpoint.
     22         *
     23         * @since 2.5.0
     24         *
     25         * @var string
     26         */
     27        public $slug_endpoint = 'activity';
     28
     29        /**
     30         * Custom hooks.
     31         *
     32         * @since 2.5.0
     33         */
     34        protected function custom_hooks() {
     35                add_action( 'embed_content_meta', array( $this, 'embed_comments_button' ), 5 );
     36        }
     37
     38        /**
     39         * Output our custom embed template part.
     40         *
     41         * @since 2.5.0
     42         */
     43        protected function content() {
     44                bp_get_asset_template_part( 'embeds/activity' );
     45        }
     46
     47        /**
     48         * Check if we're on our single activity page.
     49         *
     50         * @since 2.5.0
     51         *
     52         * @return bool
     53         */
     54        protected function is_page() {
     55                return bp_is_single_activity();
     56        }
     57
     58        /**
     59         * Validates the URL to determine if the activity item is valid.
     60         *
     61         * @since 2.5.0
     62         *
     63         * @param  string   $url The URL to check.
     64         * @return int|bool Activity ID on success; boolean false on failure.
     65         */
     66        protected function validate_url_to_item_id( $url ) {
     67                if ( bp_core_enable_root_profiles() ) {
     68                        $domain = bp_get_root_domain();
     69                } else {
     70                        $domain = bp_get_members_directory_permalink();
     71                }
     72
     73                // Check the URL to see if this is a single activity URL.
     74                if ( 0 !== strpos( $url, $domain ) ) {
     75                        return false;
     76                }
     77
     78                // Check for activity slug.
     79                if ( false === strpos( $url, '/' . bp_get_activity_slug() . '/' ) ) {
     80                        return false;
     81                }
     82
     83                // Do more checks.
     84                $url = trim( untrailingslashit( $url ) );
     85
     86                // Grab the activity ID.
     87                $activity_id = (int) substr(
     88                        $url,
     89                        strrpos( $url, '/' ) + 1
     90                );
     91
     92                if ( ! empty( $activity_id ) ) {
     93                        // Check if activity item still exists.
     94                        $activity = new BP_Activity_Activity( $activity_id );
     95
     96                        // Okay, we're good to go!
     97                        if ( ! empty( $activity->component ) && 0 === (int) $activity->is_spam ) {
     98                                return $activity_id;
     99                        }
     100                }
     101
     102                return false;
     103        }
     104
     105        /**
     106         * Sets the oEmbed response data for our activity item.
     107         *
     108         * @since 2.5.0
     109         *
     110         * @param  int $item_id The activity ID.
     111         * @return array
     112         */
     113        protected function set_oembed_response_data( $item_id ) {
     114                $activity = new BP_Activity_Activity( $item_id );
     115
     116                return array(
     117                        'user_id'    => $activity->user_id,
     118                        'content'    => $activity->content,
     119                        'title'      => __( 'Activity', 'buddypress' ),
     120                        'author_url' => bp_core_get_user_domain( $activity->user_id )
     121                );
     122        }
     123
     124        /**
     125         * Sets a custom <blockquote> for our oEmbed fallback HTML.
     126         *
     127         * @since 2.5.0
     128         *
     129         * @param  int $item_id The activity ID.
     130         * @return string
     131         */
     132        protected function set_fallback_html( $item_id ) {
     133                $activity    = new BP_Activity_Activity( $item_id );
     134                $mentionname = bp_activity_do_mentions() ? ' (@' . bp_activity_get_user_mentionname( $activity->user_id ) . ')' : '';
     135                $date        = date_i18n( get_option( 'date_format' ), strtotime( $activity->date_recorded ) );
     136
     137                // 'wp-embedded-content' CSS class is necessary due to how the embed JS works.
     138                $blockquote = sprintf( '<blockquote class="wp-embedded-content bp-activity-item">%1$s%2$s %3$s</blockquote>',
     139                        apply_filters( 'bp_get_activity_content_body', $activity->content ),
     140                        '- ' . bp_core_get_user_displayname( $activity->user_id ) . $mentionname,
     141                        '<a href="' . esc_url( bp_activity_get_permalink( $item_id ) ) . '">' . $date . '</a>'
     142                );
     143
     144                /**
     145                 * Filters the fallback HTML used when embedding a BP activity item.
     146                 *
     147                 * @since 2.5.0
     148                 *
     149                 * @param string               $blockquote Current fallback HTML
     150                 * @param BP_Activity_Activity $activity   Activity object
     151                 */
     152                return apply_filters( 'bp_activity_embed_fallback_html', $blockquote, $activity );
     153        }
     154
     155        /**
     156         * Sets a custom <iframe> title for our oEmbed item.
     157         *
     158         * @since 2.5.0
     159         *
     160         * @param  int $item_id The activity ID
     161         * @return string
     162         */
     163        protected function set_iframe_title( $item_id ) {
     164                return __( 'Embedded Activity Item', 'buddypress' );
     165        }
     166
     167        /**
     168         * Prints the markup for the activity embed comments button.
     169         *
     170         * @since 2.5.0
     171         */
     172        public function embed_comments_button() {
     173                if ( ! bp_is_single_activity() ) {
     174                        return;
     175                }
     176
     177                // Make sure our custom permalink shows up in the 'WordPress Embed' block.
     178                add_filter( 'the_permalink', array( $this, 'filter_embed_url' ) );
     179
     180                // Only show comment bubble if we have some activity comments.
     181                $count = bp_activity_get_comment_count();
     182                if ( empty( $count ) ) {
     183                        return;
     184                }
     185        ?>
     186
     187                <div class="wp-embed-comments">
     188                        <a href="<?php bp_activity_thread_permalink(); ?>">
     189                                <span class="dashicons dashicons-admin-comments"></span>
     190                                <?php
     191                                printf(
     192                                        _n(
     193                                                '%s <span class="screen-reader-text">Comment</span>',
     194                                                '%s <span class="screen-reader-text">Comments</span>',
     195                                                $count
     196                                        ),
     197                                        number_format_i18n( $count )
     198                                );
     199                                ?>
     200                        </a>
     201                </div>
     202
     203        <?php
     204        }
     205}
  • src/bp-core/bp-core-functions.php

    diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
    index f865d7c..da8540d 100644
    function bp_use_embed_in_private_messages() { 
    16661666        return apply_filters( 'bp_use_embed_in_private_messages', !defined( 'BP_EMBED_DISABLE_PRIVATE_MESSAGES' ) || !BP_EMBED_DISABLE_PRIVATE_MESSAGES );
    16671667}
    16681668
     1669/**
     1670 * Extracts media metadata from a given content.
     1671 *
     1672 * @since 2.5.0
     1673 *
     1674 * @param  string     $content The content to check.
     1675 * @param  string|int $type    The type to check. Can also use a bitmask. See the class constants in the
     1676 *                             BP_Media_Extractor class for more info.
     1677 * @return array|bool          If media exists, will return array of media metadata. Else, boolean false.
     1678 */
     1679function bp_core_extract_media_from_content( $content = '', $type = 'all' ) {
     1680        if ( is_string( $type ) ) {
     1681                $class = new ReflectionClass( 'BP_Media_Extractor' );
     1682                $bitmask = $class->getConstant( strtoupper( $type ) );
     1683        } else {
     1684                $bitmask = (int) $type;
     1685        }
     1686
     1687        // Type isn't valid, so bail.
     1688        if ( empty( $bitmask ) ) {
     1689                return false;
     1690        }
     1691
     1692        $x = new BP_Media_Extractor;
     1693        $media = $x->extract( $content, $bitmask );
     1694
     1695        unset( $media['has'] );
     1696        $retval = array_filter( $media );
     1697
     1698        return ! empty( $retval ) ? $retval : false;
     1699}
     1700
    16691701/** Admin *********************************************************************/
    16701702
    16711703/**
  • src/bp-core/bp-core-template-loader.php

    diff --git src/bp-core/bp-core-template-loader.php src/bp-core/bp-core-template-loader.php
    index 91c67ef..8f4b03c 100644
    function bp_get_template_part( $slug, $name = null ) { 
    6565}
    6666
    6767/**
     68 * Get an asset template part.
     69 *
     70 * Basically the same as {@link bp_get_template_part()}, but with 'assets/'
     71 * prepended to the slug.
     72 *
     73 * @since 2.5.0
     74 *
     75 * @see bp_get_template_part() for full documentation.
     76 */
     77function bp_get_asset_template_part( $slug, $name = null ) {
     78        return bp_get_template_part( "assets/{$slug}", $name );
     79}
     80
     81/**
    6882 * Retrieve the name of the highest priority template file that exists.
    6983 *
    7084 * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
  • src/bp-core/bp-core-theme-compatibility.php

    diff --git src/bp-core/bp-core-theme-compatibility.php src/bp-core/bp-core-theme-compatibility.php
    index da54dce..0de2895 100644
    function bp_register_theme_package( $theme = array(), $override = true ) { 
    650650}
    651651
    652652/**
     653 * Create a dummy WP_Post object.
     654 *
     655 * @since 2.5.0
     656 *
     657 * @param  array $args Array of optional arguments. Arguments parallel the properties
     658 *                    of {@link WP_Post}; see that class for more details.
     659 * @return WP_Post
     660 */
     661function bp_theme_compat_create_dummy_post( $args = array() ) {
     662        $args = wp_parse_args( $args, array(
     663                'ID'                    => -9999,
     664                'post_status'           => 'public',
     665                'post_author'           => 0,
     666                'post_parent'           => 0,
     667                'post_type'             => 'page',
     668                'post_date'             => 0,
     669                'post_date_gmt'         => 0,
     670                'post_modified'         => 0,
     671                'post_modified_gmt'     => 0,
     672                'post_content'          => '',
     673                'post_title'            => '',
     674                'post_excerpt'          => '',
     675                'post_content_filtered' => '',
     676                'post_mime_type'        => '',
     677                'post_password'         => '',
     678                'post_name'             => '',
     679                'guid'                  => '',
     680                'menu_order'            => 0,
     681                'pinged'                => '',
     682                'to_ping'               => '',
     683                'ping_status'           => '',
     684                'comment_status'        => 'closed',
     685                'comment_count'         => 0,
     686                'filter'                => 'raw',
     687
     688                'is_404'                => false,
     689                'is_page'               => false,
     690                'is_single'             => false,
     691                'is_archive'            => false,
     692                'is_tax'                => false,
     693        ) );
     694
     695        // Create the dummy post.
     696        $post = new WP_Post( (object) $args );
     697
     698        return $post;
     699}
     700
     701/**
    653702 * Populate various WordPress globals with dummy data to prevent errors.
    654703 *
    655704 * This dummy data is necessary because theme compatibility essentially fakes
    function bp_theme_compat_reset_post( $args = array() ) { 
    670719
    671720        // Switch defaults if post is set.
    672721        if ( isset( $wp_query->post ) ) {
    673                 $dummy = wp_parse_args( $args, array(
     722                $args = wp_parse_args( $args, array(
    674723                        'ID'                    => $wp_query->post->ID,
    675724                        'post_status'           => $wp_query->post->post_status,
    676725                        'post_author'           => $wp_query->post->post_author,
    function bp_theme_compat_reset_post( $args = array() ) { 
    695744                        'comment_status'        => $wp_query->post->comment_status,
    696745                        'comment_count'         => $wp_query->post->comment_count,
    697746                        'filter'                => $wp_query->post->filter,
    698 
    699                         'is_404'                => false,
    700                         'is_page'               => false,
    701                         'is_single'             => false,
    702                         'is_archive'            => false,
    703                         'is_tax'                => false,
    704                 ) );
    705         } else {
    706                 $dummy = wp_parse_args( $args, array(
    707                         'ID'                    => -9999,
    708                         'post_status'           => 'public',
    709                         'post_author'           => 0,
    710                         'post_parent'           => 0,
    711                         'post_type'             => 'page',
    712                         'post_date'             => 0,
    713                         'post_date_gmt'         => 0,
    714                         'post_modified'         => 0,
    715                         'post_modified_gmt'     => 0,
    716                         'post_content'          => '',
    717                         'post_title'            => '',
    718                         'post_excerpt'          => '',
    719                         'post_content_filtered' => '',
    720                         'post_mime_type'        => '',
    721                         'post_password'         => '',
    722                         'post_name'             => '',
    723                         'guid'                  => '',
    724                         'menu_order'            => 0,
    725                         'pinged'                => '',
    726                         'to_ping'               => '',
    727                         'ping_status'           => '',
    728                         'comment_status'        => 'closed',
    729                         'comment_count'         => 0,
    730                         'filter'                => 'raw',
    731 
    732                         'is_404'                => false,
    733                         'is_page'               => false,
    734                         'is_single'             => false,
    735                         'is_archive'            => false,
    736                         'is_tax'                => false,
    737747                ) );
    738748        }
    739749
    740750        // Bail if dummy post is empty.
    741         if ( empty( $dummy ) ) {
     751        if ( empty( $args ) ) {
    742752                return;
    743753        }
    744754
    745755        // Set the $post global.
    746         $post = new WP_Post( (object) $dummy );
     756        $post = bp_theme_compat_create_dummy_post( $args );
    747757
    748758        // Copy the new post global into the main $wp_query.
    749759        $wp_query->post       = $post;
    function bp_theme_compat_reset_post( $args = array() ) { 
    751761
    752762        // Prevent comments form from appearing.
    753763        $wp_query->post_count = 1;
    754         $wp_query->is_404     = $dummy['is_404'];
    755         $wp_query->is_page    = $dummy['is_page'];
    756         $wp_query->is_single  = $dummy['is_single'];
    757         $wp_query->is_archive = $dummy['is_archive'];
    758         $wp_query->is_tax     = $dummy['is_tax'];
    759 
    760         // Clean up the dummy post.
    761         unset( $dummy );
     764        $wp_query->is_404     = $post->is_404;
     765        $wp_query->is_page    = $post->is_page;
     766        $wp_query->is_single  = $post->is_single;
     767        $wp_query->is_archive = $post->is_archive;
     768        $wp_query->is_tax     = $post->is_tax;
    762769
    763770        /**
    764771         * Force the header back to 200 status if not a deliberate 404
  • new file src/bp-core/classes/class-bp-oembed-component.php

    diff --git src/bp-core/classes/class-bp-oembed-component.php src/bp-core/classes/class-bp-oembed-component.php
    new file mode 100644
    index 0000000..bab746f
    - +  
     1<?php
     2/**
     3 * Core component classes.
     4 *
     5 * @package BuddyPress
     6 * @subpackage Core
     7 */
     8
     9// Exit if accessed directly.
     10defined( 'ABSPATH' ) || exit;
     11
     12/**
     13 * API for responding and returning a custom oEmbed request.
     14 *
     15 * @since 2.5.0
     16 */
     17abstract class BP_oEmbed_Component {
     18
     19        /** START PROPERTIES ****************************************************/
     20
     21        /**
     22         * (required) The slug endpoint.
     23         *
     24         * Should be your component id.
     25         *
     26         * @var string
     27         */
     28        public $slug_endpoint = '';
     29
     30        /**
     31         * (optional) Embed template hierarchy.
     32         *
     33         * Define the template hierarchy for your oEmbed rendering.
     34         *
     35         * @var array
     36         */
     37        protected $template_hierarchy = array();
     38
     39        /** END PROPERTIES ******************************************************/
     40
     41        /**
     42         * Constructor.
     43         */
     44        final public function __construct() {
     45                $this->setup_properties();
     46
     47                // Some rudimentary logic checking.
     48                if ( empty( $this->slug_endpoint ) ) {
     49                        $class = get_class( $this );
     50                        throw new \LogicException( $class . ' class must define $slug_endpoint property' );
     51                }
     52
     53                $this->setup_hooks();
     54                $this->custom_hooks();
     55        }
     56
     57        /** REQUIRED METHODS ****************************************************/
     58
     59        /**
     60         * Add content for your oEmbed response here.
     61         *
     62         * @since 2.5.0
     63         */
     64        abstract protected function content();
     65
     66        /**
     67         * Add a check for when you are on the page you want to oEmbed.
     68         *
     69         * You'll want to return a boolean here. eg. bp_is_single_activity().
     70         *
     71         * @since 2.5.0
     72         *
     73         * @return bool
     74         */
     75        abstract protected function is_page();
     76
     77        /**
     78         * Validate the URL to see if it matches your item ID.
     79         *
     80         * @since 2.5.0
     81         *
     82         * @return int Your item ID
     83         */
     84        abstract protected function validate_url_to_item_id( $url );
     85
     86        /**
     87         * Set the oEmbed response data.
     88         *
     89         * @since 2.5.0
     90         *
     91         * @param  int   $item_id Your item ID to do checks against.
     92         * @return array Should contain 'user_id', 'content', 'title', 'author_url' as array keys.
     93         *               'author_url' is optional; the rest are required.
     94         */
     95        abstract protected function set_oembed_response_data( $item_id );
     96
     97        /**
     98         * Sets the fallback HTML for the oEmbed response.
     99         *
     100         * In a WordPress oEmbed item, the fallback HTML is a <blockquote>.  This is
     101         * usually hidden after the <iframe> is loaded.
     102         *
     103         * @since 2.5.0
     104         *
     105         * @param  int    $item_id Your item ID to do checks against.
     106         * @return string Fallback HTML you want to output.
     107         */
     108        abstract protected function set_fallback_html( $item_id );
     109
     110        /** OPTIONAL METHODS ****************************************************/
     111
     112        /**
     113         * Set permalink for oEmbed link discovery.
     114         *
     115         * This method will be called on the page we want to oEmbed.  Override in your
     116         * extended class method if needed.
     117         *
     118         * @since 2.5.0
     119         */
     120        protected function set_permalink() {
     121                // Remove querystring from bp_get_requested_url()
     122                return substr( bp_get_requested_url(), 0, strpos( bp_get_requested_url(), '?' ) );
     123        }
     124
     125        /**
     126         * Set the iframe title.
     127         *
     128         * If not set, this will fallback to WP's 'Embedded WordPress Post'.
     129         *
     130         * @param int $item_id The item ID to do checks for.
     131         * @return string
     132         */
     133        protected function set_iframe_title( $item_id ) {}
     134
     135        /**
     136         * Do what you need to do here to initialize any custom hooks.
     137         *
     138         * @since 2.5.0
     139         */
     140        protected function custom_hooks() {}
     141
     142        /** SET UP **************************************************************/
     143
     144        /**
     145         * Set up properties.
     146         *
     147         * @since 2.5.0
     148         */
     149        protected function setup_properties() {
     150                $this->slug_endpoint = sanitize_title( $this->slug_endpoint );
     151        }
     152
     153        /**
     154         * Hooks! We do the dirty work here, so you don't have to! :)
     155         *
     156         * @since 2.5.0
     157         */
     158        protected function setup_hooks() {
     159                add_action( 'rest_api_init',  array( $this, 'register_route' ) );
     160                add_action( 'embed_content',  array( $this, 'inject_content' ) );
     161
     162                add_filter( 'embed_template', array( $this, 'filter_template' ) );
     163                add_filter( 'post_embed_url', array( $this, 'filter_embed_url' ) );
     164                add_filter( 'embed_html',     array( $this, 'filter_embed_html' ) );
     165                add_filter( 'oembed_discovery_links', array( $this, 'add_oembed_discovery_links' ) );
     166        }
     167
     168        /** HOOKS ***************************************************************/
     169
     170        /**
     171         * Register the oEmbed REST API route.
     172         *
     173         * @since 2.5.0
     174         */
     175        public function register_route() {
     176                /** This filter is documented in wp-includes/class-wp-oembed-controller.php */
     177                $maxwidth = apply_filters( 'oembed_default_width', 600 );
     178
     179                register_rest_route( 'oembed/1.0', "/embed/{$this->slug_endpoint}", array(
     180                        array(
     181                                'methods'  => WP_REST_Server::READABLE,
     182                                'callback' => array( $this, 'get_item' ),
     183                                'args'     => array(
     184                                        'url'      => array(
     185                                                'required'          => true,
     186                                                'sanitize_callback' => 'esc_url_raw',
     187                                        ),
     188                                        'format'   => array(
     189                                                'default'           => 'json',
     190                                                'sanitize_callback' => 'wp_oembed_ensure_format',
     191                                        ),
     192                                        'maxwidth' => array(
     193                                                'default'           => $maxwidth,
     194                                                'sanitize_callback' => 'absint',
     195                                        ),
     196                                ),
     197                        ),
     198                ) );
     199        }
     200
     201        /**
     202         * Filters the embed template.
     203         *
     204         * Override if needed.
     205         *
     206         * @since 2.5.0
     207         *
     208         * @param  string $template File path to current embed template.
     209         * @return string
     210         */
     211        public function filter_template( $template ) {
     212                if ( ! $this->is_page() || is_404() ) {
     213                        return $template;
     214                }
     215
     216                // Embed template hierarchy!
     217                return bp_locate_template( array(
     218                        'assets/embeds/template.php'
     219                ) );
     220        }
     221
     222        /**
     223         * Adds oEmbed discovery links on single activity pages.
     224         *
     225         * @since 2.5.0
     226         *
     227         * @param  string $retval Current discovery links.
     228         * @return string
     229         */
     230        public function add_oembed_discovery_links( $retval ) {
     231                if ( ! $this->is_page() ) {
     232                        return $retval;
     233                }
     234
     235                $permalink = $this->set_permalink();
     236                if ( empty( $permalink ) ) {
     237                        return $retval;
     238                }
     239
     240                add_filter( 'rest_url' , array( $this, 'filter_rest_url' ) );
     241
     242                $retval = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink ) ) . '" />' . "\n";
     243
     244                if ( class_exists( 'SimpleXMLElement' ) ) {
     245                        $retval .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink, 'xml' ) ) . '" />' . "\n";
     246                }
     247
     248                remove_filter( 'rest_url' , array( $this, 'filter_rest_url' ) );
     249
     250                return $retval;
     251        }
     252
     253        /**
     254         * Callback for the API endpoint.
     255         *
     256         * Returns the JSON object for the item.
     257         *
     258         * @since 2.5.0
     259         *
     260         * @param  WP_REST_Request $request Full data about the request.
     261         * @return WP_Error|array oEmbed response data or WP_Error on failure.
     262         */
     263        public function get_item( $request ) {
     264                $url = $request['url'];
     265
     266                $data = false;
     267
     268                $item_id = (int) $this->validate_url_to_item_id( $url );
     269
     270                if ( ! empty( $item_id ) ) {
     271                        $item = $this->set_oembed_response_data( $item_id );
     272
     273                        // Create dummy post to piggyback off of get_oembed_response_data()
     274                        $post = bp_theme_compat_create_dummy_post( array(
     275                                'post_author'  => $item['user_id'],
     276                                'post_title'   => $item['title'],
     277                                'post_content' => $item['content'],
     278
     279                                // This passes the get_oembed_response_data() check.
     280                                'post_status'  => 'publish'
     281                        ) );
     282
     283                        // Add markers to tell that we're embedding a single activity.
     284                        // This is needed for various oEmbed response data filtering.
     285                        if ( empty( buddypress()->{$this->slug_endpoint} ) ) {
     286                                buddypress()->$this->slug_endpoint = new stdClass;
     287                        }
     288                        buddypress()->{$this->slug_endpoint}->embedurl_in_progress = $url;
     289                        buddypress()->{$this->slug_endpoint}->embedid_in_progress  = $item_id;
     290
     291                        // Use WP's oEmbed response data function.
     292                        $data = get_oembed_response_data( $post, $request['maxwidth'] );
     293
     294                        // Set custom 'author_url' if we have one.
     295                        if ( ! empty( $item['author_url'] ) ) {
     296                                $data['author_url'] = $item['author_url'];
     297                        }
     298                }
     299
     300                if ( ! $data ) {
     301                        return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) );
     302                }
     303
     304                return $data;
     305        }
     306
     307        /**
     308         * Pass our BuddyPress activity permalink for embedding.
     309         *
     310         * @since 2.5.0
     311         *
     312         * @see bp_activity_embed_rest_route_callback()
     313         *
     314         * @param  string $retval Current embed URL
     315         * @return string
     316         */
     317        public function filter_embed_url( $retval ) {
     318                if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) {
     319                        return $retval;
     320                }
     321
     322                $url = $this->is_page() ? $this->set_permalink() : buddypress()->{$this->slug_endpoint}->embedurl_in_progress;
     323                $url = trailingslashit( $url );
     324
     325                // This is for the 'WordPress Embed' block
     326                // @see bp_activity_embed_comments_button()
     327                if ( 'the_permalink' !== current_filter() ) {
     328                        $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) );
     329                }
     330
     331                return $url;
     332        }
     333
     334        /**
     335         * Filters the embed HTML for the default oEmbed fallback HTML.
     336         *
     337         * @since 2.5.0
     338         *
     339         * @param  string $retval Current embed HTML
     340         * @return string
     341         */
     342        public function filter_embed_html( $retval ) {
     343                if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) {
     344                        return $retval;
     345                }
     346
     347                $url = $this->set_permalink();
     348
     349                $item_id = $this->is_page() ? $this->validate_url_to_item_id( $url ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress;
     350
     351                // Change 'Embedded WordPress Post' to custom title.
     352                $custom_title = $this->set_iframe_title( $item_id );
     353                if ( ! empty( $custom_title ) ) {
     354                        $retval = str_replace( __( 'Embedded WordPress Post' ), esc_attr( $custom_title ), $retval );
     355                }
     356
     357                // Remove default <blockquote>
     358                $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 );
     359
     360                // Set up new fallback HTML
     361                // @todo Maybe use KSES?
     362                $fallback_html = $this->set_fallback_html( $item_id );
     363
     364                // Add our custom <blockquote>
     365                return $fallback_html . $retval;
     366        }
     367
     368        /**
     369         * Append our custom slug endpoint to oEmbed endpoint URL.
     370         *
     371         * Meant to be used as a filter on 'rest_url' before any call to
     372         * {@link get_oembed_endpoint_url()} is used.
     373         *
     374         * @since 2.5.0
     375         *
     376         * @see add_oembed_discovery_links()
     377         *
     378         * @param  string $retval Current oEmbed endpoint URL
     379         * @return string
     380         */
     381        function filter_rest_url( $retval = '' ) {
     382                return $retval . "/{$this->slug_endpoint}";
     383        }
     384
     385        /**
     386         * Inject activity content into the embed template.
     387         *
     388         * @since 2.5.0
     389         */
     390        public function inject_content() {
     391                if ( ! $this->is_page() ) {
     392                        return;
     393                }
     394
     395                $this->content();
     396        }
     397}
     398 No newline at end of file
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/activity.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/embeds/activity.php src/bp-templates/bp-legacy/buddypress/assets/embeds/activity.php
    new file mode 100644
    index 0000000..34264ce
    - +  
     1
     2                <?php if ( bp_has_activities( 'display_comments=threaded&show_hidden=true&include=' . bp_current_action() ) ) : ?>
     3
     4                        <?php while ( bp_activities() ) : bp_the_activity(); ?>
     5                                <div class="wp-embed-excerpt"><p><?php echo bp_activity_create_excerpt(); ?></p></div>
     6
     7                                <p class="wp-embed-timestamp"><a href="<?php bp_activity_thread_permalink(); ?>"><?php echo date_i18n( get_option( 'time_format' ) . ' - ' . get_option( 'date_format' ), strtotime( bp_get_activity_date_recorded() ) ); ?></a></p>
     8
     9                                <?php
     10                                $embeds = bp_core_extract_media_from_content( $GLOBALS['activities_template']->activity->content, 'embeds' );
     11
     12                                // Only embed the first embedded item
     13                                if ( $embeds ) {
     14                                        echo apply_filters( 'bp_get_activity_content_body', $embeds['embeds'][0]['url'] );
     15
     16                                // Add inline JS for responsive IFRAMES if an embed is detected.
     17                                ?>
     18
     19<script>
     20/*! fluidvids.js v1.2.0 | (c) 2013 @toddmotto | https://github.com/toddmotto/fluidvids */
     21window.fluidvids=function(a,b){"use strict";var c=function(a){this.elem=a};c.prototype={init:function(){var a=100*(this.elem.height/this.elem.width);this.elem.style.position="absolute",this.elem.style.top="0",this.elem.style.left="0",this.elem.width="100%",this.elem.height="100%";var c=b.createElement("div");c.className="fluidvids",c.style.width="100%",c.style.position="relative",c.style.paddingTop=a+"%";var d=this.elem.parentNode;d.insertBefore(c,this.elem),c.appendChild(this.elem)}};for(var d=b.getElementsByTagName("iframe"),e=0;e<d.length;e++){d[e].src&&new c(d[e]).init()}}(window,document);
     22</script>
     23
     24                                <?php
     25                                }
     26                                ?>
     27
     28                        <?php endwhile; ?>
     29
     30                <?php endif; ?>
     31
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/css.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/embeds/css.php src/bp-templates/bp-legacy/buddypress/assets/embeds/css.php
    new file mode 100644
    index 0000000..d946ef6
    - +  
     1<style type="text/css">
     2#wp-embed-header:after {
     3        clear: both;
     4        content: "";
     5        display: table;
     6        margin-bottom: 1em;
     7}
     8
     9.wp-embed-avatar {
     10        float: left;
     11        margin: 0 .75em 0 0;
     12}
     13
     14p.wp-embed-heading {
     15        font-size: 16px;
     16        margin-bottom: 0;
     17}
     18
     19.wp-embed-excerpt, p.wp-embed-timestamp {
     20        margin-bottom: .5em;
     21}
     22
     23.wp-embed-footer {
     24        margin-top: 20px;
     25}
     26</style>
     27 No newline at end of file
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/footer.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/embeds/footer.php src/bp-templates/bp-legacy/buddypress/assets/embeds/footer.php
    new file mode 100644
    index 0000000..22de696
    - +  
     1                        <div class="wp-embed-footer">
     2                                <div class="wp-embed-site-title">
     3                                        <?php
     4                                        $site_title = sprintf(
     5                                                '<a href="%s"><img src="%s" srcset="%s 2x" width="32" height="32" alt="" class="wp-embed-site-icon"/><span>%s</span></a>',
     6                                                esc_url( home_url() ),
     7                                                esc_url( get_site_icon_url( 32, admin_url( 'images/w-logo-blue.png' ) ) ),
     8                                                esc_url( get_site_icon_url( 64, admin_url( 'images/w-logo-blue.png' ) ) ),
     9                                                esc_html( get_bloginfo( 'name' ) )
     10                                        );
     11
     12                                        /**
     13                                         * Filter the site title HTML in the embed footer.
     14                                         *
     15                                         * @since 4.4.0
     16                                         *
     17                                         * @param string $site_title The site title HTML.
     18                                         */
     19                                        echo apply_filters( 'embed_site_title_html', $site_title );
     20                                        ?>
     21                                </div>
     22
     23                                <div class="wp-embed-meta">
     24                                        <?php
     25                                        /**
     26                                         * Print additional meta content in the embed template.
     27                                         *
     28                                         * @since 4.4.0
     29                                         */
     30                                        do_action( 'embed_content_meta');
     31                                        ?>
     32                                </div>
     33                        </div>
     34 No newline at end of file
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/header.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/embeds/header.php src/bp-templates/bp-legacy/buddypress/assets/embeds/header.php
    new file mode 100644
    index 0000000..7a4bc8a
    - +  
     1
     2                <div id="wp-embed-header">
     3                        <div class="wp-embed-avatar">
     4                                <a href="<?php bp_displayed_user_link(); ?>">
     5                                        <?php bp_displayed_user_avatar( 'type=thumb&width=36&height=36' ); ?>
     6                                </a>
     7                        </div>
     8
     9                        <p class="wp-embed-heading">
     10                                <a href="<?php bp_displayed_user_link(); ?>">
     11                                        <?php bp_displayed_user_fullname(); ?>
     12                                </a>
     13                        </p>
     14
     15                        <?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
     16                                <p class="wp-embed-mentionname">@<?php bp_displayed_user_mentionname(); ?></p>
     17                        <?php endif; ?>
     18                </div>
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/template.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/embeds/template.php src/bp-templates/bp-legacy/buddypress/assets/embeds/template.php
    new file mode 100644
    index 0000000..599c283
    - +  
     1<?php
     2/**
     3 * Generic embed template used by BuddyPress.
     4 *
     5 * When a BuddyPress item is embedded in an iframe, this file is used to
     6 * create the output.
     7 *
     8 * This is a modified version of the bundled WordPress embed template
     9 * included in WordPress 4.4+.
     10 *
     11 * @since 2.5.0
     12 *
     13 * @package BuddyPress
     14 * @subpackage Embeds
     15 */
     16
     17if ( ! headers_sent() ) {
     18        header( 'X-WP-embed: true' );
     19}
     20
     21?>
     22<!DOCTYPE html>
     23<html <?php language_attributes(); ?> class="no-js">
     24<head>
     25        <title><?php echo wp_get_document_title(); ?></title>
     26        <meta http-equiv="X-UA-Compatible" content="IE=edge">
     27        <base target="_top" />
     28        <?php
     29        /** This action is documented in wp-includes/embed-template.php */
     30        do_action( 'embed_head' );
     31
     32        // This is used by r-a-y for testing purposes at the moment.
     33        bp_get_asset_template_part( 'embeds/css' );
     34        ?>
     35</head>
     36<body <?php body_class(); ?>>
     37<div <?php post_class( 'wp-embed' ); ?>>
     38<?php
     39bp_get_asset_template_part( 'embeds/header', bp_current_component() );
     40
     41/** This action is documented in wp-includes/embed-template.php */
     42do_action( 'embed_content' );
     43
     44bp_get_asset_template_part( 'embeds/footer', bp_current_component() );
     45?>
     46
     47</div>
     48
     49<?php
     50/** This action is documented in wp-includes/embed-template.php */
     51do_action( 'embed_footer' );
     52?>
     53</body>
     54</html>
     55 No newline at end of file