* WordPress Post Template Functions.
* Gets content for the current post in the loop.
* Displays the ID of the current item in the WordPress Loop.
function the_ID() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
* Retrieves the ID of the current item in the WordPress Loop.
* @return int|false The ID of the current item in the WordPress Loop. False if $post is not set.
function get_the_ID() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
return ! empty( $post ) ? $post->ID : false;
* Displays or retrieves the current post title with optional markup.
* @param string $before Optional. Markup to prepend to the title. Default empty.
* @param string $after Optional. Markup to append to the title. Default empty.
* @param bool $display Optional. Whether to echo or return the title. Default true for echo.
* @return void|string Void if `$display` argument is true or the title is empty,
* current post title if `$display` is false.
function the_title( $before = '', $after = '', $display = true ) {
$title = get_the_title();
if ( strlen( $title ) === 0 ) {
$title = $before . $title . $after;
* Sanitizes the current title when retrieving or displaying.
* Works like the_title(), except the parameters can be in a string or
* an array. See the function for what can be override in the $args parameter.
* The title before it is displayed will have the tags stripped and esc_attr()
* before it is passed to the user or displayed. The default as with the_title(),
* is to display the title.
* @param string|array $args {
* Title attribute arguments. Optional.
* @type string $before Markup to prepend to the title. Default empty.
* @type string $after Markup to append to the title. Default empty.
* @type bool $echo Whether to echo or return the title. Default true for echo.
* @type WP_Post $post Current post object to retrieve the title for.
* @return void|string Void if 'echo' argument is true, the title attribute if 'echo' is false.
function the_title_attribute( $args = '' ) {
$parsed_args = wp_parse_args( $args, $defaults );
$title = get_the_title( $parsed_args['post'] );
if ( strlen( $title ) === 0 ) {
$title = $parsed_args['before'] . $title . $parsed_args['after'];
$title = esc_attr( strip_tags( $title ) );
if ( $parsed_args['echo'] ) {
* Retrieves the post title.
* If the post is protected and the visitor is not an admin, then "Protected"
* will be inserted before the post title. If the post is private, then
* "Private" will be inserted before the post title.
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
function get_the_title( $post = 0 ) {
$post = get_post( $post );
$post_title = isset( $post->post_title ) ? $post->post_title : '';
$post_id = isset( $post->ID ) ? $post->ID : 0;
if ( ! empty( $post->post_password ) ) {
/* translators: %s: Protected post title. */
$prepend = __( 'Protected: %s' );
* Filters the text prepended to the post title for protected posts.
* The filter is only applied on the front end.
* @param string $prepend Text displayed before the post title.
* Default 'Protected: %s'.
* @param WP_Post $post Current post object.
$protected_title_format = apply_filters( 'protected_title_format', $prepend, $post );
$post_title = sprintf( $protected_title_format, $post_title );
} elseif ( isset( $post->post_status ) && 'private' === $post->post_status ) {
/* translators: %s: Private post title. */
$prepend = __( 'Private: %s' );
* Filters the text prepended to the post title of private posts.
* The filter is only applied on the front end.
* @param string $prepend Text displayed before the post title.
* @param WP_Post $post Current post object.
$private_title_format = apply_filters( 'private_title_format', $prepend, $post );
$post_title = sprintf( $private_title_format, $post_title );
* Filters the post title.
* @param string $post_title The post title.
* @param int $post_id The post ID.
return apply_filters( 'the_title', $post_title, $post_id );
* Displays the Post Global Unique Identifier (guid).
* The guid will appear to be a link, but should not be used as a link to the
* post. The reason you should not use it as a link, is because of moving the
* URL is escaped to make it XML-safe.
* @param int|WP_Post $post Optional. Post ID or post object. Default is global $post.
function the_guid( $post = 0 ) {
$post = get_post( $post );
$post_guid = isset( $post->guid ) ? get_the_guid( $post ) : '';
$post_id = isset( $post->ID ) ? $post->ID : 0;
* Filters the escaped Global Unique Identifier (guid) of the post.
* @param string $post_guid Escaped Global Unique Identifier (guid) of the post.
* @param int $post_id The post ID.
echo apply_filters( 'the_guid', $post_guid, $post_id );
* Retrieves the Post Global Unique Identifier (guid).
* The guid will appear to be a link, but should not be used as an link to the
* post. The reason you should not use it as a link, is because of moving the
* @param int|WP_Post $post Optional. Post ID or post object. Default is global $post.
function get_the_guid( $post = 0 ) {
$post = get_post( $post );
$post_guid = isset( $post->guid ) ? $post->guid : '';
$post_id = isset( $post->ID ) ? $post->ID : 0;
* Filters the Global Unique Identifier (guid) of the post.
* @param string $post_guid Global Unique Identifier (guid) of the post.
* @param int $post_id The post ID.
return apply_filters( 'get_the_guid', $post_guid, $post_id );
* Displays the post content.
* @param string $more_link_text Optional. Content for when there is more text.
* @param bool $strip_teaser Optional. Strip teaser content before the more text. Default false.
function the_content( $more_link_text = null, $strip_teaser = false ) {
$content = get_the_content( $more_link_text, $strip_teaser );
* Filters the post content.
* @param string $content Content of the current post.
$content = apply_filters( 'the_content', $content );
$content = str_replace( ']]>', ']]>', $content );
* Retrieves the post content.
* @since 5.2.0 Added the `$post` parameter.
* @global int $page Page number of a single post/page.
* @global int $more Boolean indicator for whether single post/page is being viewed.
* @global bool $preview Whether post/page is in preview mode.
* @global array $pages Array of all pages in post/page. Each array element contains
* part of the content separated by the `<!--nextpage-->` tag.
* @global int $multipage Boolean indicator for whether multiple pages are in play.
* @param string $more_link_text Optional. Content for when there is more text.
* @param bool $strip_teaser Optional. Strip teaser content before the more text. Default false.
* @param WP_Post|object|int $post Optional. WP_Post instance or Post ID/object. Default null.
function get_the_content( $more_link_text = null, $strip_teaser = false, $post = null ) {
global $page, $more, $preview, $pages, $multipage;
$_post = get_post( $post );
if ( ! ( $_post instanceof WP_Post ) ) {
* Use the globals if the $post parameter was not specified,
* but only after they have been set up in setup_postdata().
if ( null === $post && did_action( 'the_post' ) ) {
$elements = compact( 'page', 'more', 'preview', 'pages', 'multipage' );
$elements = generate_postdata( $_post );
if ( null === $more_link_text ) {
$more_link_text = sprintf(
'<span aria-label="%1$s">%2$s</span>',
/* translators: %s: Post title. */
__( 'Continue reading %s' ),
// If post password required and it doesn't match the cookie.
if ( post_password_required( $_post ) ) {
return get_the_password_form( $_post );
// If the requested page doesn't exist.
if ( $elements['page'] > count( $elements['pages'] ) ) {
// Give them the highest numbered page that DOES exist.
$elements['page'] = count( $elements['pages'] );
$page_no = $elements['page'];
$content = $elements['pages'][ $page_no - 1 ];
if ( preg_match( '/<!--more(.*?)?-->/', $content, $matches ) ) {
if ( has_block( 'more', $content ) ) {
// Remove the core/more block delimiters. They will be left over after $content is split up.
$content = preg_replace( '/<!-- \/?wp:more(.*?) -->/', '', $content );
$content = explode( $matches[0], $content, 2 );
if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) ) {
$more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) );
$content = array( $content );
if ( str_contains( $_post->post_content, '<!--noteaser-->' )
&& ( ! $elements['multipage'] || 1 === $elements['page'] )
if ( $elements['more'] && $strip_teaser && $has_teaser ) {
if ( count( $content ) > 1 ) {
if ( $elements['more'] ) {
$output .= '<span id="more-' . $_post->ID . '"></span>' . $content[1];
if ( ! empty( $more_link_text ) ) {
* Filters the Read More link text.
* @param string $more_link_element Read More link element.
* @param string $more_link_text Read More text.
$output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink( $_post ) . "#more-{$_post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text );
$output = force_balance_tags( $output );
* Displays the post excerpt.
* Filters the displayed post excerpt.
* @param string $post_excerpt The post excerpt.
echo apply_filters( 'the_excerpt', get_the_excerpt() );
* Retrieves the post excerpt.
* @since 4.5.0 Introduced the `$post` parameter.
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string Post excerpt.
function get_the_excerpt( $post = null ) {
if ( is_bool( $post ) ) {
_deprecated_argument( __FUNCTION__, '2.3.0' );
$post = get_post( $post );
if ( post_password_required( $post ) ) {
return __( 'There is no excerpt because this is a protected post.' );
* Filters the retrieved post excerpt.
* @since 4.5.0 Introduced the `$post` parameter.
* @param string $post_excerpt The post excerpt.
* @param WP_Post $post Post object.
return apply_filters( 'get_the_excerpt', $post->post_excerpt, $post );
* Determines whether the post has a custom excerpt.
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return bool True if the post has a custom excerpt, false otherwise.
function has_excerpt( $post = 0 ) {
$post = get_post( $post );
return ( ! empty( $post->post_excerpt ) );
* Displays the classes for the post container element.
* @param string|string[] $css_class Optional. One or more classes to add to the class list.
* @param int|WP_Post $post Optional. Post ID or post object. Defaults to the global `$post`.
function post_class( $css_class = '', $post = null ) {
// Separates classes with a single space, collates classes for post DIV.
echo 'class="' . esc_attr( implode( ' ', get_post_class( $css_class, $post ) ) ) . '"';
* Retrieves an array of the class names for the post container element.
* The class names are many:
* - If the post has a post thumbnail, `has-post-thumbnail` is added as a class.
* - If the post is sticky, then the `sticky` class name is added.
* - The class `hentry` is always added to each post.
* - For each taxonomy that the post belongs to, a class will be added of the format
* `{$taxonomy}-{$slug}`, e.g. `category-foo` or `my_custom_taxonomy-bar`.
* The `post_tag` taxonomy is a special case; the class has the `tag-` prefix
* instead of `post_tag-`.
* All class names are passed through the filter, {@see 'post_class'}, followed by
* `$css_class` parameter value, with the post ID as the last parameter.
* @since 4.2.0 Custom taxonomy class names were added.
* @param string|string[] $css_class Optional. Space-separated string or array of class names
* to add to the class list. Default empty.
* @param int|WP_Post $post Optional. Post ID or post object.
* @return string[] Array of class names.
function get_post_class( $css_class = '', $post = null ) {
$post = get_post( $post );
if ( ! is_array( $css_class ) ) {