vigation( $args = array() ) { $args = wp_parse_args( $args, array( 'prev_text' => '%title', 'next_text' => '%title', 'in_same_term' => false, 'excluded_terms' => '', 'taxonomy' => 'category', 'screen_reader_text' => __( 'Post navigation' ), ) ); $navigation = ''; $previous = get_previous_post_link( '', $args['prev_text'], $args['in_same_term'], $args['excluded_terms'], $args['taxonomy'] ); $next = get_next_post_link( '', $args['next_text'], $args['in_same_term'], $args['excluded_terms'], $args['taxonomy'] ); // Only add markup if there's somewhere to navigate to. if ( $previous || $next ) { $navigation = _navigation_markup( $previous . $next, 'post-navigation', $args['screen_reader_text'] ); } return $navigation; } /** * Displays the navigation to next/previous post, when applicable. * * @since 4.1.0 * * @param array $args Optional. See get_the_post_navigation() for available arguments. * Default empty array. */ function the_post_navigation( $args = array() ) { echo get_the_post_navigation( $args ); } /** * Returns the navigation to next/previous set of posts, when applicable. * * @since 4.1.0 * * @global WP_Query $wp_query WordPress Query object. * * @param array $args { * Optional. Default posts navigation arguments. Default empty array. * * @type string $prev_text Anchor text to display in the previous posts link. * Default 'Older posts'. * @type string $next_text Anchor text to display in the next posts link. * Default 'Newer posts'. * @type string $screen_reader_text Screen reader text for nav element. * Default 'Posts navigation'. * } * @return string Markup for posts links. */ function get_the_posts_navigation( $args = array() ) { $navigation = ''; // Don't print empty markup if there's only one page. if ( $GLOBALS['wp_query']->max_num_pages > 1 ) { $args = wp_parse_args( $args, array( 'prev_text' => __( 'Older posts' ), 'next_text' => __( 'Newer posts' ), 'screen_reader_text' => __( 'Posts navigation' ), ) ); $next_link = get_previous_posts_link( $args['next_text'] ); $prev_link = get_next_posts_link( $args['prev_text'] ); if ( $prev_link ) { $navigation .= ''; } if ( $next_link ) { $navigation .= ''; } $navigation = _navigation_markup( $navigation, 'posts-navigation', $args['screen_reader_text'] ); } return $navigation; } /** * Displays the navigation to next/previous set of posts, when applicable. * * @since 4.1.0 * * @param array $args Optional. See get_the_posts_navigation() for available arguments. * Default empty array. */ function the_posts_navigation( $args = array() ) { echo get_the_posts_navigation( $args ); } /** * Retrieves a paginated navigation to next/previous set of posts, when applicable. * * @since 4.1.0 * * @param array $args { * Optional. Default pagination arguments, see paginate_links(). * * @type string $screen_reader_text Screen reader text for navigation element. * Default 'Posts navigation'. * } * @return string Markup for pagination links. */ function get_the_posts_pagination( $args = array() ) { $navigation = ''; // Don't print empty markup if there's only one page. if ( $GLOBALS['wp_query']->max_num_pages > 1 ) { $args = wp_parse_args( $args, array( 'mid_size' => 1, 'prev_text' => _x( 'Previous', 'previous set of posts' ), 'next_text' => _x( 'Next', 'next set of posts' ), 'screen_reader_text' => __( 'Posts navigation' ), ) ); // Make sure we get a string back. Plain is the next best thing. if ( isset( $args['type'] ) && 'array' == $args['type'] ) { $args['type'] = 'plain'; } // Set up paginated links. $links = paginate_links( $args ); if ( $links ) { $navigation = _navigation_markup( $links, 'pagination', $args['screen_reader_text'] ); } } return $navigation; } /** * Displays a paginated navigation to next/previous set of posts, when applicable. * * @since 4.1.0 * * @param array $args Optional. See get_the_posts_pagination() for available arguments. * Default empty array. */ function the_posts_pagination( $args = array() ) { echo get_the_posts_pagination( $args ); } /** * Wraps passed links in navigational markup. * * @since 4.1.0 * @access private * * @param string $links Navigational links. * @param string $class Optional. Custom class for nav element. Default: 'posts-navigation'. * @param string $screen_reader_text Optional. Screen reader text for nav element. Default: 'Posts navigation'. * @return string Navigation template tag. */ function _navigation_markup( $links, $class = 'posts-navigation', $screen_reader_text = '' ) { if ( empty( $screen_reader_text ) ) { $screen_reader_text = __( 'Posts navigation' ); } $template = ' '; /** * Filters the navigation markup template. * * Note: The filtered template HTML must contain specifiers for the navigation * class (%1$s), the screen-reader-text value (%2$s), and placement of the * navigation links (%3$s): * * * * @since 4.4.0 * * @param string $template The default template. * @param string $class The class passed by the calling function. * @return string Navigation template. */ $template = apply_filters( 'navigation_markup_template', $template, $class ); return sprintf( $template, sanitize_html_class( $class ), esc_html( $screen_reader_text ), $links ); } /** * Retrieves the comments page number link. * * @since 2.7.0 * * @global WP_Rewrite $wp_rewrite * * @param int $pagenum Optional. Page number. Default 1. * @param int $max_page Optional. The maximum number of comment pages. Default 0. * @return string The comments page number link URL. */ function get_comments_pagenum_link( $pagenum = 1, $max_page = 0 ) { global $wp_rewrite; $pagenum = (int) $pagenum; $result = get_permalink(); if ( 'newest' == get_option('default_comments_page') ) { if ( $pagenum != $max_page ) { if ( $wp_rewrite->using_permalinks() ) $result = user_trailingslashit( trailingslashit($result) . $wp_rewrite->comments_pagination_base . '-' . $pagenum, 'commentpaged'); else $result = add_query_arg( 'cpage', $pagenum, $result ); } } elseif ( $pagenum > 1 ) { if ( $wp_rewrite->using_permalinks() ) $result = user_trailingslashit( trailingslashit($result) . $wp_rewrite->comments_pagination_base . '-' . $pagenum, 'commentpaged'); else $result = add_query_arg( 'cpage', $pagenum, $result ); } $result .= '#comments'; /** * Filters the comments page number link for the current request. * * @since 2.7.0 * * @param string $result The comments page number link. */ return apply_filters( 'get_comments_pagenum_link', $result ); } /** * Retrieves the link to the next comments page. * * @since 2.7.1 * * @global WP_Query $wp_query * * @param string $label Optional. Label for link text. Default empty. * @param int $max_page Optional. Max page. Default 0. * @return string|void HTML-formatted link for the next page of comments. */ function get_next_comments_link( $label = '', $max_page = 0 ) { global $wp_query; if ( ! is_singular() ) return; $page = get_query_var('cpage'); if ( ! $page ) { $page = 1; } $nextpage = intval($page) + 1; if ( empty($max_page) ) $max_page = $wp_query->max_num_comment_pages; if ( empty($max_page) ) $max_page = get_comment_pages_count(); if ( $nextpage > $max_page ) return; if ( empty($label) ) $label = __('Newer Comments »'); /** * Filters the anchor tag attributes for the next comments page link. * * @since 2.7.0 * * @param string $attributes Attributes for the anchor tag. */ return ''. preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&$1', $label) .''; } /** * Displays the link to the next comments page. * * @since 2.7.0 * * @param string $label Optional. Label for link text. Default empty. * @param int $max_page Optional. Max page. Default 0. */ function next_comments_link( $label = '', $max_page = 0 ) { echo get_next_comments_link( $label, $max_page ); } /** * Retrieves the link to the previous comments page. * * @since 2.7.1 * * @param string $label Optional. Label for comments link text. Default empty. * @return string|void HTML-formatted link for the previous page of comments. */ function get_previous_comments_link( $label = '' ) { if ( ! is_singular() ) return; $page = get_query_var('cpage'); if ( intval($page) <= 1 ) return; $prevpage = intval($page) - 1; if ( empty($label) ) $label = __('« Older Comments'); /** * Filters the anchor tag attributes for the previous comments page link. * * @since 2.7.0 * * @param string $attributes Attributes for the anchor tag. */ return '' . preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&$1', $label) .''; } /** * Displays the link to the previous comments page. * * @since 2.7.0 * * @param string $label Optional. Label for comments link text. Default empty. */ function previous_comments_link( $label = '' ) { echo get_previous_comments_link( $label ); } /** * Displays or retrieves pagination links for the comments on the current post. * * @see paginate_links() * @since 2.7.0 * * @global WP_Rewrite $wp_rewrite * * @param string|array $args Optional args. See paginate_links(). Default empty array. * @return string|void Markup for pagination links. */ function paginate_comments_links( $args = array() ) { global $wp_rewrite; if ( ! is_singular() ) return; $page = get_query_var('cpage'); if ( !$page ) $page = 1; $max_page = get_comment_pages_count(); $defaults = array( 'base' => add_query_arg( 'cpage', '%#%' ), 'format' => '', 'total' => $max_page, 'current' => $page, 'echo' => true, 'add_fragment' => '#comments' ); if ( $wp_rewrite->using_permalinks() ) $defaults['base'] = user_trailingslashit(trailingslashit(get_permalink()) . $wp_rewrite->comments_pagination_base . '-%#%', 'commentpaged'); $args = wp_parse_args( $args, $defaults ); $page_links = paginate_links( $args ); if ( $args['echo'] ) echo $page_links; else return $page_links; } /** * Retrieves navigation to next/previous set of comments, when applicable. * * @since 4.4.0 * * @param array $args { * Optional. Default comments navigation arguments. * * @type string $prev_text Anchor text to display in the previous comments link. * Default 'Older comments'. * @type string $next_text Anchor text to display in the next comments link. * Default 'Newer comments'. * @type string $screen_reader_text Screen reader text for nav element. Default 'Comments navigation'. * } * @return string Markup for comments links. */ function get_the_comments_navigation( $args = array() ) { $navigation = ''; // Are there comments to navigate through? if ( get_comment_pages_count() > 1 ) { $args = wp_parse_args( $args, array( 'prev_text' => __( 'Older comments' ), 'next_text' => __( 'Newer comments' ), 'screen_reader_text' => __( 'Comments navigation' ), ) ); $prev_link = get_previous_comments_link( $args['prev_text'] ); $next_link = get_next_comments_link( $args['next_text'] ); if ( $prev_link ) { $navigation .= ''; } if ( $next_link ) { $navigation .= ''; } $navigation = _navigation_markup( $navigation, 'comment-navigation', $args['screen_reader_text'] ); } return $navigation; } /** * Displays navigation to next/previous set of comments, when applicable. * * @since 4.4.0 * * @param array $args See get_the_comments_navigation() for available arguments. Default empty array. */ function the_comments_navigation( $args = array() ) { echo get_the_comments_navigation( $args ); } /** * Retrieves a paginated navigation to next/previous set of comments, when applicable. * * @since 4.4.0 * * @see paginate_comments_links() * * @param array $args { * Optional. Default pagination arguments. * * @type string $screen_reader_text Screen reader text for nav element. Default 'Comments navigation'. * } * @return string Markup for pagination links. */ function get_the_comments_pagination( $args = array() ) { $navigation = ''; $args = wp_parse_args( $args, array( 'screen_reader_text' => __( 'Comments navigation' ), ) ); $args['echo'] = false; // Make sure we get a string back. Plain is the next best thing. if ( isset( $args['type'] ) && 'array' == $args['type'] ) { $args['type'] = 'plain'; } $links = paginate_comments_links( $args ); if ( $links ) { $navigation = _navigation_markup( $links, 'comments-pagination', $args['screen_reader_text'] ); } return $navigation; } /** * Displays a paginated navigation to next/previous set of comments, when applicable. * * @since 4.4.0 * * @param array $args See get_the_comments_pagination() for available arguments. Default empty array. */ function the_comments_pagination( $args = array() ) { echo get_the_comments_pagination( $args ); } /** * Retrieves the URL for the current site where the front end is accessible. * * Returns the 'home' option with the appropriate protocol. The protocol will be 'https' * if is_ssl() evaluates to true; otherwise, it will be the same as the 'home' option. * If `$scheme` is 'http' or 'https', is_ssl() is overridden. * * @since 3.0.0 * * @param string $path Optional. Path relative to the home URL. Default empty. * @param string|null $scheme Optional. Scheme to give the home URL context. Accepts * 'http', 'https', 'relative', 'rest', or null. Default null. * @return string Home URL link with optional path appended. */ function home_url( $path = '', $scheme = null ) { return get_home_url( null, $path, $scheme ); } /** * Retrieves the URL for a given site where the front end is accessible. * * Returns the 'home' option with the appropriate protocol. The protocol will be 'https' * if is_ssl() evaluates to true; otherwise, it will be the same as the 'home' option. * If `$scheme` is 'http' or 'https', is_ssl() is overridden. * * @since 3.0.0 * * @global string $pagenow * * @param int $blog_id Optional. Site ID. Default null (current site). * @param string $path Optional. Path relative to the home URL. Default empty. * @param string|null $scheme Optional. Scheme to give the home URL context. Accepts * 'http', 'https', 'relative', 'rest', or null. Default null. * @return string Home URL link with optional path appended. */ function get_home_url( $blog_id = null, $path = '', $scheme = null ) { global $pagenow; $orig_scheme = $scheme; if ( empty( $blog_id ) || !is_multisite() ) { $url = get_option( 'home' ); } else { switch_to_blog( $blog_id ); $url = get_option( 'home' ); restore_current_blog(); } if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ) ) ) { if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $pagenow ) $scheme = 'https'; else $scheme = parse_url( $url, PHP_URL_SCHEME ); } $url = set_url_scheme( $url, $scheme ); if ( $path && is_string( $path ) ) $url .= '/' . ltrim( $path, '/' ); /** * Filters the home URL. * * @since 3.0.0 * * @param string $url The complete home URL including scheme and path. * @param string $path Path relative to the home URL. Blank string if no path is specified. * @param string|null $orig_scheme Scheme to give the home URL context. Accepts 'http', 'https', * 'relative', 'rest', or null. * @param int|null $blog_id Site ID, or null for the current site. */ return apply_filters( 'home_url', $url, $path, $orig_scheme, $blog_id ); } /** * Retrieves the URL for the current site where WordPress application files * (e.g. wp-blog-header.php or the wp-admin/ folder) are accessible. * * Returns the 'site_url' option with the appropriate protocol, 'https' if * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is * overridden. * * @since 3.0.0 * * @param string $path Optional. Path relative to the site URL. Default empty. * @param string $scheme Optional. Scheme to give the site URL context. See set_url_scheme(). * @return string Site URL link with optional path appended. */ function site_url( $path = '', $scheme = null ) { return get_site_url( null, $path, $scheme ); } /** * Retrieves the URL for a given site where WordPress application files * (e.g. wp-blog-header.php or the wp-admin/ folder) are accessible. * * Returns the 'site_url' option with the appropriate protocol, 'https' if * is_ssl() and 'http' otherwise. If `$scheme` is 'http' or 'https', * `is_ssl()` is overridden. * * @since 3.0.0 * * @param int $blog_id Optional. Site ID. Default null (current site). * @param string $path Optional. Path relative to the site URL. Default empty. * @param string $scheme Optional. Scheme to give the site URL context. Accepts * 'http', 'https', 'login', 'login_post', 'admin', or * 'relative'. Default null. * @return string Site URL link with optional path appended. */ function get_site_url( $blog_id = null, $path = '', $scheme = null ) { if ( empty( $blog_id ) || !is_multisite() ) { $url = get_option( 'siteurl' ); } else { switch_to_blog( $blog_id ); $url = get_option( 'siteurl' ); restore_current_blog(); } $url = set_url_scheme( $url, $scheme ); if ( $path && is_string( $path ) ) $url .= '/' . ltrim( $path, '/' ); /** * Filters the site URL. * * @since 2.7.0 * * @param string $url The complete site URL including scheme and path. * @param string $path Path relative to the site URL. Blank string if no path is specified. * @param string|null $scheme Scheme to give the site URL context. Accepts 'http', 'https', 'login', * 'login_post', 'admin', 'relative' or null. * @param int|null $blog_id Site ID, or null for the current site. */ return apply_filters( 'site_url', $url, $path, $scheme, $blog_id ); } /** * Retrieves the URL to the admin area for the current site. * * @since 2.6.0 * * @param string $path Optional path relative to the admin URL. * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). * 'http' or 'https' can be passed to force those schemes. * @return string Admin URL link with optional path appended. */ function admin_url( $path = '', $scheme = 'admin' ) { return get_admin_url( null, $path, $scheme ); } /** * Retrieves the URL to the admin area for a given site. * * @since 3.0.0 * * @param int $blog_id Optional. Site ID. Default null (current site). * @param string $path Optional. Path relative to the admin URL. Default empty. * @param string $scheme Optional. The scheme to use. Accepts 'http' or 'https', * to force those schemes. Default 'admin', which obeys * force_ssl_admin() and is_ssl(). * @return string Admin URL link with optional path appended. */ function get_admin_url( $blog_id = null, $path = '', $scheme = 'admin' ) { $url = get_site_url($blog_id, 'wp-admin/', $scheme); if ( $path && is_string( $path ) ) $url .= ltrim( $path, '/' ); /** * Filters the admin area URL. * * @since 2.8.0 * * @param string $url The complete admin area URL including scheme and path. * @param string $path Path relative to the admin area URL. Blank string if no path is specified. * @param int|null $blog_id Site ID, or null for the current site. */ return apply_filters( 'admin_url', $url, $path, $blog_id ); } /** * Retrieves the URL to the includes directory. * * @since 2.6.0 * * @param string $path Optional. Path relative to the includes URL. Default empty. * @param string $scheme Optional. Scheme to give the includes URL context. Accepts * 'http', 'https', or 'relative'. Default null. * @return string Includes URL link with optional path appended. */ function includes_url( $path = '', $scheme = null ) { $url = site_url( '/' . WPINC . '/', $scheme ); if ( $path && is_string( $path ) ) $url .= ltrim($path, '/'); /** * Filters the URL to the includes directory. * * @since 2.8.0 * * @param string $url The complete URL to the includes directory including scheme and path. * @param string $path Path relative to the URL to the wp-includes directory. Blank string * if no path is specified. */ return apply_filters( 'includes_url', $url, $path ); } /** * Retrieves the URL to the content directory. * * @since 2.6.0 * * @param string $path Optional. Path relative to the content URL. Default empty. * @return string Content URL link with optional path appended. */ function content_url( $path = '' ) { $url = set_url_scheme( WP_CONTENT_URL ); if ( $path && is_string( $path ) ) $url .= '/' . ltrim($path, '/'); /** * Filters the URL to the content directory. * * @since 2.8.0 * * @param string $url The complete URL to the content directory including scheme and path. * @param string $path Path relative to the URL to the content directory. Blank string * if no path is specified. */ return apply_filters( 'content_url', $url, $path); } /** * Retrieves a URL within the plugins or mu-plugins directory. * * Defaults to the plugins directory URL if no arguments are supplied. * * @since 2.6.0 * * @param string $path Optional. Extra path appended to the end of the URL, including * the relative directory if $plugin is supplied. Default empty. * @param string $plugin Optional. A full path to a file inside a plugin or mu-plugin. * The URL will be relative to its directory. Default empty. * Typically this is done by passing `__FILE__` as the argument. * @return string Plugins URL link with optional paths appended. */ function plugins_url( $path = '', $plugin = '' ) { $path = wp_normalize_path( $path ); $plugin = wp_normalize_path( $plugin ); $mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR ); if ( !empty($plugin) && 0 === strpos($plugin, $mu_plugin_dir) ) $url = WPMU_PLUGIN_URL; else $url = WP_PLUGIN_URL; $url = set_url_scheme( $url ); if ( !empty($plugin) && is_string($plugin) ) { $folder = dirname(plugin_basename($plugin)); if ( '.' != $folder ) $url .= '/' . ltrim($folder, '/'); } if ( $path && is_string( $path ) ) $url .= '/' . ltrim($path, '/'); /** * Filters the URL to the plugins directory. * * @since 2.8.0 * * @param string $url The complete URL to the plugins directory including scheme and path. * @param string $path Path relative to the URL to the plugins directory. Blank string * if no path is specified. * @param string $plugin The plugin file path to be relative to. Blank string if no plugin * is specified. */ return apply_filters( 'plugins_url', $url, $path, $plugin ); } /** * Retrieves the site URL for the current network. * * Returns the site URL with the appropriate protocol, 'https' if * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is * overridden. * * @since 3.0.0 * * @see set_url_scheme() * * @param string $path Optional. Path relative to the site URL. Default empty. * @param string $scheme Optional. Scheme to give the site URL context. Accepts * 'http', 'https', or 'relative'. Default null. * @return string Site URL link with optional path appended. */ function network_site_url( $path = '', $scheme = null ) { if ( ! is_multisite() ) return site_url($path, $scheme); $current_network = get_network(); if ( 'relative' == $scheme ) $url = $current_network->path; else $url = set_url_scheme( 'http://' . $current_network->domain . $current_network->path, $scheme ); if ( $path && is_string( $path ) ) $url .= ltrim( $path, '/' ); /** * Filters the network site URL. * * @since 3.0.0 * * @param string $url The complete network site URL including scheme and path. * @param string $path Path relative to the network site URL. Blank string if * no path is specified. * @param string|null $scheme Scheme to give the URL context. Accepts 'http', 'https', * 'relative' or null. */ return apply_filters( 'network_site_url', $url, $path, $scheme ); } /** * Retrieves the home URL for the current network. * * Returns the home URL with the appropriate protocol, 'https' is_ssl() * and 'http' otherwise. If `$scheme` is 'http' or 'https', `is_ssl()` is * overridden. * * @since 3.0.0 * * @param string $path Optional. Path relative to the home URL. Default empty. * @param string $scheme Optional. Scheme to give the home URL context. Accepts * 'http', 'https', or 'relative'. Default null. * @return string Home URL link with optional path appended. */ function network_home_url( $path = '', $scheme = null ) { if ( ! is_multisite() ) return home_url($path, $scheme); $current_network = get_network(); $orig_scheme = $scheme; if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ) ) ) $scheme = is_ssl() && ! is_admin() ? 'https' : 'http'; if ( 'relative' == $scheme ) $url = $current_network->path; else $url = set_url_scheme( 'http://' . $current_network->domain . $current_network->path, $scheme ); if ( $path && is_string( $path ) ) $url .= ltrim( $path, '/' ); /** * Filters the network home URL. * * @since 3.0.0 * * @param string $url The complete network home URL including scheme and path. * @param string $path Path relative to the network home URL. Blank string * if no path is specified. * @param string|null $orig_scheme Scheme to give the URL context. Accepts 'http', 'https', * 'relative' or null. */ return apply_filters( 'network_home_url', $url, $path, $orig_scheme); } /** * Retrieves the URL to the admin area for the network. * * @since 3.0.0 * * @param string $path Optional path relative to the admin URL. Default empty. * @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin() * and is_ssl(). 'http' or 'https' can be passed to force those schemes. * @return string Admin URL link with optional path appended. */ function network_admin_url( $path = '', $scheme = 'admin' ) { if ( ! is_multisite() ) return admin_url( $path, $scheme ); $url = network_site_url('wp-admin/network/', $scheme); if ( $path && is_string( $path ) ) $url .= ltrim($path, '/'); /** * Filters the network admin URL. * * @since 3.0.0 * * @param string $url The complete network admin URL including scheme and path. * @param string $path Path relative to the network admin URL. Blank string if * no path is specified. */ return apply_filters( 'network_admin_url', $url, $path ); } /** * Retrieves the URL to the admin area for the current user. * * @since 3.0.0 * * @param string $path Optional. Path relative to the admin URL. Default empty. * @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin() * and is_ssl(). 'http' or 'https' can be passed to force those schemes. * @return string Admin URL link with optional path appended. */ function user_admin_url( $path = '', $scheme = 'admin' ) { $url = network_site_url('wp-admin/user/', $scheme); if ( $path && is_string( $path ) ) $url .= ltrim($path, '/'); /** * Filters the user admin URL for the current user. * * @since 3.1.0 * * @param string $url The complete URL including scheme and path. * @param string $path Path relative to the URL. Blank string if * no path is specified. */ return apply_filters( 'user_admin_url', $url, $path ); } /** * Retrieves the URL to the admin area for either the current site or the network depending on context. * * @since 3.1.0 * * @param string $path Optional. Path relative to the admin URL. Default empty. * @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin() * and is_ssl(). 'http' or 'https' can be passed to force those schemes. * @return string Admin URL link with optional path appended. */ function self_admin_url( $path = '', $scheme = 'admin' ) { if ( is_network_admin() ) { $url = network_admin_url( $path, $scheme ); } elseif ( is_user_admin() ) { $url = user_admin_url( $path, $scheme ); } else { $url = admin_url( $path, $scheme ); } /** * Filters the admin URL for the current site or network depending on context. * * @since 4.9.0 * * @param string $url The complete URL including scheme and path. * @param string $path Path relative to the URL. Blank string if no path is specified. * @param string $scheme The scheme to use. */ return apply_filters( 'self_admin_url', $url, $path, $scheme ); } /** * Sets the scheme for a URL. * * @since 3.4.0 * @since 4.4.0 The 'rest' scheme was added. * * @param string $url Absolute URL that includes a scheme * @param string|null $scheme Optional. Scheme to give $url. Currently 'http', 'https', 'login', * 'login_post', 'admin', 'relative', 'rest', 'rpc', or null. Default null. * @return string $url URL with chosen scheme. */ function set_url_scheme( $url, $scheme = null ) { $orig_scheme = $scheme; if ( ! $scheme ) { $scheme = is_ssl() ? 'https' : 'http'; } elseif ( $scheme === 'admin' || $scheme === 'login' || $scheme === 'login_post' || $scheme === 'rpc' ) { $scheme = is_ssl() || force_ssl_admin() ? 'https' : 'http'; } elseif ( $scheme !== 'http' && $scheme !== 'https' && $scheme !== 'relative' ) { $scheme = is_ssl() ? 'https' : 'http'; } $url = trim( $url ); if ( substr( $url, 0, 2 ) === '//' ) $url = 'http:' . $url; if ( 'relative' == $scheme ) { $url = ltrim( preg_replace( '#^\w+://[^/]*#', '', $url ) ); if ( $url !== '' && $url[0] === '/' ) $url = '/' . ltrim($url , "/ \t\n\r\0\x0B" ); } else { $url = preg_replace( '#^\w+://#', $scheme . '://', $url ); } /** * Filters the resulting URL after setting the scheme. * * @since 3.4.0 * * @param string $url The complete URL including scheme and path. * @param string $scheme Scheme applied to the URL. One of 'http', 'https', or 'relative'. * @param string|null $orig_scheme Scheme requested for the URL. One of 'http', 'https', 'login', * 'login_post', 'admin', 'relative', 'rest', 'rpc', or null. */ return apply_filters( 'set_url_scheme', $url, $scheme, $orig_scheme ); } /** * Retrieves the URL to the user's dashboard. * * If a user does not belong to any site, the global user dashboard is used. If the user * belongs to the current site, the dashboard for the current site is returned. If the user * cannot edit the current site, the dashboard to the user's primary site is returned. * * @since 3.1.0 * * @param int $user_id Optional. User ID. Defaults to current user. * @param string $path Optional path relative to the dashboard. Use only paths known to * both site and user admins. Default empty. * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() * and is_ssl(). 'http' or 'https' can be passed to force those schemes. * @return string Dashboard URL link with optional path appended. */ function get_dashboard_url( $user_id = 0, $path = '', $scheme = 'admin' ) { $user_id = $user_id ? (int) $user_id : get_current_user_id(); $blogs = get_blogs_of_user( $user_id ); if ( is_multisite() && ! user_can( $user_id, 'manage_network' ) && empty($blogs) ) { $url = user_admin_url( $path, $scheme ); } elseif ( ! is_multisite() ) { $url = admin_url( $path, $scheme ); } else { $current_blog = get_current_blog_id(); if ( $current_blog && ( user_can( $user_id, 'manage_network' ) || in_array( $current_blog, array_keys( $blogs ) ) ) ) { $url = admin_url( $path, $scheme ); } else { $active = get_active_blog_for_user( $user_id ); if ( $active ) $url = get_admin_url( $active->blog_id, $path, $scheme ); else $url = user_admin_url( $path, $scheme ); } } /** * Filters the dashboard URL for a user. * * @since 3.1.0 * * @param string $url The complete URL including scheme and path. * @param int $user_id The user ID. * @param string $path Path relative to the URL. Blank string if no path is specified. * @param string $scheme Scheme to give the URL context. Accepts 'http', 'https', 'login', * 'login_post', 'admin', 'relative' or null. */ return apply_filters( 'user_dashboard_url', $url, $user_id, $path, $scheme); } /** * Retrieves the URL to the user's profile editor. * * @since 3.1.0 * * @param int $user_id Optional. User ID. Defaults to current user. * @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin() * and is_ssl(). 'http' or 'https' can be passed to force those schemes. * @return string Dashboard URL link with optional path appended. */ function get_edit_profile_url( $user_id = 0, $scheme = 'admin' ) { $user_id = $user_id ? (int) $user_id : get_current_user_id(); if ( is_user_admin() ) $url = user_admin_url( 'profile.php', $scheme ); elseif ( is_network_admin() ) $url = network_admin_url( 'profile.php', $scheme ); else $url = get_dashboard_url( $user_id, 'profile.php', $scheme ); /** * Filters the URL for a user's profile editor. * * @since 3.1.0 * * @param string $url The complete URL including scheme and path. * @param int $user_id The user ID. * @param string $scheme Scheme to give the URL context. Accepts 'http', 'https', 'login', * 'login_post', 'admin', 'relative' or null. */ return apply_filters( 'edit_profile_url', $url, $user_id, $scheme); } /** * Returns the canonical URL for a post. * * When the post is the same as the current requested page the function will handle the * pagination arguments too. * * @since 4.6.0 * * @param int|WP_Post $post Optional. Post ID or object. Default is global `$post`. * @return string|false The canonical URL, or false if the post does not exist or has not * been published yet. */ function wp_get_canonical_url( $post = null ) { $post = get_post( $post ); if ( ! $post ) { return false; } if ( 'publish' !== $post->post_status ) { return false; } $canonical_url = get_permalink( $post ); // If a canonical is being generated for the current page, make sure it has pagination if needed. if ( $post->ID === get_queried_object_id() ) { $page = get_query_var( 'page', 0 ); if ( $page >= 2 ) { if ( '' == get_option( 'permalink_structure' ) ) { $canonical_url = add_query_arg( 'page', $page, $canonical_url ); } else { $canonical_url = trailingslashit( $canonical_url ) . user_trailingslashit( $page, 'single_paged' ); } } $cpage = get_query_var( 'cpage', 0 ); if ( $cpage ) { $canonical_url = get_comments_pagenum_link( $cpage ); } } /** * Filters the canonical URL for a post. * * @since 4.6.0 * * @param string $canonical_url The post's canonical URL. * @param WP_Post $post Post object. */ return apply_filters( 'get_canonical_url', $canonical_url, $post ); } /** * Outputs rel=canonical for singular queries. * * @since 2.9.0 * @since 4.6.0 Adjusted to use wp_get_canonical_url(). */ function rel_canonical() { if ( ! is_singular() ) { return; } $id = get_queried_object_id(); if ( 0 === $id ) { return; } $url = wp_get_canonical_url( $id ); if ( ! empty( $url ) ) { echo '' . "\n"; } } /** * Returns a shortlink for a post, page, attachment, or site. * * This function exists to provide a shortlink tag that all themes and plugins can target. * A plugin must hook in to provide the actual shortlinks. Default shortlink support is * limited to providing ?p= style links for posts. Plugins can short-circuit this function * via the {@see 'pre_get_shortlink'} filter or filter the output via the {@see 'get_shortlink'} * filter. * * @since 3.0.0. * * @param int $id Optional. A post or site id. Default is 0, which means the current post or site. * @param string $context Optional. Whether the id is a 'site' id, 'post' id, or 'media' id. If 'post', * the post_type of the post is consulted. If 'query', the current query is consulted * to determine the id and context. Default 'post'. * @param bool $allow_slugs Optional. Whether to allow post slugs in the shortlink. It is up to the plugin how * and whether to honor this. Default true. * @return string A shortlink or an empty string if no shortlink exists for the requested resource or if shortlinks * are not enabled. */ function wp_get_shortlink( $id = 0, $context = 'post', $allow_slugs = true ) { /** * Filters whether to preempt generating a shortlink for the given post. * * Passing a truthy value to the filter will effectively short-circuit the * shortlink-generation process, returning that value instead. * * @since 3.0.0 * * @param bool|string $return Short-circuit return value. Either false or a URL string. * @param int $id Post ID, or 0 for the current post. * @param string $context The context for the link. One of 'post' or 'query', * @param bool $allow_slugs Whether to allow post slugs in the shortlink. */ $shortlink = apply_filters( 'pre_get_shortlink', false, $id, $context, $allow_slugs ); if ( false !== $shortlink ) { return $shortlink; } $post_id = 0; if ( 'query' == $context && is_singular() ) { $post_id = get_queried_object_id(); $post = get_post( $post_id ); } elseif ( 'post' == $context ) { $post = get_post( $id ); if ( ! empty( $post->ID ) ) $post_id = $post->ID; } $shortlink = ''; // Return p= link for all public post types. if ( ! empty( $post_id ) ) { $post_type = get_post_type_object( $post->post_type ); if ( 'page' === $post->post_type && $post->ID == get_option( 'page_on_front' ) && 'page' == get_option( 'show_on_front' ) ) { $shortlink = home_url( '/' ); } elseif ( $post_type->public ) { $shortlink = home_url( '?p=' . $post_id ); } } /** * Filters the shortlink for a post. * * @since 3.0.0 * * @param string $shortlink Shortlink URL. * @param int $id Post ID, or 0 for the current post. * @param string $context The context for the link. One of 'post' or 'query', * @param bool $allow_slugs Whether to allow post slugs in the shortlink. Not used by default. */ return apply_filters( 'get_shortlink', $shortlink, $id, $context, $allow_slugs ); } /** * Injects rel=shortlink into the head if a shortlink is defined for the current page. * * Attached to the {@see 'wp_head'} action. * * @since 3.0.0 */ function wp_shortlink_wp_head() { $shortlink = wp_get_shortlink( 0, 'query' ); if ( empty( $shortlink ) ) return; echo "\n"; } /** * Sends a Link: rel=shortlink header if a shortlink is defined for the current page. * * Attached to the {@see 'wp'} action. * * @since 3.0.0 */ function wp_shortlink_header() { if ( headers_sent() ) return; $shortlink = wp_get_shortlink(0, 'query'); if ( empty($shortlink) ) return; header('Link: <' . $shortlink . '>; rel=shortlink', false); } /** * Displays the shortlink for a post. * * Must be called from inside "The Loop" * * Call like the_shortlink( __( 'Shortlinkage FTW' ) ) * * @since 3.0.0 * * @param string $text Optional The link text or HTML to be displayed. Defaults to 'This is the short link.' * @param string $title Optional The tooltip for the link. Must be sanitized. Defaults to the sanitized post title. * @param string $before Optional HTML to display before the link. Default empty. * @param string $after Optional HTML to display after the link. Default empty. */ function the_shortlink( $text = '', $title = '', $before = '', $after = '' ) { $post = get_post(); if ( empty( $text ) ) $text = __('This is the short link.'); if ( empty( $title ) ) $title = the_title_attribute( array( 'echo' => false ) ); $shortlink = wp_get_shortlink( $post->ID ); if ( !empty( $shortlink ) ) { $link = '' . $text . ''; /** * Filters the short link anchor tag for a post. * * @since 3.0.0 * * @param string $link Shortlink anchor tag. * @param string $shortlink Shortlink URL. * @param string $text Shortlink's text. * @param string $title Shortlink's title attribute. */ $link = apply_filters( 'the_shortlink', $link, $shortlink, $text, $title ); echo $before, $link, $after; } } /** * Retrieves the avatar URL. * * @since 4.2.0 * * @param mixed $id_or_email The Gravatar to retrieve a URL for. Accepts a user_id, gravatar md5 hash, * user email, WP_User object, WP_Post object, or WP_Comment object. * @param array $args { * Optional. Arguments to return instead of the default arguments. * * @type int $size Height and width of the avatar in pixels. Default 96. * @type string $default URL for the default image or a default type. Accepts '404' (return * a 404 instead of a default image), 'retro' (8bit), 'monsterid' (monster), * 'wavatar' (cartoon face), 'indenticon' (the "quilt"), 'mystery', 'mm', * or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF), or * 'gravatar_default' (the Gravatar logo). Default is the value of the * 'avatar_default' option, with a fallback of 'mystery'. * @type bool $force_default Whether to always show the default image, never the Gravatar. Default false. * @type string $rating What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are * judged in that order. Default is the value of the 'avatar_rating' option. * @type string $scheme URL scheme to use. See set_url_scheme() for accepted values. * Default null. * @type array $processed_args When the function returns, the value will be the processed/sanitized $args * plus a "found_avatar" guess. Pass as a reference. Default null. * } * @return false|string The URL of the avatar we found, or false if we couldn't find an avatar. */ function get_avatar_url( $id_or_email, $args = null ) { $args = get_avatar_data( $id_or_email, $args ); return $args['url']; } /** * Retrieves default data about the avatar. * * @since 4.2.0 * * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash, * user email, WP_User object, WP_Post object, or WP_Comment object. * @param array $args { * Optional. Arguments to return instead of the default arguments. * * @type int $size Height and width of the avatar image file in pixels. Default 96. * @type int $height Display height of the avatar in pixels. Defaults to $size. * @type int $width Display width of the avatar in pixels. Defaults to $size. * @type string $default URL for the default image or a default type. Accepts '404' (return * a 404 instead of a default image), 'retro' (8bit), 'monsterid' (monster), * 'wavatar' (cartoon face), 'indenticon' (the "quilt"), 'mystery', 'mm', * or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF), or * 'gravatar_default' (the Gravatar logo). Default is the value of the * 'avatar_default' option, with a fallback of 'mystery'. * @type bool $force_default Whether to always show the default image, never the Gravatar. Default false. * @type string $rating What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are * judged in that order. Default is the value of the 'avatar_rating' option. * @type string $scheme URL scheme to use. See set_url_scheme() for accepted values. * Default null. * @type array $processed_args When the function returns, the value will be the processed/sanitized $args * plus a "found_avatar" guess. Pass as a reference. Default null. * @type string $extra_attr HTML attributes to insert in the IMG element. Is not sanitized. Default empty. * } * @return array $processed_args { * Along with the arguments passed in `$args`, this will contain a couple of extra arguments. * * @type bool $found_avatar True if we were able to find an avatar for this user, * false or not set if we couldn't. * @type string $url The URL of the avatar we found. * } */ function get_avatar_data( $id_or_email, $args = null ) { $args = wp_parse_args( $args, array( 'size' => 96, 'height' => null, 'width' => null, 'default' => get_option( 'avatar_default', 'mystery' ), 'force_default' => false, 'rating' => get_option( 'avatar_rating' ), 'scheme' => null, 'processed_args' => null, // if used, should be a reference 'extra_attr' => '', ) ); if ( is_numeric( $args['size'] ) ) { $args['size'] = absint( $args['size'] ); if ( ! $args['size'] ) { $args['size'] = 96; } } else { $args['size'] = 96; } if ( is_numeric( $args['height'] ) ) { $args['height'] = absint( $args['height'] ); if ( ! $args['height'] ) { $args['height'] = $args['size']; } } else { $args['height'] = $args['size']; } if ( is_numeric( $args['width'] ) ) { $args['width'] = absint( $args['width'] ); if ( ! $args['width'] ) { $args['width'] = $args['size']; } } else { $args['width'] = $args['size']; } if ( empty( $args['default'] ) ) { $args['default'] = get_option( 'avatar_default', 'mystery' ); } switch ( $args['default'] ) { case 'mm' : case 'mystery' : case 'mysteryman' : $args['default'] = 'mm'; break; case 'gravatar_default' : $args['default'] = false; break; } $args['force_default'] = (bool) $args['force_default']; $args['rating'] = strtolower( $args['rating'] ); $args['found_avatar'] = false; /** * Filters whether to retrieve the avatar URL early. * * Passing a non-null value in the 'url' member of the return array will * effectively short circuit get_avatar_data(), passing the value through * the {@see 'get_avatar_data'} filter and returning early. * * @since 4.2.0 * * @param array $args Arguments passed to get_avatar_data(), after processing. * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash, * user email, WP_User object, WP_Post object, or WP_Comment object. */ $args = apply_filters( 'pre_get_avatar_data', $args, $id_or_email ); if ( isset( $args['url'] ) && ! is_null( $args['url'] ) ) { /** This filter is documented in wp-includes/link-template.php */ return apply_filters( 'get_avatar_data', $args, $id_or_email ); } $email_hash = ''; $user = $email = false; if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) { $id_or_email = get_comment( $id_or_email ); } // Process the user identifier. if ( is_numeric( $id_or_email ) ) { $user = get_user_by( 'id', absint( $id_or_email ) ); } elseif ( is_string( $id_or_email ) ) { if ( strpos( $id_or_email, '@md5.gravatar.com' ) ) { // md5 hash list( $email_hash ) = explode( '@', $id_or_email ); } else { // email address $email = $id_or_email; } } elseif ( $id_or_email instanceof WP_User ) { // User Object $user = $id_or_email; } elseif ( $id_or_email instanceof WP_Post ) { // Post Object $user = get_user_by( 'id', (int) $id_or_email->post_author ); } elseif ( $id_or_email instanceof WP_Comment ) { /** * Filters the list of allowed comment types for retrieving avatars. * * @since 3.0.0 * * @param array $types An array of content types. Default only contains 'comment'. */ $allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) ); if ( ! empty( $id_or_email->comment_type ) && ! in_array( $id_or_email->comment_type, (array) $allowed_comment_types ) ) { $args['url'] = false; /** This filter is documented in wp-includes/link-template.php */ return apply_filters( 'get_avatar_data', $args, $id_or_email ); } if ( ! empty( $id_or_email->user_id ) ) { $user = get_user_by( 'id', (int) $id_or_email->user_id ); } if ( ( ! $user || is_wp_error( $user ) ) && ! empty( $id_or_email->comment_author_email ) ) { $email = $id_or_email->comment_author_email; } } if ( ! $email_hash ) { if ( $user ) { $email = $user->user_email; } if ( $email ) { $email_hash = md5( strtolower( trim( $email ) ) ); } } if ( $email_hash ) { $args['found_avatar'] = true; $gravatar_server = hexdec( $email_hash[0] ) % 3; } else { $gravatar_server = rand( 0, 2 ); } $url_args = array( 's' => $args['size'], 'd' => $args['default'], 'f' => $args['force_default'] ? 'y' : false, 'r' => $args['rating'], ); if ( is_ssl() ) { $url = 'https://secure.gravatar.com/avatar/' . $email_hash; } else { $url = sprintf( 'http://%d.gravatar.com/avatar/%s', $gravatar_server, $email_hash ); } $url = add_query_arg( rawurlencode_deep( array_filter( $url_args ) ), set_url_scheme( $url, $args['scheme'] ) ); /** * Filters the avatar URL. * * @since 4.2.0 * * @param string $url The URL of the avatar. * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash, * user email, WP_User object, WP_Post object, or WP_Comment object. * @param array $args Arguments passed to get_avatar_data(), after processing. */ $args['url'] = apply_filters( 'get_avatar_url', $url, $id_or_email, $args ); /** * Filters the avatar data. * * @since 4.2.0 * * @param array $args Arguments passed to get_avatar_data(), after processing. * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash, * user email, WP_User object, WP_Post object, or WP_Comment object. */ return apply_filters( 'get_avatar_data', $args, $id_or_email ); } /** * Retrieves the URL of a file in the theme. * * Searches in the stylesheet directory before the template directory so themes * which inherit from a parent theme can just override one file. * * @since 4.7.0 * * @param string $file Optional. File to search for in the stylesheet directory. * @return string The URL of the file. */ function get_theme_file_uri( $file = '' ) { $file = ltrim( $file, '/' ); if ( empty( $file ) ) { $url = get_stylesheet_directory_uri(); } elseif ( file_exists( get_stylesheet_directory() . '/' . $file ) ) { $url = get_stylesheet_directory_uri() . '/' . $file; } else { $url = get_template_directory_uri() . '/' . $file; } /** * Filters the URL to a file in the theme. * * @since 4.7.0 * * @param string $url The file URL. * @param string $file The requested file to search for. */ return apply_filters( 'theme_file_uri', $url, $file ); } /** * Retrieves the URL of a file in the parent theme. * * @since 4.7.0 * * @param string $file Optional. File to return the URL for in the template directory. * @return string The URL of the file. */ function get_parent_theme_file_uri( $file = '' ) { $file = ltrim( $file, '/' ); if ( empty( $file ) ) { $url = get_template_directory_uri(); } else { $url = get_template_directory_uri() . '/' . $file; } /** * Filters the URL to a file in the parent theme. * * @since 4.7.0 * * @param string $url The file URL. * @param string $file The requested file to search for. */ return apply_filters( 'parent_theme_file_uri', $url, $file ); } /** * Retrieves the path of a file in the theme. * * Searches in the stylesheet directory before the template directory so themes * which inherit from a parent theme can just override one file. * * @since 4.7.0 * * @param string $file Optional. File to search for in the stylesheet directory. * @return string The path of the file. */ function get_theme_file_path( $file = '' ) { $file = ltrim( $file, '/' ); if ( empty( $file ) ) { $path = get_stylesheet_directory(); } elseif ( file_exists( get_stylesheet_directory() . '/' . $file ) ) { $path = get_stylesheet_directory() . '/' . $file; } else { $path = get_template_directory() . '/' . $file; } /** * Filters the path to a file in the theme. * * @since 4.7.0 * * @param string $path The file path. * @param string $file The requested file to search for. */ return apply_filters( 'theme_file_path', $path, $file ); } /** * Retrieves the path of a file in the parent theme. * * @since 4.7.0 * * @param string $file Optional. File to return the path for in the template directory. * @return string The path of the file. */ function get_parent_theme_file_path( $file = '' ) { $file = ltrim( $file, '/' ); if ( empty( $file ) ) { $path = get_template_directory(); } else { $path = get_template_directory() . '/' . $file; } /** * Filters the path to a file in the parent theme. * * @since 4.7.0 * * @param string $path The file path. * @param string $file The requested file to search for. */ return apply_filters( 'parent_theme_file_path', $path, $file ); } /** * Retrieves the URL to the privacy policy page. * * @since 4.9.6 * * @return string The URL to the privacy policy page. Empty string if it doesn't exist. */ function get_privacy_policy_url() { $url = ''; $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); if ( ! empty( $policy_page_id ) && get_post_status( $policy_page_id ) === 'publish' ) { $url = (string) get_permalink( $policy_page_id ); } /** * Filters the URL of the privacy policy page. * * @since 4.9.6 * * @param string $url The URL to the privacy policy page. Empty string * if it doesn't exist. * @param int $policy_page_id The ID of privacy policy page. */ return apply_filters( 'privacy_policy_url', $url, $policy_page_id ); } /** * Displays the privacy policy link with formatting, when applicable. * * @since 4.9.6 * * @param string $before Optional. Display before privacy policy link. Default empty. * @param string $after Optional. Display after privacy policy link. Default empty. */ function the_privacy_policy_link( $before = '', $after = '' ) { echo get_the_privacy_policy_link( $before, $after ); } /** * Returns the privacy policy link with formatting, when applicable. * * @since 4.9.6 * * @param string $before Optional. Display before privacy policy link. Default empty. * @param string $after Optional. Display after privacy policy link. Default empty. * * @return string Markup for the link and surrounding elements. Empty string if it * doesn't exist. */ function get_the_privacy_policy_link( $before = '', $after = '' ) { $link = ''; $privacy_policy_url = get_privacy_policy_url(); $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); $page_title = ( $policy_page_id ) ? get_the_title( $policy_page_id ) : ''; if ( $privacy_policy_url && $page_title ) { $link = sprintf( '%s', esc_url( $privacy_policy_url ), esc_html( $page_title ) ); } /** * Filters the privacy policy link. * * @since 4.9.6 * * @param string $link The privacy policy link. Empty string if it * doesn't exist. * @param string $privacy_policy_url The URL of the privacy policy. Empty string * if it doesn't exist. */ $link = apply_filters( 'the_privacy_policy_link', $link, $privacy_policy_url ); if ( $link ) { return $before . $link . $after; } return ''; } $default_types, 'src' ); } else { foreach ( $default_types as $ext ) { if ( ! empty( $atts[ $ext ] ) ) { $type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() ); if ( strtolower( $type['ext'] ) === $ext ) { $primary = true; } } } } if ( ! $primary ) { $videos = get_attached_media( 'video', $post_id ); if ( empty( $videos ) ) { return; } $video = reset( $videos ); $atts['src'] = wp_get_attachment_url( $video->ID ); if ( empty( $atts['src'] ) ) { return; } array_unshift( $default_types, 'src' ); } /** * Filters the media library used for the video shortcode. * * @since 3.6.0 * * @param string $library Media library used for the video shortcode. */ $library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' ); if ( 'mediaelement' === $library && did_action( 'init' ) ) { wp_enqueue_style( 'wp-mediaelement' ); wp_enqueue_script( 'wp-mediaelement' ); wp_enqueue_script( 'mediaelement-vimeo' ); } // Mediaelement has issues with some URL formats for Vimeo and YouTube, so // update the URL to prevent the ME.js player from breaking. if ( 'mediaelement' === $library ) { if ( $is_youtube ) { // Remove `feature` query arg and force SSL - see #40866. $atts['src'] = remove_query_arg( 'feature', $atts['src'] ); $atts['src'] = set_url_scheme( $atts['src'], 'https' ); } elseif ( $is_vimeo ) { // Remove all query arguments and force SSL - see #40866. $parsed_vimeo_url = wp_parse_url( $atts['src'] ); $vimeo_src = 'https://' . $parsed_vimeo_url['host'] . $parsed_vimeo_url['path']; // Add loop param for mejs bug - see #40977, not needed after #39686. $loop = $atts['loop'] ? '1' : '0'; $atts['src'] = add_query_arg( 'loop', $loop, $vimeo_src ); } } /** * Filters the class attribute for the video shortcode output container. * * @since 3.6.0 * @since 4.9.0 The `$atts` parameter was added. * * @param string $class CSS class or list of space-separated classes. * @param array $atts Array of video shortcode attributes. */ $atts['class'] = apply_filters( 'wp_video_shortcode_class', $atts['class'], $atts ); $html_atts = array( 'class' => $atts['class'], 'id' => sprintf( 'video-%d-%d', $post_id, $instance ), 'width' => absint( $atts['width'] ), 'height' => absint( $atts['height'] ), 'poster' => esc_url( $atts['poster'] ), 'loop' => wp_validate_boolean( $atts['loop'] ), 'autoplay' => wp_validate_boolean( $atts['autoplay'] ), 'preload' => $atts['preload'], ); // These ones should just be omitted altogether if they are blank foreach ( array( 'poster', 'loop', 'autoplay', 'preload' ) as $a ) { if ( empty( $html_atts[$a] ) ) { unset( $html_atts[$a] ); } } $attr_strings = array(); foreach ( $html_atts as $k => $v ) { $attr_strings[] = $k . '="' . esc_attr( $v ) . '"'; } $html = ''; if ( 'mediaelement' === $library && 1 === $instance ) { $html .= "\n"; } $html .= sprintf( ''; $width_rule = ''; if ( ! empty( $atts['width'] ) ) { $width_rule = sprintf( 'width: %dpx;', $atts['width'] ); } $output = sprintf( '
%s
', $width_rule, $html ); /** * Filters the output of the video shortcode. * * @since 3.6.0 * * @param string $output Video shortcode HTML output. * @param array $atts Array of video shortcode attributes. * @param string $video Video file. * @param int $post_id Post ID. * @param string $library Media library used for the video shortcode. */ return apply_filters( 'wp_video_shortcode', $output, $atts, $video, $post_id, $library ); } add_shortcode( 'video', 'wp_video_shortcode' ); /** * Displays previous image link that has the same post parent. * * @since 2.5.0 * * @see adjacent_image_link() * * @param string|array $size Optional. Image size. Accepts any valid image size, an array of width and * height values in pixels (in that order), 0, or 'none'. 0 or 'none' will * default to 'post_title' or `$text`. Default 'thumbnail'. * @param string $text Optional. Link text. Default false. */ function previous_image_link( $size = 'thumbnail', $text = false ) { adjacent_image_link(true, $size, $text); } /** * Displays next image link that has the same post parent. * * @since 2.5.0 * * @see adjacent_image_link() * * @param string|array $size Optional. Image size. Accepts any valid image size, an array of width and * height values in pixels (in that order), 0, or 'none'. 0 or 'none' will * default to 'post_title' or `$text`. Default 'thumbnail'. * @param string $text Optional. Link text. Default false. */ function next_image_link( $size = 'thumbnail', $text = false ) { adjacent_image_link(false, $size, $text); } /** * Displays next or previous image link that has the same post parent. * * Retrieves the current attachment object from the $post global. * * @since 2.5.0 * * @param bool $prev Optional. Whether to display the next (false) or previous (true) link. Default true. * @param string|array $size Optional. Image size. Accepts any valid image size, or an array of width and height * values in pixels (in that order). Default 'thumbnail'. * @param bool $text Optional. Link text. Default false. */ function adjacent_image_link( $prev = true, $size = 'thumbnail', $text = false ) { $post = get_post(); $attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) ); foreach ( $attachments as $k => $attachment ) { if ( $attachment->ID == $post->ID ) { break; } } $output = ''; $attachment_id = 0; if ( $attachments ) { $k = $prev ? $k - 1 : $k + 1; if ( isset( $attachments[ $k ] ) ) { $attachment_id = $attachments[ $k ]->ID; $output = wp_get_attachment_link( $attachment_id, $size, true, false, $text ); } } $adjacent = $prev ? 'previous' : 'next'; /** * Filters the adjacent image link. * * The dynamic portion of the hook name, `$adjacent`, refers to the type of adjacency, * either 'next', or 'previous'. * * @since 3.5.0 * * @param string $output Adjacent image HTML markup. * @param int $attachment_id Attachment ID * @param string $size Image size. * @param string $text Link text. */ echo apply_filters( "{$adjacent}_image_link", $output, $attachment_id, $size, $text ); } /** * Retrieves taxonomies attached to given the attachment. * * @since 2.5.0 * @since 4.7.0 Introduced the `$output` parameter. * * @param int|array|object $attachment Attachment ID, data array, or data object. * @param string $output Output type. 'names' to return an array of taxonomy names, * or 'objects' to return an array of taxonomy objects. * Default is 'names'. * @return array Empty array on failure. List of taxonomies on success. */ function get_attachment_taxonomies( $attachment, $output = 'names' ) { if ( is_int( $attachment ) ) { $attachment = get_post( $attachment ); } elseif ( is_array( $attachment ) ) { $attachment = (object) $attachment; } if ( ! is_object($attachment) ) return array(); $file = get_attached_file( $attachment->ID ); $filename = basename( $file ); $objects = array('attachment'); if ( false !== strpos($filename, '.') ) $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1); if ( !empty($attachment->post_mime_type) ) { $objects[] = 'attachment:' . $attachment->post_mime_type; if ( false !== strpos($attachment->post_mime_type, '/') ) foreach ( explode('/', $attachment->post_mime_type) as $token ) if ( !empty($token) ) $objects[] = "attachment:$token"; } $taxonomies = array(); foreach ( $objects as $object ) { if ( $taxes = get_object_taxonomies( $object, $output ) ) { $taxonomies = array_merge( $taxonomies, $taxes ); } } if ( 'names' === $output ) { $taxonomies = array_unique( $taxonomies ); } return $taxonomies; } /** * Retrieves all of the taxonomy names that are registered for attachments. * * Handles mime-type-specific taxonomies such as attachment:image and attachment:video. * * @since 3.5.0 * * @see get_taxonomies() * * @param string $output Optional. The type of taxonomy output to return. Accepts 'names' or 'objects'. * Default 'names'. * @return array The names of all taxonomy of $object_type. */ function get_taxonomies_for_attachments( $output = 'names' ) { $taxonomies = array(); foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) { foreach ( $taxonomy->object_type as $object_type ) { if ( 'attachment' == $object_type || 0 === strpos( $object_type, 'attachment:' ) ) { if ( 'names' == $output ) $taxonomies[] = $taxonomy->name; else $taxonomies[ $taxonomy->name ] = $taxonomy; break; } } } return $taxonomies; } /** * Create new GD image resource with transparency support * * @todo: Deprecate if possible. * * @since 2.9.0 * * @param int $width Image width in pixels. * @param int $height Image height in pixels.. * @return resource The GD image resource. */ function wp_imagecreatetruecolor($width, $height) { $img = imagecreatetruecolor($width, $height); if ( is_resource($img) && function_exists('imagealphablending') && function_exists('imagesavealpha') ) { imagealphablending($img, false); imagesavealpha($img, true); } return $img; } /** * Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height. * * @since 2.9.0 * * @see wp_constrain_dimensions() * * @param int $example_width The width of an example embed. * @param int $example_height The height of an example embed. * @param int $max_width The maximum allowed width. * @param int $max_height The maximum allowed height. * @return array The maximum possible width and height based on the example ratio. */ function wp_expand_dimensions( $example_width, $example_height, $max_width, $max_height ) { $example_width = (int) $example_width; $example_height = (int) $example_height; $max_width = (int) $max_width; $max_height = (int) $max_height; return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height ); } /** * Determines the maximum upload size allowed in php.ini. * * @since 2.5.0 * * @return int Allowed upload size. */ function wp_max_upload_size() { $u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) ); $p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) ); /** * Filters the maximum upload size allowed in php.ini. * * @since 2.5.0 * * @param int $size Max upload size limit in bytes. * @param int $u_bytes Maximum upload filesize in bytes. * @param int $p_bytes Maximum size of POST data in bytes. */ return apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes ); } /** * Returns a WP_Image_Editor instance and loads file into it. * * @since 3.5.0 * * @param string $path Path to the file to load. * @param array $args Optional. Additional arguments for retrieving the image editor. * Default empty array. * @return WP_Image_Editor|WP_Error The WP_Image_Editor object if successful, an WP_Error * object otherwise. */ function wp_get_image_editor( $path, $args = array() ) { $args['path'] = $path; if ( ! isset( $args['mime_type'] ) ) { $file_info = wp_check_filetype( $args['path'] ); // If $file_info['type'] is false, then we let the editor attempt to // figure out the file type, rather than forcing a failure based on extension. if ( isset( $file_info ) && $file_info['type'] ) $args['mime_type'] = $file_info['type']; } $implementation = _wp_image_editor_choose( $args ); if ( $implementation ) { $editor = new $implementation( $path ); $loaded = $editor->load(); if ( is_wp_error( $loaded ) ) return $loaded; return $editor; } return new WP_Error( 'image_no_editor', __('No editor could be selected.') ); } /** * Tests whether there is an editor that supports a given mime type or methods. * * @since 3.5.0 * * @param string|array $args Optional. Array of arguments to retrieve the image editor supports. * Default empty array. * @return bool True if an eligible editor is found; false otherwise. */ function wp_image_editor_supports( $args = array() ) { return (bool) _wp_image_editor_choose( $args ); } /** * Tests which editors are capable of supporting the request. * * @ignore * @since 3.5.0 * * @param array $args Optional. Array of arguments for choosing a capable editor. Default empty array. * @return string|false Class name for the first editor that claims to support the request. False if no * editor claims to support the request. */ function _wp_image_editor_choose( $args = array() ) { require_once ABSPATH . WPINC . '/class-wp-image-editor.php'; require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php'; require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php'; /** * Filters the list of image editing library classes. * * @since 3.5.0 * * @param array $image_editors List of available image editors. Defaults are * 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'. */ $implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) ); foreach ( $implementations as $implementation ) { if ( ! call_user_func( array( $implementation, 'test' ), $args ) ) continue; if ( isset( $args['mime_type'] ) && ! call_user_func( array( $implementation, 'supports_mime_type' ), $args['mime_type'] ) ) { continue; } if ( isset( $args['methods'] ) && array_diff( $args['methods'], get_class_methods( $implementation ) ) ) { continue; } return $implementation; } return false; } /** * Prints default Plupload arguments. * * @since 3.4.0 */ function wp_plupload_default_settings() { $wp_scripts = wp_scripts(); $data = $wp_scripts->get_data( 'wp-plupload', 'data' ); if ( $data && false !== strpos( $data, '_wpPluploadSettings' ) ) return; $max_upload_size = wp_max_upload_size(); $allowed_extensions = array_keys( get_allowed_mime_types() ); $extensions = array(); foreach ( $allowed_extensions as $extension ) { $extensions = array_merge( $extensions, explode( '|', $extension ) ); } /* * Since 4.9 the `runtimes` setting is hardcoded in our version of Plupload to `html5,html4`, * and the `flash_swf_url` and `silverlight_xap_url` are not used. */ $defaults = array( 'file_data_name' => 'async-upload', // key passed to $_FILE. 'url' => admin_url( 'async-upload.php', 'relative' ), 'filters' => array( 'max_file_size' => $max_upload_size . 'b', 'mime_types' => array( array( 'extensions' => implode( ',', $extensions ) ) ), ), ); // Currently only iOS Safari supports multiple files uploading but iOS 7.x has a bug that prevents uploading of videos // when enabled. See #29602. if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false && strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) { $defaults['multi_selection'] = false; } /** * Filters the Plupload default settings. * * @since 3.4.0 * * @param array $defaults Default Plupload settings array. */ $defaults = apply_filters( 'plupload_default_settings', $defaults ); $params = array( 'action' => 'upload-attachment', ); /** * Filters the Plupload default parameters. * * @since 3.4.0 * * @param array $params Default Plupload parameters array. */ $params = apply_filters( 'plupload_default_params', $params ); $params['_wpnonce'] = wp_create_nonce( 'media-form' ); $defaults['multipart_params'] = $params; $settings = array( 'defaults' => $defaults, 'browser' => array( 'mobile' => wp_is_mobile(), 'supported' => _device_can_upload(), ), 'limitExceeded' => is_multisite() && ! is_upload_space_available() ); $script = 'var _wpPluploadSettings = ' . wp_json_encode( $settings ) . ';'; if ( $data ) $script = "$data\n$script"; $wp_scripts->add_data( 'wp-plupload', 'data', $script ); } /** * Prepares an attachment post object for JS, where it is expected * to be JSON-encoded and fit into an Attachment model. * * @since 3.5.0 * * @param mixed $attachment Attachment ID or object. * @return array|void Array of attachment details. */ function wp_prepare_attachment_for_js( $attachment ) { if ( ! $attachment = get_post( $attachment ) ) return; if ( 'attachment' != $attachment->post_type ) return; $meta = wp_get_attachment_metadata( $attachment->ID ); if ( false !== strpos( $attachment->post_mime_type, '/' ) ) list( $type, $subtype ) = explode( '/', $attachment->post_mime_type ); else list( $type, $subtype ) = array( $attachment->post_mime_type, '' ); $attachment_url = wp_get_attachment_url( $attachment->ID ); $base_url = str_replace( wp_basename( $attachment_url ), '', $attachment_url ); $response = array( 'id' => $attachment->ID, 'title' => $attachment->post_title, 'filename' => wp_basename( get_attached_file( $attachment->ID ) ), 'url' => $attachment_url, 'link' => get_attachment_link( $attachment->ID ), 'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ), 'author' => $attachment->post_author, 'description' => $attachment->post_content, 'caption' => $attachment->post_excerpt, 'name' => $attachment->post_name, 'status' => $attachment->post_status, 'uploadedTo' => $attachment->post_parent, 'date' => strtotime( $attachment->post_date_gmt ) * 1000, 'modified' => strtotime( $attachment->post_modified_gmt ) * 1000, 'menuOrder' => $attachment->menu_order, 'mime' => $attachment->post_mime_type, 'type' => $type, 'subtype' => $subtype, 'icon' => wp_mime_type_icon( $attachment->ID ), 'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ), 'nonces' => array( 'update' => false, 'delete' => false, 'edit' => false ), 'editLink' => false, 'meta' => false, ); $author = new WP_User( $attachment->post_author ); if ( $author->exists() ) { $response['authorName'] = html_entity_decode( $author->display_name, ENT_QUOTES, get_bloginfo( 'charset' ) ); } else { $response['authorName'] = __( '(no author)' ); } if ( $attachment->post_parent ) { $post_parent = get_post( $attachment->post_parent ); } else { $post_parent = false; } if ( $post_parent ) { $parent_type = get_post_type_object( $post_parent->post_type ); if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $attachment->post_parent ) ) { $response['uploadedToLink'] = get_edit_post_link( $attachment->post_parent, 'raw' ); } if ( $parent_type && current_user_can( 'read_post', $attachment->post_parent ) ) { $response['uploadedToTitle'] = $post_parent->post_title ? $post_parent->post_title : __( '(no title)' ); } } $attached_file = get_attached_file( $attachment->ID ); if ( isset( $meta['filesize'] ) ) { $bytes = $meta['filesize']; } elseif ( file_exists( $attached_file ) ) { $bytes = filesize( $attached_file ); } else { $bytes = ''; } if ( $bytes ) { $response['filesizeInBytes'] = $bytes; $response['filesizeHumanReadable'] = size_format( $bytes ); } $context = get_post_meta( $attachment->ID, '_wp_attachment_context', true ); $response['context'] = ( $context ) ? $context : ''; if ( current_user_can( 'edit_post', $attachment->ID ) ) { $response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID ); $response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID ); $response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' ); } if ( current_user_can( 'delete_post', $attachment->ID ) ) $response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID ); if ( $meta && ( 'image' === $type || ! empty( $meta['sizes'] ) ) ) { $sizes = array(); /** This filter is documented in wp-admin/includes/media.php */ $possible_sizes = apply_filters( 'image_size_names_choose', array( 'thumbnail' => __('Thumbnail'), 'medium' => __('Medium'), 'large' => __('Large'), 'full' => __('Full Size'), ) ); unset( $possible_sizes['full'] ); // Loop through all potential sizes that may be chosen. Try to do this with some efficiency. // First: run the image_downsize filter. If it returns something, we can use its data. // If the filter does not return something, then image_downsize() is just an expensive // way to check the image metadata, which we do second. foreach ( $possible_sizes as $size => $label ) { /** This filter is documented in wp-includes/media.php */ if ( $downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size ) ) { if ( empty( $downsize[3] ) ) { continue; } $sizes[ $size ] = array( 'height' => $downsize[2], 'width' => $downsize[1], 'url' => $downsize[0], 'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape', ); } elseif ( isset( $meta['sizes'][ $size ] ) ) { // Nothing from the filter, so consult image metadata if we have it. $size_meta = $meta['sizes'][ $size ]; // We have the actual image size, but might need to further constrain it if content_width is narrower. // Thumbnail, medium, and full sizes are also checked against the site's height/width options. list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' ); $sizes[ $size ] = array( 'height' => $height, 'width' => $width, 'url' => $base_url . $size_meta['file'], 'orientation' => $height > $width ? 'portrait' : 'landscape', ); } } if ( 'image' === $type ) { $sizes['full'] = array( 'url' => $attachment_url ); if ( isset( $meta['height'], $meta['width'] ) ) { $sizes['full']['height'] = $meta['height']; $sizes['full']['width'] = $meta['width']; $sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape'; } $response = array_merge( $response, $sizes['full'] ); } elseif ( $meta['sizes']['full']['file'] ) { $sizes['full'] = array( 'url' => $base_url . $meta['sizes']['full']['file'], 'height' => $meta['sizes']['full']['height'], 'width' => $meta['sizes']['full']['width'], 'orientation' => $meta['sizes']['full']['height'] > $meta['sizes']['full']['width'] ? 'portrait' : 'landscape' ); } $response = array_merge( $response, array( 'sizes' => $sizes ) ); } if ( $meta && 'video' === $type ) { if ( isset( $meta['width'] ) ) $response['width'] = (int) $meta['width']; if ( isset( $meta['height'] ) ) $response['height'] = (int) $meta['height']; } if ( $meta && ( 'audio' === $type || 'video' === $type ) ) { if ( isset( $meta['length_formatted'] ) ) $response['fileLength'] = $meta['length_formatted']; $response['meta'] = array(); foreach ( wp_get_attachment_id3_keys( $attachment, 'js' ) as $key => $label ) { $response['meta'][ $key ] = false; if ( ! empty( $meta[ $key ] ) ) { $response['meta'][ $key ] = $meta[ $key ]; } } $id = get_post_thumbnail_id( $attachment->ID ); if ( ! empty( $id ) ) { list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' ); $response['image'] = compact( 'src', 'width', 'height' ); list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' ); $response['thumb'] = compact( 'src', 'width', 'height' ); } else { $src = wp_mime_type_icon( $attachment->ID ); $width = 48; $height = 64; $response['image'] = compact( 'src', 'width', 'height' ); $response['thumb'] = compact( 'src', 'width', 'height' ); } } if ( function_exists('get_compat_media_markup') ) $response['compat'] = get_compat_media_markup( $attachment->ID, array( 'in_modal' => true ) ); /** * Filters the attachment data prepared for JavaScript. * * @since 3.5.0 * * @param array $response Array of prepared attachment data. * @param int|object $attachment Attachment ID or object. * @param array $meta Array of attachment meta data. */ return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta ); } /** * Enqueues all scripts, styles, settings, and templates necessary to use * all media JS APIs. * * @since 3.5.0 * * @global int $content_width * @global wpdb $wpdb * @global WP_Locale $wp_locale * * @param array $args { * Arguments for enqueuing media scripts. * * @type int|WP_Post A post object or ID. * } */ function wp_enqueue_media( $args = array() ) { // Enqueue me just once per page, please. if ( did_action( 'wp_enqueue_media' ) ) return; global $content_width, $wpdb, $wp_locale; $defaults = array( 'post' => null, ); $args = wp_parse_args( $args, $defaults ); // We're going to pass the old thickbox media tabs to `media_upload_tabs` // to ensure plugins will work. We will then unset those tabs. $tabs = array( // handler action suffix => tab label 'type' => '', 'type_url' => '', 'gallery' => '', 'library' => '', ); /** This filter is documented in wp-admin/includes/media.php */ $tabs = apply_filters( 'media_upload_tabs', $tabs ); unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] ); $props = array( 'link' => get_option( 'image_default_link_type' ), // db default is 'file' 'align' => get_option( 'image_default_align' ), // empty default 'size' => get_option( 'image_default_size' ), // empty default ); $exts = array_merge( wp_get_audio_extensions(), wp_get_video_extensions() ); $mimes = get_allowed_mime_types(); $ext_mimes = array(); foreach ( $exts as $ext ) { foreach ( $mimes as $ext_preg => $mime_match ) { if ( preg_match( '#' . $ext . '#i', $ext_preg ) ) { $ext_mimes[ $ext ] = $mime_match; break; } } } /** * Allows showing or hiding the "Create Audio Playlist" button in the media library. * * By default, the "Create Audio Playlist" button will always be shown in * the media library. If this filter returns `null`, a query will be run * to determine whether the media library contains any audio items. This * was the default behavior prior to version 4.8.0, but this query is * expensive for large media libraries. * * @since 4.7.4 * @since 4.8.0 The filter's default value is `true` rather than `null`. * * @link https://core.trac.wordpress.org/ticket/31071 * * @param bool|null Whether to show the button, or `null` to decide based * on whether any audio files exist in the media library. */ $show_audio_playlist = apply_filters( 'media_library_show_audio_playlist', true ); if ( null === $show_audio_playlist ) { $show_audio_playlist = $wpdb->get_var( " SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'audio%' LIMIT 1 " ); } /** * Allows showing or hiding the "Create Video Playlist" button in the media library. * * By default, the "Create Video Playlist" button will always be shown in * the media library. If this filter returns `null`, a query will be run * to determine whether the media library contains any video items. This * was the default behavior prior to version 4.8.0, but this query is * expensive for large media libraries. * * @since 4.7.4 * @since 4.8.0 The filter's default value is `true` rather than `null`. * * @link https://core.trac.wordpress.org/ticket/31071 * * @param bool|null Whether to show the button, or `null` to decide based * on whether any video files exist in the media library. */ $show_video_playlist = apply_filters( 'media_library_show_video_playlist', true ); if ( null === $show_video_playlist ) { $show_video_playlist = $wpdb->get_var( " SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'video%' LIMIT 1 " ); } /** * Allows overriding the list of months displayed in the media library. * * By default (if this filter does not return an array), a query will be * run to determine the months that have media items. This query can be * expensive for large media libraries, so it may be desirable for sites to * override this behavior. * * @since 4.7.4 * * @link https://core.trac.wordpress.org/ticket/31071 * * @param array|null An array of objects with `month` and `year` * properties, or `null` (or any other non-array value) * for default behavior. */ $months = apply_filters( 'media_library_months_with_files', null ); if ( ! is_array( $months ) ) { $months = $wpdb->get_results( $wpdb->prepare( " SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM $wpdb->posts WHERE post_type = %s ORDER BY post_date DESC ", 'attachment' ) ); } foreach ( $months as $month_year ) { $month_year->text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month_year->month ), $month_year->year ); } $settings = array( 'tabs' => $tabs, 'tabUrl' => add_query_arg( array( 'chromeless' => true ), admin_url('media-upload.php') ), 'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ), /** This filter is documented in wp-admin/includes/media.php */ 'captions' => ! apply_filters( 'disable_captions', '' ), 'nonce' => array( 'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ), 'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ), ), 'post' => array( 'id' => 0, ), 'defaultProps' => $props, 'attachmentCounts' => array( 'audio' => ( $show_audio_playlist ) ? 1 : 0, 'video' => ( $show_video_playlist ) ? 1 : 0, ), 'oEmbedProxyUrl' => rest_url( 'oembed/1.0/proxy' ), 'embedExts' => $exts, 'embedMimes' => $ext_mimes, 'contentWidth' => $content_width, 'months' => $months, 'mediaTrash' => MEDIA_TRASH ? 1 : 0, ); $post = null; if ( isset( $args['post'] ) ) { $post = get_post( $args['post'] ); $settings['post'] = array( 'id' => $post->ID, 'nonce' => wp_create_nonce( 'update-post_' . $post->ID ), ); $thumbnail_support = current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' ); if ( ! $thumbnail_support && 'attachment' === $post->post_type && $post->post_mime_type ) { if ( wp_attachment_is( 'audio', $post ) ) { $thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' ); } elseif ( wp_attachment_is( 'video', $post ) ) { $thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' ); } } if ( $thumbnail_support ) { $featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true ); $settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1; } } if ( $post ) { $post_type_object = get_post_type_object( $post->post_type ); } else { $post_type_object = get_post_type_object( 'post' ); } $strings = array( // Generic 'url' => __( 'URL' ), 'addMedia' => __( 'Add Media' ), 'search' => __( 'Search' ), 'select' => __( 'Select' ), 'cancel' => __( 'Cancel' ), 'update' => __( 'Update' ), 'replace' => __( 'Replace' ), 'remove' => __( 'Remove' ), 'back' => __( 'Back' ), /* translators: This is a would-be plural string used in the media manager. If there is not a word you can use in your language to avoid issues with the lack of plural support here, turn it into "selected: %d" then translate it. */ 'selected' => __( '%d selected' ), 'dragInfo' => __( 'Drag and drop to reorder media files.' ), // Upload 'uploadFilesTitle' => __( 'Upload Files' ), 'uploadImagesTitle' => __( 'Upload Images' ), // Library 'mediaLibraryTitle' => __( 'Media Library' ), 'insertMediaTitle' => __( 'Add Media' ), 'createNewGallery' => __( 'Create a new gallery' ), 'createNewPlaylist' => __( 'Create a new playlist' ), 'createNewVideoPlaylist' => __( 'Create a new video playlist' ), 'returnToLibrary' => __( '← Return to library' ), 'allMediaItems' => __( 'All media items' ), 'allDates' => __( 'All dates' ), 'noItemsFound' => __( 'No items found.' ), 'insertIntoPost' => $post_type_object->labels->insert_into_item, 'unattached' => __( 'Unattached' ), 'mine' => _x( 'Mine', 'media items' ), 'trash' => _x( 'Trash', 'noun' ), 'uploadedToThisPost' => $post_type_object->labels->uploaded_to_this_item, 'warnDelete' => __( "You are about to permanently delete this item from your site.\nThis action cannot be undone.\n 'Cancel' to stop, 'OK' to delete." ), 'warnBulkDelete' => __( "You are about to permanently delete these items from your site.\nThis action cannot be undone.\n 'Cancel' to stop, 'OK' to delete." ), 'warnBulkTrash' => __( "You are about to trash these items.\n 'Cancel' to stop, 'OK' to delete." ), 'bulkSelect' => __( 'Bulk Select' ), 'cancelSelection' => __( 'Cancel Selection' ), 'trashSelected' => __( 'Trash Selected' ), 'untrashSelected' => __( 'Untrash Selected' ), 'deleteSelected' => __( 'Delete Selected' ), 'deletePermanently' => __( 'Delete Permanently' ), 'apply' => __( 'Apply' ), 'filterByDate' => __( 'Filter by date' ), 'filterByType' => __( 'Filter by type' ), 'searchMediaLabel' => __( 'Search Media' ), 'searchMediaPlaceholder' => __( 'Search media items...' ), // placeholder (no ellipsis) 'noMedia' => __( 'No media files found.' ), // Library Details 'attachmentDetails' => __( 'Attachment Details' ), // From URL 'insertFromUrlTitle' => __( 'Insert from URL' ), // Featured Images 'setFeaturedImageTitle' => $post_type_object->labels->featured_image, 'setFeaturedImage' => $post_type_object->labels->set_featured_image, // Gallery 'createGalleryTitle' => __( 'Create Gallery' ), 'editGalleryTitle' => __( 'Edit Gallery' ), 'cancelGalleryTitle' => __( '← Cancel Gallery' ), 'insertGallery' => __( 'Insert gallery' ), 'updateGallery' => __( 'Update gallery' ), 'addToGallery' => __( 'Add to gallery' ), 'addToGalleryTitle' => __( 'Add to Gallery' ), 'reverseOrder' => __( 'Reverse order' ), // Edit Image 'imageDetailsTitle' => __( 'Image Details' ), 'imageReplaceTitle' => __( 'Replace Image' ), 'imageDetailsCancel' => __( 'Cancel Edit' ), 'editImage' => __( 'Edit Image' ), // Crop Image 'chooseImage' => __( 'Choose Image' ), 'selectAndCrop' => __( 'Select and Crop' ), 'skipCropping' => __( 'Skip Cropping' ), 'cropImage' => __( 'Crop Image' ), 'cropYourImage' => __( 'Crop your image' ), 'cropping' => __( 'Cropping…' ), /* translators: 1: suggested width number, 2: suggested height number. */ 'suggestedDimensions' => __( 'Suggested image dimensions: %1$s by %2$s pixels.' ), 'cropError' => __( 'There has been an error cropping your image.' ), // Edit Audio 'audioDetailsTitle' => __( 'Audio Details' ), 'audioReplaceTitle' => __( 'Replace Audio' ), 'audioAddSourceTitle' => __( 'Add Audio Source' ), 'audioDetailsCancel' => __( 'Cancel Edit' ), // Edit Video 'videoDetailsTitle' => __( 'Video Details' ), 'videoReplaceTitle' => __( 'Replace Video' ), 'videoAddSourceTitle' => __( 'Add Video Source' ), 'videoDetailsCancel' => __( 'Cancel Edit' ), 'videoSelectPosterImageTitle' => __( 'Select Poster Image' ), 'videoAddTrackTitle' => __( 'Add Subtitles' ), // Playlist 'playlistDragInfo' => __( 'Drag and drop to reorder tracks.' ), 'createPlaylistTitle' => __( 'Create Audio Playlist' ), 'editPlaylistTitle' => __( 'Edit Audio Playlist' ), 'cancelPlaylistTitle' => __( '← Cancel Audio Playlist' ), 'insertPlaylist' => __( 'Insert audio playlist' ), 'updatePlaylist' => __( 'Update audio playlist' ), 'addToPlaylist' => __( 'Add to audio playlist' ), 'addToPlaylistTitle' => __( 'Add to Audio Playlist' ), // Video Playlist 'videoPlaylistDragInfo' => __( 'Drag and drop to reorder videos.' ), 'createVideoPlaylistTitle' => __( 'Create Video Playlist' ), 'editVideoPlaylistTitle' => __( 'Edit Video Playlist' ), 'cancelVideoPlaylistTitle' => __( '← Cancel Video Playlist' ), 'insertVideoPlaylist' => __( 'Insert video playlist' ), 'updateVideoPlaylist' => __( 'Update video playlist' ), 'addToVideoPlaylist' => __( 'Add to video playlist' ), 'addToVideoPlaylistTitle' => __( 'Add to Video Playlist' ), ); /** * Filters the media view settings. * * @since 3.5.0 * * @param array $settings List of media view settings. * @param WP_Post $post Post object. */ $settings = apply_filters( 'media_view_settings', $settings, $post ); /** * Filters the media view strings. * * @since 3.5.0 * * @param array $strings List of media view strings. * @param WP_Post $post Post object. */ $strings = apply_filters( 'media_view_strings', $strings, $post ); $strings['settings'] = $settings; // Ensure we enqueue media-editor first, that way media-views is // registered internally before we try to localize it. see #24724. wp_enqueue_script( 'media-editor' ); wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings ); wp_enqueue_script( 'media-audiovideo' ); wp_enqueue_style( 'media-views' ); if ( is_admin() ) { wp_enqueue_script( 'mce-view' ); wp_enqueue_script( 'image-edit' ); } wp_enqueue_style( 'imgareaselect' ); wp_plupload_default_settings(); require_once ABSPATH . WPINC . '/media-template.php'; add_action( 'admin_footer', 'wp_print_media_templates' ); add_action( 'wp_footer', 'wp_print_media_templates' ); add_action( 'customize_controls_print_footer_scripts', 'wp_print_media_templates' ); /** * Fires at the conclusion of wp_enqueue_media(). * * @since 3.5.0 */ do_action( 'wp_enqueue_media' ); } /** * Retrieves media attached to the passed post. * * @since 3.6.0 * * @param string $type Mime type. * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @return array Found attachments. */ function get_attached_media( $type, $post = 0 ) { if ( ! $post = get_post( $post ) ) return array(); $args = array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => $type, 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC', ); /** * Filters arguments used to retrieve media attached to the given post. * * @since 3.6.0 * * @param array $args Post query arguments. * @param string $type Mime type of the desired media. * @param mixed $post Post ID or object. */ $args = apply_filters( 'get_attached_media_args', $args, $type, $post ); $children = get_children( $args ); /** * Filters the list of media attached to the given post. * * @since 3.6.0 * * @param array $children Associative array of media attached to the given post. * @param string $type Mime type of the media desired. * @param mixed $post Post ID or object. */ return (array) apply_filters( 'get_attached_media', $children, $type, $post ); } /** * Check the content blob for an audio, video, object, embed, or iframe tags. * * @since 3.6.0 * * @param string $content A string which might contain media data. * @param array $types An array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'. * @return array A list of found HTML media embeds. */ function get_media_embedded_in_content( $content, $types = null ) { $html = array(); /** * Filters the embedded media types that are allowed to be returned from the content blob. * * @since 4.2.0 * * @param array $allowed_media_types An array of allowed media types. Default media types are * 'audio', 'video', 'object', 'embed', and 'iframe'. */ $allowed_media_types = apply_filters( 'media_embedded_in_content_allowed_types', array( 'audio', 'video', 'object', 'embed', 'iframe' ) ); if ( ! empty( $types ) ) { if ( ! is_array( $types ) ) { $types = array( $types ); } $allowed_media_types = array_intersect( $allowed_media_types, $types ); } $tags = implode( '|', $allowed_media_types ); if ( preg_match_all( '#<(?P' . $tags . ')[^<]*?(?:>[\s\S]*?<\/(?P=tag)>|\s*\/>)#', $content, $matches ) ) { foreach ( $matches[0] as $match ) { $html[] = $match; } } return $html; } /** * Retrieves galleries from the passed post's content. * * @since 3.6.0 * * @param int|WP_Post $post Post ID or object. * @param bool $html Optional. Whether to return HTML or data in the array. Default true. * @return array A list of arrays, each containing gallery data and srcs parsed * from the expanded shortcode. */ function get_post_galleries( $post, $html = true ) { if ( ! $post = get_post( $post ) ) return array(); if ( ! has_shortcode( $post->post_content, 'gallery' ) ) return array(); $galleries = array(); if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $post->post_content, $matches, PREG_SET_ORDER ) ) { foreach ( $matches as $shortcode ) { if ( 'gallery' === $shortcode[2] ) { $srcs = array(); $shortcode_attrs = shortcode_parse_atts( $shortcode[3] ); if ( ! is_array( $shortcode_attrs ) ) { $shortcode_attrs = array(); } // Specify the post id of the gallery we're viewing if the shortcode doesn't reference another post already. if ( ! isset( $shortcode_attrs['id'] ) ) { $shortcode[3] .= ' id="' . intval( $post->ID ) . '"'; } $gallery = do_shortcode_tag( $shortcode ); if ( $html ) { $galleries[] = $gallery; } else { preg_match_all( '#src=([\'"])(.+?)\1#is', $gallery, $src, PREG_SET_ORDER ); if ( ! empty( $src ) ) { foreach ( $src as $s ) { $srcs[] = $s[2]; } } $galleries[] = array_merge( $shortcode_attrs, array( 'src' => array_values( array_unique( $srcs ) ) ) ); } } } } /** * Filters the list of all found galleries in the given post. * * @since 3.6.0 * * @param array $galleries Associative array of all found post galleries. * @param WP_Post $post Post object. */ return apply_filters( 'get_post_galleries', $galleries, $post ); } /** * Check a specified post's content for gallery and, if present, return the first * * @since 3.6.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @param bool $html Optional. Whether to return HTML or data. Default is true. * @return string|array Gallery data and srcs parsed from the expanded shortcode. */ function get_post_gallery( $post = 0, $html = true ) { $galleries = get_post_galleries( $post, $html ); $gallery = reset( $galleries ); /** * Filters the first-found post gallery. * * @since 3.6.0 * * @param array $gallery The first-found post gallery. * @param int|WP_Post $post Post ID or object. * @param array $galleries Associative array of all found post galleries. */ return apply_filters( 'get_post_gallery', $gallery, $post, $galleries ); } /** * Retrieve the image srcs from galleries from a post's content, if present * * @since 3.6.0 * * @see get_post_galleries() * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`. * @return array A list of lists, each containing image srcs parsed. * from an expanded shortcode */ function get_post_galleries_images( $post = 0 ) { $galleries = get_post_galleries( $post, false ); return wp_list_pluck( $galleries, 'src' ); } /** * Checks a post's content for galleries and return the image srcs for the first found gallery * * @since 3.6.0 * * @see get_post_gallery() * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`. * @return array A list of a gallery's image srcs in order. */ function get_post_gallery_images( $post = 0 ) { $gallery = get_post_gallery( $post, false ); return empty( $gallery['src'] ) ? array() : $gallery['src']; } /** * Maybe attempts to generate attachment metadata, if missing. * * @since 3.9.0 * * @param WP_Post $attachment Attachment object. */ function wp_maybe_generate_attachment_metadata( $attachment ) { if ( empty( $attachment ) || ( empty( $attachment->ID ) || ! $attachment_id = (int) $attachment->ID ) ) { return; } $file = get_attached_file( $attachment_id ); $meta = wp_get_attachment_metadata( $attachment_id ); if ( empty( $meta ) && file_exists( $file ) ) { $_meta = get_post_meta( $attachment_id ); $regeneration_lock = 'wp_generating_att_' . $attachment_id; if ( ! array_key_exists( '_wp_attachment_metadata', $_meta ) && ! get_transient( $regeneration_lock ) ) { set_transient( $regeneration_lock, $file ); wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); delete_transient( $regeneration_lock ); } } } /** * Tries to convert an attachment URL into a post ID. * * @since 4.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $url The URL to resolve. * @return int The found post ID, or 0 on failure. */ function attachment_url_to_postid( $url ) { global $wpdb; $dir = wp_get_upload_dir(); $path = $url; $site_url = parse_url( $dir['url'] ); $image_path = parse_url( $path ); //force the protocols to match if needed if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) { $path = str_replace( $image_path['scheme'], $site_url['scheme'], $path ); } if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) { $path = substr( $path, strlen( $dir['baseurl'] . '/' ) ); } $sql = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s", $path ); $post_id = $wpdb->get_var( $sql ); /** * Filters an attachment id found by URL. * * @since 4.2.0 * * @param int|null $post_id The post_id (if any) found by the function. * @param string $url The URL being looked up. */ return (int) apply_filters( 'attachment_url_to_postid', $post_id, $url ); } /** * Returns the URLs for CSS files used in an iframe-sandbox'd TinyMCE media view. * * @since 4.0.0 * * @return array The relevant CSS file URLs. */ function wpview_media_sandbox_styles() { $version = 'ver=' . get_bloginfo( 'version' ); $mediaelement = includes_url( "js/mediaelement/mediaelementplayer-legacy.min.css?$version" ); $wpmediaelement = includes_url( "js/mediaelement/wp-mediaelement.css?$version" ); return array( $mediaelement, $wpmediaelement ); } /** * Registers the personal data exporter for media * * @param array $exporters An array of personal data exporters. * @return array An array of personal data exporters. */ function wp_register_media_personal_data_exporter( $exporters ) { $exporters['wordpress-media'] = array( 'exporter_friendly_name' => __( 'WordPress Media' ), 'callback' => 'wp_media_personal_data_exporter', ); return $exporters; } /** * Finds and exports attachments associated with an email address. * * @since 4.9.6 * * @param string $email_address The attachment owner email address. * @param int $page Attachment page. * @return array $return An array of personal data. */ function wp_media_personal_data_exporter( $email_address, $page = 1 ) { // Limit us to 50 attachments at a time to avoid timing out. $number = 50; $page = (int) $page; $data_to_export = array(); $user = get_user_by( 'email' , $email_address ); if ( false === $user ) { return array( 'data' => $data_to_export, 'done' => true, ); } $post_query = new WP_Query( array( 'author' => $user->ID, 'posts_per_page' => $number, 'paged' => $page, 'post_type' => 'attachment', 'post_status' => 'any', 'orderby' => 'ID', 'order' => 'ASC', ) ); foreach ( (array) $post_query->posts as $post ) { $attachment_url = wp_get_attachment_url( $post->ID ); if ( $attachment_url ) { $post_data_to_export = array( array( 'name' => __( 'URL' ), 'value' => $attachment_url ), ); $data_to_export[] = array( 'group_id' => 'media', 'group_label' => __( 'Media' ), 'item_id' => "post-{$post->ID}", 'data' => $post_data_to_export, ); } } $done = $post_query->max_num_pages <= $page; return array( 'data' => $data_to_export, 'done' => $done, ); }