'%1$s%2$s',
'logo_class' => 'site-logo',
'title' => '%2$s',
'title_class' => 'site-title',
'home_wrap' => '
%2$s
',
'single_wrap' => '%2$s
',
'condition' => ( is_front_page() || is_home() ) && ! is_page(),
);
$args = wp_parse_args( $args, $defaults );
/**
* Filters the arguments for `twentytwenty_site_logo()`.
*
* @since Twenty Twenty 1.0
*
* @param array $args Parsed arguments.
* @param array $defaults Function's default arguments.
*/
$args = apply_filters( 'twentytwenty_site_logo_args', $args, $defaults );
if ( has_custom_logo() ) {
$contents = sprintf( $args['logo'], $logo, esc_html( $site_title ) );
$classname = $args['logo_class'];
} else {
$contents = sprintf( $args['title'], esc_url( get_home_url( null, '/' ) ), esc_html( $site_title ) );
$classname = $args['title_class'];
}
$wrap = $args['condition'] ? 'home_wrap' : 'single_wrap';
$html = sprintf( $args[ $wrap ], $classname, $contents );
/**
* Filters the arguments for `twentytwenty_site_logo()`.
*
* @since Twenty Twenty 1.0
*
* @param string $html Compiled HTML based on our arguments.
* @param array $args Parsed arguments.
* @param string $classname Class name based on current view, home or single.
* @param string $contents HTML for site title or logo.
*/
$html = apply_filters( 'twentytwenty_site_logo', $html, $args, $classname, $contents );
if ( ! $display ) {
return $html;
}
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Displays the site description.
*
* @since Twenty Twenty 1.0
*
* @param bool $display Display or return the HTML.
* @return string The HTML to display.
*/
function twentytwenty_site_description( $display = true ) {
$description = get_bloginfo( 'description' );
if ( ! $description ) {
return;
}
$wrapper = '%s
';
$html = sprintf( $wrapper, esc_html( $description ) );
/**
* Filters the HTML for the site description.
*
* @since Twenty Twenty 1.0
*
* @param string $html The HTML to display.
* @param string $description Site description via `bloginfo()`.
* @param string $wrapper The format used in case you want to reuse it in a `sprintf()`.
*/
$html = apply_filters( 'twentytwenty_site_description', $html, $description, $wrapper );
if ( ! $display ) {
return $html;
}
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Comments
*/
/**
* Checks if the specified comment is written by the author of the post commented on.
*
* @since Twenty Twenty 1.0
*
* @param object $comment Comment data.
* @return bool
*/
function twentytwenty_is_comment_by_post_author( $comment = null ) {
if ( is_object( $comment ) && $comment->user_id > 0 ) {
$user = get_userdata( $comment->user_id );
$post = get_post( $comment->comment_post_ID );
if ( ! empty( $user ) && ! empty( $post ) ) {
return $comment->user_id === $post->post_author;
}
}
return false;
}
/**
* Filters comment reply link to not JS scroll.
*
* Filter the comment reply link to add a class indicating it should not use JS slow-scroll, as it
* makes it scroll to the wrong position on the page.
*
* @since Twenty Twenty 1.0
*
* @param string $link Link to the top of the page.
* @return string Link to the top of the page.
*/
function twentytwenty_filter_comment_reply_link( $link ) {
$link = str_replace( 'class=\'', 'class=\'do-not-scroll ', $link );
return $link;
}
add_filter( 'comment_reply_link', 'twentytwenty_filter_comment_reply_link' );
/**
* Post Meta
*/
/**
* Retrieves and displays the post meta.
*
* If it's a single post, outputs the post meta values specified in the Customizer settings.
*
* @since Twenty Twenty 1.0
*
* @param int $post_id The ID of the post for which the post meta should be output.
* @param string $location Which post meta location to output – single or preview.
*/
function twentytwenty_the_post_meta( $post_id = null, $location = 'single-top' ) {
echo twentytwenty_get_post_meta( $post_id, $location ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in twentytwenty_get_post_meta().
}
/**
* Filters the edit post link to add an icon and use the post meta structure.
*
* @since Twenty Twenty 1.0
*
* @param string $link Anchor tag for the edit link.
* @param int $post_id Post ID.
* @param string $text Anchor text.
*/
function twentytwenty_edit_post_link( $link, $post_id, $text ) {
if ( is_admin() ) {
return $link;
}
$edit_url = get_edit_post_link( $post_id );
if ( ! $edit_url ) {
return;
}
$text = sprintf(
wp_kses(
/* translators: %s: Post title. Only visible to screen readers. */
__( 'Edit %s', 'twentytwenty' ),
array(
'span' => array(
'class' => array(),
),
)
),
get_the_title( $post_id )
);
return '';
}
add_filter( 'edit_post_link', 'twentytwenty_edit_post_link', 10, 3 );
/**
* Retrieves the post meta.
*
* @since Twenty Twenty 1.0
*
* @global WP_Post $post Global post object.
*
* @param int $post_id The ID of the post.
* @param string $location The location where the meta is shown.
*/
function twentytwenty_get_post_meta( $post_id = null, $location = 'single-top' ) {
// Require post ID.
if ( ! $post_id ) {
return;
}
/**
* Filters post types array.
*
* This filter can be used to hide post meta information of post, page or custom post type
* registered by child themes or plugins.
*
* @since Twenty Twenty 1.0
*
* @param array Array of post types.
*/
$disallowed_post_types = apply_filters( 'twentytwenty_disallowed_post_types_for_meta_output', array( 'page' ) );
// Check whether the post type is allowed to output post meta.
if ( in_array( get_post_type( $post_id ), $disallowed_post_types, true ) ) {
return;
}
$post_meta_wrapper_classes = '';
$post_meta_classes = '';
// Get the post meta settings for the location specified.
if ( 'single-top' === $location ) {
/**
* Filters post meta info visibility.
*
* Use this filter to hide post meta information like Author, Post date, Comments, Is sticky status.
*
* @since Twenty Twenty 1.0
*
* @param array $args {
* @type string $author
* @type string $post-date
* @type string $comments
* @type string $sticky
* }
*/
$post_meta = apply_filters(
'twentytwenty_post_meta_location_single_top',
array(
'author',
'post-date',
'comments',
'sticky',
)
);
$post_meta_wrapper_classes = ' post-meta-single post-meta-single-top';
} elseif ( 'single-bottom' === $location ) {
/**
* Filters post tags visibility.
*
* Use this filter to hide post tags.
*
* @since Twenty Twenty 1.0
*
* @param array $args {
* @type string $tags
* }
*/
$post_meta = apply_filters(
'twentytwenty_post_meta_location_single_bottom',
array(
'tags',
)
);
$post_meta_wrapper_classes = ' post-meta-single post-meta-single-bottom';
}
// If the post meta setting has the value 'empty', it's explicitly empty and the default post meta shouldn't be output.
if ( $post_meta && ! in_array( 'empty', $post_meta, true ) ) {
// Make sure we don't output an empty container.
$has_meta = false;
global $post;
$the_post = get_post( $post_id );
setup_postdata( $the_post );
ob_start();
?>
-
' . esc_html( get_the_author_meta( 'display_name' ) ) . ''
);
?>
-
-
-
-
show_toggles ) && $args->show_toggles ) {
// Wrap the menu item link contents in a div, used for positioning.
$args->before = '';
$args->after = '';
// Add a toggle to items with children.
if ( in_array( 'menu-item-has-children', $item->classes, true ) ) {
$toggle_target_string = '.menu-modal .menu-item-' . $item->ID . ' > .sub-menu';
$toggle_duration = twentytwenty_toggle_duration();
// Add the sub menu toggle.
$args->after .= '';
}
// Close the wrapper.
$args->after .= '
';
// Add sub menu icons to the primary menu without toggles.
} elseif ( 'primary' === $args->theme_location ) {
if ( in_array( 'menu-item-has-children', $item->classes, true ) ) {
$args->after = '';
} else {
$args->after = '';
}
}
return $args;
}
add_filter( 'nav_menu_item_args', 'twentytwenty_add_sub_toggles_to_main_menu', 10, 3 );
/**
* Displays SVG icons in social links menu.
*
* @since Twenty Twenty 1.0
*
* @param string $item_output The menu item's starting HTML output.
* @param WP_Post $item Menu item data object.
* @param int $depth Depth of the menu. Used for padding.
* @param stdClass $args An object of wp_nav_menu() arguments.
* @return string The menu item output with social icon.
*/
function twentytwenty_nav_menu_social_icons( $item_output, $item, $depth, $args ) {
// Change SVG icon inside social links menu if there is supported URL.
if ( 'social' === $args->theme_location ) {
$svg = TwentyTwenty_SVG_Icons::get_social_link_svg( $item->url );
if ( empty( $svg ) ) {
$svg = twentytwenty_get_theme_svg( 'link' );
}
$item_output = str_replace( $args->link_after, '' . $svg, $item_output );
}
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'twentytwenty_nav_menu_social_icons', 10, 4 );
/**
* Classes
*/
/**
* Adds 'no-js' class.
*
* If we're missing JavaScript support, the HTML element will have a 'no-js' class.
*
* @since Twenty Twenty 1.0
*/
function twentytwenty_no_js_class() {
?>
post_type : false;
// Check whether we're singular.
if ( is_singular() ) {
$classes[] = 'singular';
}
// Check whether the current page should have an overlay header.
if ( is_page_template( array( 'templates/template-cover.php' ) ) ) {
$classes[] = 'overlay-header';
}
// Check whether the current page has full-width content.
if ( is_page_template( array( 'templates/template-full-width.php' ) ) ) {
$classes[] = 'has-full-width-content';
}
// Check for enabled search.
if ( true === get_theme_mod( 'enable_header_search', true ) ) {
$classes[] = 'enable-search-modal';
}
// Check for post thumbnail.
if ( is_singular() && has_post_thumbnail() ) {
$classes[] = 'has-post-thumbnail';
} elseif ( is_singular() ) {
$classes[] = 'missing-post-thumbnail';
}
// Check whether we're in the customizer preview.
if ( is_customize_preview() ) {
$classes[] = 'customizer-preview';
}
// Check if posts have single pagination.
if ( is_single() && ( get_next_post() || get_previous_post() ) ) {
$classes[] = 'has-single-pagination';
} else {
$classes[] = 'has-no-pagination';
}
// Check if we're showing comments.
if ( $post && ( ( 'post' === $post_type || comments_open() || get_comments_number() ) && ! post_password_required() ) ) {
$classes[] = 'showing-comments';
} else {
$classes[] = 'not-showing-comments';
}
// Check if avatars are visible.
$classes[] = get_option( 'show_avatars' ) ? 'show-avatars' : 'hide-avatars';
// Slim page template class names (class = name - file suffix).
if ( is_page_template() ) {
$classes[] = basename( get_page_template_slug(), '.php' );
}
// Check for the elements output in the top part of the footer.
$has_footer_menu = has_nav_menu( 'footer' );
$has_social_menu = has_nav_menu( 'social' );
$has_sidebar_1 = is_active_sidebar( 'sidebar-1' );
$has_sidebar_2 = is_active_sidebar( 'sidebar-2' );
// Add a class indicating whether those elements are output.
if ( $has_footer_menu || $has_social_menu || $has_sidebar_1 || $has_sidebar_2 ) {
$classes[] = 'footer-top-visible';
} else {
$classes[] = 'footer-top-hidden';
}
// Get header/footer background color.
$header_footer_background = get_theme_mod( 'header_footer_background_color', '#ffffff' );
$header_footer_background = strtolower( '#' . ltrim( $header_footer_background, '#' ) );
// Get content background color.
$background_color = get_theme_mod( 'background_color', 'f5efe0' );
$background_color = strtolower( '#' . ltrim( $background_color, '#' ) );
// Add extra class if main background and header/footer background are the same color.
if ( $background_color === $header_footer_background ) {
$classes[] = 'reduced-spacing';
}
return $classes;
}
add_filter( 'body_class', 'twentytwenty_body_classes' );
/**
* Archives
*/
/**
* Filters the archive title and styles the word before the first colon.
*
* @since Twenty Twenty 1.0
*
* @param string $title Current archive title.
* @return string Current archive title.
*/
function twentytwenty_get_the_archive_title( $title ) {
/**
* Filters the regular expression used to style the word before the first colon.
*
* @since Twenty Twenty 1.0
*
* @param array $regex An array of regular expression pattern and replacement.
*/
$regex = apply_filters(
'twentytwenty_get_the_archive_title_regex',
array(
'pattern' => '/(\A[^\:]+\:)/',
'replacement' => '$1',
)
);
if ( empty( $regex ) ) {
return $title;
}
return preg_replace( $regex['pattern'], $regex['replacement'], $title );
}
add_filter( 'get_the_archive_title', 'twentytwenty_get_the_archive_title' );
/**
* Miscellaneous
*/
/**
* Toggles animation duration in milliseconds.
*
* @since Twenty Twenty 1.0
*
* @return int Duration in milliseconds
*/
function twentytwenty_toggle_duration() {
/**
* Filters the animation duration/speed used usually for submenu toggles.
*
* @since Twenty Twenty 1.0
*
* @param int $duration Duration in milliseconds.
*/
$duration = apply_filters( 'twentytwenty_toggle_duration', 250 );
return $duration;
}
/**
* Gets unique ID.
*
* This is a PHP implementation of Underscore's uniqueId method. A static variable
* contains an integer that is incremented with each call. This number is returned
* with the optional prefix. As such the returned value is not universally unique,
* but it is unique across the life of the PHP process.
*
* @since Twenty Twenty 1.0
*
* @see wp_unique_id() Themes requiring WordPress 5.0.3 and greater should use this instead.
*
* @param string $prefix Prefix for the returned ID.
* @return string Unique ID.
*/
function twentytwenty_unique_id( $prefix = '' ) {
static $id_counter = 0;
if ( function_exists( 'wp_unique_id' ) ) {
return wp_unique_id( $prefix );
}
return $prefix . (string) ++$id_counter;
}