WordPress/wp-content/themes/twentytwenty/inc/template-tags.php

862 lines
23 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Custom template tags for this theme.
*
* @package WordPress
* @subpackage Twenty_Twenty
* @since Twenty Twenty 1.0
*/
/**
* Table of Contents:
* Logo & Description
* Comments
* Post Meta
* Menus
* Classes
* Archives
* Miscellaneous
*/
/**
* Logo & Description
*/
/**
* Displays the site logo, either text or image.
*
* @since Twenty Twenty 1.0
*
* @param array $args Arguments for displaying the site logo either as an image or text.
* @param bool $display Display or return the HTML.
* @return string Compiled HTML based on our arguments.
*/
function twentytwenty_site_logo( $args = array(), $display = true ) {
$logo = get_custom_logo();
$site_title = get_bloginfo( 'name' );
$contents = '';
$classname = '';
$defaults = array(
'logo' => '%1$s<span class="screen-reader-text">%2$s</span>',
'logo_class' => 'site-logo',
'title' => '<a href="%1$s">%2$s</a>',
'title_class' => 'site-title',
'home_wrap' => '<h1 class="%1$s">%2$s</h1>',
'single_wrap' => '<div class="%1$s faux-heading">%2$s</div>',
'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 = '<div class="site-description">%s</div><!-- .site-description -->';
$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 <span class="screen-reader-text">%s</span>', 'twentytwenty' ),
array(
'span' => array(
'class' => array(),
),
)
),
get_the_title( $post_id )
);
return '<div class="post-meta-wrapper post-meta-edit-link-wrapper"><ul class="post-meta"><li class="post-edit meta-wrapper"><span class="meta-icon">' . twentytwenty_get_theme_svg( 'edit' ) . '</span><span class="meta-text"><a href="' . esc_url( $edit_url ) . '">' . $text . '</a></span></li></ul><!-- .post-meta --></div><!-- .post-meta-wrapper -->';
}
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();
?>
<div class="post-meta-wrapper<?php echo esc_attr( $post_meta_wrapper_classes ); ?>">
<ul class="post-meta<?php echo esc_attr( $post_meta_classes ); ?>">
<?php
/**
* Fires before post meta HTML display.
*
* Allow output of additional post meta info to be added by child themes and plugins.
*
* @since Twenty Twenty 1.0
* @since Twenty Twenty 1.1 Added the `$post_meta` and `$location` parameters.
*
* @param int $post_id Post ID.
* @param array $post_meta An array of post meta information.
* @param string $location The location where the meta is shown.
* Accepts 'single-top' or 'single-bottom'.
*/
do_action( 'twentytwenty_start_of_post_meta_list', $post_id, $post_meta, $location );
// Author.
if ( post_type_supports( get_post_type( $post_id ), 'author' ) && in_array( 'author', $post_meta, true ) ) {
$has_meta = true;
?>
<li class="post-author meta-wrapper">
<span class="meta-icon">
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Post author', 'twentytwenty' );
?>
</span>
<?php twentytwenty_the_theme_svg( 'user' ); ?>
</span>
<span class="meta-text">
<?php
printf(
/* translators: %s: Author name. */
__( 'By %s', 'twentytwenty' ),
'<a href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author_meta( 'display_name' ) ) . '</a>'
);
?>
</span>
</li>
<?php
}
// Post date.
if ( in_array( 'post-date', $post_meta, true ) ) {
$has_meta = true;
?>
<li class="post-date meta-wrapper">
<span class="meta-icon">
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Post date', 'twentytwenty' );
?>
</span>
<?php twentytwenty_the_theme_svg( 'calendar' ); ?>
</span>
<span class="meta-text">
<a href="<?php the_permalink(); ?>"><?php the_time( get_option( 'date_format' ) ); ?></a>
</span>
</li>
<?php
}
// Categories.
if ( in_array( 'categories', $post_meta, true ) && has_category() ) {
$has_meta = true;
?>
<li class="post-categories meta-wrapper">
<span class="meta-icon">
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Categories', 'twentytwenty' );
?>
</span>
<?php twentytwenty_the_theme_svg( 'folder' ); ?>
</span>
<span class="meta-text">
<?php _ex( 'In', 'A string that is output before one or more categories', 'twentytwenty' ); ?> <?php the_category( ', ' ); ?>
</span>
</li>
<?php
}
// Tags.
if ( in_array( 'tags', $post_meta, true ) && has_tag() ) {
$has_meta = true;
?>
<li class="post-tags meta-wrapper">
<span class="meta-icon">
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Tags', 'twentytwenty' );
?>
</span>
<?php twentytwenty_the_theme_svg( 'tag' ); ?>
</span>
<span class="meta-text">
<?php the_tags( '', ', ', '' ); ?>
</span>
</li>
<?php
}
// Comments link.
if ( in_array( 'comments', $post_meta, true ) && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
$has_meta = true;
?>
<li class="post-comment-link meta-wrapper">
<span class="meta-icon">
<?php twentytwenty_the_theme_svg( 'comment' ); ?>
</span>
<span class="meta-text">
<?php comments_popup_link(); ?>
</span>
</li>
<?php
}
// Sticky.
if ( in_array( 'sticky', $post_meta, true ) && is_sticky() ) {
$has_meta = true;
?>
<li class="post-sticky meta-wrapper">
<span class="meta-icon">
<?php twentytwenty_the_theme_svg( 'bookmark' ); ?>
</span>
<span class="meta-text">
<?php _e( 'Sticky post', 'twentytwenty' ); ?>
</span>
</li>
<?php
}
/**
* Fires after post meta HTML display.
*
* Allow output of additional post meta info to be added by child themes and plugins.
*
* @since Twenty Twenty 1.0
* @since Twenty Twenty 1.1 Added the `$post_meta` and `$location` parameters.
*
* @param int $post_id Post ID.
* @param array $post_meta An array of post meta information.
* @param string $location The location where the meta is shown.
* Accepts 'single-top' or 'single-bottom'.
*/
do_action( 'twentytwenty_end_of_post_meta_list', $post_id, $post_meta, $location );
?>
</ul><!-- .post-meta -->
</div><!-- .post-meta-wrapper -->
<?php
wp_reset_postdata();
$meta_output = ob_get_clean();
// If there is meta to output, return it.
if ( $has_meta && $meta_output ) {
return $meta_output;
}
}
}
/**
* Menus
*/
/**
* Filters classes of wp_list_pages items to match menu items.
*
* Filter the class applied to wp_list_pages() items with children to match the menu class, to simplify.
* styling of sub levels in the fallback. Only applied if the match_menu_classes argument is set.
*
* @since Twenty Twenty 1.0
*
* @param string[] $css_class An array of CSS classes to be applied to each list item.
* @param WP_Post $page Page data object.
* @param int $depth Depth of page, used for padding.
* @param array $args An array of arguments.
* @param int $current_page ID of the current page.
* @return array CSS class names.
*/
function twentytwenty_filter_wp_list_pages_item_classes( $css_class, $page, $depth, $args, $current_page ) {
// Only apply to wp_list_pages() calls with match_menu_classes set to true.
$match_menu_classes = isset( $args['match_menu_classes'] );
if ( ! $match_menu_classes ) {
return $css_class;
}
// Add current menu item class.
if ( in_array( 'current_page_item', $css_class, true ) ) {
$css_class[] = 'current-menu-item';
}
// Add menu item has children class.
if ( in_array( 'page_item_has_children', $css_class, true ) ) {
$css_class[] = 'menu-item-has-children';
}
return $css_class;
}
add_filter( 'page_css_class', 'twentytwenty_filter_wp_list_pages_item_classes', 10, 5 );
/**
* Adds a Sub Nav Toggle to the Expanded Menu and Mobile Menu.
*
* @since Twenty Twenty 1.0
*
* @param stdClass $args An object of wp_nav_menu() arguments.
* @param WP_Post $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @return stdClass An object of wp_nav_menu() arguments.
*/
function twentytwenty_add_sub_toggles_to_main_menu( $args, $item, $depth ) {
// Add sub menu toggles to the Expanded Menu with toggles.
if ( isset( $args->show_toggles ) && $args->show_toggles ) {
// Wrap the menu item link contents in a div, used for positioning.
$args->before = '<div class="ancestor-wrapper">';
$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 .= '<button class="toggle sub-menu-toggle fill-children-current-color" data-toggle-target="' . $toggle_target_string . '" data-toggle-type="slidetoggle" data-toggle-duration="' . absint( $toggle_duration ) . '" aria-expanded="false"><span class="screen-reader-text">' .
/* translators: Hidden accessibility text. */
__( 'Show sub menu', 'twentytwenty' ) .
'</span>' . twentytwenty_get_theme_svg( 'chevron-down' ) . '</button>';
}
// Close the wrapper.
$args->after .= '</div><!-- .ancestor-wrapper -->';
// 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 = '<span class="icon"></span>';
} 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, '</span>' . $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() {
?>
<script>document.documentElement.className = document.documentElement.className.replace( 'no-js', 'js' );</script>
<?php
}
add_action( 'wp_head', 'twentytwenty_no_js_class' );
/**
* Adds conditional body classes.
*
* @since Twenty Twenty 1.0
*
* @global WP_Post $post Global post object.
*
* @param array $classes Classes added to the body tag.
* @return array Classes added to the body tag.
*/
function twentytwenty_body_classes( $classes ) {
global $post;
$post_type = isset( $post ) ? $post->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' => '<span class="color-accent">$1</span>',
)
);
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;
}