[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * oEmbed API: Top-level oEmbed functionality 4 * 5 * @package WordPress 6 * @subpackage oEmbed 7 * @since 4.4.0 8 */ 9 10 /** 11 * Registers an embed handler. 12 * 13 * Should probably only be used for sites that do not support oEmbed. 14 * 15 * @since 2.9.0 16 * 17 * @global WP_Embed $wp_embed WordPress Embed object. 18 * 19 * @param string $id An internal ID/name for the handler. Needs to be unique. 20 * @param string $regex The regex that will be used to see if this handler should be used for a URL. 21 * @param callable $callback The callback function that will be called if the regex is matched. 22 * @param int $priority Optional. Used to specify the order in which the registered handlers will 23 * be tested. Default 10. 24 */ 25 function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) { 26 global $wp_embed; 27 $wp_embed->register_handler( $id, $regex, $callback, $priority ); 28 } 29 30 /** 31 * Unregisters a previously-registered embed handler. 32 * 33 * @since 2.9.0 34 * 35 * @global WP_Embed $wp_embed WordPress Embed object. 36 * 37 * @param string $id The handler ID that should be removed. 38 * @param int $priority Optional. The priority of the handler to be removed. Default 10. 39 */ 40 function wp_embed_unregister_handler( $id, $priority = 10 ) { 41 global $wp_embed; 42 $wp_embed->unregister_handler( $id, $priority ); 43 } 44 45 /** 46 * Creates default array of embed parameters. 47 * 48 * The width defaults to the content width as specified by the theme. If the 49 * theme does not specify a content width, then 500px is used. 50 * 51 * The default height is 1.5 times the width, or 1000px, whichever is smaller. 52 * 53 * The {@see 'embed_defaults'} filter can be used to adjust either of these values. 54 * 55 * @since 2.9.0 56 * 57 * @global int $content_width 58 * 59 * @param string $url Optional. The URL that should be embedded. Default empty. 60 * @return int[] { 61 * Indexed array of the embed width and height in pixels. 62 * 63 * @type int $0 The embed width. 64 * @type int $1 The embed height. 65 * } 66 */ 67 function wp_embed_defaults( $url = '' ) { 68 if ( ! empty( $GLOBALS['content_width'] ) ) { 69 $width = (int) $GLOBALS['content_width']; 70 } 71 72 if ( empty( $width ) ) { 73 $width = 500; 74 } 75 76 $height = min( (int) ceil( $width * 1.5 ), 1000 ); 77 78 /** 79 * Filters the default array of embed dimensions. 80 * 81 * @since 2.9.0 82 * 83 * @param int[] $size { 84 * Indexed array of the embed width and height in pixels. 85 * 86 * @type int $0 The embed width. 87 * @type int $1 The embed height. 88 * } 89 * @param string $url The URL that should be embedded. 90 */ 91 return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url ); 92 } 93 94 /** 95 * Attempts to fetch the embed HTML for a provided URL using oEmbed. 96 * 97 * @since 2.9.0 98 * 99 * @see WP_oEmbed 100 * 101 * @param string $url The URL that should be embedded. 102 * @param array|string $args { 103 * Optional. Additional arguments for retrieving embed HTML. Default empty. 104 * 105 * @type int|string $width Optional. The `maxwidth` value passed to the provider URL. 106 * @type int|string $height Optional. The `maxheight` value passed to the provider URL. 107 * @type bool $discover Optional. Determines whether to attempt to discover link tags 108 * at the given URL for an oEmbed provider when the provider URL 109 * is not found in the built-in providers list. Default true. 110 * } 111 * @return string|false The embed HTML on success, false on failure. 112 */ 113 function wp_oembed_get( $url, $args = '' ) { 114 $oembed = _wp_oembed_get_object(); 115 return $oembed->get_html( $url, $args ); 116 } 117 118 /** 119 * Returns the initialized WP_oEmbed object. 120 * 121 * @since 2.9.0 122 * @access private 123 * 124 * @return WP_oEmbed object. 125 */ 126 function _wp_oembed_get_object() { 127 static $wp_oembed = null; 128 129 if ( is_null( $wp_oembed ) ) { 130 $wp_oembed = new WP_oEmbed(); 131 } 132 return $wp_oembed; 133 } 134 135 /** 136 * Adds a URL format and oEmbed provider URL pair. 137 * 138 * @since 2.9.0 139 * 140 * @see WP_oEmbed 141 * 142 * @param string $format The format of URL that this provider can handle. You can use asterisks 143 * as wildcards. 144 * @param string $provider The URL to the oEmbed provider. 145 * @param bool $regex Optional. Whether the `$format` parameter is in a RegEx format. Default false. 146 */ 147 function wp_oembed_add_provider( $format, $provider, $regex = false ) { 148 if ( did_action( 'plugins_loaded' ) ) { 149 $oembed = _wp_oembed_get_object(); 150 $oembed->providers[ $format ] = array( $provider, $regex ); 151 } else { 152 WP_oEmbed::_add_provider_early( $format, $provider, $regex ); 153 } 154 } 155 156 /** 157 * Removes an oEmbed provider. 158 * 159 * @since 3.5.0 160 * 161 * @see WP_oEmbed 162 * 163 * @param string $format The URL format for the oEmbed provider to remove. 164 * @return bool Was the provider removed successfully? 165 */ 166 function wp_oembed_remove_provider( $format ) { 167 if ( did_action( 'plugins_loaded' ) ) { 168 $oembed = _wp_oembed_get_object(); 169 170 if ( isset( $oembed->providers[ $format ] ) ) { 171 unset( $oembed->providers[ $format ] ); 172 return true; 173 } 174 } else { 175 WP_oEmbed::_remove_provider_early( $format ); 176 } 177 178 return false; 179 } 180 181 /** 182 * Determines if default embed handlers should be loaded. 183 * 184 * Checks to make sure that the embeds library hasn't already been loaded. If 185 * it hasn't, then it will load the embeds library. 186 * 187 * @since 2.9.0 188 * 189 * @see wp_embed_register_handler() 190 */ 191 function wp_maybe_load_embeds() { 192 /** 193 * Filters whether to load the default embed handlers. 194 * 195 * Returning a falsey value will prevent loading the default embed handlers. 196 * 197 * @since 2.9.0 198 * 199 * @param bool $maybe_load_embeds Whether to load the embeds library. Default true. 200 */ 201 if ( ! apply_filters( 'load_default_embeds', true ) ) { 202 return; 203 } 204 205 wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' ); 206 207 /** 208 * Filters the audio embed handler callback. 209 * 210 * @since 3.6.0 211 * 212 * @param callable $handler Audio embed handler callback function. 213 */ 214 wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . implode( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 ); 215 216 /** 217 * Filters the video embed handler callback. 218 * 219 * @since 3.6.0 220 * 221 * @param callable $handler Video embed handler callback function. 222 */ 223 wp_embed_register_handler( 'video', '#^https?://.+?\.(' . implode( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 ); 224 } 225 226 /** 227 * YouTube iframe embed handler callback. 228 * 229 * Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is. 230 * 231 * @since 4.0.0 232 * 233 * @global WP_Embed $wp_embed WordPress Embed object. 234 * 235 * @param array $matches The RegEx matches from the provided regex when calling 236 * wp_embed_register_handler(). 237 * @param array $attr Embed attributes. 238 * @param string $url The original URL that was matched by the regex. 239 * @param array $rawattr The original unmodified attributes. 240 * @return string The embed HTML. 241 */ 242 function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) { 243 global $wp_embed; 244 $embed = $wp_embed->autoembed( sprintf( 'https://youtube.com/watch?v=%s', urlencode( $matches[2] ) ) ); 245 246 /** 247 * Filters the YouTube embed output. 248 * 249 * @since 4.0.0 250 * 251 * @see wp_embed_handler_youtube() 252 * 253 * @param string $embed YouTube embed output. 254 * @param array $attr An array of embed attributes. 255 * @param string $url The original URL that was matched by the regex. 256 * @param array $rawattr The original unmodified attributes. 257 */ 258 return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr ); 259 } 260 261 /** 262 * Audio embed handler callback. 263 * 264 * @since 3.6.0 265 * 266 * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler(). 267 * @param array $attr Embed attributes. 268 * @param string $url The original URL that was matched by the regex. 269 * @param array $rawattr The original unmodified attributes. 270 * @return string The embed HTML. 271 */ 272 function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) { 273 $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) ); 274 275 /** 276 * Filters the audio embed output. 277 * 278 * @since 3.6.0 279 * 280 * @param string $audio Audio embed output. 281 * @param array $attr An array of embed attributes. 282 * @param string $url The original URL that was matched by the regex. 283 * @param array $rawattr The original unmodified attributes. 284 */ 285 return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr ); 286 } 287 288 /** 289 * Video embed handler callback. 290 * 291 * @since 3.6.0 292 * 293 * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler(). 294 * @param array $attr Embed attributes. 295 * @param string $url The original URL that was matched by the regex. 296 * @param array $rawattr The original unmodified attributes. 297 * @return string The embed HTML. 298 */ 299 function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) { 300 $dimensions = ''; 301 if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) { 302 $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] ); 303 $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] ); 304 } 305 $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) ); 306 307 /** 308 * Filters the video embed output. 309 * 310 * @since 3.6.0 311 * 312 * @param string $video Video embed output. 313 * @param array $attr An array of embed attributes. 314 * @param string $url The original URL that was matched by the regex. 315 * @param array $rawattr The original unmodified attributes. 316 */ 317 return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr ); 318 } 319 320 /** 321 * Registers the oEmbed REST API route. 322 * 323 * @since 4.4.0 324 */ 325 function wp_oembed_register_route() { 326 $controller = new WP_oEmbed_Controller(); 327 $controller->register_routes(); 328 } 329 330 /** 331 * Adds oEmbed discovery links in the head element of the website. 332 * 333 * @since 4.4.0 334 * @since 6.8.0 Output was adjusted to only embed if the post supports it. 335 */ 336 function wp_oembed_add_discovery_links() { 337 $output = ''; 338 339 if ( is_singular() && is_post_embeddable() ) { 340 $output .= '<link rel="alternate" title="' . _x( 'oEmbed (JSON)', 'oEmbed resource link name' ) . '" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n"; 341 342 if ( class_exists( 'SimpleXMLElement' ) ) { 343 $output .= '<link rel="alternate" title="' . _x( 'oEmbed (XML)', 'oEmbed resource link name' ) . '" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n"; 344 } 345 } 346 347 /** 348 * Filters the oEmbed discovery links HTML. 349 * 350 * @since 4.4.0 351 * 352 * @param string $output HTML of the discovery links. 353 */ 354 echo apply_filters( 'oembed_discovery_links', $output ); 355 } 356 357 /** 358 * Adds the necessary JavaScript to communicate with the embedded iframes. 359 * 360 * This function is no longer used directly. For back-compat it exists exclusively as a way to indicate that the oEmbed 361 * host JS _should_ be added. In `default-filters.php` there remains this code: 362 * 363 * add_action( 'wp_head', 'wp_oembed_add_host_js' ) 364 * 365 * Historically a site has been able to disable adding the oEmbed host script by doing: 366 * 367 * remove_action( 'wp_head', 'wp_oembed_add_host_js' ) 368 * 369 * In order to ensure that such code still works as expected, this function remains. There is now a `has_action()` check 370 * in `wp_maybe_enqueue_oembed_host_js()` to see if `wp_oembed_add_host_js()` has not been unhooked from running at the 371 * `wp_head` action. 372 * 373 * @since 4.4.0 374 * @deprecated 5.9.0 Use {@see wp_maybe_enqueue_oembed_host_js()} instead. 375 */ 376 function wp_oembed_add_host_js() {} 377 378 /** 379 * Enqueue the wp-embed script if the provided oEmbed HTML contains a post embed. 380 * 381 * In order to only enqueue the wp-embed script on pages that actually contain post embeds, this function checks if the 382 * provided HTML contains post embed markup and if so enqueues the script so that it will get printed in the footer. 383 * 384 * @since 5.9.0 385 * 386 * @param string $html Embed markup. 387 * @return string Embed markup (without modifications). 388 */ 389 function wp_maybe_enqueue_oembed_host_js( $html ) { 390 if ( 391 has_action( 'wp_head', 'wp_oembed_add_host_js' ) 392 && 393 preg_match( '/<blockquote\s[^>]*?wp-embedded-content/', $html ) 394 ) { 395 wp_enqueue_script( 'wp-embed' ); 396 } 397 return $html; 398 } 399 400 /** 401 * Retrieves the URL to embed a specific post in an iframe. 402 * 403 * @since 4.4.0 404 * 405 * @param int|WP_Post $post Optional. Post ID or object. Defaults to the current post. 406 * @return string|false The post embed URL on success, false if the post doesn't exist. 407 */ 408 function get_post_embed_url( $post = null ) { 409 $post = get_post( $post ); 410 411 if ( ! $post ) { 412 return false; 413 } 414 415 $embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' ); 416 $path_conflict = get_page_by_path( str_replace( home_url(), '', $embed_url ), OBJECT, get_post_types( array( 'public' => true ) ) ); 417 418 if ( ! get_option( 'permalink_structure' ) || $path_conflict ) { 419 $embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) ); 420 } 421 422 /** 423 * Filters the URL to embed a specific post. 424 * 425 * @since 4.4.0 426 * 427 * @param string $embed_url The post embed URL. 428 * @param WP_Post $post The corresponding post object. 429 */ 430 return sanitize_url( apply_filters( 'post_embed_url', $embed_url, $post ) ); 431 } 432 433 /** 434 * Retrieves the oEmbed endpoint URL for a given permalink. 435 * 436 * Pass an empty string as the first argument to get the endpoint base URL. 437 * 438 * @since 4.4.0 439 * 440 * @param string $permalink Optional. The permalink used for the `url` query arg. Default empty. 441 * @param string $format Optional. The requested response format. Default 'json'. 442 * @return string The oEmbed endpoint URL. 443 */ 444 function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) { 445 $url = rest_url( 'oembed/1.0/embed' ); 446 447 if ( '' !== $permalink ) { 448 $url = add_query_arg( 449 array( 450 'url' => urlencode( $permalink ), 451 'format' => ( 'json' !== $format ) ? $format : false, 452 ), 453 $url 454 ); 455 } 456 457 /** 458 * Filters the oEmbed endpoint URL. 459 * 460 * @since 4.4.0 461 * 462 * @param string $url The URL to the oEmbed endpoint. 463 * @param string $permalink The permalink used for the `url` query arg. 464 * @param string $format The requested response format. 465 */ 466 return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format ); 467 } 468 469 /** 470 * Retrieves the embed code for a specific post. 471 * 472 * @since 4.4.0 473 * 474 * @param int $width The width for the response. 475 * @param int $height The height for the response. 476 * @param int|WP_Post $post Optional. Post ID or object. Default is global `$post`. 477 * @return string|false Embed code on success, false if post doesn't exist. 478 */ 479 function get_post_embed_html( $width, $height, $post = null ) { 480 $post = get_post( $post ); 481 482 if ( ! $post ) { 483 return false; 484 } 485 486 $embed_url = get_post_embed_url( $post ); 487 488 $secret = wp_generate_password( 10, false ); 489 $embed_url .= "#?secret={$secret}"; 490 491 $output = sprintf( 492 '<blockquote class="wp-embedded-content" data-secret="%1$s"><a href="%2$s">%3$s</a></blockquote>', 493 esc_attr( $secret ), 494 esc_url( get_permalink( $post ) ), 495 get_the_title( $post ) 496 ); 497 498 $output .= sprintf( 499 '<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" data-secret="%5$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>', 500 esc_url( $embed_url ), 501 absint( $width ), 502 absint( $height ), 503 esc_attr( 504 sprintf( 505 /* translators: 1: Post title, 2: Site title. */ 506 __( '“%1$s” — %2$s' ), 507 get_the_title( $post ), 508 get_bloginfo( 'name' ) 509 ) 510 ), 511 esc_attr( $secret ) 512 ); 513 514 /* 515 * Note that the script must be placed after the <blockquote> and <iframe> due to a regexp parsing issue in 516 * `wp_filter_oembed_result()`. Because of the regex pattern starts with `|(<blockquote>.*?</blockquote>)?.*|` 517 * wherein the <blockquote> is marked as being optional, if it is not at the beginning of the string then the group 518 * will fail to match and everything will be matched by `.*` and not included in the group. This regex issue goes 519 * back to WordPress 4.4, so in order to not break older installs this script must come at the end. 520 */ 521 $output .= wp_get_inline_script_tag( 522 file_get_contents( ABSPATH . WPINC . '/js/wp-embed' . wp_scripts_get_suffix() . '.js' ) 523 ); 524 525 /** 526 * Filters the embed HTML output for a given post. 527 * 528 * @since 4.4.0 529 * 530 * @param string $output The default iframe tag to display embedded content. 531 * @param WP_Post $post Current post object. 532 * @param int $width Width of the response. 533 * @param int $height Height of the response. 534 */ 535 return apply_filters( 'embed_html', $output, $post, $width, $height ); 536 } 537 538 /** 539 * Retrieves the oEmbed response data for a given post. 540 * 541 * @since 4.4.0 542 * @since 6.8.0 Output was adjusted to only embed if the post type supports it. 543 * 544 * @param WP_Post|int $post Post ID or post object. 545 * @param int $width The requested width. 546 * @return array|false Response data on success, false if post doesn't exist, 547 * is not publicly viewable or post type is not embeddable. 548 */ 549 function get_oembed_response_data( $post, $width ) { 550 $post = get_post( $post ); 551 $width = absint( $width ); 552 553 if ( ! $post ) { 554 return false; 555 } 556 557 if ( ! is_post_publicly_viewable( $post ) ) { 558 return false; 559 } 560 561 if ( ! is_post_embeddable( $post ) ) { 562 return false; 563 } 564 565 /** 566 * Filters the allowed minimum and maximum widths for the oEmbed response. 567 * 568 * @since 4.4.0 569 * 570 * @param array $min_max_width { 571 * Minimum and maximum widths for the oEmbed response. 572 * 573 * @type int $min Minimum width. Default 200. 574 * @type int $max Maximum width. Default 600. 575 * } 576 */ 577 $min_max_width = apply_filters( 578 'oembed_min_max_width', 579 array( 580 'min' => 200, 581 'max' => 600, 582 ) 583 ); 584 585 $width = min( max( $min_max_width['min'], $width ), $min_max_width['max'] ); 586 $height = max( (int) ceil( $width / 16 * 9 ), 200 ); 587 588 $data = array( 589 'version' => '1.0', 590 'provider_name' => get_bloginfo( 'name' ), 591 'provider_url' => get_home_url(), 592 'author_name' => get_bloginfo( 'name' ), 593 'author_url' => get_home_url(), 594 'title' => get_the_title( $post ), 595 'type' => 'link', 596 ); 597 598 $author = get_userdata( $post->post_author ); 599 600 if ( $author ) { 601 $data['author_name'] = $author->display_name; 602 $data['author_url'] = get_author_posts_url( $author->ID ); 603 } 604 605 /** 606 * Filters the oEmbed response data. 607 * 608 * @since 4.4.0 609 * 610 * @param array $data The response data. 611 * @param WP_Post $post The post object. 612 * @param int $width The requested width. 613 * @param int $height The calculated height. 614 */ 615 return apply_filters( 'oembed_response_data', $data, $post, $width, $height ); 616 } 617 618 619 /** 620 * Retrieves the oEmbed response data for a given URL. 621 * 622 * @since 5.0.0 623 * 624 * @param string $url The URL that should be inspected for discovery `<link>` tags. 625 * @param array $args oEmbed remote get arguments. 626 * @return object|false oEmbed response data if the URL does belong to the current site. False otherwise. 627 */ 628 function get_oembed_response_data_for_url( $url, $args ) { 629 $switched_blog = false; 630 631 if ( is_multisite() ) { 632 $url_parts = wp_parse_args( 633 wp_parse_url( $url ), 634 array( 635 'host' => '', 636 'port' => null, 637 'path' => '/', 638 ) 639 ); 640 641 $qv = array( 642 'domain' => $url_parts['host'] . ( $url_parts['port'] ? ':' . $url_parts['port'] : '' ), 643 'path' => '/', 644 'update_site_meta_cache' => false, 645 ); 646 647 // In case of subdirectory configs, set the path. 648 if ( ! is_subdomain_install() ) { 649 $path = explode( '/', ltrim( $url_parts['path'], '/' ) ); 650 $path = reset( $path ); 651 652 if ( $path ) { 653 $qv['path'] = get_network()->path . $path . '/'; 654 } 655 } 656 657 $sites = get_sites( $qv ); 658 $site = reset( $sites ); 659 660 // Do not allow embeds for deleted/archived/spam sites. 661 if ( ! empty( $site->deleted ) || ! empty( $site->spam ) || ! empty( $site->archived ) ) { 662 return false; 663 } 664 665 if ( $site && get_current_blog_id() !== (int) $site->blog_id ) { 666 switch_to_blog( $site->blog_id ); 667 $switched_blog = true; 668 } 669 } 670 671 $post_id = url_to_postid( $url ); 672 673 /** This filter is documented in wp-includes/class-wp-oembed-controller.php */ 674 $post_id = apply_filters( 'oembed_request_post_id', $post_id, $url ); 675 676 if ( ! $post_id ) { 677 if ( $switched_blog ) { 678 restore_current_blog(); 679 } 680 681 return false; 682 } 683 684 $width = isset( $args['width'] ) ? $args['width'] : 0; 685 686 $data = get_oembed_response_data( $post_id, $width ); 687 688 if ( $switched_blog ) { 689 restore_current_blog(); 690 } 691 692 return $data ? (object) $data : false; 693 } 694 695 696 /** 697 * Filters the oEmbed response data to return an iframe embed code. 698 * 699 * @since 4.4.0 700 * 701 * @param array $data The response data. 702 * @param WP_Post $post The post object. 703 * @param int $width The requested width. 704 * @param int $height The calculated height. 705 * @return array The modified response data. 706 */ 707 function get_oembed_response_data_rich( $data, $post, $width, $height ) { 708 $data['width'] = absint( $width ); 709 $data['height'] = absint( $height ); 710 $data['type'] = 'rich'; 711 $data['html'] = get_post_embed_html( $width, $height, $post ); 712 713 // Add post thumbnail to response if available. 714 $thumbnail_id = false; 715 716 if ( has_post_thumbnail( $post->ID ) ) { 717 $thumbnail_id = get_post_thumbnail_id( $post->ID ); 718 } 719 720 if ( 'attachment' === get_post_type( $post ) ) { 721 if ( wp_attachment_is_image( $post ) ) { 722 $thumbnail_id = $post->ID; 723 } elseif ( wp_attachment_is( 'video', $post ) ) { 724 $thumbnail_id = get_post_thumbnail_id( $post ); 725 $data['type'] = 'video'; 726 } 727 } 728 729 if ( $thumbnail_id ) { 730 list( $thumbnail_url, $thumbnail_width, $thumbnail_height ) = wp_get_attachment_image_src( $thumbnail_id, array( $width, 0 ) ); 731 $data['thumbnail_url'] = $thumbnail_url; 732 $data['thumbnail_width'] = $thumbnail_width; 733 $data['thumbnail_height'] = $thumbnail_height; 734 } 735 736 return $data; 737 } 738 739 /** 740 * Ensures that the specified format is either 'json' or 'xml'. 741 * 742 * @since 4.4.0 743 * 744 * @param string $format The oEmbed response format. Accepts 'json' or 'xml'. 745 * @return string The format, either 'xml' or 'json'. Default 'json'. 746 */ 747 function wp_oembed_ensure_format( $format ) { 748 if ( ! in_array( $format, array( 'json', 'xml' ), true ) ) { 749 return 'json'; 750 } 751 752 return $format; 753 } 754 755 /** 756 * Hooks into the REST API output to print XML instead of JSON. 757 * 758 * This is only done for the oEmbed API endpoint, 759 * which supports both formats. 760 * 761 * @access private 762 * @since 4.4.0 763 * 764 * @param bool $served Whether the request has already been served. 765 * @param WP_HTTP_Response $result Result to send to the client. Usually a `WP_REST_Response`. 766 * @param WP_REST_Request $request Request used to generate the response. 767 * @param WP_REST_Server $server Server instance. 768 * @return true 769 */ 770 function _oembed_rest_pre_serve_request( $served, $result, $request, $server ) { 771 $params = $request->get_params(); 772 773 if ( '/oembed/1.0/embed' !== $request->get_route() || 'GET' !== $request->get_method() ) { 774 return $served; 775 } 776 777 if ( ! isset( $params['format'] ) || 'xml' !== $params['format'] ) { 778 return $served; 779 } 780 781 // Embed links inside the request. 782 $data = $server->response_to_data( $result, false ); 783 784 if ( ! class_exists( 'SimpleXMLElement' ) ) { 785 status_header( 501 ); 786 die( get_status_header_desc( 501 ) ); 787 } 788 789 $result = _oembed_create_xml( $data ); 790 791 // Bail if there's no XML. 792 if ( ! $result ) { 793 status_header( 501 ); 794 return get_status_header_desc( 501 ); 795 } 796 797 if ( ! headers_sent() ) { 798 $server->send_header( 'Content-Type', 'text/xml; charset=' . get_option( 'blog_charset' ) ); 799 } 800 801 echo $result; 802 803 return true; 804 } 805 806 /** 807 * Creates an XML string from a given array. 808 * 809 * @since 4.4.0 810 * @access private 811 * 812 * @param array $data The original oEmbed response data. 813 * @param SimpleXMLElement $node Optional. XML node to append the result to recursively. 814 * @return string|false XML string on success, false on error. 815 */ 816 function _oembed_create_xml( $data, $node = null ) { 817 if ( ! is_array( $data ) || empty( $data ) ) { 818 return false; 819 } 820 821 if ( null === $node ) { 822 $node = new SimpleXMLElement( '<oembed></oembed>' ); 823 } 824 825 foreach ( $data as $key => $value ) { 826 if ( is_numeric( $key ) ) { 827 $key = 'oembed'; 828 } 829 830 if ( is_array( $value ) ) { 831 $item = $node->addChild( $key ); 832 _oembed_create_xml( $value, $item ); 833 } else { 834 $node->addChild( $key, esc_html( $value ) ); 835 } 836 } 837 838 return $node->asXML(); 839 } 840 841 /** 842 * Filters the given oEmbed HTML to make sure iframes have a title attribute. 843 * 844 * @since 5.2.0 845 * 846 * @param string $result The oEmbed HTML result. 847 * @param object $data A data object result from an oEmbed provider. 848 * @param string $url The URL of the content to be embedded. 849 * @return string The filtered oEmbed result. 850 */ 851 function wp_filter_oembed_iframe_title_attribute( $result, $data, $url ) { 852 if ( false === $result || ! in_array( $data->type, array( 'rich', 'video' ), true ) ) { 853 return $result; 854 } 855 856 $title = ! empty( $data->title ) ? $data->title : ''; 857 858 $pattern = '`<iframe([^>]*)>`i'; 859 if ( preg_match( $pattern, $result, $matches ) ) { 860 $attrs = wp_kses_hair( $matches[1], wp_allowed_protocols() ); 861 862 foreach ( $attrs as $attr => $item ) { 863 $lower_attr = strtolower( $attr ); 864 if ( $lower_attr === $attr ) { 865 continue; 866 } 867 if ( ! isset( $attrs[ $lower_attr ] ) ) { 868 $attrs[ $lower_attr ] = $item; 869 unset( $attrs[ $attr ] ); 870 } 871 } 872 } 873 874 if ( ! empty( $attrs['title']['value'] ) ) { 875 $title = $attrs['title']['value']; 876 } 877 878 /** 879 * Filters the title attribute of the given oEmbed HTML iframe. 880 * 881 * @since 5.2.0 882 * 883 * @param string $title The title attribute. 884 * @param string $result The oEmbed HTML result. 885 * @param object $data A data object result from an oEmbed provider. 886 * @param string $url The URL of the content to be embedded. 887 */ 888 $title = apply_filters( 'oembed_iframe_title_attribute', $title, $result, $data, $url ); 889 890 if ( '' === $title ) { 891 return $result; 892 } 893 894 if ( isset( $attrs['title'] ) ) { 895 unset( $attrs['title'] ); 896 $attr_string = implode( ' ', wp_list_pluck( $attrs, 'whole' ) ); 897 $result = str_replace( $matches[0], '<iframe ' . trim( $attr_string ) . '>', $result ); 898 } 899 return str_ireplace( '<iframe ', sprintf( '<iframe title="%s" ', esc_attr( $title ) ), $result ); 900 } 901 902 903 /** 904 * Filters the given oEmbed HTML. 905 * 906 * If the `$url` isn't on the trusted providers list, 907 * we need to filter the HTML heavily for security. 908 * 909 * Only filters 'rich' and 'video' response types. 910 * 911 * @since 4.4.0 912 * 913 * @param string $result The oEmbed HTML result. 914 * @param object $data A data object result from an oEmbed provider. 915 * @param string $url The URL of the content to be embedded. 916 * @return string The filtered and sanitized oEmbed result. 917 */ 918 function wp_filter_oembed_result( $result, $data, $url ) { 919 if ( false === $result || ! in_array( $data->type, array( 'rich', 'video' ), true ) ) { 920 return $result; 921 } 922 923 $wp_oembed = _wp_oembed_get_object(); 924 925 // Don't modify the HTML for trusted providers. 926 if ( false !== $wp_oembed->get_provider( $url, array( 'discover' => false ) ) ) { 927 return $result; 928 } 929 930 $allowed_html = array( 931 'a' => array( 932 'href' => true, 933 ), 934 'blockquote' => array(), 935 'iframe' => array( 936 'src' => true, 937 'width' => true, 938 'height' => true, 939 'frameborder' => true, 940 'marginwidth' => true, 941 'marginheight' => true, 942 'scrolling' => true, 943 'title' => true, 944 ), 945 ); 946 947 $html = wp_kses( $result, $allowed_html ); 948 949 preg_match( '|(<blockquote>.*?</blockquote>)?.*(<iframe.*?></iframe>)|ms', $html, $content ); 950 // We require at least the iframe to exist. 951 if ( empty( $content[2] ) ) { 952 return false; 953 } 954 $html = $content[1] . $content[2]; 955 956 preg_match( '/ src=([\'"])(.*?)\1/', $html, $results ); 957 958 if ( ! empty( $results ) ) { 959 $secret = wp_generate_password( 10, false ); 960 961 $url = esc_url( "{$results[2]}#?secret=$secret" ); 962 $q = $results[1]; 963 964 $html = str_replace( $results[0], ' src=' . $q . $url . $q . ' data-secret=' . $q . $secret . $q, $html ); 965 $html = str_replace( '<blockquote', "<blockquote data-secret=\"$secret\"", $html ); 966 } 967 968 $allowed_html['blockquote']['data-secret'] = true; 969 $allowed_html['iframe']['data-secret'] = true; 970 971 $html = wp_kses( $html, $allowed_html ); 972 973 if ( ! empty( $content[1] ) ) { 974 // We have a blockquote to fall back on. Hide the iframe by default. 975 $html = str_replace( '<iframe', '<iframe style="position: absolute; visibility: hidden;"', $html ); 976 $html = str_replace( '<blockquote', '<blockquote class="wp-embedded-content"', $html ); 977 } 978 979 $html = str_ireplace( '<iframe', '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"', $html ); 980 981 return $html; 982 } 983 984 /** 985 * Filters the string in the 'more' link displayed after a trimmed excerpt. 986 * 987 * Replaces '[...]' (appended to automatically generated excerpts) with an 988 * ellipsis and a "Continue reading" link in the embed template. 989 * 990 * @since 4.4.0 991 * 992 * @param string $more_string Default 'more' string. 993 * @return string 'Continue reading' link prepended with an ellipsis. 994 */ 995 function wp_embed_excerpt_more( $more_string ) { 996 if ( ! is_embed() ) { 997 return $more_string; 998 } 999 1000 $link = sprintf( 1001 '<a href="%1$s" class="wp-embed-more" target="_top">%2$s</a>', 1002 esc_url( get_permalink() ), 1003 /* translators: %s: Post title. */ 1004 sprintf( __( 'Continue reading %s' ), '<span class="screen-reader-text">' . get_the_title() . '</span>' ) 1005 ); 1006 return ' … ' . $link; 1007 } 1008 1009 /** 1010 * Displays the post excerpt for the embed template. 1011 * 1012 * Intended to be used in 'The Loop'. 1013 * 1014 * @since 4.4.0 1015 */ 1016 function the_excerpt_embed() { 1017 $output = get_the_excerpt(); 1018 1019 /** 1020 * Filters the post excerpt for the embed template. 1021 * 1022 * @since 4.4.0 1023 * 1024 * @param string $output The current post excerpt. 1025 */ 1026 echo apply_filters( 'the_excerpt_embed', $output ); 1027 } 1028 1029 /** 1030 * Filters the post excerpt for the embed template. 1031 * 1032 * Shows players for video and audio attachments. 1033 * 1034 * @since 4.4.0 1035 * 1036 * @param string $content The current post excerpt. 1037 * @return string The modified post excerpt. 1038 */ 1039 function wp_embed_excerpt_attachment( $content ) { 1040 if ( is_attachment() ) { 1041 return prepend_attachment( '' ); 1042 } 1043 1044 return $content; 1045 } 1046 1047 /** 1048 * Enqueues embed iframe default CSS and JS. 1049 * 1050 * Enqueue PNG fallback CSS for embed iframe for legacy versions of IE. 1051 * 1052 * Allows plugins to queue scripts for the embed iframe end using wp_enqueue_script(). 1053 * Runs first in oembed_head(). 1054 * 1055 * @since 4.4.0 1056 */ 1057 function enqueue_embed_scripts() { 1058 wp_enqueue_style( 'wp-embed-template-ie' ); 1059 1060 /** 1061 * Fires when scripts and styles are enqueued for the embed iframe. 1062 * 1063 * @since 4.4.0 1064 */ 1065 do_action( 'enqueue_embed_scripts' ); 1066 } 1067 1068 /** 1069 * Enqueues the CSS in the embed iframe header. 1070 * 1071 * @since 6.4.0 1072 */ 1073 function wp_enqueue_embed_styles() { 1074 // Back-compat for plugins that disable functionality by unhooking this action. 1075 if ( ! has_action( 'embed_head', 'print_embed_styles' ) ) { 1076 return; 1077 } 1078 remove_action( 'embed_head', 'print_embed_styles' ); 1079 1080 $suffix = wp_scripts_get_suffix(); 1081 $handle = 'wp-embed-template'; 1082 wp_register_style( $handle, false ); 1083 wp_add_inline_style( $handle, file_get_contents( ABSPATH . WPINC . "/css/wp-embed-template$suffix.css" ) ); 1084 wp_enqueue_style( $handle ); 1085 } 1086 1087 /** 1088 * Prints the JavaScript in the embed iframe header. 1089 * 1090 * @since 4.4.0 1091 */ 1092 function print_embed_scripts() { 1093 wp_print_inline_script_tag( 1094 file_get_contents( ABSPATH . WPINC . '/js/wp-embed-template' . wp_scripts_get_suffix() . '.js' ) 1095 ); 1096 } 1097 1098 /** 1099 * Prepare the oembed HTML to be displayed in an RSS feed. 1100 * 1101 * @since 4.4.0 1102 * @access private 1103 * 1104 * @param string $content The content to filter. 1105 * @return string The filtered content. 1106 */ 1107 function _oembed_filter_feed_content( $content ) { 1108 $p = new WP_HTML_Tag_Processor( $content ); 1109 while ( $p->next_tag( array( 'tag_name' => 'iframe' ) ) ) { 1110 if ( $p->has_class( 'wp-embedded-content' ) ) { 1111 $p->remove_attribute( 'style' ); 1112 } 1113 } 1114 return $p->get_updated_html(); 1115 } 1116 1117 /** 1118 * Prints the necessary markup for the embed comments button. 1119 * 1120 * @since 4.4.0 1121 */ 1122 function print_embed_comments_button() { 1123 if ( is_404() || ! ( get_comments_number() || comments_open() ) ) { 1124 return; 1125 } 1126 ?> 1127 <div class="wp-embed-comments"> 1128 <a href="<?php comments_link(); ?>" target="_top"> 1129 <span class="dashicons dashicons-admin-comments"></span> 1130 <?php 1131 printf( 1132 /* translators: %s: Number of comments. */ 1133 _n( 1134 '%s <span class="screen-reader-text">Comment</span>', 1135 '%s <span class="screen-reader-text">Comments</span>', 1136 get_comments_number() 1137 ), 1138 number_format_i18n( get_comments_number() ) 1139 ); 1140 ?> 1141 </a> 1142 </div> 1143 <?php 1144 } 1145 1146 /** 1147 * Prints the necessary markup for the embed sharing button. 1148 * 1149 * @since 4.4.0 1150 */ 1151 function print_embed_sharing_button() { 1152 if ( is_404() ) { 1153 return; 1154 } 1155 ?> 1156 <div class="wp-embed-share"> 1157 <button type="button" class="wp-embed-share-dialog-open" aria-label="<?php esc_attr_e( 'Open sharing dialog' ); ?>"> 1158 <span class="dashicons dashicons-share"></span> 1159 </button> 1160 </div> 1161 <?php 1162 } 1163 1164 /** 1165 * Prints the necessary markup for the embed sharing dialog. 1166 * 1167 * @since 4.4.0 1168 */ 1169 function print_embed_sharing_dialog() { 1170 if ( is_404() ) { 1171 return; 1172 } 1173 1174 $unique_suffix = get_the_ID() . '-' . wp_rand(); 1175 $share_tab_wordpress_id = 'wp-embed-share-tab-wordpress-' . $unique_suffix; 1176 $share_tab_html_id = 'wp-embed-share-tab-html-' . $unique_suffix; 1177 $description_wordpress_id = 'wp-embed-share-description-wordpress-' . $unique_suffix; 1178 $description_html_id = 'wp-embed-share-description-html-' . $unique_suffix; 1179 ?> 1180 <div class="wp-embed-share-dialog hidden" role="dialog" aria-label="<?php esc_attr_e( 'Sharing options' ); ?>"> 1181 <div class="wp-embed-share-dialog-content"> 1182 <div class="wp-embed-share-dialog-text"> 1183 <ul class="wp-embed-share-tabs" role="tablist"> 1184 <li class="wp-embed-share-tab-button wp-embed-share-tab-button-wordpress" role="presentation"> 1185 <button type="button" role="tab" aria-controls="<?php echo $share_tab_wordpress_id; ?>" aria-selected="true" tabindex="0"><?php esc_html_e( 'WordPress Embed' ); ?></button> 1186 </li> 1187 <li class="wp-embed-share-tab-button wp-embed-share-tab-button-html" role="presentation"> 1188 <button type="button" role="tab" aria-controls="<?php echo $share_tab_html_id; ?>" aria-selected="false" tabindex="-1"><?php esc_html_e( 'HTML Embed' ); ?></button> 1189 </li> 1190 </ul> 1191 <div id="<?php echo $share_tab_wordpress_id; ?>" class="wp-embed-share-tab" role="tabpanel" aria-hidden="false"> 1192 <input type="text" value="<?php the_permalink(); ?>" class="wp-embed-share-input" aria-label="<?php esc_attr_e( 'URL' ); ?>" aria-describedby="<?php echo $description_wordpress_id; ?>" tabindex="0" readonly/> 1193 1194 <p class="wp-embed-share-description" id="<?php echo $description_wordpress_id; ?>"> 1195 <?php _e( 'Copy and paste this URL into your WordPress site to embed' ); ?> 1196 </p> 1197 </div> 1198 <div id="<?php echo $share_tab_html_id; ?>" class="wp-embed-share-tab" role="tabpanel" aria-hidden="true"> 1199 <textarea class="wp-embed-share-input" aria-label="<?php esc_attr_e( 'HTML' ); ?>" aria-describedby="<?php echo $description_html_id; ?>" tabindex="0" readonly><?php echo esc_textarea( get_post_embed_html( 600, 400 ) ); ?></textarea> 1200 1201 <p class="wp-embed-share-description" id="<?php echo $description_html_id; ?>"> 1202 <?php _e( 'Copy and paste this code into your site to embed' ); ?> 1203 </p> 1204 </div> 1205 </div> 1206 1207 <button type="button" class="wp-embed-share-dialog-close" aria-label="<?php esc_attr_e( 'Close sharing dialog' ); ?>"> 1208 <span class="dashicons dashicons-no"></span> 1209 </button> 1210 </div> 1211 </div> 1212 <?php 1213 } 1214 1215 /** 1216 * Prints the necessary markup for the site title in an embed template. 1217 * 1218 * @since 4.5.0 1219 */ 1220 function the_embed_site_title() { 1221 $site_title = sprintf( 1222 '<a href="%s" target="_top"><img src="%s" srcset="%s 2x" width="32" height="32" alt="" class="wp-embed-site-icon" /><span>%s</span></a>', 1223 esc_url( home_url() ), 1224 esc_url( get_site_icon_url( 32, includes_url( 'images/w-logo-blue.png' ) ) ), 1225 esc_url( get_site_icon_url( 64, includes_url( 'images/w-logo-blue.png' ) ) ), 1226 esc_html( get_bloginfo( 'name' ) ) 1227 ); 1228 1229 $site_title = '<div class="wp-embed-site-title">' . $site_title . '</div>'; 1230 1231 /** 1232 * Filters the site title HTML in the embed footer. 1233 * 1234 * @since 4.4.0 1235 * 1236 * @param string $site_title The site title HTML. 1237 */ 1238 echo apply_filters( 'embed_site_title_html', $site_title ); 1239 } 1240 1241 /** 1242 * Filters the oEmbed result before any HTTP requests are made. 1243 * 1244 * If the URL belongs to the current site, the result is fetched directly instead of 1245 * going through the oEmbed discovery process. 1246 * 1247 * @since 4.5.3 1248 * 1249 * @param null|string $result The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. Default null. 1250 * @param string $url The URL that should be inspected for discovery `<link>` tags. 1251 * @param array $args oEmbed remote get arguments. 1252 * @return null|string The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. 1253 * Null if the URL does not belong to the current site. 1254 */ 1255 function wp_filter_pre_oembed_result( $result, $url, $args ) { 1256 $data = get_oembed_response_data_for_url( $url, $args ); 1257 1258 if ( $data ) { 1259 return _wp_oembed_get_object()->data2html( $data, $url ); 1260 } 1261 1262 return $result; 1263 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Fri Feb 21 08:20:01 2025 | Cross-referenced by PHPXref |