, $user_id = false ) { $author_meta = get_the_author_meta( $field, $user_id ); /** * The value of the requested user metadata. * * The filter name is dynamic and depends on the $field parameter of the function. * * @since 2.8.0 * * @param string $author_meta The value of the metadata. * @param int $user_id The user ID. */ echo apply_filters( "the_author_{$field}", $author_meta, $user_id ); } /** * Retrieve either author's link or author's name. * * If the author has a home page set, return an HTML link, otherwise just return the * author's name. * * @since 3.0.0 * * @return string|null An HTML link if the author's url exist in user meta, * else the result of get_the_author(). */ function get_the_author_link() { if ( get_the_author_meta('url') ) { return sprintf( '%3$s', esc_url( get_the_author_meta('url') ), /* translators: %s: author's display name */ esc_attr( sprintf( __( 'Visit %s’s website' ), get_the_author() ) ), get_the_author() ); } else { return get_the_author(); } } /** * Display either author's link or author's name. * * If the author has a home page set, echo an HTML link, otherwise just echo the * author's name. * * @link https://codex.wordpress.org/Template_Tags/the_author_link * * @since 2.1.0 */ function the_author_link() { echo get_the_author_link(); } /** * Retrieve the number of posts by the author of the current post. * * @since 1.5.0 * * @return int The number of posts by the author. */ function get_the_author_posts() { $post = get_post(); if ( ! $post ) { return 0; } return count_user_posts( $post->post_author, $post->post_type ); } /** * Display the number of posts by the author of the current post. * * @link https://codex.wordpress.org/Template_Tags/the_author_posts * @since 0.71 */ function the_author_posts() { echo get_the_author_posts(); } /** * Retrieves an HTML link to the author page of the current post's author. * * Returns an HTML-formatted link using get_author_posts_url(). * * @since 4.4.0 * * @global object $authordata The current author's DB object. * * @return string An HTML link to the author page. */ function get_the_author_posts_link() { global $authordata; if ( ! is_object( $authordata ) ) { return; } $link = sprintf( '', esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ), /* translators: %s: author's display name */ esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ), get_the_author() ); /** * Filters the link to the author page of the author of the current post. * * @since 2.9.0 * * @param string $link HTML link. */ return apply_filters( 'the_author_posts_link', $link ); } /** * Displays an HTML link to the author page of the current post's author. * * @since 1.2.0 * @since 4.4.0 Converted into a wrapper for get_the_author_posts_link() * * @param string $deprecated Unused. */ function the_author_posts_link( $deprecated = '' ) { if ( ! empty( $deprecated ) ) { _deprecated_argument( __FUNCTION__, '2.1.0' ); } echo get_the_author_posts_link(); } /** * Retrieve the URL to the author page for the user with the ID provided. * * @since 2.1.0 * * @global WP_Rewrite $wp_rewrite * * @param int $author_id Author ID. * @param string $author_nicename Optional. The author's nicename (slug). Default empty. * @return string The URL to the author's page. */ function get_author_posts_url( $author_id, $author_nicename = '' ) { global $wp_rewrite; $auth_ID = (int) $author_id; $link = $wp_rewrite->get_author_permastruct(); if ( empty($link) ) { $file = home_url( '/' ); $link = $file . '?author=' . $auth_ID; } else { if ( '' == $author_nicename ) { $user = get_userdata($author_id); if ( !empty($user->user_nicename) ) $author_nicename = $user->user_nicename; } $link = str_replace('%author%', $author_nicename, $link); $link = home_url( user_trailingslashit( $link ) ); } /** * Filters the URL to the author's page. * * @since 2.1.0 * * @param string $link The URL to the author's page. * @param int $author_id The author's id. * @param string $author_nicename The author's nice name. */ $link = apply_filters( 'author_link', $link, $author_id, $author_nicename ); return $link; } /** * List all the authors of the site, with several options available. * * @link https://codex.wordpress.org/Template_Tags/wp_list_authors * * @since 1.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string|array $args { * Optional. Array or string of default arguments. * * @type string $orderby How to sort the authors. Accepts 'nicename', 'email', 'url', 'registered', * 'user_nicename', 'user_email', 'user_url', 'user_registered', 'name', * 'display_name', 'post_count', 'ID', 'meta_value', 'user_login'. Default 'name'. * @type string $order Sorting direction for $orderby. Accepts 'ASC', 'DESC'. Default 'ASC'. * @type int $number Maximum authors to return or display. Default empty (all authors). * @type bool $optioncount Show the count in parenthesis next to the author's name. Default false. * @type bool $exclude_admin Whether to exclude the 'admin' account, if it exists. Default false. * @type bool $show_fullname Whether to show the author's full name. Default false. * @type bool $hide_empty Whether to hide any authors with no posts. Default true. * @type string $feed If not empty, show a link to the author's feed and use this text as the alt * parameter of the link. Default empty. * @type string $feed_image If not empty, show a link to the author's feed and use this image URL as * clickable anchor. Default empty. * @type string $feed_type The feed type to link to, such as 'rss2'. Defaults to default feed type. * @type bool $echo Whether to output the result or instead return it. Default true. * @type string $style If 'list', each author is wrapped in an `
  • ` element, otherwise the authors * will be separated by commas. * @type bool $html Whether to list the items in HTML form or plaintext. Default true. * @type array|string $exclude Array or comma/space-separated list of author IDs to exclude. Default empty. * @type array|string $include Array or comma/space-separated list of author IDs to include. Default empty. * } * @return string|void The output, if echo is set to false. */ function wp_list_authors( $args = '' ) { global $wpdb; $defaults = array( 'orderby' => 'name', 'order' => 'ASC', 'number' => '', 'optioncount' => false, 'exclude_admin' => true, 'show_fullname' => false, 'hide_empty' => true, 'feed' => '', 'feed_image' => '', 'feed_type' => '', 'echo' => true, 'style' => 'list', 'html' => true, 'exclude' => '', 'include' => '' ); $args = wp_parse_args( $args, $defaults ); $return = ''; $query_args = wp_array_slice_assoc( $args, array( 'orderby', 'order', 'number', 'exclude', 'include' ) ); $query_args['fields'] = 'ids'; $authors = get_users( $query_args ); $author_count = array(); foreach ( (array) $wpdb->get_results( "SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author" ) as $row ) { $author_count[$row->post_author] = $row->count; } foreach ( $authors as $author_id ) { $author = get_userdata( $author_id ); if ( $args['exclude_admin'] && 'admin' == $author->display_name ) { continue; } $posts = isset( $author_count[$author->ID] ) ? $author_count[$author->ID] : 0; if ( ! $posts && $args['hide_empty'] ) { continue; } if ( $args['show_fullname'] && $author->first_name && $author->last_name ) { $name = "$author->first_name $author->last_name"; } else { $name = $author->display_name; } if ( ! $args['html'] ) { $return .= $name . ', '; continue; // No need to go further to process HTML. } if ( 'list' == $args['style'] ) { $return .= '
  • '; } $link = sprintf( '%3$s', get_author_posts_url( $author->ID, $author->user_nicename ), /* translators: %s: author's display name */ esc_attr( sprintf( __( 'Posts by %s' ), $author->display_name ) ), $name ); if ( ! empty( $args['feed_image'] ) || ! empty( $args['feed'] ) ) { $link .= ' '; if ( empty( $args['feed_image'] ) ) { $link .= '('; } $link .= ''; } else { $link .= $name; } $link .= ''; if ( empty( $args['feed_image'] ) ) { $link .= ')'; } } if ( $args['optioncount'] ) { $link .= ' ('. $posts . ')'; } $return .= $link; $return .= ( 'list' == $args['style'] ) ? '
  • ' : ', '; } $return = rtrim( $return, ', ' ); if ( ! $args['echo'] ) { return $return; } echo $return; } /** * Does this site have more than one author * * Checks to see if more than one author has published posts. * * @since 3.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @return bool Whether or not we have more than one author */ function is_multi_author() { global $wpdb; if ( false === ( $is_multi_author = get_transient( 'is_multi_author' ) ) ) { $rows = (array) $wpdb->get_col("SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' LIMIT 2"); $is_multi_author = 1 < count( $rows ) ? 1 : 0; set_transient( 'is_multi_author', $is_multi_author ); } /** * Filters whether the site has more than one author with published posts. * * @since 3.2.0 * * @param bool $is_multi_author Whether $is_multi_author should evaluate as true. */ return apply_filters( 'is_multi_author', (bool) $is_multi_author ); } /** * Helper function to clear the cache for number of authors. * * @since 3.2.0 * @access private */ function __clear_multi_author_cache() { delete_transient( 'is_multi_author' ); } s://api.meetup.com/oembed', true ), '#https?://(www\.)?issuu\.com/.+/docs/.+#i' => array( 'https://issuu.com/oembed_wp', true ), '#https?://(www\.)?collegehumor\.com/video/.*#i' => array( 'https://www.collegehumor.com/oembed.{format}', true ), '#https?://(www\.)?mixcloud\.com/.*#i' => array( 'https://www.mixcloud.com/oembed', true ), '#https?://(www\.|embed\.)?ted\.com/talks/.*#i' => array( 'https://www.ted.com/services/v1/oembed.{format}', true ), '#https?://(www\.)?(animoto|video214)\.com/play/.*#i' => array( 'https://animoto.com/oembeds/create', true ), '#https?://(.+)\.tumblr\.com/post/.*#i' => array( 'https://www.tumblr.com/oembed/1.0', true ), '#https?://(www\.)?kickstarter\.com/projects/.*#i' => array( 'https://www.kickstarter.com/services/oembed', true ), '#https?://kck\.st/.*#i' => array( 'https://www.kickstarter.com/services/oembed', true ), '#https?://cloudup\.com/.*#i' => array( 'https://cloudup.com/oembed', true ), '#https?://(www\.)?reverbnation\.com/.*#i' => array( 'https://www.reverbnation.com/oembed', true ), '#https?://videopress\.com/v/.*#' => array( 'https://public-api.wordpress.com/oembed/?for=' . $host, true ), '#https?://(www\.)?reddit\.com/r/[^/]+/comments/.*#i' => array( 'https://www.reddit.com/oembed', true ), '#https?://(www\.)?speakerdeck\.com/.*#i' => array( 'https://speakerdeck.com/oembed.{format}', true ), '#https?://www\.facebook\.com/.*/posts/.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/.*/activity/.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/.*/photos/.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/photo(s/|\.php).*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/permalink\.php.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/media/.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/questions/.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/notes/.*#i' => array( 'https://www.facebook.com/plugins/post/oembed.json/', true ), '#https?://www\.facebook\.com/.*/videos/.*#i' => array( 'https://www.facebook.com/plugins/video/oembed.json/', true ), '#https?://www\.facebook\.com/video\.php.*#i' => array( 'https://www.facebook.com/plugins/video/oembed.json/', true ), '#https?://(www\.)?screencast\.com/.*#i' => array( 'https://api.screencast.com/external/oembed', true ), '#https?://([a-z0-9-]+\.)?amazon\.(com|com\.mx|com\.br|ca)/.*#i' => array( 'https://read.amazon.com/kp/api/oembed', true ), '#https?://([a-z0-9-]+\.)?amazon\.(co\.uk|de|fr|it|es|in|nl|ru)/.*#i' => array( 'https://read.amazon.co.uk/kp/api/oembed', true ), '#https?://([a-z0-9-]+\.)?amazon\.(co\.jp|com\.au)/.*#i' => array( 'https://read.amazon.com.au/kp/api/oembed', true ), '#https?://([a-z0-9-]+\.)?amazon\.cn/.*#i' => array( 'https://read.amazon.cn/kp/api/oembed', true ), '#https?://(www\.)?a\.co/.*#i' => array( 'https://read.amazon.com/kp/api/oembed', true ), '#https?://(www\.)?amzn\.to/.*#i' => array( 'https://read.amazon.com/kp/api/oembed', true ), '#https?://(www\.)?amzn\.eu/.*#i' => array( 'https://read.amazon.co.uk/kp/api/oembed', true ), '#https?://(www\.)?amzn\.in/.*#i' => array( 'https://read.amazon.in/kp/api/oembed', true ), '#https?://(www\.)?amzn\.asia/.*#i' => array( 'https://read.amazon.com.au/kp/api/oembed', true ), '#https?://(www\.)?z\.cn/.*#i' => array( 'https://read.amazon.cn/kp/api/oembed', true ), '#https?://www\.someecards\.com/.+-cards/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ), '#https?://www\.someecards\.com/usercards/viewcard/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ), '#https?://some\.ly\/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ), ); if ( ! empty( self::$early_providers['add'] ) ) { foreach ( self::$early_providers['add'] as $format => $data ) { $providers[ $format ] = $data; } } if ( ! empty( self::$early_providers['remove'] ) ) { foreach ( self::$early_providers['remove'] as $format ) { unset( $providers[ $format ] ); } } self::$early_providers = array(); /** * Filters the list of whitelisted oEmbed providers. * * Since WordPress 4.4, oEmbed discovery is enabled for all users and allows embedding of sanitized * iframes. The providers in this list are whitelisted, meaning they are trusted and allowed to * embed any content, such as iframes, videos, JavaScript, and arbitrary HTML. * * Supported providers: * * | Provider | Flavor | Supports HTTPS | Since | * | ------------ | --------------------------------- | :------------: | ------- | * | Dailymotion | dailymotion.com | Yes | 2.9.0 | * | Flickr | flickr.com | Yes | 2.9.0 | * | Hulu | hulu.com | Yes | 2.9.0 | * | Photobucket | photobucket.com | No | 2.9.0 | * | Scribd | scribd.com | Yes | 2.9.0 | * | Vimeo | vimeo.com | Yes | 2.9.0 | * | WordPress.tv | wordpress.tv | Yes | 2.9.0 | * | YouTube | youtube.com/watch | Yes | 2.9.0 | * | Funny or Die | funnyordie.com | Yes | 3.0.0 | * | Polldaddy | polldaddy.com | Yes | 3.0.0 | * | SmugMug | smugmug.com | Yes | 3.0.0 | * | YouTube | youtu.be | Yes | 3.0.0 | * | Twitter | twitter.com | Yes | 3.4.0 | * | Instagram | instagram.com | Yes | 3.5.0 | * | Instagram | instagr.am | Yes | 3.5.0 | * | Slideshare | slideshare.net | Yes | 3.5.0 | * | SoundCloud | soundcloud.com | Yes | 3.5.0 | * | Dailymotion | dai.ly | Yes | 3.6.0 | * | Flickr | flic.kr | Yes | 3.6.0 | * | Spotify | spotify.com | Yes | 3.6.0 | * | Imgur | imgur.com | Yes | 3.9.0 | * | Meetup.com | meetup.com | Yes | 3.9.0 | * | Meetup.com | meetu.ps | Yes | 3.9.0 | * | Animoto | animoto.com | Yes | 4.0.0 | * | Animoto | video214.com | Yes | 4.0.0 | * | CollegeHumor | collegehumor.com | Yes | 4.0.0 | * | Issuu | issuu.com | Yes | 4.0.0 | * | Mixcloud | mixcloud.com | Yes | 4.0.0 | * | Polldaddy | poll.fm | Yes | 4.0.0 | * | TED | ted.com | Yes | 4.0.0 | * | YouTube | youtube.com/playlist | Yes | 4.0.0 | * | Tumblr | tumblr.com | Yes | 4.2.0 | * | Kickstarter | kickstarter.com | Yes | 4.2.0 | * | Kickstarter | kck.st | Yes | 4.2.0 | * | Cloudup | cloudup.com | Yes | 4.3.0 | * | ReverbNation | reverbnation.com | Yes | 4.4.0 | * | VideoPress | videopress.com | Yes | 4.4.0 | * | Reddit | reddit.com | Yes | 4.4.0 | * | Speaker Deck | speakerdeck.com | Yes | 4.4.0 | * | Twitter | twitter.com/timelines | Yes | 4.5.0 | * | Twitter | twitter.com/moments | Yes | 4.5.0 | * | Facebook | facebook.com | Yes | 4.7.0 | * | Twitter | twitter.com/user | Yes | 4.7.0 | * | Twitter | twitter.com/likes | Yes | 4.7.0 | * | Twitter | twitter.com/lists | Yes | 4.7.0 | * | Screencast | screencast.com | Yes | 4.8.0 | * | Amazon | amazon.com|com.mx|com.br|ca | Yes | 4.9.0 | * | Amazon | amazon.de|fr|it|es|in|nl|ru|co.uk | Yes | 4.9.0 | * | Amazon | amazon.co.jp|com.au | Yes | 4.9.0 | * | Amazon | amazon.cn | Yes | 4.9.0 | * | Amazon | a.co | Yes | 4.9.0 | * | Amazon | amzn.to|eu|in|asia | Yes | 4.9.0 | * | Amazon | z.cn | Yes | 4.9.0 | * | Someecards | someecards.com | Yes | 4.9.0 | * | Someecards | some.ly | Yes | 4.9.0 | * * No longer supported providers: * * | Provider | Flavor | Supports HTTPS | Since | Removed | * | ------------ | -------------------- | :------------: | --------- | --------- | * | Qik | qik.com | Yes | 2.9.0 | 3.9.0 | * | Viddler | viddler.com | Yes | 2.9.0 | 4.0.0 | * | Revision3 | revision3.com | No | 2.9.0 | 4.2.0 | * | Blip | blip.tv | No | 2.9.0 | 4.4.0 | * | Rdio | rdio.com | Yes | 3.6.0 | 4.4.1 | * | Rdio | rd.io | Yes | 3.6.0 | 4.4.1 | * | Vine | vine.co | Yes | 4.1.0 | 4.9.0 | * * @see wp_oembed_add_provider() * * @since 2.9.0 * * @param array $providers An array of popular oEmbed providers. */ $this->providers = apply_filters( 'oembed_providers', $providers ); // Fix any embeds that contain new lines in the middle of the HTML which breaks wpautop(). add_filter( 'oembed_dataparse', array($this, '_strip_newlines'), 10, 3 ); } /** * Exposes private/protected methods for backward compatibility. * * @since 4.0.0 * * @param callable $name Method to call. * @param array $arguments Arguments to pass when calling. * @return mixed|bool Return value of the callback, false otherwise. */ public function __call( $name, $arguments ) { if ( in_array( $name, $this->compat_methods ) ) { return call_user_func_array( array( $this, $name ), $arguments ); } return false; } /** * Takes a URL and returns the corresponding oEmbed provider's URL, if there is one. * * @since 4.0.0 * * @see WP_oEmbed::discover() * * @param string $url The URL to the content. * @param string|array $args Optional provider arguments. * @return false|string False on failure, otherwise the oEmbed provider URL. */ public function get_provider( $url, $args = '' ) { $args = wp_parse_args( $args ); $provider = false; if ( !isset($args['discover']) ) $args['discover'] = true; foreach ( $this->providers as $matchmask => $data ) { list( $providerurl, $regex ) = $data; // Turn the asterisk-type provider URLs into regex if ( !$regex ) { $matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i'; $matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask ); } if ( preg_match( $matchmask, $url ) ) { $provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML break; } } if ( !$provider && $args['discover'] ) $provider = $this->discover( $url ); return $provider; } /** * Adds an oEmbed provider. * * The provider is added just-in-time when wp_oembed_add_provider() is called before * the {@see 'plugins_loaded'} hook. * * The just-in-time addition is for the benefit of the {@see 'oembed_providers'} filter. * * @static * @since 4.0.0 * * @see wp_oembed_add_provider() * * @param string $format Format of URL that this provider can handle. You can use * asterisks as wildcards. * @param string $provider The URL to the oEmbed provider.. * @param bool $regex Optional. Whether the $format parameter is in a regex format. * Default false. */ public static function _add_provider_early( $format, $provider, $regex = false ) { if ( empty( self::$early_providers['add'] ) ) { self::$early_providers['add'] = array(); } self::$early_providers['add'][ $format ] = array( $provider, $regex ); } /** * Removes an oEmbed provider. * * The provider is removed just-in-time when wp_oembed_remove_provider() is called before * the {@see 'plugins_loaded'} hook. * * The just-in-time removal is for the benefit of the {@see 'oembed_providers'} filter. * * @since 4.0.0 * @static * * @see wp_oembed_remove_provider() * * @param string $format The format of URL that this provider can handle. You can use * asterisks as wildcards. */ public static function _remove_provider_early( $format ) { if ( empty( self::$early_providers['remove'] ) ) { self::$early_providers['remove'] = array(); } self::$early_providers['remove'][] = $format; } /** * Takes a URL and attempts to return the oEmbed data. * * @see WP_oEmbed::fetch() * * @since 4.8.0 * * @param string $url The URL to the content that should be attempted to be embedded. * @param array|string $args Optional. Arguments, usually passed from a shortcode. Default empty. * @return false|object False on failure, otherwise the result in the form of an object. */ public function get_data( $url, $args = '' ) { $args = wp_parse_args( $args ); $provider = $this->get_provider( $url, $args ); if ( ! $provider ) { return false; } $data = $this->fetch( $provider, $url, $args ); if ( false === $data ) { return false; } return $data; } /** * The do-it-all function that takes a URL and attempts to return the HTML. * * @see WP_oEmbed::fetch() * @see WP_oEmbed::data2html() * * @since 2.9.0 * * @param string $url The URL to the content that should be attempted to be embedded. * @param array|string $args Optional. Arguments, usually passed from a shortcode. Default empty. * @return false|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed. */ public function get_html( $url, $args = '' ) { /** * Filters the oEmbed result before any HTTP requests are made. * * This allows one to short-circuit the default logic, perhaps by * replacing it with a routine that is more optimal for your setup. * * Passing a non-null value to the filter will effectively short-circuit retrieval, * returning the passed value instead. * * @since 4.5.3 * * @param null|string $result The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. Default null. * @param string $url The URL to the content that should be attempted to be embedded. * @param array $args Optional. Arguments, usually passed from a shortcode. Default empty. */ $pre = apply_filters( 'pre_oembed_result', null, $url, $args ); if ( null !== $pre ) { return $pre; } $data = $this->get_data( $url, $args ); if ( false === $data ) { return false; } /** * Filters the HTML returned by the oEmbed provider. * * @since 2.9.0 * * @param string $data The returned oEmbed HTML. * @param string $url URL of the content to be embedded. * @param array $args Optional arguments, usually passed from a shortcode. */ return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args ); } /** * Attempts to discover link tags at the given URL for an oEmbed provider. * * @since 2.9.0 * * @param string $url The URL that should be inspected for discovery `` tags. * @return false|string False on failure, otherwise the oEmbed provider URL. */ public function discover( $url ) { $providers = array(); $args = array( 'limit_response_size' => 153600, // 150 KB ); /** * Filters oEmbed remote get arguments. * * @since 4.0.0 * * @see WP_Http::request() * * @param array $args oEmbed remote get arguments. * @param string $url URL to be inspected. */ $args = apply_filters( 'oembed_remote_get_args', $args, $url ); // Fetch URL content $request = wp_safe_remote_get( $url, $args ); if ( $html = wp_remote_retrieve_body( $request ) ) { /** * Filters the link types that contain oEmbed provider URLs. * * @since 2.9.0 * * @param array $format Array of oEmbed link types. Accepts 'application/json+oembed', * 'text/xml+oembed', and 'application/xml+oembed' (incorrect, * used by at least Vimeo). */ $linktypes = apply_filters( 'oembed_linktypes', array( 'application/json+oembed' => 'json', 'text/xml+oembed' => 'xml', 'application/xml+oembed' => 'xml', ) ); // Strip if ( $html_head_end = stripos( $html, '' ) ) { $html = substr( $html, 0, $html_head_end ); } // Do a quick check $tagfound = false; foreach ( $linktypes as $linktype => $format ) { if ( stripos($html, $linktype) ) { $tagfound = true; break; } } if ( $tagfound && preg_match_all( '#]+)/?>#iU', $html, $links ) ) { foreach ( $links[1] as $link ) { $atts = shortcode_parse_atts( $link ); if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) { $providers[$linktypes[$atts['type']]] = htmlspecialchars_decode( $atts['href'] ); // Stop here if it's JSON (that's all we need) if ( 'json' == $linktypes[$atts['type']] ) break; } } } } // JSON is preferred to XML if ( !empty($providers['json']) ) return $providers['json']; elseif ( !empty($providers['xml']) ) return $providers['xml']; else return false; } /** * Connects to a oEmbed provider and returns the result. * * @since 2.9.0 * * @param string $provider The URL to the oEmbed provider. * @param string $url The URL to the content that is desired to be embedded. * @param array|string $args Optional. Arguments, usually passed from a shortcode. Default empty. * @return false|object False on failure, otherwise the result in the form of an object. */ public function fetch( $provider, $url, $args = '' ) { $args = wp_parse_args( $args, wp_embed_defaults( $url ) ); $provider = add_query_arg( 'maxwidth', (int) $args['width'], $provider ); $provider = add_query_arg( 'maxheight', (int) $args['height'], $provider ); $provider = add_query_arg( 'url', urlencode($url), $provider ); $provider = add_query_arg( 'dnt', 1, $provider ); /** * Filters the oEmbed URL to be fetched. * * @since 2.9.0 * @since 4.9.0 The `dnt` (Do Not Track) query parameter was added to all oEmbed provider URLs. * * @param string $provider URL of the oEmbed provider. * @param string $url URL of the content to be embedded. * @param array $args Optional arguments, usually passed from a shortcode. */ $provider = apply_filters( 'oembed_fetch_url', $provider, $url, $args ); foreach ( array( 'json', 'xml' ) as $format ) { $result = $this->_fetch_with_format( $provider, $format ); if ( is_wp_error( $result ) && 'not-implemented' == $result->get_error_code() ) continue; return ( $result && ! is_wp_error( $result ) ) ? $result : false; } return false; } /** * Fetches result from an oEmbed provider for a specific format and complete provider URL * * @since 3.0.0 * * @param string $provider_url_with_args URL to the provider with full arguments list (url, maxheight, etc.) * @param string $format Format to use * @return false|object|WP_Error False on failure, otherwise the result in the form of an object. */ private function _fetch_with_format( $provider_url_with_args, $format ) { $provider_url_with_args = add_query_arg( 'format', $format, $provider_url_with_args ); /** This filter is documented in wp-includes/class-oembed.php */ $args = apply_filters( 'oembed_remote_get_args', array(), $provider_url_with_args ); $response = wp_safe_remote_get( $provider_url_with_args, $args ); if ( 501 == wp_remote_retrieve_response_code( $response ) ) return new WP_Error( 'not-implemented' ); if ( ! $body = wp_remote_retrieve_body( $response ) ) return false; $parse_method = "_parse_$format"; return $this->$parse_method( $body ); } /** * Parses a json response body. * * @since 3.0.0 * * @param string $response_body * @return object|false */ private function _parse_json( $response_body ) { $data = json_decode( trim( $response_body ) ); return ( $data && is_object( $data ) ) ? $data : false; } /** * Parses an XML response body. * * @since 3.0.0 * * @param string $response_body * @return object|false */ private function _parse_xml( $response_body ) { if ( ! function_exists( 'libxml_disable_entity_loader' ) ) return false; $loader = libxml_disable_entity_loader( true ); $errors = libxml_use_internal_errors( true ); $return = $this->_parse_xml_body( $response_body ); libxml_use_internal_errors( $errors ); libxml_disable_entity_loader( $loader ); return $return; } /** * Serves as a helper function for parsing an XML response body. * * @since 3.6.0 * * @param string $response_body * @return stdClass|false */ private function _parse_xml_body( $response_body ) { if ( ! function_exists( 'simplexml_import_dom' ) || ! class_exists( 'DOMDocument', false ) ) return false; $dom = new DOMDocument; $success = $dom->loadXML( $response_body ); if ( ! $success ) return false; if ( isset( $dom->doctype ) ) return false; foreach ( $dom->childNodes as $child ) { if ( XML_DOCUMENT_TYPE_NODE === $child->nodeType ) return false; } $xml = simplexml_import_dom( $dom ); if ( ! $xml ) return false; $return = new stdClass; foreach ( $xml as $key => $value ) { $return->$key = (string) $value; } return $return; } /** * Converts a data object from WP_oEmbed::fetch() and returns the HTML. * * @since 2.9.0 * * @param object $data A data object result from an oEmbed provider. * @param string $url The URL to the content that is desired to be embedded. * @return false|string False on error, otherwise the HTML needed to embed. */ public function data2html( $data, $url ) { if ( ! is_object( $data ) || empty( $data->type ) ) return false; $return = false; switch ( $data->type ) { case 'photo': if ( empty( $data->url ) || empty( $data->width ) || empty( $data->height ) ) break; if ( ! is_string( $data->url ) || ! is_numeric( $data->width ) || ! is_numeric( $data->height ) ) break; $title = ! empty( $data->title ) && is_string( $data->title ) ? $data->title : ''; $return = '' . esc_attr($title) . ''; break; case 'video': case 'rich': if ( ! empty( $data->html ) && is_string( $data->html ) ) $return = $data->html; break; case 'link': if ( ! empty( $data->title ) && is_string( $data->title ) ) $return = '' . esc_html( $data->title ) . ''; break; default: $return = false; } /** * Filters the returned oEmbed HTML. * * Use this filter to add support for custom data types, or to filter the result. * * @since 2.9.0 * * @param string $return The returned oEmbed HTML. * @param object $data A data object result from an oEmbed provider. * @param string $url The URL of the content to be embedded. */ return apply_filters( 'oembed_dataparse', $return, $data, $url ); } /** * Strips any new lines from the HTML. * * @since 2.9.0 as strip_scribd_newlines() * @since 3.0.0 * * @param string $html Existing HTML. * @param object $data Data object from WP_oEmbed::data2html() * @param string $url The original URL passed to oEmbed. * @return string Possibly modified $html */ public function _strip_newlines( $html, $data, $url ) { if ( false === strpos( $html, "\n" ) ) { return $html; } $count = 1; $found = array(); $token = '__PRE__'; $search = array( "\t", "\n", "\r", ' ' ); $replace = array( '__TAB__', '__NL__', '__CR__', '__SPACE__' ); $tokenized = str_replace( $search, $replace, $html ); preg_match_all( '#(]*>.+?)#i', $tokenized, $matches, PREG_SET_ORDER ); foreach ( $matches as $i => $match ) { $tag_html = str_replace( $replace, $search, $match[0] ); $tag_token = $token . $i; $found[ $tag_token ] = $tag_html; $html = str_replace( $tag_html, $tag_token, $html, $count ); } $replaced = str_replace( $replace, $search, $html ); $stripped = str_replace( array( "\r\n", "\n" ), '', $replaced ); $pre = array_values( $found ); $tokens = array_keys( $found ); return str_replace( $tokens, $pre, $stripped ); } }