[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Functions related to embedding single activity items externally. 4 * 5 * @since 2.6.0 6 * 7 * @package BuddyPress 8 * @subpackage ActivityEmbeds 9 */ 10 11 // Exit if accessed directly. 12 defined( 'ABSPATH' ) || exit; 13 14 /** 15 * Loads our activity oEmbed component. 16 * 17 * @since 2.6.0 18 */ 19 function bp_activity_setup_oembed() { 20 buddypress()->activity->oembed = new BP_Activity_oEmbed_Extension; 21 } 22 add_action( 'bp_loaded', 'bp_activity_setup_oembed' ); 23 24 /** 25 * Catch links in embed excerpt so top.location.href can be added. 26 * 27 * Due to <iframe sandbox="allow-top-navigation">, links in embeds can only be 28 * clicked if invoked with top.location.href via JS. 29 * 30 * @since 2.6.0 31 * 32 * @param string $text Embed excerpt 33 * @return string 34 */ 35 function bp_activity_embed_excerpt_onclick_location_filter( $text ) { 36 return preg_replace_callback( '/<a\s+[^>]*href=\"([^\"]*)\"/iU', 'bp_activity_embed_excerpt_onclick_location_filter_callback', $text ); 37 } 38 /** 39 * Add onclick="top.location.href" to a link. 40 * 41 * @since 2.6.0 42 * 43 * @param array $matches Items matched by bp_activity_embed_excerpt_onclick_location_filter(). 44 * @return string 45 */ 46 function bp_activity_embed_excerpt_onclick_location_filter_callback( $matches ) { 47 return sprintf( '<a href="%1$s" onclick="top.location.href=\'%1$s\'"', $matches[1] ); 48 } 49 50 /** 51 * Add inline styles for BP activity embeds. 52 * 53 * @since 2.6.0 54 */ 55 function bp_activity_embed_add_inline_styles() { 56 if ( false === bp_is_single_activity() ) { 57 return; 58 } 59 60 $min = bp_core_get_minified_asset_suffix(); 61 62 if ( is_rtl() ) { 63 $css = bp_locate_template_asset( "css/embeds-activity-rtl{$min}.css" ); 64 } else { 65 $css = bp_locate_template_asset( "css/embeds-activity{$min}.css" ); 66 } 67 68 // Bail if file wasn't found. 69 if ( false === $css ) { 70 return; 71 } 72 73 // Grab contents of CSS file and do some rudimentary CSS protection. 74 $css = file_get_contents( $css['file'] ); 75 $css = wp_kses( $css, array( "\'", '\"' ) ); 76 77 printf( '<style type="text/css">%s</style>', $css ); 78 } 79 add_action( 'embed_head', 'bp_activity_embed_add_inline_styles', 20 ); 80 81 /** 82 * Query for the activity item on the activity embed template. 83 * 84 * Basically a wrapper for {@link bp_has_activities()}, but allows us to 85 * use the activity loop without requerying for it again. 86 * 87 * @since 2.6.0 88 * 89 * @param int $activity_id The activity ID. 90 * @return bool 91 */ 92 function bp_activity_embed_has_activity( $activity_id = 0 ) { 93 global $activities_template; 94 95 if ( empty( $activity_id ) ) { 96 return false; 97 } 98 99 if ( ! empty( $activities_template->activities ) ) { 100 $activity = (array) $activities_template->activities; 101 $activity = reset( $activity ); 102 103 // No need to requery if we already got the embed activity. 104 if ( (int) $activity_id === $activity->id ) { 105 return $activities_template->has_activities(); 106 } 107 } 108 109 return bp_has_activities( array( 110 'display_comments' => 'threaded', 111 'show_hidden' => true, 112 'include' => (int) $activity_id, 113 ) ); 114 } 115 116 /** 117 * Outputs excerpt for an activity embed item. 118 * 119 * @since 2.6.0 120 */ 121 function bp_activity_embed_excerpt( $content = '' ) { 122 echo bp_activity_get_embed_excerpt( $content ); 123 } 124 125 /** 126 * Generates excerpt for an activity embed item. 127 * 128 * @since 2.6.0 129 * 130 * @param string $content The content to generate an excerpt for. 131 * @return string 132 */ 133 function bp_activity_get_embed_excerpt( $content = '' ) { 134 if ( empty( $content ) && ! empty( $GLOBALS['activities_template']->in_the_loop ) ) { 135 $content = $GLOBALS['activities_template']->activity->content; 136 } 137 138 /* 139 * bp_activity_truncate_entry() includes the 'Read More' link, which is why 140 * we're using this instead of bp_create_excerpt(). 141 */ 142 $content = html_entity_decode( $content ); 143 $content = bp_activity_truncate_entry( $content, array( 144 'html' => false, 145 'filter_shortcodes' => true, 146 'strip_tags' => true, 147 'force_truncate' => true 148 ) ); 149 150 /** 151 * Filter the activity embed excerpt. 152 * 153 * @since 2.6.0 154 * 155 * @var string $content Embed Excerpt. 156 * @var string $unmodified_content Unmodified activity content. 157 */ 158 return apply_filters( 'bp_activity_get_embed_excerpt', $content, $GLOBALS['activities_template']->activity->content ); 159 } 160 161 /** 162 * Outputs the first embedded item in the activity oEmbed template. 163 * 164 * @since 2.6.0 165 */ 166 function bp_activity_embed_media() { 167 // Bail if oEmbed request explicitly hides media. 168 if ( isset( $_GET['hide_media'] ) && true == wp_validate_boolean( $_GET['hide_media'] ) ) { 169 /** 170 * Do something after media is rendered for an activity oEmbed item. 171 * 172 * @since 2.6.0 173 */ 174 do_action( 'bp_activity_embed_after_media' ); 175 176 return; 177 } 178 179 /** 180 * Should we display media in the oEmbed template? 181 * 182 * @since 2.6.0 183 * 184 * @param bool $retval Defaults to true. 185 */ 186 $allow_media = apply_filters( 'bp_activity_embed_display_media', true ); 187 188 // Find oEmbeds from only WP registered providers. 189 bp_remove_all_filters( 'oembed_providers' ); 190 $media = bp_core_extract_media_from_content( $GLOBALS['activities_template']->activity->content, 'embeds' ); 191 bp_restore_all_filters( 'oembed_providers' ); 192 193 // oEmbeds have precedence over inline video / audio. 194 if ( isset( $media['embeds'] ) && true === $allow_media ) { 195 // Autoembed first URL. 196 $oembed_defaults = wp_embed_defaults(); 197 $oembed_args = array( 198 'width' => $oembed_defaults['width'], 199 'height' => $oembed_defaults['height'], 200 'discover' => true 201 ); 202 $url = $media['embeds'][0]['url']; 203 $cachekey = '_oembed_response_' . md5( $url . serialize( $oembed_args ) ); 204 205 // Try to fetch oEmbed response from meta. 206 $oembed = bp_activity_get_meta( bp_get_activity_id(), $cachekey ); 207 208 // No cache, so fetch full oEmbed response now! 209 if ( '' === $oembed ) { 210 $o = _wp_oembed_get_object(); 211 $oembed = $o->fetch( $o->get_provider( $url, $oembed_args ), $url, $oembed_args ); 212 213 // Cache oEmbed response. 214 bp_activity_update_meta( bp_get_activity_id(), $cachekey, $oembed ); 215 } 216 217 $content = ''; 218 219 /** 220 * Filters the default embed display max width. 221 * 222 * This is used if the oEmbed response does not return a thumbnail width. 223 * 224 * @since 2.6.0 225 * 226 * @param int $width. 227 */ 228 $width = (int) apply_filters( 'bp_activity_embed_display_media_width', 550 ); 229 230 // Set thumbnail. 231 if ( 'photo' === $oembed->type ) { 232 $thumbnail = $oembed->url; 233 } elseif ( isset( $oembed->thumbnail_url ) ) { 234 $thumbnail = $oembed->thumbnail_url; 235 236 /* Non-oEmbed standard attributes */ 237 // Mixcloud. 238 } elseif ( isset( $oembed->image ) ) { 239 $thumbnail = $oembed->image; 240 // ReverbNation. 241 } elseif ( isset( $oembed->{'thumbnail-url'} ) ) { 242 $thumbnail = $oembed->{'thumbnail-url'}; 243 } 244 245 // Display thumb and related oEmbed meta. 246 if ( true === isset ( $thumbnail ) ) { 247 $play_icon = $caption = ''; 248 249 // Add play icon for non-photos. 250 if ( 'photo' !== $oembed->type ) { 251 /** 252 * ion-play icon from Ionicons. 253 * 254 * @link http://ionicons.com/ 255 * @license MIT 256 */ 257 $play_icon = <<<EOD 258 <svg id="Layer_1" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"/></svg> 259 EOD; 260 261 $play_icon = sprintf( '<a rel="nofollow" class="play-btn" href="%1$s" onclick="top.location.href=\'%1$s\'">%2$s</a>', esc_url( $url ), $play_icon ); 262 } 263 264 // Thumb width. 265 $thumb_width = isset( $oembed->thumbnail_width ) && 'photo' !== $oembed->type && (int) $oembed->thumbnail_width < 550 ? (int) $oembed->thumbnail_width : $width; 266 267 $float_width = 350; 268 269 // Set up thumb. 270 $content = sprintf( '<div class="thumb" style="max-width:%1$spx">%2$s<a href="%3$s" rel="nofollow" onclick="top.location.href=\'%3$s\'"><img loading="lazy" src="%4$s" alt="" /></a></div>', $thumb_width, $play_icon, esc_url( $url ), esc_url( $thumbnail ) ); 271 272 // Show title. 273 if ( isset( $oembed->title ) ) { 274 $caption .= sprintf( '<p class="caption-title"><strong>%s</strong></p>', apply_filters( 'single_post_title', $oembed->title ) ); 275 } 276 277 // Show description (non-oEmbed standard). 278 if ( isset( $oembed->description ) ) { 279 $caption .= sprintf( '<div class="caption-description">%s</div>', apply_filters( 'bp_activity_get_embed_excerpt', $oembed->description ) ); 280 } 281 282 // Show author info. 283 if ( isset( $oembed->provider_name ) && isset( $oembed->author_name ) ) { 284 /* translators: 1: oEmbed author. 2: oEmbed provider. eg. By BuddyPress on YouTube. */ 285 $anchor_text = sprintf( __( 'By %1$s on %2$s', 'buddypress' ), $oembed->author_name, $oembed->provider_name ); 286 287 } elseif ( isset( $oembed->provider_name ) ) { 288 /* translators: %s: oEmbed provider. */ 289 $anchor_text = sprintf( __( 'View on %s', 'buddypress' ), $oembed->provider_name ); 290 } 291 292 if ( true === isset( $anchor_text ) ) { 293 $caption .= sprintf( '<a rel="nofollow" href="%1$s" onclick="top.location.href=\'%1$s\'">%2$s</a>', esc_url( $url ), apply_filters( 'the_title', $anchor_text ) ); 294 } 295 296 // Set up caption. 297 if ( '' !== $caption ) { 298 $css_class = isset( $oembed->provider_name ) ? sprintf( ' provider-%s', sanitize_html_class( strtolower( $oembed->provider_name ) ) ) : ''; 299 $caption = sprintf( '<div class="caption%1$s" style="width:%2$s">%3$s</div>', 300 $css_class, 301 $thumb_width > $float_width ? 100 . '%' : round( ( $width - (int) $thumb_width ) / $width * 100 ) . '%', 302 $caption 303 ); 304 305 $content .= $caption; 306 } 307 } 308 309 // Print rich content. 310 if ( '' !== $content ) { 311 printf( '<div class="bp-activity-embed-display-media %s" style="max-width:%spx">%s</div>', 312 $thumb_width < $float_width ? 'two-col' : 'one-col', 313 $thumb_width < $float_width ? $width : $thumb_width, 314 $content 315 ); 316 } 317 318 // Video / audio. 319 } elseif ( true === $allow_media ) { 320 // Call BP_Embed if it hasn't already loaded. 321 bp_embed_init(); 322 323 // Run shortcode and embed routine. 324 $content = buddypress()->embed->run_shortcode( $GLOBALS['activities_template']->activity->content ); 325 $content = buddypress()->embed->autoembed( $content ); 326 327 // Try to find inline video / audio. 328 $media = bp_core_extract_media_from_content( $content, 96 ); 329 330 // Video takes precedence. HTML5-only. 331 if ( isset( $media['videos'] ) && 'shortcodes' === $media['videos'][0]['source'] ) { 332 printf( '<video controls preload="metadata"><source src="%1$s"><p>%2$s</p></video>', 333 esc_url( $media['videos'][0]['url'] ), 334 esc_html__( 'Your browser does not support HTML5 video', 'buddypress' ) 335 ); 336 337 // No video? Try audio. HTML5-only. 338 } elseif ( isset( $media['audio'] ) && 'shortcodes' === $media['audio'][0]['source'] ) { 339 printf( '<audio controls preload="metadata"><source src="%1$s"><p>%2$s</p></audio>', 340 esc_url( $media['audio'][0]['url'] ), 341 esc_html__( 'Your browser does not support HTML5 audio', 'buddypress' ) 342 ); 343 } 344 345 } 346 347 /** This hook is documented in /bp-activity/bp-activity-embeds.php */ 348 do_action( 'bp_activity_embed_after_media' ); 349 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:57 2024 | Cross-referenced by PHPXref 0.7.1 |