Skip to:
Content

BuddyPress.org

Ticket #6772: 6772.07.patch

File 6772.07.patch, 49.1 KB (added by r-a-y, 8 years ago)
  • src/bp-activity/bp-activity-classes.php

     
    1313require dirname( __FILE__ ) . '/classes/class-bp-activity-activity.php';
    1414require dirname( __FILE__ ) . '/classes/class-bp-activity-feed.php';
    1515require dirname( __FILE__ ) . '/classes/class-bp-activity-query.php';
     16
     17// Embeds - only applicable for WP 4.5+
     18if ( bp_get_major_wp_version() >= 4.5 && bp_is_active( 'activity', 'embeds' ) ) {
     19        require dirname( __FILE__ ) . '/classes/class-bp-activity-oembed-component.php';
     20}
     21 No newline at end of file
  • new file src/bp-activity/bp-activity-embeds.php

    new file mode 100644
    - +  
     1<?php
     2/**
     3 * Functions related to embedding single activity items externally.
     4 *
     5 * Relies on WordPress 4.5.
     6 *
     7 * @since 2.6.0
     8 *
     9 * @package BuddyPress
     10 * @subpackage ActivityEmbeds
     11 */
     12
     13// Exit if accessed directly.
     14defined( 'ABSPATH' ) || exit;
     15
     16/**
     17 * Loads our activity oEmbed component.
     18 *
     19 * @since 2.6.0
     20 */
     21function bp_activity_setup_oembed() {
     22        if ( bp_get_major_wp_version() >= 4.5 && bp_is_active( 'activity', 'embeds' ) ) {
     23                buddypress()->activity->oembed = new BP_Activity_oEmbed_Component;
     24        }
     25
     26        add_filter( 'bp_activity_get_embed_excerpt', 'wptexturize' );
     27        add_filter( 'bp_activity_get_embed_excerpt', 'convert_chars' );
     28        add_filter( 'bp_activity_get_embed_excerpt', 'make_clickable', 9 );
     29        add_filter( 'bp_activity_get_embed_excerpt', 'bp_activity_at_name_filter' );
     30        add_filter( 'bp_activity_get_embed_excerpt', 'convert_smilies', 20 );
     31        add_filter( 'bp_activity_get_embed_excerpt', 'wpautop', 30 );
     32}
     33add_action( 'bp_loaded', 'bp_activity_setup_oembed' );
     34
     35/**
     36 * Add inline styles for BP activity embeds.
     37 *
     38 * This is subject to change or be removed entirely for a different system.
     39 * See PHPDoc for BP_Legacy::locate_asset_in_stack().
     40 *
     41 * @since  2.6.0
     42 * @access private
     43 */
     44function _bp_activity_embed_add_inline_styles() {
     45        $inline_css = <<<EOD
     46
     47#wp-embed-header:after {
     48        clear: both;
     49        content: "";
     50        display: table;
     51        margin-bottom: 1em;
     52}
     53
     54.wp-embed-avatar {
     55        float: left;
     56        margin: 0 .75em 0 0;
     57}
     58
     59p.wp-embed-heading {
     60        font-size: 16px;
     61        margin-bottom: 0;
     62}
     63
     64.wp-embed-excerpt, p.wp-embed-timestamp {
     65        margin-bottom: .5em;
     66}
     67
     68.wp-embed-excerpt a {
     69        color: #21759b;
     70        display: inline-block;
     71        overflow: hidden;
     72        text-overflow: ellipsis;
     73        vertical-align: top;
     74        white-space: nowrap;
     75        max-width: 250px;
     76}
     77
     78.bp-activity-embed-display-media {
     79        height: auto;
     80        max-width: 550px;
     81}
     82
     83.bp-activity-embed-display-media img {
     84        height: auto;
     85        max-width: 100%;
     86}
     87
     88.activity-read-more {
     89        margin-left: .5em;
     90}
     91
     92.activity-read-more a {
     93        color: #b4b9be;
     94}
     95
     96.wp-embed-footer {
     97        margin-top: 20px;
     98}
     99
     100EOD;
     101
     102        // Piggyback off of 'open-sans' handle so we can use our inline CSS.
     103        wp_add_inline_style( 'open-sans', $inline_css );
     104}
     105add_action( 'bp_enqueue_embed_scripts', '_bp_activity_embed_add_inline_styles' );
     106
     107/**
     108 * Outputs excerpt for an activity embed item.
     109 *
     110 * @since 2.6.0
     111 */
     112function bp_activity_embed_excerpt( $content = '' ) {
     113        echo bp_activity_get_embed_excerpt( $content = '' );
     114}
     115
     116        /**
     117         * Generates excerpt for an activity embed item.
     118         *
     119         * @since 2.6.0
     120         *
     121         * @param  string $content The content to generate an excerpt for.
     122         * @return string
     123         */
     124        function bp_activity_get_embed_excerpt( $content = '' ) {
     125                if ( empty( $content ) && ! empty( $GLOBALS['activities_template']->in_the_loop ) ) {
     126                        $content = $GLOBALS['activities_template']->activity->content;
     127
     128                        // No content, so use action value.
     129                        if ( empty( $content ) ) {
     130                                $action = bp_activity_get_action( bp_get_activity_object_name(), bp_get_activity_type() );
     131                                $content = false !== $action ? $action['value'] : '';
     132                        }
     133                }
     134
     135                /**
     136                 * bp_activity_truncate_entry() includes the 'Read More' link, which is why
     137                 * we're using this instead of bp_create_excerpt().
     138                 */
     139                $content = html_entity_decode( $content );
     140                $content = bp_activity_truncate_entry( $content, array(
     141                        'html' => false,
     142                        'filter_shortcodes' => true,
     143                        'strip_tags'        => true,
     144                        'force_truncate'    => true
     145                ) );
     146
     147                /**
     148                 * Filter the activity embed excerpt.
     149                 *
     150                 * @since 2.6.0
     151                 *
     152                 * @var string $content Embed Excerpt.
     153                 * @var string $unmodified_content Unmodified activity content.
     154                 */
     155                return apply_filters( 'bp_activity_get_embed_excerpt', $content, $GLOBALS['activities_template']->activity->content );
     156        }
     157
     158/**
     159 * Outputs the first embedded item in the activity oEmbed template.
     160 *
     161 * @since 2.6.0
     162 */
     163function bp_activity_embed_response_display_media() {
     164        // Bail if oEmbed request explicitly hides media.
     165        if ( isset( $_REQUEST['hide_media'] ) && true == wp_validate_boolean( $_REQUEST['hide_media'] ) ) {
     166                return;
     167        }
     168
     169        // Find all embeds for the activity item.
     170        $embeds = bp_core_extract_media_from_content( $GLOBALS['activities_template']->activity->content, 'embeds' );
     171
     172        /**
     173         * Should we display media in the oEmbed template?
     174         *
     175         * @since 2.6.0
     176         *
     177         * @param bool $retval Defaults to true.
     178         */
     179        $allow_embeds = apply_filters( 'bp_activity_embed_display_media', true );
     180
     181        // Only embed the first embedded item.
     182        if ( $embeds && $allow_embeds ) {
     183                // Call BP_Embed if it hasn't already loaded.
     184                bp_embed_init();
     185
     186                // Autoembed first URL.
     187                $content = buddypress()->embed->autoembed( $embeds['embeds'][0]['url'] );
     188
     189                // Wrap content around a custom DIV.
     190                echo '<div class="bp-activity-embed-display-media">' . $content . '</div>';
     191
     192                // Add fluidvids.js for responsive IFRAMEs / OBJECTs.
     193                if ( false !== strpos( $content, '<iframe' ) || false !== strpos( $content, '<object' ) ) {
     194        ?>
     195
     196<script>
     197/*! fluidvids.js v2.4.1 | (c) 2014 @toddmotto | License: MIT | https://github.com/toddmotto/fluidvids */
     198!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t:e.fluidvids=t()}(this,function(){"use strict";function e(e){return new RegExp("^(https?:)?//(?:"+d.players.join("|")+").*$","i").test(e)}function t(e,t){return parseInt(e,10)/parseInt(t,10)*100+"%"}function i(i){if((e(i.src)||e(i.data))&&!i.getAttribute("data-fluidvids")){var n=document.createElement("div");i.parentNode.insertBefore(n,i),i.className+=(i.className?" ":"")+"fluidvids-item",i.setAttribute("data-fluidvids","loaded"),n.className+="fluidvids",n.style.paddingTop=t(i.height,i.width),n.appendChild(i)}}function n(){var e=document.createElement("div");e.innerHTML="<p>x</p><style>"+o+"</style>",r.appendChild(e.childNodes[1])}var d={selector:["iframe","object"],players:["www.youtube.com","player.vimeo.com"]},o=[".fluidvids {","width: 100%; max-width: 100%; position: relative;","}",".fluidvids-item {","position: absolute; top: 0px; left: 0px; width: 100%; height: 100%;","}"].join(""),r=document.head||document.getElementsByTagName("head")[0];return d.render=function(){for(var e=document.querySelectorAll(d.selector.join()),t=e.length;t--;)i(e[t])},d.init=function(e){for(var t in e)d[t]=e[t];d.render(),n()},d});
     199
     200// init
     201fluidvids.init({
     202        selector: ['iframe', 'object'],
     203        players: ['.'] // remove default youtube / vimeo restriction.
     204});
     205</script>
     206
     207        <?php
     208                }
     209        }
     210}
     211add_action( 'bp_activity_embed_after_content', 'bp_activity_embed_response_display_media' );
  • src/bp-activity/bp-activity-filters.php

     
    395395 * This method can only be used inside the Activity loop.
    396396 *
    397397 * @since 1.5.0
    398  *
    399  * @uses bp_is_single_activity()
    400  * @uses apply_filters() To call the 'bp_activity_excerpt_append_text' hook.
    401  * @uses apply_filters() To call the 'bp_activity_excerpt_length' hook.
    402  * @uses bp_create_excerpt()
    403  * @uses bp_get_activity_id()
    404  * @uses bp_get_activity_thread_permalink()
    405  * @uses apply_filters() To call the 'bp_activity_truncate_entry' hook.
     398 * @since 2.6.0 Added $args parameter.
    406399 *
    407400 * @param string $text The original activity entry text.
    408401 * @return string $excerpt The truncated text.
    409402 */
    410 function bp_activity_truncate_entry( $text ) {
     403function bp_activity_truncate_entry( $text, $args = array() ) {
    411404        global $activities_template;
    412405
    413406        /**
     
    423416        );
    424417
    425418        // The full text of the activity update should always show on the single activity screen.
    426         if ( ! $maybe_truncate_text || bp_is_single_activity() ) {
     419        if ( empty( $args['force_truncate'] ) && ( ! $maybe_truncate_text || bp_is_single_activity() ) ) {
    427420                return $text;
    428421        }
    429422
     
    445438         */
    446439        $excerpt_length = apply_filters( 'bp_activity_excerpt_length', 358 );
    447440
     441        $args = wp_parse_args( $args, array( 'ending' => __( '&hellip;', 'buddypress' ) ) );
     442
    448443        // Run the text through the excerpt function. If it's too short, the original text will be returned.
    449         $excerpt        = bp_create_excerpt( $text, $excerpt_length, array( 'ending' => __( '&hellip;', 'buddypress' ) ) );
     444        $excerpt        = bp_create_excerpt( $text, $excerpt_length, $args );
    450445
    451446        /*
    452447         * If the text returned by bp_create_excerpt() is different from the original text (ie it's
    453448         * been truncated), add the "Read More" link. Note that bp_create_excerpt() is stripping
    454449         * shortcodes, so we have strip them from the $text before the comparison.
    455450         */
    456         if ( $excerpt != strip_shortcodes( $text ) ) {
     451        if ( strlen( $excerpt ) > strlen( strip_shortcodes( $text ) ) ) {
    457452                $id = !empty( $activities_template->activity->current_comment->id ) ? 'acomment-read-more-' . $activities_template->activity->current_comment->id : 'activity-read-more-' . bp_get_activity_id();
    458453
    459454                $excerpt = sprintf( '%1$s<span class="activity-read-more" id="%2$s"><a href="%3$s" rel="nofollow">%4$s</a></span>', $excerpt, $id, bp_get_activity_thread_permalink(), $append_text );
  • src/bp-activity/bp-activity-functions.php

     
    33373337        }
    33383338
    33393339        // Generate a text excerpt for this activity item (and remove any oEmbeds URLs).
    3340         $summary = strip_shortcodes( html_entity_decode( strip_tags( $content ) ) );
    3341         $summary = bp_create_excerpt( preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $summary ) );
     3340        $summary = bp_create_excerpt( html_entity_decode( $content ), 225, array(
     3341                'html' => false,
     3342                'filter_shortcodes' => true,
     3343                'strip_tags'        => true,
     3344                'remove_links'      => true
     3345        ) );
    33423346
    33433347        if ( $use_media_type === 'embeds' ) {
    33443348                $summary .= PHP_EOL . PHP_EOL . $extracted_media['url'];
  • src/bp-activity/classes/class-bp-activity-component.php

     
    3232                        array(
    3333                                'adminbar_myaccount_order' => 10,
    3434                                'search_query_arg' => 'activity_search',
     35                                'features' => array( 'embeds' )
    3536                        )
    3637                );
    3738        }
     
    7273                        $includes[] = 'akismet';
    7374                }
    7475
     76                // Embeds - only applicable for WP 4.5+
     77                if ( bp_get_major_wp_version() >= 4.5 && bp_is_active( $this->id, 'embeds' ) ) {
     78                        $includes[] = 'embeds';
     79                }
     80
    7581                if ( is_admin() ) {
    7682                        $includes[] = 'admin';
    7783                }
  • new file src/bp-activity/classes/class-bp-activity-oembed-component.php

    new file mode 100644
    - +  
     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.6.0
     18 */
     19class BP_Activity_oEmbed_Component extends BP_oEmbed_Component {
     20        /**
     21         * Custom oEmbed slug endpoint.
     22         *
     23         * @since 2.6.0
     24         *
     25         * @var string
     26         */
     27        public $slug_endpoint = 'activity';
     28
     29        /**
     30         * Custom hooks.
     31         *
     32         * @since 2.6.0
     33         */
     34        protected function custom_hooks() {
     35                add_action( 'embed_content_meta',     array( $this, 'embed_comments_button' ), 5 );
     36
     37                add_filter( 'bp_activity_embed_html', array( $this, 'modify_iframe' ) );
     38        }
     39
     40        /**
     41         * Add custom endpoint arguments.
     42         *
     43         * Currently, includes 'hide_media'.
     44         *
     45         * @since 2.6.0
     46         *
     47         * @return array
     48         */
     49        protected function set_route_args() {
     50                return array(
     51                        'hide_media' => array(
     52                                'default' => false,
     53                                'sanitize_callback' => 'wp_validate_boolean'
     54                        )
     55                );
     56        }
     57
     58        /**
     59         * Output our custom embed template part.
     60         *
     61         * @since 2.6.0
     62         */
     63        protected function content() {
     64                bp_get_asset_template_part( 'embeds/activity' );
     65        }
     66
     67        /**
     68         * Check if we're on our single activity page.
     69         *
     70         * @since 2.6.0
     71         *
     72         * @return bool
     73         */
     74        protected function is_page() {
     75                return bp_is_single_activity();
     76        }
     77
     78        /**
     79         * Validates the URL to determine if the activity item is valid.
     80         *
     81         * @since 2.6.0
     82         *
     83         * @param  string   $url The URL to check.
     84         * @return int|bool Activity ID on success; boolean false on failure.
     85         */
     86        protected function validate_url_to_item_id( $url ) {
     87                if ( bp_core_enable_root_profiles() ) {
     88                        $domain = bp_get_root_domain();
     89                } else {
     90                        $domain = bp_get_members_directory_permalink();
     91                }
     92
     93                // Check the URL to see if this is a single activity URL.
     94                if ( 0 !== strpos( $url, $domain ) ) {
     95                        return false;
     96                }
     97
     98                // Check for activity slug.
     99                if ( false === strpos( $url, '/' . bp_get_activity_slug() . '/' ) ) {
     100                        return false;
     101                }
     102
     103                // Do more checks.
     104                $url = trim( untrailingslashit( $url ) );
     105
     106                // Grab the activity ID.
     107                $activity_id = (int) substr(
     108                        $url,
     109                        strrpos( $url, '/' ) + 1
     110                );
     111
     112                if ( ! empty( $activity_id ) ) {
     113                        // Check if activity item still exists.
     114                        $activity = new BP_Activity_Activity( $activity_id );
     115
     116                        // Okay, we're good to go!
     117                        if ( ! empty( $activity->component ) && 0 === (int) $activity->is_spam ) {
     118                                return $activity_id;
     119                        }
     120                }
     121
     122                return false;
     123        }
     124
     125        /**
     126         * Sets the oEmbed response data for our activity item.
     127         *
     128         * @since 2.6.0
     129         *
     130         * @param  int $item_id The activity ID.
     131         * @return array
     132         */
     133        protected function set_oembed_response_data( $item_id ) {
     134                $activity = new BP_Activity_Activity( $item_id );
     135
     136                return array(
     137                        'user_id'    => $activity->user_id,
     138                        'content'    => $activity->content,
     139                        'title'      => __( 'Activity', 'buddypress' ),
     140                        'author_url' => bp_core_get_user_domain( $activity->user_id )
     141                );
     142        }
     143
     144        /**
     145         * Sets a custom <blockquote> for our oEmbed fallback HTML.
     146         *
     147         * @since 2.6.0
     148         *
     149         * @param  int $item_id The activity ID.
     150         * @return string
     151         */
     152        protected function set_fallback_html( $item_id ) {
     153                $activity    = new BP_Activity_Activity( $item_id );
     154                $mentionname = bp_activity_do_mentions() ? ' (@' . bp_activity_get_user_mentionname( $activity->user_id ) . ')' : '';
     155                $date        = date_i18n( get_option( 'date_format' ), strtotime( $activity->date_recorded ) );
     156
     157                // Make sure we can use some activity functions that depend on the loop.
     158                $GLOBALS['activities_template'] = new stdClass;
     159                $GLOBALS['activities_template']->activity = $activity;
     160
     161                // 'wp-embedded-content' CSS class is necessary due to how the embed JS works.
     162                $blockquote = sprintf( '<blockquote class="wp-embedded-content bp-activity-item">%1$s%2$s %3$s</blockquote>',
     163                        '<p>' . bp_activity_get_embed_excerpt( $activity->content ) . '</p>',
     164                        '- ' . bp_core_get_user_displayname( $activity->user_id ) . $mentionname,
     165                        '<a href="' . esc_url( bp_activity_get_permalink( $item_id ) ) . '">' . $date . '</a>'
     166                );
     167
     168                // Clean up.
     169                unset( $GLOBALS['activities_template'] );
     170
     171                /**
     172                 * Filters the fallback HTML used when embedding a BP activity item.
     173                 *
     174                 * @since 2.6.0
     175                 *
     176                 * @param string               $blockquote Current fallback HTML
     177                 * @param BP_Activity_Activity $activity   Activity object
     178                 */
     179                return apply_filters( 'bp_activity_embed_fallback_html', $blockquote, $activity );
     180        }
     181
     182        /**
     183         * Sets a custom <iframe> title for our oEmbed item.
     184         *
     185         * @since 2.6.0
     186         *
     187         * @param  int $item_id The activity ID
     188         * @return string
     189         */
     190        protected function set_iframe_title( $item_id ) {
     191                return __( 'Embedded Activity Item', 'buddypress' );
     192        }
     193
     194        /**
     195         * Modify various IFRAME-related items if embeds are allowed.
     196         *
     197         * IFRAME attributes added:
     198         *  - sandbox="allow-same-origin" - Only added for Twitter and Soundcloud
     199         *    embeds to allow them to work.
     200         *  - allowfullscreen="true" - Allows users to view embed content fullscreen.
     201         *
     202         * JS modified:
     203         *  - remove IFRAME height restriction of 1000px. Fixes long embed items being
     204         *    truncated.
     205         *  - delay IFRAME onload script by 550ms. Fixes resize issues with Tumblr embeds.
     206         *
     207         * @since 2.6.0
     208         *
     209         * @param  string $retval Current embed HTML.
     210         * @return string
     211         */
     212        public function modify_iframe( $retval ) {
     213                // Bail if oEmbed request explicitly hides media.
     214                if ( isset( $_REQUEST['hide_media'] ) && true == wp_validate_boolean( $_REQUEST['hide_media'] ) ) {
     215                        return $retval;
     216                }
     217
     218                // Check filter-configured value.
     219                if ( false == apply_filters( 'bp_activity_embed_display_media', true ) ) {
     220                        return $retval;
     221                }
     222
     223                // Add 'allow-same-origin' sandbox attribute to IFRAME.
     224                // This is only applicable for Twitter and Soundcloud embeds.
     225                if ( false === strpos( $retval, 'allow-same-origin' ) ) {
     226                        // Grab activity meta for this item.
     227                        $meta = bp_activity_get_meta( $this->get_item_id() );
     228
     229                        $checked = false;
     230                        foreach( $meta as $key => $val ) {
     231                                if ( $checked ) {
     232                                        break;
     233                                }
     234
     235                                // Not an oEmbed meta item.
     236                                if ( false === strpos( $key, '_oembed' ) ) {
     237                                        continue;
     238                                }
     239
     240                                $checked = true;
     241
     242                                // See if the first embed is a Soundcloud or Twitter item.
     243                                if ( false === strpos( $val[0], 'soundcloud.com' ) && false === strpos( $val[0], 'twitter.com' ) ) {
     244                                        continue;
     245                                }
     246
     247                                // Add the 'allow-same-origin' attribute.
     248                                $retval = str_replace( 'sandbox="', 'sandbox="allow-same-origin ', $retval );
     249                        }
     250                }
     251
     252                // Add 'allowfullscreen' attribute to IFRAME.
     253                if ( false === strpos( $retval, 'allowfullscreen=' ) ) {
     254                        $retval = str_replace( '<iframe', '<iframe allowfullscreen="true"', $retval );
     255                }
     256
     257                // See /wp-includes/js/wp-embed.js.
     258                if ( SCRIPT_DEBUG ) {
     259                        // Removes WP's hardcoded IFRAME height restriction.
     260                        $retval = str_replace( 'height = 1000;', 'height = height;', $retval );
     261
     262                        // Delay IFRAME postMessage script so Tumblr embeds are not truncated.
     263                        $retval = str_replace(
     264                                "window.addEventListener( 'message', window.wp.receiveEmbedMessage, false );",
     265                                "window.addEventListener( 'message', function(e) {
     266                                        if ( e.source.frameElement.contentDocument.querySelector('iframe.tumblr-embed') ) {
     267                                                setTimeout( function() {
     268                                                        window.wp.receiveEmbedMessage(e);
     269                                                }, 550 );
     270                                        } else {
     271                                                window.wp.receiveEmbedMessage(e);
     272                                        }
     273                                }, false );",
     274                                $retval
     275                        );
     276
     277                // This is for the WP build minified version.
     278                } else {
     279                        $retval = str_replace( 'g=1e3', 'g=g', $retval );
     280                        $retval = str_replace(
     281                                'a.addEventListener("message",a.wp.receiveEmbedMessage,!1)',
     282                                'a.addEventListener("message",function(e){if(e.source.frameElement.contentDocument.querySelector("iframe.tumblr-embed")){setTimeout(function(){a.wp.receiveEmbedMessage(e);},550);}else{a.wp.receiveEmbedMessage(e);}},!1)',
     283                                $retval
     284                        );
     285                }
     286
     287                return $retval;
     288        }
     289
     290        /**
     291         * Prints the markup for the activity embed comments button.
     292         *
     293         * Basically a copy of {@link print_embed_comments_button()}, but modified for
     294         * the BP activity component.
     295         *
     296         * @since 2.6.0
     297         */
     298        public function embed_comments_button() {
     299                if ( ! bp_is_single_activity() ) {
     300                        return;
     301                }
     302
     303                // Make sure our custom permalink shows up in the 'WordPress Embed' block.
     304                add_filter( 'the_permalink', array( $this, 'filter_embed_url' ) );
     305
     306                // Only show comment bubble if we have some activity comments.
     307                $count = bp_activity_get_comment_count();
     308                if ( empty( $count ) ) {
     309                        return;
     310                }
     311        ?>
     312
     313                <div class="wp-embed-comments">
     314                        <a href="<?php bp_activity_thread_permalink(); ?>">
     315                                <span class="dashicons dashicons-admin-comments"></span>
     316                                <?php
     317                                printf(
     318                                        _n(
     319                                                '%s <span class="screen-reader-text">Comment</span>',
     320                                                '%s <span class="screen-reader-text">Comments</span>',
     321                                                $count,
     322                                                'buddypress'
     323                                        ),
     324                                        number_format_i18n( $count )
     325                                );
     326                                ?>
     327                        </a>
     328                </div>
     329
     330        <?php
     331        }
     332}
  • src/bp-core/bp-core-actions.php

     
    4040add_action( 'setup_theme',             'bp_setup_theme',            10    );
    4141add_action( 'after_setup_theme',       'bp_after_setup_theme',      100   ); // After WP themes.
    4242add_action( 'wp_enqueue_scripts',      'bp_enqueue_scripts',        10    );
     43add_action( 'enqueue_embed_scripts',   'bp_enqueue_embed_scripts',  10    );
    4344add_action( 'admin_bar_menu',          'bp_setup_admin_bar',        20    ); // After WP core.
    4445add_action( 'template_redirect',       'bp_template_redirect',      10    );
    4546add_action( 'widgets_init',            'bp_widgets_init',           10    );
  • src/bp-core/bp-core-dependency.php

     
    477477}
    478478
    479479/**
     480 * Fires the 'bp_enqueue_embed_scripts' action in the <head> for BP oEmbeds.
     481 *
     482 * @since 2.6.0
     483 */
     484function bp_enqueue_embed_scripts() {
     485        if ( ! is_buddypress() ) {
     486                return;
     487        }
     488
     489        /**
     490         * Enqueue CSS and JS files for BuddyPress embeds.
     491         *
     492         * @since 2.6.0
     493         */
     494        do_action ( 'bp_enqueue_embed_scripts' );
     495}
     496
     497/**
    480498 * Fire the 'bp_add_rewrite_tag' action, where BP adds its custom rewrite tags.
    481499 *
    482500 * @since 1.8.0
  • src/bp-core/bp-core-functions.php

     
    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.6.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

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

     
    769769 * This function is borrowed from CakePHP v2.0, under the MIT license. See
    770770 * http://book.cakephp.org/view/1469/Text#truncate-1625
    771771 *
     772 * @since 2.6.0 Added 'strip_tags' and 'remove_links' as $options args.
     773 *
    772774 * ### Options:
    773775 *
    774776 * - `ending` Will be used as Ending and appended to the trimmed string.
     
    791793 *                                     excerpt length. Default: true.
    792794 *     @type bool   $filter_shortcodes If true, shortcodes will be stripped.
    793795 *                                     Default: true.
     796 *     @type bool   $strip_tags        If true, HTML tags will be stripped. Default: false.
     797 *                                     Only applicable if $html is set to false.
     798 *     @type bool   $remove_links      If true, URLs will be stripped. Default: false.
     799 *                                     Only applicable if $html is set to false.
    794800 * }
    795801 * @return string Trimmed string.
    796802 */
     
    803809                'ending'            => __( ' [&hellip;]', 'buddypress' ),
    804810                'exact'             => false,
    805811                'html'              => true,
    806                 'filter_shortcodes' => $filter_shortcodes_default
     812                'filter_shortcodes' => $filter_shortcodes_default,
     813                'strip_tags'        => false,
     814                'remove_links'      => false,
    807815        ), 'create_excerpt' );
    808816
    809817        // Save the original text, to be passed along to the filter.
     
    889897                        }
    890898                }
    891899        } else {
     900                // Strip HTML tags if necessary.
     901                if ( ! empty( $r['strip_tags'] ) ) {
     902                        $text = strip_tags( $text );
     903                }
     904
     905                // Remove links if necessary.
     906                if ( ! empty( $r['remove_links'] ) ) {
     907                        $text = preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $text );
     908                }
     909
    892910                if ( mb_strlen( $text ) <= $length ) {
    893                         return $text;
     911                        /**
     912                         * Filters the final generated excerpt.
     913                         *
     914                         * @since 1.1.0
     915                         *
     916                         * @param string $truncate      Generated excerpt.
     917                         * @param string $original_text Original text provided.
     918                         * @param int    $length        Length of returned string, including ellipsis.
     919                         * @param array  $options       Array of HTML attributes and options.
     920                         */
     921                        return apply_filters( 'bp_create_excerpt', $text, $original_text, $length, $options );
    894922                } else {
    895923                        $truncate = mb_substr( $text, 0, $length - mb_strlen( $ending ) );
    896924                }
  • src/bp-core/bp-core-theme-compatibility.php

     
    547547}
    548548
    549549/**
     550 * Create a dummy WP_Post object.
     551 *
     552 * @since 2.6.0
     553 *
     554 * @param  array $args Array of optional arguments. Arguments parallel the properties
     555 *                    of {@link WP_Post}; see that class for more details.
     556 * @return WP_Post
     557 */
     558function bp_theme_compat_create_dummy_post( $args = array() ) {
     559        $args = wp_parse_args( $args, array(
     560                'ID'                    => -9999,
     561                'post_status'           => 'public',
     562                'post_author'           => 0,
     563                'post_parent'           => 0,
     564                'post_type'             => 'page',
     565                'post_date'             => 0,
     566                'post_date_gmt'         => 0,
     567                'post_modified'         => 0,
     568                'post_modified_gmt'     => 0,
     569                'post_content'          => '',
     570                'post_title'            => '',
     571                'post_excerpt'          => '',
     572                'post_content_filtered' => '',
     573                'post_mime_type'        => '',
     574                'post_password'         => '',
     575                'post_name'             => '',
     576                'guid'                  => '',
     577                'menu_order'            => 0,
     578                'pinged'                => '',
     579                'to_ping'               => '',
     580                'ping_status'           => '',
     581                'comment_status'        => 'closed',
     582                'comment_count'         => 0,
     583                'filter'                => 'raw',
     584
     585                'is_404'                => false,
     586                'is_page'               => false,
     587                'is_single'             => false,
     588                'is_archive'            => false,
     589                'is_tax'                => false,
     590        ) );
     591
     592        // Create the dummy post.
     593        $post = new WP_Post( (object) $args );
     594
     595        return $post;
     596}
     597
     598/**
    550599 * Populate various WordPress globals with dummy data to prevent errors.
    551600 *
    552601 * This dummy data is necessary because theme compatibility essentially fakes
     
    567616
    568617        // Switch defaults if post is set.
    569618        if ( isset( $wp_query->post ) ) {
    570                 $dummy = wp_parse_args( $args, array(
     619                $args = wp_parse_args( $args, array(
    571620                        'ID'                    => $wp_query->post->ID,
    572621                        'post_status'           => $wp_query->post->post_status,
    573622                        'post_author'           => $wp_query->post->post_author,
     
    592641                        'comment_status'        => $wp_query->post->comment_status,
    593642                        'comment_count'         => $wp_query->post->comment_count,
    594643                        'filter'                => $wp_query->post->filter,
    595 
    596                         'is_404'                => false,
    597                         'is_page'               => false,
    598                         'is_single'             => false,
    599                         'is_archive'            => false,
    600                         'is_tax'                => false,
    601                 ) );
    602         } else {
    603                 $dummy = wp_parse_args( $args, array(
    604                         'ID'                    => -9999,
    605                         'post_status'           => 'public',
    606                         'post_author'           => 0,
    607                         'post_parent'           => 0,
    608                         'post_type'             => 'page',
    609                         'post_date'             => 0,
    610                         'post_date_gmt'         => 0,
    611                         'post_modified'         => 0,
    612                         'post_modified_gmt'     => 0,
    613                         'post_content'          => '',
    614                         'post_title'            => '',
    615                         'post_excerpt'          => '',
    616                         'post_content_filtered' => '',
    617                         'post_mime_type'        => '',
    618                         'post_password'         => '',
    619                         'post_name'             => '',
    620                         'guid'                  => '',
    621                         'menu_order'            => 0,
    622                         'pinged'                => '',
    623                         'to_ping'               => '',
    624                         'ping_status'           => '',
    625                         'comment_status'        => 'closed',
    626                         'comment_count'         => 0,
    627                         'filter'                => 'raw',
    628 
    629                         'is_404'                => false,
    630                         'is_page'               => false,
    631                         'is_single'             => false,
    632                         'is_archive'            => false,
    633                         'is_tax'                => false,
    634644                ) );
    635645        }
    636646
    637647        // Bail if dummy post is empty.
    638         if ( empty( $dummy ) ) {
     648        if ( empty( $args ) ) {
    639649                return;
    640650        }
    641651
    642652        // Set the $post global.
    643         $post = new WP_Post( (object) $dummy );
     653        $post = bp_theme_compat_create_dummy_post( $args );
    644654
    645655        // Copy the new post global into the main $wp_query.
    646656        $wp_query->post       = $post;
     
    648658
    649659        // Prevent comments form from appearing.
    650660        $wp_query->post_count = 1;
    651         $wp_query->is_404     = $dummy['is_404'];
    652         $wp_query->is_page    = $dummy['is_page'];
    653         $wp_query->is_single  = $dummy['is_single'];
    654         $wp_query->is_archive = $dummy['is_archive'];
    655         $wp_query->is_tax     = $dummy['is_tax'];
    656 
    657         // Clean up the dummy post.
    658         unset( $dummy );
     661        $wp_query->is_404     = $post->is_404;
     662        $wp_query->is_page    = $post->is_page;
     663        $wp_query->is_single  = $post->is_single;
     664        $wp_query->is_archive = $post->is_archive;
     665        $wp_query->is_tax     = $post->is_tax;
    659666
    660667        /**
    661668         * Force the header back to 200 status if not a deliberate 404
     
    700707 * @return string $template Template name.
    701708 */
    702709function bp_template_include_theme_compat( $template = '' ) {
     710        // If embed template, bail.
     711        if ( is_embed() ) {
     712                return $template;
     713        }
    703714
    704715        // If the current theme doesn't need theme compat, bail at this point.
    705716        if ( ! bp_use_theme_compat_with_current_theme() ) {
  • src/bp-core/classes/class-bp-admin.php

     
    836836                                <a href="https://bbpress.org">bbPress</a>,
    837837                                <a href="https://github.com/ichord/Caret.js">Caret.js</a>,
    838838                                <a href="http://tedgoas.github.io/Cerberus/">Cerberus</a>,
     839                                <a href="https://github.com/toddmotto/fluidvids">fluidvids.js</a>,
    839840                                <a href="https://github.com/carhartl/jquery-cookie">jquery.cookie</a>,
    840841                                <a href="https://www.mediawiki.org/wiki/MediaWiki">MediaWiki</a>,
    841842                                <a href="https://wordpress.org">WordPress</a>.
  • new file src/bp-core/classes/class-bp-oembed-component.php

    new file mode 100644
    - +  
     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.6.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.6.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.6.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.6.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.6.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.6.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         * If your oEmbed endpoint requires additional arguments, set them here.
     114         *
     115         * @see register_rest_route() View the $args parameter for more info.
     116         *
     117         * @since 2.6.0
     118         *
     119         * @return array
     120         */
     121        protected function set_route_args() {
     122                return array();
     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.6.0
     139         */
     140        protected function custom_hooks() {}
     141
     142        /**
     143         * Set permalink for oEmbed link discovery.
     144         *
     145         * This method will be called on the page we want to oEmbed.  In most cases,
     146         * you will not need to override this method.  However, if you need to, do
     147         * override in your extended class.
     148         *
     149         * @since 2.6.0
     150         */
     151        protected function set_permalink() {
     152                $url = bp_get_requested_url();
     153
     154                // Remove querystring from bp_get_requested_url()
     155                if ( false !== strpos( bp_get_requested_url(), '?' ) ) {
     156                        $url = substr( bp_get_requested_url(), 0, strpos( bp_get_requested_url(), '?' ) );
     157                }
     158
     159                return $url;
     160        }
     161
     162        /** HELPERS *************************************************************/
     163
     164        /**
     165         * Get the item ID when filtering the oEmbed HTML.
     166         *
     167         * Should only be used during the 'embed_html' hook.
     168         *
     169         * @since 2.6.0
     170         */
     171        protected function get_item_id() {
     172                return $this->is_page() ? $this->validate_url_to_item_id( $this->set_permalink() ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress;
     173        }
     174
     175        /** SET UP **************************************************************/
     176
     177        /**
     178         * Set up properties.
     179         *
     180         * @since 2.6.0
     181         */
     182        protected function setup_properties() {
     183                $this->slug_endpoint = sanitize_title( $this->slug_endpoint );
     184        }
     185
     186        /**
     187         * Hooks! We do the dirty work here, so you don't have to! :)
     188         *
     189         * More hooks are available in the setup_template_parts() method.
     190         *
     191         * @since 2.6.0
     192         */
     193        protected function setup_hooks() {
     194                add_action( 'rest_api_init',    array( $this, 'register_route' ) );
     195                add_action( 'bp_embed_content', array( $this, 'inject_content' ) );
     196
     197                add_filter( 'embed_template', array( $this, 'setup_template_parts' ) );
     198                add_filter( 'post_embed_url', array( $this, 'filter_embed_url' ) );
     199                add_filter( 'embed_html',     array( $this, 'filter_embed_html' ) );
     200                add_filter( 'oembed_discovery_links', array( $this, 'add_oembed_discovery_links' ) );
     201        }
     202
     203        /** HOOKS ***************************************************************/
     204
     205        /**
     206         * Register the oEmbed REST API route.
     207         *
     208         * @since 2.6.0
     209         */
     210        public function register_route() {
     211                /** This filter is documented in wp-includes/class-wp-oembed-controller.php */
     212                $maxwidth = apply_filters( 'oembed_default_width', 600 );
     213
     214                // Required arguments.
     215                $args = array(
     216                        'url'      => array(
     217                                'required'          => true,
     218                                'sanitize_callback' => 'esc_url_raw',
     219                        ),
     220                        'format'   => array(
     221                                'default'           => 'json',
     222                                'sanitize_callback' => 'wp_oembed_ensure_format',
     223                        ),
     224                        'maxwidth' => array(
     225                                'default'           => $maxwidth,
     226                                'sanitize_callback' => 'absint',
     227                        )
     228                );
     229
     230                // Merge custom arguments here.
     231                $args = $args + (array) $this->set_route_args();
     232
     233                register_rest_route( 'oembed/1.0', "/embed/{$this->slug_endpoint}", array(
     234                        array(
     235                                'methods'  => WP_REST_Server::READABLE,
     236                                'callback' => array( $this, 'get_item' ),
     237                                'args'     => $args
     238                        ),
     239                ) );
     240        }
     241
     242        /**
     243         * Set up custom embed template parts for BuddyPress use.
     244         *
     245         * @since 2.6.0
     246         *
     247         * @param  string $template File path to current embed template.
     248         * @return string
     249         */
     250        public function setup_template_parts( $template ) {
     251                // Determine if we're on our BP page.
     252                if ( ! $this->is_page() || is_404() ) {
     253                        return $template;
     254                }
     255
     256                // Set up some BP-specific embed template overrides.
     257                add_action( 'embed_head',              array( $this, 'add_base_element' ), 1 );
     258                add_action( 'get_template_part_embed', array( $this, 'content_buffer_start' ), -999, 2 );
     259                add_action( 'get_footer',              array( $this, 'content_buffer_end' ), -999 );
     260
     261                // Return the original WP embed template.
     262                return $template;
     263        }
     264
     265        /**
     266         * Add <base> element to embed <head>.
     267         */
     268        public function add_base_element() {
     269                echo '<base target="_top" />';
     270        }
     271
     272        /**
     273         * Start object buffer.
     274         *
     275         * We're going to override WP's get_template_part( 'embed, 'content' ) call
     276         * and inject our own template for BuddyPress use.
     277         */
     278        public function content_buffer_start( $slug, $name ) {
     279                if ( 'embed' !== $slug || 'content' !== $name ) {
     280                        return;
     281                }
     282
     283                // Start the buffer to wipe out get_template_part( 'embed, 'content' ).
     284                ob_start();
     285        }
     286
     287        /**
     288         * End object buffer.
     289         *
     290         * We're going to override WP's get_template_part( 'embed, 'content' ) call
     291         * and inject our own template for BuddyPress use.
     292         */
     293        public function content_buffer_end( $name ) {
     294                if ( 'embed' !== $name || is_404() ) {
     295                        return;
     296                }
     297
     298                // Wipe out get_template_part( 'embed, 'content' ).
     299                ob_end_clean();
     300
     301                // Start our custom BuddyPress embed template!
     302                echo '<div ';
     303                post_class( 'wp-embed' );
     304                echo '>';
     305
     306                // Template part for our embed header.
     307                bp_get_asset_template_part( 'embeds/header', bp_current_component() );
     308
     309                /**
     310                 * Inject BuddyPress embed content on this hook.
     311                 *
     312                 * You shouldn't really need to use this if you extend the
     313                 * {@link BP_oEmbed_Component} class.
     314                 *
     315                 * @since 2.6.0
     316                 */
     317                do_action( 'bp_embed_content' );
     318
     319                // Template part for our embed footer.
     320                bp_get_asset_template_part( 'embeds/footer', bp_current_component() );
     321
     322                echo '</div>';
     323        }
     324
     325        /**
     326         * Adds oEmbed discovery links on single activity pages.
     327         *
     328         * @since 2.6.0
     329         *
     330         * @param  string $retval Current discovery links.
     331         * @return string
     332         */
     333        public function add_oembed_discovery_links( $retval ) {
     334                if ( ! $this->is_page() ) {
     335                        return $retval;
     336                }
     337
     338                $permalink = $this->set_permalink();
     339                if ( empty( $permalink ) ) {
     340                        return $retval;
     341                }
     342
     343                add_filter( 'rest_url' , array( $this, 'filter_rest_url' ) );
     344
     345                $retval = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink ) ) . '" />' . "\n";
     346
     347                if ( class_exists( 'SimpleXMLElement' ) ) {
     348                        $retval .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink, 'xml' ) ) . '" />' . "\n";
     349                }
     350
     351                remove_filter( 'rest_url' , array( $this, 'filter_rest_url' ) );
     352
     353                return $retval;
     354        }
     355
     356        /**
     357         * Callback for the API endpoint.
     358         *
     359         * Returns the JSON object for the item.
     360         *
     361         * @since 2.6.0
     362         *
     363         * @param  WP_REST_Request $request Full data about the request.
     364         * @return WP_Error|array oEmbed response data or WP_Error on failure.
     365         */
     366        public function get_item( $request ) {
     367                $url = $request['url'];
     368
     369                $data = false;
     370
     371                $item_id = (int) $this->validate_url_to_item_id( $url );
     372
     373                if ( ! empty( $item_id ) ) {
     374                        $item = $this->set_oembed_response_data( $item_id );
     375
     376                        // Create dummy post to piggyback off of get_oembed_response_data()
     377                        $post = bp_theme_compat_create_dummy_post( array(
     378                                'post_author'  => $item['user_id'],
     379                                'post_title'   => $item['title'],
     380                                'post_content' => $item['content'],
     381
     382                                // This passes the get_oembed_response_data() check.
     383                                'post_status'  => 'publish'
     384                        ) );
     385
     386                        // Add markers to tell that we're embedding a single activity.
     387                        // This is needed for various oEmbed response data filtering.
     388                        if ( empty( buddypress()->{$this->slug_endpoint} ) ) {
     389                                buddypress()->{$this->slug_endpoint} = new stdClass;
     390                        }
     391                        buddypress()->{$this->slug_endpoint}->embedurl_in_progress = $url;
     392                        buddypress()->{$this->slug_endpoint}->embedid_in_progress  = $item_id;
     393
     394                        // Save custom route args as well.
     395                        $custom_args = array_keys( (array) $this->set_route_args() );
     396                        if ( ! empty( $custom_args ) ) {
     397                                buddypress()->{$this->slug_endpoint}->embedargs_in_progress = array();
     398
     399                                foreach( $custom_args as $arg ) {
     400                                        if ( isset( $request[ $arg ] ) ) {
     401                                                buddypress()->{$this->slug_endpoint}->embedargs_in_progress[ $arg ] = $request[ $arg ];
     402                                        }
     403                                }
     404                        }
     405
     406                        // Use WP's oEmbed response data function.
     407                        $data = get_oembed_response_data( $post, $request['maxwidth'] );
     408
     409                        // Set custom 'author_url' if we have one.
     410                        if ( ! empty( $item['author_url'] ) ) {
     411                                $data['author_url'] = $item['author_url'];
     412                        }
     413                }
     414
     415                if ( ! $data ) {
     416                        return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) );
     417                }
     418
     419                return $data;
     420        }
     421
     422        /**
     423         * Pass our BuddyPress activity permalink for embedding.
     424         *
     425         * @since 2.6.0
     426         *
     427         * @see bp_activity_embed_rest_route_callback()
     428         *
     429         * @param  string $retval Current embed URL
     430         * @return string
     431         */
     432        public function filter_embed_url( $retval ) {
     433                if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) {
     434                        return $retval;
     435                }
     436
     437                $url = $this->is_page() ? $this->set_permalink() : buddypress()->{$this->slug_endpoint}->embedurl_in_progress;
     438                $url = trailingslashit( $url );
     439
     440                // This is for the 'WordPress Embed' block
     441                // @see bp_activity_embed_comments_button()
     442                if ( 'the_permalink' !== current_filter() ) {
     443                        $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) );
     444
     445                        // Add custom route args to iframe.
     446                        if ( ! empty( buddypress()->{$this->slug_endpoint}->embedargs_in_progress ) ) {
     447                                foreach( buddypress()->{$this->slug_endpoint}->embedargs_in_progress as $key => $value ) {
     448                                        $url = add_query_arg( $key, $value, $url );
     449                                }
     450                        }
     451                }
     452
     453                return $url;
     454        }
     455
     456        /**
     457         * Filters the embed HTML for our BP oEmbed endpoint.
     458         *
     459         * @since 2.6.0
     460         *
     461         * @param  string $retval Current embed HTML
     462         * @return string
     463         */
     464        public function filter_embed_html( $retval ) {
     465                if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) {
     466                        return $retval;
     467                }
     468
     469                $url = $this->set_permalink();
     470
     471                $item_id = $this->is_page() ? $this->validate_url_to_item_id( $url ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress;
     472
     473                // Change 'Embedded WordPress Post' to custom title.
     474                $custom_title = $this->set_iframe_title( $item_id );
     475                if ( ! empty( $custom_title ) ) {
     476                        $title_pos = strpos( $retval, 'title=' ) + 7;
     477                        $title_end_pos = strpos( $retval, '"', $title_pos );
     478
     479                        $retval = substr_replace( $retval, esc_attr( $custom_title ), $title_pos, $title_end_pos - $title_pos );
     480                }
     481
     482                // Add 'max-width' CSS attribute to IFRAME.
     483                // This will make our oEmbeds responsive.
     484                if ( false === strpos( $retval, 'style="max-width' ) ) {
     485                        $retval = str_replace( '<iframe', '<iframe style="max-width:100%"', $retval );
     486                }
     487
     488                // Remove default <blockquote>
     489                $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 );
     490
     491                // Set up new fallback HTML
     492                // @todo Maybe use KSES?
     493                $fallback_html = $this->set_fallback_html( $item_id );
     494
     495                /**
     496                 * Dynamic filter to return BP oEmbed HTML.
     497                 *
     498                 * @since 2.6.0
     499                 *
     500                 * @var string $retval
     501                 */
     502                return apply_filters( "bp_{$this->slug_endpoint}_embed_html", $fallback_html . $retval );
     503        }
     504
     505        /**
     506         * Append our custom slug endpoint to oEmbed endpoint URL.
     507         *
     508         * Meant to be used as a filter on 'rest_url' before any call to
     509         * {@link get_oembed_endpoint_url()} is used.
     510         *
     511         * @since 2.6.0
     512         *
     513         * @see add_oembed_discovery_links()
     514         *
     515         * @param  string $retval Current oEmbed endpoint URL
     516         * @return string
     517         */
     518        function filter_rest_url( $retval = '' ) {
     519                return $retval . "/{$this->slug_endpoint}";
     520        }
     521
     522        /**
     523         * Inject activity content into the embed template.
     524         *
     525         * @since 2.6.0
     526         */
     527        public function inject_content() {
     528                if ( ! $this->is_page() ) {
     529                        return;
     530                }
     531
     532                $this->content();
     533        }
     534}
     535 No newline at end of file
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/activity.php

    new file mode 100644
    - +  
     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"><?php bp_activity_embed_excerpt(); ?></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 do_action( 'bp_activity_embed_after_content' ); ?>
     10
     11                        <?php endwhile; ?>
     12
     13                <?php endif; ?>
     14
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/footer.php

    new file mode 100644
    - +  
     1                        <div class="wp-embed-footer">
     2                                <?php the_embed_site_title() ?>
     3
     4                                <div class="wp-embed-meta">
     5                                        <?php
     6                                        /** This action is documented in wp-includes/theme-compat/embed-content.php */
     7                                        do_action( 'embed_content_meta'); ?>
     8                                </div>
     9                        </div>
     10 No newline at end of file
  • new file src/bp-templates/bp-legacy/buddypress/assets/embeds/header.php

    new file mode 100644
    - +  
     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>