[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Core component classes. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 2.6.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * API for responding and returning a custom oEmbed request. 15 * 16 * @since 2.6.0 17 */ 18 abstract class BP_Core_oEmbed_Extension { 19 20 /** START PROPERTIES ****************************************************/ 21 22 /** 23 * (required) The slug endpoint. 24 * 25 * Should be your component id. 26 * 27 * @since 2.6.0 28 * 29 * @var string 30 */ 31 public $slug_endpoint = ''; 32 33 /** END PROPERTIES ******************************************************/ 34 35 /** 36 * Constructor. 37 */ 38 final public function __construct() { 39 $this->setup_properties(); 40 41 // Some rudimentary logic checking. 42 if ( empty( $this->slug_endpoint ) ) { 43 return; 44 } 45 46 $this->setup_hooks(); 47 $this->custom_hooks(); 48 } 49 50 /** REQUIRED METHODS ****************************************************/ 51 52 /** 53 * Add content for your oEmbed response here. 54 * 55 * @since 2.6.0 56 * 57 * @return null 58 */ 59 abstract protected function content(); 60 61 /** 62 * Add a check for when you are on the page you want to oEmbed. 63 * 64 * You'll want to return a boolean here. eg. bp_is_single_activity(). 65 * 66 * @since 2.6.0 67 * 68 * @return bool 69 */ 70 abstract protected function is_page(); 71 72 /** 73 * Validate the URL to see if it matches your item ID. 74 * 75 * @since 2.6.0 76 * 77 * @param string $url URL to validate. 78 * @return int Your item ID 79 */ 80 abstract protected function validate_url_to_item_id( $url ); 81 82 /** 83 * Set the oEmbed response data. 84 * 85 * @since 2.6.0 86 * 87 * @param int $item_id Your item ID to do checks against. 88 * @return array Should contain 'content', 'title', 'author_url', 'author_name' as array 89 * keys. 'author_url' and 'author_name' is optional; the rest are required. 90 */ 91 abstract protected function set_oembed_response_data( $item_id ); 92 93 /** 94 * Sets the fallback HTML for the oEmbed response. 95 * 96 * In a WordPress oEmbed item, the fallback HTML is a <blockquote>. This is 97 * usually hidden after the <iframe> is loaded. 98 * 99 * @since 2.6.0 100 * 101 * @param int $item_id Your item ID to do checks against. 102 * @return string Fallback HTML you want to output. 103 */ 104 abstract protected function set_fallback_html( $item_id ); 105 106 /** OPTIONAL METHODS ****************************************************/ 107 108 /** 109 * If your oEmbed endpoint requires additional arguments, set them here. 110 * 111 * @see register_rest_route() View the $args parameter for more info. 112 * 113 * @since 2.6.0 114 * 115 * @return array 116 */ 117 protected function set_route_args() { 118 return array(); 119 } 120 121 /** 122 * Set the iframe title. 123 * 124 * If not set, this will fallback to WP's 'Embedded WordPress Post'. 125 * 126 * @since 2.6.0 127 * 128 * @param int $item_id The item ID to do checks for. 129 */ 130 protected function set_iframe_title( $item_id ) {} 131 132 /** 133 * Do what you need to do here to initialize any custom hooks. 134 * 135 * @since 2.6.0 136 */ 137 protected function custom_hooks() {} 138 139 /** 140 * Set permalink for oEmbed link discovery. 141 * 142 * This method will be called on the page we want to oEmbed. In most cases, 143 * you will not need to override this method. However, if you need to, do 144 * override in your extended class. 145 * 146 * @since 2.6.0 147 */ 148 protected function set_permalink() { 149 $url = bp_get_requested_url(); 150 151 // Remove querystring from bp_get_requested_url(). 152 if ( false !== strpos( bp_get_requested_url(), '?' ) ) { 153 $url = substr( bp_get_requested_url(), 0, strpos( bp_get_requested_url(), '?' ) ); 154 } 155 156 return $url; 157 } 158 159 /** HELPERS *************************************************************/ 160 161 /** 162 * Get the item ID when filtering the oEmbed HTML. 163 * 164 * Should only be used during the 'embed_html' hook. 165 * 166 * @since 2.6.0 167 */ 168 protected function get_item_id() { 169 return $this->is_page() ? $this->validate_url_to_item_id( $this->set_permalink() ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress; 170 } 171 172 /** SET UP **************************************************************/ 173 174 /** 175 * Set up properties. 176 * 177 * @since 2.6.0 178 */ 179 protected function setup_properties() { 180 $this->slug_endpoint = sanitize_title( $this->slug_endpoint ); 181 } 182 183 /** 184 * Hooks! We do the dirty work here, so you don't have to! :) 185 * 186 * More hooks are available in the setup_template_parts() method. 187 * 188 * @since 2.6.0 189 */ 190 protected function setup_hooks() { 191 add_action( 'rest_api_init', array( $this, 'register_route' ) ); 192 add_action( 'bp_embed_content', array( $this, 'inject_content' ) ); 193 194 add_filter( 'embed_template', array( $this, 'setup_template_parts' ) ); 195 add_filter( 'post_embed_url', array( $this, 'filter_embed_url' ) ); 196 add_filter( 'embed_html', array( $this, 'filter_embed_html' ) ); 197 add_filter( 'oembed_discovery_links', array( $this, 'add_oembed_discovery_links' ) ); 198 add_filter( 'rest_pre_serve_request', array( $this, 'oembed_xml_request' ), 20, 4 ); 199 } 200 201 /** HOOKS ***************************************************************/ 202 203 /** 204 * Register the oEmbed REST API route. 205 * 206 * @since 2.6.0 207 */ 208 public function register_route() { 209 /** This filter is documented in wp-includes/class-wp-oembed-controller.php */ 210 $maxwidth = apply_filters( 'oembed_default_width', 600 ); 211 212 // Required arguments. 213 $args = array( 214 'url' => array( 215 'required' => true, 216 'sanitize_callback' => 'esc_url_raw', 217 ), 218 'format' => array( 219 'default' => 'json', 220 'sanitize_callback' => 'wp_oembed_ensure_format', 221 ), 222 'maxwidth' => array( 223 'default' => $maxwidth, 224 'sanitize_callback' => 'absint', 225 ) 226 ); 227 228 // Merge custom arguments here. 229 $args = $args + (array) $this->set_route_args(); 230 231 register_rest_route( 'oembed/1.0', "/embed/{$this->slug_endpoint}", array( 232 array( 233 'methods' => WP_REST_Server::READABLE, 234 'callback' => array( $this, 'get_item' ), 235 'permission_callback' => '__return_true', 236 'args' => $args 237 ), 238 ) ); 239 } 240 241 /** 242 * Set up custom embed template parts for BuddyPress use. 243 * 244 * @since 2.6.0 245 * 246 * @param string $template File path to current embed template. 247 * @return string 248 */ 249 public function setup_template_parts( $template ) { 250 // Determine if we're on our BP page. 251 if ( ! $this->is_page() || is_404() ) { 252 return $template; 253 } 254 255 // Set up some BP-specific embed template overrides. 256 add_action( 'get_template_part_embed', array( $this, 'content_buffer_start' ), -999, 2 ); 257 add_action( 'get_footer', array( $this, 'content_buffer_end' ), -999 ); 258 259 // Return the original WP embed template. 260 return $template; 261 } 262 263 /** 264 * Start object buffer. 265 * 266 * We're going to override WP's get_template_part( 'embed, 'content' ) call 267 * and inject our own template for BuddyPress use. 268 * 269 * @since 2.6.0 270 * 271 * @param string $slug Template slug. 272 * @param string $name Template name. 273 */ 274 public function content_buffer_start( $slug, $name ) { 275 if ( 'embed' !== $slug || 'content' !== $name ) { 276 return; 277 } 278 279 // Start the buffer to wipe out get_template_part( 'embed, 'content' ). 280 ob_start(); 281 } 282 283 /** 284 * End object buffer. 285 * 286 * We're going to override WP's get_template_part( 'embed, 'content' ) call 287 * and inject our own template for BuddyPress use. 288 * 289 * @since 2.6.0 290 * 291 * @param string $name Template name. 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 * Fetch our oEmbed response data to return. 358 * 359 * A simplified version of {@link get_oembed_response_data()}. 360 * 361 * @since 2.6.0 362 * 363 * @link http://oembed.com/ View the 'Response parameters' section for more details. 364 * 365 * @param array $item Custom oEmbed response data. 366 * @param int $width The requested width. 367 * @return array 368 */ 369 protected function get_oembed_response_data( $item, $width ) { 370 $data = bp_parse_args( 371 $item, 372 array( 373 'version' => '1.0', 374 'provider_name' => get_bloginfo( 'name' ), 375 'provider_url' => get_home_url(), 376 'author_name' => get_bloginfo( 'name' ), 377 'author_url' => get_home_url(), 378 'title' => ucfirst( $this->slug_endpoint ), 379 'type' => 'rich', 380 ) 381 ); 382 383 /** This filter is documented in /wp-includes/embed.php */ 384 $min_max_width = apply_filters( 'oembed_min_max_width', array( 385 'min' => 200, 386 'max' => 600 387 ) ); 388 389 $width = min( max( $min_max_width['min'], $width ), $min_max_width['max'] ); 390 $height = max( ceil( $width / 16 * 9 ), 200 ); 391 392 $data['width'] = absint( $width ); 393 $data['height'] = absint( $height ); 394 395 // Set 'html' parameter. 396 if ( 'video' === $data['type'] || 'rich' === $data['type'] ) { 397 // Fake a WP post so we can use get_post_embed_html(). 398 $post = new stdClass; 399 $post->post_content = $data['content']; 400 $post->post_title = $data['title']; 401 402 $data['html'] = get_post_embed_html( $data['width'], $data['height'], $post ); 403 } 404 405 // Remove temporary parameters. 406 unset( $data['content'] ); 407 408 return $data; 409 } 410 411 /** 412 * Callback for the API endpoint. 413 * 414 * Returns the JSON object for the item. 415 * 416 * @since 2.6.0 417 * 418 * @param WP_REST_Request $request Full data about the request. 419 * @return WP_Error|array oEmbed response data or WP_Error on failure. 420 */ 421 public function get_item( $request ) { 422 $url = $request['url']; 423 424 $data = false; 425 426 $item_id = (int) $this->validate_url_to_item_id( $url ); 427 428 if ( ! empty( $item_id ) ) { 429 // Add markers to tell that we're embedding a single activity. 430 // This is needed for various oEmbed response data filtering. 431 if ( ! isset( buddypress()->{$this->slug_endpoint} ) || ! buddypress()->{$this->slug_endpoint} ) { 432 buddypress()->{$this->slug_endpoint} = new stdClass; 433 } 434 buddypress()->{$this->slug_endpoint}->embedurl_in_progress = $url; 435 buddypress()->{$this->slug_endpoint}->embedid_in_progress = $item_id; 436 437 // Save custom route args as well. 438 $custom_args = array_keys( (array) $this->set_route_args() ); 439 if ( ! empty( $custom_args ) ) { 440 buddypress()->{$this->slug_endpoint}->embedargs_in_progress = array(); 441 442 foreach( $custom_args as $arg ) { 443 if ( isset( $request[ $arg ] ) ) { 444 buddypress()->{$this->slug_endpoint}->embedargs_in_progress[ $arg ] = $request[ $arg ]; 445 } 446 } 447 } 448 449 // Grab custom oEmbed response data. 450 $item = $this->set_oembed_response_data( $item_id ); 451 452 // Set oEmbed response data. 453 $data = $this->get_oembed_response_data( $item, $request['maxwidth'] ); 454 } 455 456 if ( ! $data ) { 457 return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) ); 458 } 459 460 return $data; 461 } 462 463 /** 464 * If oEmbed request wants XML, return XML instead of JSON. 465 * 466 * Basically a copy of {@link _oembed_rest_pre_serve_request()}. Unfortunate 467 * that we have to duplicate this just for a URL check. 468 * 469 * @since 2.6.0 470 * 471 * @param bool $served Whether the request has already been served. 472 * @param WP_HTTP_ResponseInterface $result Result to send to the client. Usually a WP_REST_Response. 473 * @param WP_REST_Request $request Request used to generate the response. 474 * @param WP_REST_Server $server Server instance. 475 * @return bool 476 */ 477 public function oembed_xml_request( $served, $result, $request, $server ) { 478 $params = $request->get_params(); 479 480 if ( ! isset( $params['format'] ) || 'xml' !== $params['format'] ) { 481 return $served; 482 } 483 484 // Validate URL against our oEmbed endpoint. If not valid, bail. 485 // This is our mod to _oembed_rest_pre_serve_request(). 486 $query_params = $request->get_query_params(); 487 if ( ! isset( $query_params['url'] ) || false === $this->validate_url_to_item_id( $query_params['url'] ) ) { 488 return $served; 489 } 490 491 // Embed links inside the request. 492 $data = $server->response_to_data( $result, false ); 493 494 if ( ! class_exists( 'SimpleXMLElement' ) ) { 495 status_header( 501 ); 496 die( get_status_header_desc( 501 ) ); 497 } 498 499 $result = _oembed_create_xml( $data ); 500 501 // Bail if there's no XML. 502 if ( ! $result ) { 503 status_header( 501 ); 504 return get_status_header_desc( 501 ); 505 } 506 507 if ( ! headers_sent() ) { 508 $server->send_header( 'Content-Type', 'text/xml; charset=' . get_option( 'blog_charset' ) ); 509 } 510 511 echo $result; 512 513 return true; 514 } 515 516 /** 517 * Pass our BuddyPress activity permalink for embedding. 518 * 519 * @since 2.6.0 520 * 521 * @see bp_activity_embed_rest_route_callback() 522 * 523 * @param string $retval Current embed URL. 524 * @return string 525 */ 526 public function filter_embed_url( $retval ) { 527 if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) { 528 return $retval; 529 } 530 531 $url = $this->is_page() ? $this->set_permalink() : buddypress()->{$this->slug_endpoint}->embedurl_in_progress; 532 $url = trailingslashit( $url ); 533 534 // This is for the 'WordPress Embed' block 535 // @see bp_activity_embed_comments_button(). 536 if ( 'the_permalink' !== current_filter() ) { 537 $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) ); 538 539 // Add custom route args to iframe. 540 if ( isset( buddypress()->{$this->slug_endpoint}->embedargs_in_progress ) && buddypress()->{$this->slug_endpoint}->embedargs_in_progress ) { 541 foreach( buddypress()->{$this->slug_endpoint}->embedargs_in_progress as $key => $value ) { 542 $url = add_query_arg( $key, $value, $url ); 543 } 544 } 545 } 546 547 return $url; 548 } 549 550 /** 551 * Filters the embed HTML for our BP oEmbed endpoint. 552 * 553 * @since 2.6.0 554 * 555 * @param string $retval Current embed HTML. 556 * @return string 557 */ 558 public function filter_embed_html( $retval ) { 559 if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) { 560 return $retval; 561 } 562 563 $url = $this->set_permalink(); 564 565 $item_id = $this->is_page() ? $this->validate_url_to_item_id( $url ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress; 566 567 // Change 'Embedded WordPress Post' to custom title. 568 $custom_title = $this->set_iframe_title( $item_id ); 569 if ( ! empty( $custom_title ) ) { 570 $title_pos = strpos( $retval, 'title=' ) + 7; 571 $title_end_pos = strpos( $retval, '"', $title_pos ); 572 573 $retval = substr_replace( $retval, esc_attr( $custom_title ), $title_pos, $title_end_pos - $title_pos ); 574 } 575 576 // Add 'max-width' CSS attribute to IFRAME. 577 // This will make our oEmbeds responsive. 578 if ( false === strpos( $retval, 'style="max-width' ) ) { 579 $retval = str_replace( '<iframe', '<iframe style="max-width:100%"', $retval ); 580 } 581 582 // Remove default <blockquote>. 583 $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 ); 584 585 // Set up new fallback HTML 586 // @todo Maybe use KSES? 587 $fallback_html = $this->set_fallback_html( $item_id ); 588 589 /** 590 * Dynamic filter to return BP oEmbed HTML. 591 * 592 * @since 2.6.0 593 * 594 * @var string $retval 595 */ 596 return apply_filters( "bp_{$this->slug_endpoint}_embed_html", $fallback_html . $retval ); 597 } 598 599 /** 600 * Append our custom slug endpoint to oEmbed endpoint URL. 601 * 602 * Meant to be used as a filter on 'rest_url' before any call to 603 * {@link get_oembed_endpoint_url()} is used. 604 * 605 * @since 2.6.0 606 * 607 * @see add_oembed_discovery_links() 608 * 609 * @param string $retval Current oEmbed endpoint URL. 610 * @return string 611 */ 612 public function filter_rest_url( $retval = '' ) { 613 return $retval . "/{$this->slug_endpoint}"; 614 } 615 616 /** 617 * Inject content into the embed template. 618 * 619 * @since 2.6.0 620 */ 621 public function inject_content() { 622 if ( ! $this->is_page() ) { 623 return; 624 } 625 626 $this->content(); 627 } 628 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Nov 5 01:00:58 2024 | Cross-referenced by PHPXref 0.7.1 |