Ticket #6772: 6772.05.patch
File 6772.05.patch, 39.9 KB (added by , 9 years ago) |
---|
-
new file src/bp-activity/bp-activity-embeds.php
diff --git src/bp-activity/bp-activity-embeds.php src/bp-activity/bp-activity-embeds.php new file mode 100644 index 0000000..31a4e02
- + 1 <?php 2 /** 3 * Functions related to embedding single activity items externally. 4 * 5 * Relies on WordPress 4.4. 6 * 7 * @since 2.5.0 8 * 9 * @package BuddyPress 10 * @subpackage ActivityEmbeds 11 */ 12 13 // Exit if accessed directly. 14 defined( 'ABSPATH' ) || exit; 15 16 /** 17 * Loads our activity oEmbed component. 18 * 19 * @since 2.5.0 20 */ 21 function bp_activity_setup_oembed() { 22 if ( bp_get_major_wp_version() >= 4.4 && bp_is_active( 'activity', 'embeds' ) ) { 23 buddypress()->activity->oembed = new BP_Activity_oEmbed_Component; 24 } 25 } 26 27 /** 28 * Outputs a text excerpt for an activity item (and remove any oEmbeds URLs). 29 * 30 * @since 2.5.0 31 */ 32 function bp_activity_embed_excerpt( $content = '' ) { 33 echo bp_activity_get_embed_excerpt( $content = '' ); 34 } 35 36 /** 37 * Generate a text excerpt for an activity item (and remove any oEmbeds URLs). 38 * 39 * @since 2.5.0 40 * 41 * @param string $content The content to generate an excerpt for. 42 * @return string 43 */ 44 function bp_activity_get_embed_excerpt( $content = '' ) { 45 if ( empty( $content ) && ! empty( $GLOBALS['activities_template']->in_the_loop ) ) { 46 $content = $GLOBALS['activities_template']->activity->content; 47 } 48 49 /** 50 * bp_activity_truncate_entry() includes the 'Read More' link, which is why 51 * we're using this instead of bp_create_excerpt(). 52 */ 53 $content = html_entity_decode( $content ); 54 $content = bp_activity_truncate_entry( $content, array( 55 'html' => false, 56 'filter_shortcodes' => true, 57 'strip_tags' => true, 58 'force_truncate' => true 59 ) ); 60 61 // Remove links from content. 62 $content = preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $content ); 63 64 return $content; 65 } 66 67 /** 68 * Outputs the first embedded item in the activity oEmbed template. 69 * 70 * @since 2.5.0 71 */ 72 function bp_activity_embed_response_display_media() { 73 // Bail if oEmbed request explicitly hides media. 74 if ( isset( $_REQUEST['hide_media'] ) && true == wp_validate_boolean( $_REQUEST['hide_media'] ) ) { 75 return; 76 } 77 78 // Find all embeds for the activity item. 79 $embeds = bp_core_extract_media_from_content( $GLOBALS['activities_template']->activity->content, 'embeds' ); 80 81 /** 82 * Should we display media in the oEmbed template? 83 * 84 * @since 2.5.0 85 * 86 * @param bool $retval Defaults to true. 87 */ 88 $allow_embeds = apply_filters( 'bp_activity_embed_display_media', true ); 89 90 // Only embed the first embedded item. 91 if ( $embeds && $allow_embeds ) { 92 $content = apply_filters( 'bp_get_activity_content_body', $embeds['embeds'][0]['url'] ); 93 echo $content; 94 95 if ( false !== strpos( $content, '<iframe' ) ) { 96 ?> 97 98 <script> 99 /*! fluidvids.js v1.2.0 | (c) 2013 @toddmotto | https://github.com/toddmotto/fluidvids */ 100 window.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); 101 </script> 102 103 <?php 104 } 105 } 106 } 107 add_action( 'bp_activity_embed_after_content', 'bp_activity_embed_response_display_media' ); -
src/bp-activity/bp-activity-filters.php
diff --git src/bp-activity/bp-activity-filters.php src/bp-activity/bp-activity-filters.php index bc61bdc..1ff8ade 100644
function bp_activity_make_nofollow_filter( $text ) { 387 387 * This method can only be used inside the Activity loop. 388 388 * 389 389 * @since 1.5.0 390 * 391 * @uses bp_is_single_activity() 392 * @uses apply_filters() To call the 'bp_activity_excerpt_append_text' hook. 393 * @uses apply_filters() To call the 'bp_activity_excerpt_length' hook. 394 * @uses bp_create_excerpt() 395 * @uses bp_get_activity_id() 396 * @uses bp_get_activity_thread_permalink() 397 * @uses apply_filters() To call the 'bp_activity_truncate_entry' hook. 390 * @since 2.5.0 Added $args parameter. 398 391 * 399 392 * @param string $text The original activity entry text. 400 393 * @return string $excerpt The truncated text. 401 394 */ 402 function bp_activity_truncate_entry( $text ) {395 function bp_activity_truncate_entry( $text, $args = array() ) { 403 396 global $activities_template; 404 397 405 398 /** … … function bp_activity_truncate_entry( $text ) { 415 408 ); 416 409 417 410 // The full text of the activity update should always show on the single activity screen. 418 if ( ! $maybe_truncate_text || bp_is_single_activity() ) {411 if ( empty( $args['force_truncate'] ) && ( ! $maybe_truncate_text || bp_is_single_activity() ) ) { 419 412 return $text; 420 413 } 421 414 … … function bp_activity_truncate_entry( $text ) { 437 430 */ 438 431 $excerpt_length = apply_filters( 'bp_activity_excerpt_length', 358 ); 439 432 433 $args = wp_parse_args( $args, array( 'ending' => __( '…', 'buddypress' ) ) ); 434 440 435 // Run the text through the excerpt function. If it's too short, the original text will be returned. 441 $excerpt = bp_create_excerpt( $text, $excerpt_length, array( 'ending' => __( '…', 'buddypress' ) ));436 $excerpt = bp_create_excerpt( $text, $excerpt_length, $args ); 442 437 443 438 /* 444 439 * If the text returned by bp_create_excerpt() is different from the original text (ie it's -
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..6f474a7 100644
function bp_activity_create_summary( $content, $activity ) { 2789 2789 } 2790 2790 2791 2791 // 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 ) ); 2792 $summary = bp_create_excerpt( html_entity_decode( $content ), 225, array( 2793 'html' => false, 2794 'filter_shortcodes' => true, 2795 'strip_tags' => true, 2796 'remove_links' => true 2797 ) ); 2794 2798 2795 2799 if ( $use_media_type === 'embeds' ) { 2796 2800 $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..f41630e 100644
class BP_Activity_Component extends BP_Component { 31 31 array( 32 32 'adminbar_myaccount_order' => 10, 33 33 'search_query_arg' => 'activity_search', 34 'features' => array( 'embeds' ) 34 35 ) 35 36 ); 36 37 } … … class BP_Activity_Component extends BP_Component { 67 68 $includes[] = 'akismet'; 68 69 } 69 70 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 $includes[] = 'embeds'; 75 } 76 70 77 if ( is_admin() ) { 71 78 $includes[] = 'admin'; 72 79 } … … class BP_Activity_Component extends BP_Component { 365 372 // Spam prevention. 366 373 add_action( 'bp_include', 'bp_activity_setup_akismet' ); 367 374 375 // oEmbed handler. 376 add_action( 'bp_loaded', 'bp_activity_setup_oembed' ); 377 368 378 parent::setup_actions(); 369 379 } 370 380 -
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..8deaa8b
- + 1 <?php 2 /** 3 * BuddyPress Activity Classes. 4 * 5 * @package BuddyPress 6 * @subpackage Embeds 7 */ 8 9 // Exit if accessed directly. 10 defined( 'ABSPATH' ) || exit; 11 12 require_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 */ 19 class 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 * Add custom endpoint arguments. 40 * 41 * Currently, includes 'hide_media'. 42 * 43 * @since 2.5.0 44 * 45 * @return array 46 */ 47 protected function set_route_args() { 48 return array( 49 'hide_media' => array( 50 'default' => false, 51 'sanitize_callback' => 'wp_validate_boolean' 52 ) 53 ); 54 } 55 56 /** 57 * Output our custom embed template part. 58 * 59 * @since 2.5.0 60 */ 61 protected function content() { 62 bp_get_asset_template_part( 'embeds/activity' ); 63 } 64 65 /** 66 * Check if we're on our single activity page. 67 * 68 * @since 2.5.0 69 * 70 * @return bool 71 */ 72 protected function is_page() { 73 return bp_is_single_activity(); 74 } 75 76 /** 77 * Validates the URL to determine if the activity item is valid. 78 * 79 * @since 2.5.0 80 * 81 * @param string $url The URL to check. 82 * @return int|bool Activity ID on success; boolean false on failure. 83 */ 84 protected function validate_url_to_item_id( $url ) { 85 if ( bp_core_enable_root_profiles() ) { 86 $domain = bp_get_root_domain(); 87 } else { 88 $domain = bp_get_members_directory_permalink(); 89 } 90 91 // Check the URL to see if this is a single activity URL. 92 if ( 0 !== strpos( $url, $domain ) ) { 93 return false; 94 } 95 96 // Check for activity slug. 97 if ( false === strpos( $url, '/' . bp_get_activity_slug() . '/' ) ) { 98 return false; 99 } 100 101 // Do more checks. 102 $url = trim( untrailingslashit( $url ) ); 103 104 // Grab the activity ID. 105 $activity_id = (int) substr( 106 $url, 107 strrpos( $url, '/' ) + 1 108 ); 109 110 if ( ! empty( $activity_id ) ) { 111 // Check if activity item still exists. 112 $activity = new BP_Activity_Activity( $activity_id ); 113 114 // Okay, we're good to go! 115 if ( ! empty( $activity->component ) && 0 === (int) $activity->is_spam ) { 116 return $activity_id; 117 } 118 } 119 120 return false; 121 } 122 123 /** 124 * Sets the oEmbed response data for our activity item. 125 * 126 * @since 2.5.0 127 * 128 * @param int $item_id The activity ID. 129 * @return array 130 */ 131 protected function set_oembed_response_data( $item_id ) { 132 $activity = new BP_Activity_Activity( $item_id ); 133 134 return array( 135 'user_id' => $activity->user_id, 136 'content' => $activity->content, 137 'title' => __( 'Activity', 'buddypress' ), 138 'author_url' => bp_core_get_user_domain( $activity->user_id ) 139 ); 140 } 141 142 /** 143 * Sets a custom <blockquote> for our oEmbed fallback HTML. 144 * 145 * @since 2.5.0 146 * 147 * @param int $item_id The activity ID. 148 * @return string 149 */ 150 protected function set_fallback_html( $item_id ) { 151 $activity = new BP_Activity_Activity( $item_id ); 152 $mentionname = bp_activity_do_mentions() ? ' (@' . bp_activity_get_user_mentionname( $activity->user_id ) . ')' : ''; 153 $date = date_i18n( get_option( 'date_format' ), strtotime( $activity->date_recorded ) ); 154 155 // Make sure we can use some activity functions that depend on the loop. 156 $GLOBALS['activities_template'] = new stdClass; 157 $GLOBALS['activities_template']->activity = $activity; 158 159 // 'wp-embedded-content' CSS class is necessary due to how the embed JS works. 160 $blockquote = sprintf( '<blockquote class="wp-embedded-content bp-activity-item">%1$s%2$s %3$s</blockquote>', 161 '<p>' . bp_activity_get_embed_excerpt( $activity->content ) . '</p>', 162 '- ' . bp_core_get_user_displayname( $activity->user_id ) . $mentionname, 163 '<a href="' . esc_url( bp_activity_get_permalink( $item_id ) ) . '">' . $date . '</a>' 164 ); 165 166 // Clean up. 167 unset( $GLOBALS['activities_template'] ); 168 169 /** 170 * Filters the fallback HTML used when embedding a BP activity item. 171 * 172 * @since 2.5.0 173 * 174 * @param string $blockquote Current fallback HTML 175 * @param BP_Activity_Activity $activity Activity object 176 */ 177 return apply_filters( 'bp_activity_embed_fallback_html', $blockquote, $activity ); 178 } 179 180 /** 181 * Sets a custom <iframe> title for our oEmbed item. 182 * 183 * @since 2.5.0 184 * 185 * @param int $item_id The activity ID 186 * @return string 187 */ 188 protected function set_iframe_title( $item_id ) { 189 return __( 'Embedded Activity Item', 'buddypress' ); 190 } 191 192 /** 193 * Prints the markup for the activity embed comments button. 194 * 195 * @since 2.5.0 196 */ 197 public function embed_comments_button() { 198 if ( ! bp_is_single_activity() ) { 199 return; 200 } 201 202 // Make sure our custom permalink shows up in the 'WordPress Embed' block. 203 add_filter( 'the_permalink', array( $this, 'filter_embed_url' ) ); 204 205 // Only show comment bubble if we have some activity comments. 206 $count = bp_activity_get_comment_count(); 207 if ( empty( $count ) ) { 208 return; 209 } 210 ?> 211 212 <div class="wp-embed-comments"> 213 <a href="<?php bp_activity_thread_permalink(); ?>"> 214 <span class="dashicons dashicons-admin-comments"></span> 215 <?php 216 printf( 217 _n( 218 '%s <span class="screen-reader-text">Comment</span>', 219 '%s <span class="screen-reader-text">Comments</span>', 220 $count 221 ), 222 number_format_i18n( $count ) 223 ); 224 ?> 225 </a> 226 </div> 227 228 <?php 229 } 230 } -
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() { 1666 1666 return apply_filters( 'bp_use_embed_in_private_messages', !defined( 'BP_EMBED_DISABLE_PRIVATE_MESSAGES' ) || !BP_EMBED_DISABLE_PRIVATE_MESSAGES ); 1667 1667 } 1668 1668 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 */ 1679 function 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 1669 1701 /** Admin *********************************************************************/ 1670 1702 1671 1703 /** -
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 ) { 65 65 } 66 66 67 67 /** 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 */ 77 function bp_get_asset_template_part( $slug, $name = null ) { 78 return bp_get_template_part( "assets/{$slug}", $name ); 79 } 80 81 /** 68 82 * Retrieve the name of the highest priority template file that exists. 69 83 * 70 84 * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which -
src/bp-core/bp-core-template.php
diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php index 7a3a2d4..ad02fda 100644
function bp_button( $args = '' ) { 742 742 * This function is borrowed from CakePHP v2.0, under the MIT license. See 743 743 * http://book.cakephp.org/view/1469/Text#truncate-1625 744 744 * 745 * @since 2.5.0 Added 'strip_tags' and 'remove_links' as $options args. 746 * 745 747 * ### Options: 746 748 * 747 749 * - `ending` Will be used as Ending and appended to the trimmed string. … … function bp_button( $args = '' ) { 762 764 * excerpt length. Default: true. 763 765 * @type bool $filter_shortcodes If true, shortcodes will be stripped. 764 766 * Default: true. 767 * @type bool $strip_tags If true, HTML tags will be stripped. Default: false. 768 * Only applicable if $html is set to false. 769 * @type bool $remove_links If true, URLs will be stripped. Default: false. 770 * Only applicable if $html is set to false. 765 771 * } 766 772 * @return string Trimmed string. 767 773 */ … … function bp_create_excerpt( $text, $length = 225, $options = array() ) { 774 780 'ending' => __( ' […]', 'buddypress' ), 775 781 'exact' => false, 776 782 'html' => true, 777 'filter_shortcodes' => $filter_shortcodes_default 783 'filter_shortcodes' => $filter_shortcodes_default, 784 'strip_tags' => false, 785 'remove_links' => false, 778 786 ), 'create_excerpt' ); 779 787 780 788 // Save the original text, to be passed along to the filter. … … function bp_create_excerpt( $text, $length = 225, $options = array() ) { 860 868 } 861 869 } 862 870 } else { 871 // Strip HTML tags if necessary. 872 if ( ! empty( $r['strip_tags'] ) ) { 873 $text = strip_tags( $text ); 874 } 875 876 // Remove links if necessary. 877 if ( ! empty( $r['remove_links'] ) ) { 878 $text = preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $text ); 879 } 880 863 881 if ( mb_strlen( $text ) <= $length ) { 864 882 return $text; 865 883 } else { -
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 ) { 650 650 } 651 651 652 652 /** 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 */ 661 function 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 /** 653 702 * Populate various WordPress globals with dummy data to prevent errors. 654 703 * 655 704 * This dummy data is necessary because theme compatibility essentially fakes … … function bp_theme_compat_reset_post( $args = array() ) { 670 719 671 720 // Switch defaults if post is set. 672 721 if ( isset( $wp_query->post ) ) { 673 $ dummy= wp_parse_args( $args, array(722 $args = wp_parse_args( $args, array( 674 723 'ID' => $wp_query->post->ID, 675 724 'post_status' => $wp_query->post->post_status, 676 725 'post_author' => $wp_query->post->post_author, … … function bp_theme_compat_reset_post( $args = array() ) { 695 744 'comment_status' => $wp_query->post->comment_status, 696 745 'comment_count' => $wp_query->post->comment_count, 697 746 '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,737 747 ) ); 738 748 } 739 749 740 750 // Bail if dummy post is empty. 741 if ( empty( $ dummy) ) {751 if ( empty( $args ) ) { 742 752 return; 743 753 } 744 754 745 755 // Set the $post global. 746 $post = new WP_Post( (object) $dummy);756 $post = bp_theme_compat_create_dummy_post( $args ); 747 757 748 758 // Copy the new post global into the main $wp_query. 749 759 $wp_query->post = $post; … … function bp_theme_compat_reset_post( $args = array() ) { 751 761 752 762 // Prevent comments form from appearing. 753 763 $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; 762 769 763 770 /** 764 771 * 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..4e0b9f9
- + 1 <?php 2 /** 3 * Core component classes. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 */ 8 9 // Exit if accessed directly. 10 defined( 'ABSPATH' ) || exit; 11 12 /** 13 * API for responding and returning a custom oEmbed request. 14 * 15 * @since 2.5.0 16 */ 17 abstract 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 * 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.5.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.5.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.5.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 /** SET UP **************************************************************/ 163 164 /** 165 * Set up properties. 166 * 167 * @since 2.5.0 168 */ 169 protected function setup_properties() { 170 $this->slug_endpoint = sanitize_title( $this->slug_endpoint ); 171 } 172 173 /** 174 * Hooks! We do the dirty work here, so you don't have to! :) 175 * 176 * @since 2.5.0 177 */ 178 protected function setup_hooks() { 179 add_action( 'rest_api_init', array( $this, 'register_route' ) ); 180 add_action( 'embed_content', array( $this, 'inject_content' ) ); 181 182 add_filter( 'embed_template', array( $this, 'filter_template' ) ); 183 add_filter( 'post_embed_url', array( $this, 'filter_embed_url' ) ); 184 add_filter( 'embed_html', array( $this, 'filter_embed_html' ) ); 185 add_filter( 'oembed_discovery_links', array( $this, 'add_oembed_discovery_links' ) ); 186 } 187 188 /** HOOKS ***************************************************************/ 189 190 /** 191 * Register the oEmbed REST API route. 192 * 193 * @since 2.5.0 194 */ 195 public function register_route() { 196 /** This filter is documented in wp-includes/class-wp-oembed-controller.php */ 197 $maxwidth = apply_filters( 'oembed_default_width', 600 ); 198 199 // Required arguments. 200 $args = array( 201 'url' => array( 202 'required' => true, 203 'sanitize_callback' => 'esc_url_raw', 204 ), 205 'format' => array( 206 'default' => 'json', 207 'sanitize_callback' => 'wp_oembed_ensure_format', 208 ), 209 'maxwidth' => array( 210 'default' => $maxwidth, 211 'sanitize_callback' => 'absint', 212 ) 213 ); 214 215 // Merge custom arguments here. 216 $args = $args + (array) $this->set_route_args(); 217 218 register_rest_route( 'oembed/1.0', "/embed/{$this->slug_endpoint}", array( 219 array( 220 'methods' => WP_REST_Server::READABLE, 221 'callback' => array( $this, 'get_item' ), 222 'args' => $args 223 ), 224 ) ); 225 } 226 227 /** 228 * Filters the embed template. 229 * 230 * Override if needed. 231 * 232 * @since 2.5.0 233 * 234 * @param string $template File path to current embed template. 235 * @return string 236 */ 237 public function filter_template( $template ) { 238 if ( ! $this->is_page() || is_404() ) { 239 return $template; 240 } 241 242 // Embed template hierarchy! 243 return bp_locate_template( array( 244 'assets/embeds/template.php' 245 ) ); 246 } 247 248 /** 249 * Adds oEmbed discovery links on single activity pages. 250 * 251 * @since 2.5.0 252 * 253 * @param string $retval Current discovery links. 254 * @return string 255 */ 256 public function add_oembed_discovery_links( $retval ) { 257 if ( ! $this->is_page() ) { 258 return $retval; 259 } 260 261 $permalink = $this->set_permalink(); 262 if ( empty( $permalink ) ) { 263 return $retval; 264 } 265 266 add_filter( 'rest_url' , array( $this, 'filter_rest_url' ) ); 267 268 $retval = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink ) ) . '" />' . "\n"; 269 270 if ( class_exists( 'SimpleXMLElement' ) ) { 271 $retval .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink, 'xml' ) ) . '" />' . "\n"; 272 } 273 274 remove_filter( 'rest_url' , array( $this, 'filter_rest_url' ) ); 275 276 return $retval; 277 } 278 279 /** 280 * Callback for the API endpoint. 281 * 282 * Returns the JSON object for the item. 283 * 284 * @since 2.5.0 285 * 286 * @param WP_REST_Request $request Full data about the request. 287 * @return WP_Error|array oEmbed response data or WP_Error on failure. 288 */ 289 public function get_item( $request ) { 290 $url = $request['url']; 291 292 $data = false; 293 294 $item_id = (int) $this->validate_url_to_item_id( $url ); 295 296 if ( ! empty( $item_id ) ) { 297 $item = $this->set_oembed_response_data( $item_id ); 298 299 // Create dummy post to piggyback off of get_oembed_response_data() 300 $post = bp_theme_compat_create_dummy_post( array( 301 'post_author' => $item['user_id'], 302 'post_title' => $item['title'], 303 'post_content' => $item['content'], 304 305 // This passes the get_oembed_response_data() check. 306 'post_status' => 'publish' 307 ) ); 308 309 // Add markers to tell that we're embedding a single activity. 310 // This is needed for various oEmbed response data filtering. 311 if ( empty( buddypress()->{$this->slug_endpoint} ) ) { 312 buddypress()->{$this->slug_endpoint} = new stdClass; 313 } 314 buddypress()->{$this->slug_endpoint}->embedurl_in_progress = $url; 315 buddypress()->{$this->slug_endpoint}->embedid_in_progress = $item_id; 316 317 // Save custom route args as well. 318 $custom_args = array_keys( (array) $this->set_route_args() ); 319 if ( ! empty( $custom_args ) ) { 320 buddypress()->{$this->slug_endpoint}->embedargs_in_progress = array(); 321 322 foreach( $custom_args as $arg ) { 323 if ( isset( $request[ $arg ] ) ) { 324 buddypress()->{$this->slug_endpoint}->embedargs_in_progress[ $arg ] = $request[ $arg ]; 325 } 326 } 327 } 328 329 // Use WP's oEmbed response data function. 330 $data = get_oembed_response_data( $post, $request['maxwidth'] ); 331 332 // Set custom 'author_url' if we have one. 333 if ( ! empty( $item['author_url'] ) ) { 334 $data['author_url'] = $item['author_url']; 335 } 336 } 337 338 if ( ! $data ) { 339 return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) ); 340 } 341 342 return $data; 343 } 344 345 /** 346 * Pass our BuddyPress activity permalink for embedding. 347 * 348 * @since 2.5.0 349 * 350 * @see bp_activity_embed_rest_route_callback() 351 * 352 * @param string $retval Current embed URL 353 * @return string 354 */ 355 public function filter_embed_url( $retval ) { 356 if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) { 357 return $retval; 358 } 359 360 $url = $this->is_page() ? $this->set_permalink() : buddypress()->{$this->slug_endpoint}->embedurl_in_progress; 361 $url = trailingslashit( $url ); 362 363 // This is for the 'WordPress Embed' block 364 // @see bp_activity_embed_comments_button() 365 if ( 'the_permalink' !== current_filter() ) { 366 $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) ); 367 368 // Add custom route args to iframe. 369 if ( ! empty( buddypress()->{$this->slug_endpoint}->embedargs_in_progress ) ) { 370 foreach( buddypress()->{$this->slug_endpoint}->embedargs_in_progress as $key => $value ) { 371 $url = add_query_arg( $key, $value, $url ); 372 } 373 } 374 } 375 376 return $url; 377 } 378 379 /** 380 * Filters the embed HTML for the default oEmbed fallback HTML. 381 * 382 * @since 2.5.0 383 * 384 * @param string $retval Current embed HTML 385 * @return string 386 */ 387 public function filter_embed_html( $retval ) { 388 if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) { 389 return $retval; 390 } 391 392 $url = $this->set_permalink(); 393 394 $item_id = $this->is_page() ? $this->validate_url_to_item_id( $url ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress; 395 396 // Change 'Embedded WordPress Post' to custom title. 397 $custom_title = $this->set_iframe_title( $item_id ); 398 if ( ! empty( $custom_title ) ) { 399 $retval = str_replace( __( 'Embedded WordPress Post' ), esc_attr( $custom_title ), $retval ); 400 } 401 402 // Remove default <blockquote> 403 $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 ); 404 405 // Set up new fallback HTML 406 // @todo Maybe use KSES? 407 $fallback_html = $this->set_fallback_html( $item_id ); 408 409 // Add our custom <blockquote> 410 return $fallback_html . $retval; 411 } 412 413 /** 414 * Append our custom slug endpoint to oEmbed endpoint URL. 415 * 416 * Meant to be used as a filter on 'rest_url' before any call to 417 * {@link get_oembed_endpoint_url()} is used. 418 * 419 * @since 2.5.0 420 * 421 * @see add_oembed_discovery_links() 422 * 423 * @param string $retval Current oEmbed endpoint URL 424 * @return string 425 */ 426 function filter_rest_url( $retval = '' ) { 427 return $retval . "/{$this->slug_endpoint}"; 428 } 429 430 /** 431 * Inject activity content into the embed template. 432 * 433 * @since 2.5.0 434 */ 435 public function inject_content() { 436 if ( ! $this->is_page() ) { 437 return; 438 } 439 440 $this->content(); 441 } 442 } 443 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..1fdae1a
- + 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 bp_activity_embed_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 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/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..beaa782
- + 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 14 p.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 .activity-read-more { 24 margin-left: .5em; 25 } 26 27 .activity-read-more a { 28 color: #b4b9be; 29 } 30 31 .wp-embed-footer { 32 margin-top: 20px; 33 } 34 </style> 35 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 17 if ( ! 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 39 bp_get_asset_template_part( 'embeds/header', bp_current_component() ); 40 41 /** This action is documented in wp-includes/embed-template.php */ 42 do_action( 'embed_content' ); 43 44 bp_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 */ 51 do_action( 'embed_footer' ); 52 ?> 53 </body> 54 </html> 55 No newline at end of file