* @param int $size Optional. Size of the site icon. Default 512 (pixels).
* @param string $url Optional. Fallback url if no site icon is found. Default empty.
* @param int $blog_id Optional. ID of the blog to get the site icon for. Default current blog.
function site_icon_url( $size = 512, $url = '', $blog_id = 0 ) {
echo esc_url( get_site_icon_url( $size, $url, $blog_id ) );
* Determines whether the site has a Site Icon.
* @param int $blog_id Optional. ID of the blog in question. Default current blog.
* @return bool Whether the site has a site icon or not.
function has_site_icon( $blog_id = 0 ) {
return (bool) get_site_icon_url( 512, '', $blog_id );
* Determines whether the site has a custom logo.
* @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog.
* @return bool Whether the site has a custom logo or not.
function has_custom_logo( $blog_id = 0 ) {
if ( is_multisite() && ! empty( $blog_id ) && get_current_blog_id() !== (int) $blog_id ) {
switch_to_blog( $blog_id );
$custom_logo_id = get_theme_mod( 'custom_logo' );
$is_image = ( $custom_logo_id ) ? wp_attachment_is_image( $custom_logo_id ) : false;
* Returns a custom logo, linked to home unless the theme supports removing the link on the home page.
* @since 5.5.0 Added option to remove the link on the home page with `unlink-homepage-logo` theme support
* for the `custom-logo` theme feature.
* @since 5.5.1 Disabled lazy-loading by default.
* @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog.
* @return string Custom logo markup.
function get_custom_logo( $blog_id = 0 ) {
if ( is_multisite() && ! empty( $blog_id ) && get_current_blog_id() !== (int) $blog_id ) {
switch_to_blog( $blog_id );
// We have a logo. Logo is go.
if ( has_custom_logo() ) {
$custom_logo_id = get_theme_mod( 'custom_logo' );
$custom_logo_attr = array(
'class' => 'custom-logo',
$unlink_homepage_logo = (bool) get_theme_support( 'custom-logo', 'unlink-homepage-logo' );
if ( $unlink_homepage_logo && is_front_page() && ! is_paged() ) {
* If on the home page, set the logo alt attribute to an empty string,
* as the image is decorative and doesn't need its purpose to be described.
$custom_logo_attr['alt'] = '';
* If the logo alt attribute is empty, get the site title and explicitly pass it
* to the attributes used by wp_get_attachment_image().
$image_alt = get_post_meta( $custom_logo_id, '_wp_attachment_image_alt', true );
if ( empty( $image_alt ) ) {
$custom_logo_attr['alt'] = get_bloginfo( 'name', 'display' );
* Filters the list of custom logo image attributes.
* @param array $custom_logo_attr Custom logo image attributes.
* @param int $custom_logo_id Custom logo attachment ID.
* @param int $blog_id ID of the blog to get the custom logo for.
$custom_logo_attr = apply_filters( 'get_custom_logo_image_attributes', $custom_logo_attr, $custom_logo_id, $blog_id );
* If the alt attribute is not empty, there's no need to explicitly pass it
* because wp_get_attachment_image() already adds the alt attribute.
$image = wp_get_attachment_image( $custom_logo_id, 'full', false, $custom_logo_attr );
// Check that we have a proper HTML img element.
if ( $unlink_homepage_logo && is_front_page() && ! is_paged() ) {
// If on the home page, don't link the logo to home.
'<span class="custom-logo-link">%1$s</span>',
$aria_current = ! is_paged() && ( is_front_page() || is_home() && ( (int) get_option( 'page_for_posts' ) !== get_queried_object_id() ) ) ? ' aria-current="page"' : '';
'<a href="%1$s" class="custom-logo-link" rel="home"%2$s>%3$s</a>',
esc_url( home_url( '/' ) ),
} elseif ( is_customize_preview() ) {
// If no logo is set but we're in the Customizer, leave a placeholder (needed for the live preview).
'<a href="%1$s" class="custom-logo-link" style="display:none;"><img class="custom-logo" alt="" /></a>',
esc_url( home_url( '/' ) )
* Filters the custom logo output.
* @since 4.6.0 Added the `$blog_id` parameter.
* @param string $html Custom logo HTML output.
* @param int $blog_id ID of the blog to get the custom logo for.
return apply_filters( 'get_custom_logo', $html, $blog_id );
* Displays a custom logo, linked to home unless the theme supports removing the link on the home page.
* @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog.
function the_custom_logo( $blog_id = 0 ) {
echo get_custom_logo( $blog_id );
* Returns document title for the current page.
* @global int $page Page number of a single post.
* @global int $paged Page number of a list of posts.
* @return string Tag with the document title.
function wp_get_document_title() {
* Filters the document title before it is generated.
* Passing a non-empty value will short-circuit wp_get_document_title(),
* returning that value instead.
* @param string $title The document title. Default empty string.
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
// If it's a 404 page, use a "Page not found" title.
$title['title'] = __( 'Page not found' );
// If it's a search, use a dynamic search results title.
} elseif ( is_search() ) {
/* translators: %s: Search query. */
$title['title'] = sprintf( __( 'Search Results for “%s”' ), get_search_query() );
// If on the front page, use the site title.
} elseif ( is_front_page() ) {
$title['title'] = get_bloginfo( 'name', 'display' );
// If on a post type archive, use the post type archive title.
} elseif ( is_post_type_archive() ) {
$title['title'] = post_type_archive_title( '', false );
// If on a taxonomy archive, use the term title.
$title['title'] = single_term_title( '', false );
* If we're on the blog page that is not the homepage
* or a single post of any post type, use the post title.
} elseif ( is_home() || is_singular() ) {
$title['title'] = single_post_title( '', false );
// If on a category or tag archive, use the term title.
} elseif ( is_category() || is_tag() ) {
$title['title'] = single_term_title( '', false );
// If on an author archive, use the author's display name.
} elseif ( is_author() && get_queried_object() ) {
$author = get_queried_object();
$title['title'] = $author->display_name;
// If it's a date archive, use the date as the title.
$title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) );
} elseif ( is_month() ) {
$title['title'] = get_the_date( _x( 'F Y', 'monthly archives date format' ) );
$title['title'] = get_the_date();
// Add a page number if necessary.
if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
/* translators: %s: Page number. */
$title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) );
// Append the description or site title to give context.
$title['tagline'] = get_bloginfo( 'description', 'display' );
$title['site'] = get_bloginfo( 'name', 'display' );
* Filters the separator for the document title.
* @param string $sep Document title separator. Default '-'.
$sep = apply_filters( 'document_title_separator', '-' );
* Filters the parts of the document title.
* The document title parts.
* @type string $title Title of the viewed page.
* @type string $page Optional. Page number if paginated.
* @type string $tagline Optional. Site description when on home page.
* @type string $site Optional. Site title when not on home page.
$title = apply_filters( 'document_title_parts', $title );
$title = implode( " $sep ", array_filter( $title ) );
* Filters the document title.
* @param string $title Document title.
$title = apply_filters( 'document_title', $title );
* Displays title tag with content.
* @since 4.4.0 Improved title output replaced `wp_title()`.
function _wp_render_title_tag() {
if ( ! current_theme_supports( 'title-tag' ) ) {
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
* Displays or retrieves page title for all areas of blog.
* By default, the page title will display the separator before the page title,
* so that the blog title will be before the page title. This is not good for
* title display, since the blog title shows up on most tabs and not what is
* important, which is the page that the user is looking at.
* There are also SEO benefits to having the blog title after or to the 'right'
* of the page title. However, it is mostly common sense to have the blog title
* to the right with most browsers supporting tabs. You can achieve this by
* using the seplocation parameter and setting the value to 'right'. This change
* was introduced around 2.5.0, in case backward compatibility of themes is
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @param string $sep Optional. How to separate the various items within the page title.
* @param bool $display Optional. Whether to display or retrieve title. Default true.
* @param string $seplocation Optional. Location of the separator (either 'left' or 'right').
* @return string|void String when `$display` is false, nothing otherwise.
function wp_title( $sep = '»', $display = true, $seplocation = '' ) {
$m = get_query_var( 'm' );
$year = get_query_var( 'year' );
$monthnum = get_query_var( 'monthnum' );
$day = get_query_var( 'day' );
$search = get_query_var( 's' );
$t_sep = '%WP_TITLE_SEP%'; // Temporary separator, for accurate flipping, if necessary.
if ( is_single() || ( is_home() && ! is_front_page() ) || ( is_page() && ! is_front_page() ) ) {
$title = single_post_title( '', false );
// If there's a post type archive.
if ( is_post_type_archive() ) {
$post_type = get_query_var( 'post_type' );
if ( is_array( $post_type ) ) {
$post_type = reset( $post_type );
$post_type_object = get_post_type_object( $post_type );
if ( ! $post_type_object->has_archive ) {
$title = post_type_archive_title( '', false );
// If there's a category or tag.
if ( is_category() || is_tag() ) {
$title = single_term_title( '', false );
// If there's a taxonomy.
$term = get_queried_object();
$tax = get_taxonomy( $term->taxonomy );
$title = single_term_title( $tax->labels->name . $t_sep, false );
if ( is_author() && ! is_post_type_archive() ) {
$author = get_queried_object();
$title = $author->display_name;
// Post type archives with has_archive should override terms.
if ( is_post_type_archive() && $post_type_object->has_archive ) {
$title = post_type_archive_title( '', false );
if ( is_archive() && ! empty( $m ) ) {
$my_year = substr( $m, 0, 4 );
$my_month = substr( $m, 4, 2 );
$my_day = (int) substr( $m, 6, 2 );
( $my_month ? $t_sep . $wp_locale->get_month( $my_month ) : '' ) .
( $my_day ? $t_sep . $my_day : '' );
if ( is_archive() && ! empty( $year ) ) {
if ( ! empty( $monthnum ) ) {
$title .= $t_sep . $wp_locale->get_month( $monthnum );
$title .= $t_sep . zeroise( $day, 2 );
/* translators: 1: Separator, 2: Search query. */
$title = sprintf( __( 'Search Results %1$s %2$s' ), $t_sep, strip_tags( $search ) );
$title = __( 'Page not found' );
if ( ! is_string( $title ) ) {
$title_array = explode( $t_sep, $title );
* Filters the parts of the page title.
* @param string[] $title_array Array of parts of the page title.
$title_array = apply_filters( 'wp_title_parts', $title_array );
// Determines position of the separator and direction of the breadcrumb.
if ( 'right' === $seplocation ) { // Separator on right, so reverse the order.
$title_array = array_reverse( $title_array );
$title = implode( " $sep ", $title_array ) . $prefix;
$title = $prefix . implode( " $sep ", $title_array );
* Filters the text of the page title.
* @param string $title Page title.
* @param string $sep Title separator.
* @param string $seplocation Location of the separator (either 'left' or 'right').
$title = apply_filters( 'wp_title', $title, $sep, $seplocation );
* Displays or retrieves page title for post.
* This is optimized for single.php template file for displaying the post title.
* It does not support placing the separator after the title, but by leaving the
* prefix parameter empty, you can set the title separator manually. The prefix
* does not automatically place a space between the prefix, so if there should
* be a space, the parameter value will need to have it at the end.
* @param string $prefix Optional. What to display before the title.
* @param bool $display Optional. Whether to display or retrieve title. Default true.
* @return string|void Title when retrieving.
function single_post_title( $prefix = '', $display = true ) {
$_post = get_queried_object();
if ( ! isset( $_post->post_title ) ) {
* Filters the page title for a single post.