Skip to main content

Overview

Template parts are modular PHP files used to display different types of content. They promote code reusability and follow WordPress template hierarchy conventions. Location: template-parts/ Zalbi Theme includes four template parts:
  • content.php - Standard post display
  • content-page.php - Page content display
  • content-search.php - Search result items
  • content-none.php - No content found message

Loading Template Parts

get_template_part()

Template parts are loaded using WordPress’s get_template_part() function:
get_template_part( 'template-parts/content', get_post_type() );

Common Usage Patterns

<?php
if ( have_posts() ) :
    while ( have_posts() ) :
        the_post();
        get_template_part( 'template-parts/content', get_post_type() );
    endwhile;
else :
    get_template_part( 'template-parts/content', 'none' );
endif;
?>

content.php

Standard Post Template

Displays regular blog posts with full metadata. File: template-parts/content.php Used for: Standard posts, custom post types (fallback)

Structure

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
        
        <div class="entry-meta">
            <?php
            zalbi_posted_on();   // Date
            zalbi_posted_by();   // Author
            ?>
        </div>
    </header>

    <?php zalbi_post_thumbnail(); ?>

    <div class="entry-content">
        <?php the_content(); ?>
        <?php wp_link_pages(); ?>
    </div>

    <footer class="entry-footer">
        <?php zalbi_entry_footer(); ?>
    </footer>
</article>

Features

  • Dynamic Title Tag: Uses <h1> on singular pages, <h2> on archives
  • Post Metadata: Shows publish date and author for posts
  • Featured Image: Displays via zalbi_post_thumbnail()
  • Entry Footer: Categories, tags, edit link via zalbi_entry_footer()
  • Pagination: Multi-page post support with wp_link_pages()

Title Logic

if ( is_singular() ) :
    the_title( '<h1 class="entry-title">', '</h1>' );
else :
    the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
endif;
On archive pages, titles link to the full post. On single pages, they’re plain text.

Conditional Metadata

if ( 'post' === get_post_type() ) :
    ?>
    <div class="entry-meta">
        <?php
        zalbi_posted_on();
        zalbi_posted_by();
        ?>
    </div>
    <?php
endif;
Metadata only displays for the post post type, not pages or custom post types.

content-page.php

Page Content Template

Simplified template for static pages. File: template-parts/content-page.php Used for: Pages, custom page templates

Structure

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
    </header>

    <?php zalbi_post_thumbnail(); ?>

    <div class="entry-content">
        <?php
        the_content();
        wp_link_pages();
        ?>
    </div>

    <?php if ( get_edit_post_link() ) : ?>
        <footer class="entry-footer">
            <?php edit_post_link(); ?>
        </footer>
    <?php endif; ?>
</article>

Differences from content.php

Featurecontent.phpcontent-page.php
Post MetaShows date/authorNone
Entry FooterCategories, tags, commentsEdit link only
TitleConditional h1/h2Always h1
Use CaseBlog postsStatic pages
Only shown to users with edit permissions:
<?php if ( get_edit_post_link() ) : ?>
    <footer class="entry-footer">
        <?php
        edit_post_link(
            sprintf(
                __( 'Edit <span class="screen-reader-text">%s</span>', 'zalbi' ),
                wp_kses_post( get_the_title() )
            ),
            '<span class="edit-link">',
            '</span>'
        );
        ?>
    </footer>
<?php endif; ?>

content-search.php

Search Results Template

Optimized display for search result listings. File: template-parts/content-search.php Used for: Search results page (search.php)

Structure

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( sprintf( '<h2 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?>

        <?php if ( 'post' === get_post_type() ) : ?>
        <div class="entry-meta">
            <?php
            zalbi_posted_on();
            zalbi_posted_by();
            ?>
        </div>
        <?php endif; ?>
    </header>

    <?php zalbi_post_thumbnail(); ?>

    <div class="entry-summary">
        <?php the_excerpt(); ?>
    </div>

    <footer class="entry-footer">
        <?php zalbi_entry_footer(); ?>
    </footer>
</article>

Key Features

  • Linked Titles: All titles link to full content
  • Excerpt Display: Uses the_excerpt() instead of full content
  • Post Metadata: Shows for posts, hidden for pages
  • Footer Info: Categories, tags, comments

Excerpt vs Content

// content.php uses full content
<div class="entry-content">
    <?php the_content(); ?>
</div>

// content-search.php uses excerpt
<div class="entry-summary">
    <?php the_excerpt(); ?>
</div>
Search results show excerpts to provide quick scanning of multiple results.

content-none.php

No Content Template

Displays helpful messages when no posts are found. File: template-parts/content-none.php Used for: Empty archives, failed searches, empty blogs

Structure

<section class="no-results not-found">
    <header class="page-header">
        <h1 class="page-title"><?php esc_html_e( 'Nothing Found', 'zalbi' ); ?></h1>
    </header>

    <div class="page-content">
        <?php
        if ( is_home() && current_user_can( 'publish_posts' ) ) :
            // Message for admins on empty blog
        elseif ( is_search() ) :
            // Message for failed search
        else :
            // Generic no content message
        endif;
        ?>
    </div>
</section>

Conditional Messages

if ( is_home() && current_user_can( 'publish_posts' ) ) :
    printf(
        '<p>' . __( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'zalbi' ) . '</p>',
        esc_url( admin_url( 'post-new.php' ) )
    );
Shows link to create first post (admins only).

Custom Template Functions

zalbi_post_thumbnail()

Displays featured images with conditional markup. Location: inc/template-tags.php:122
function zalbi_post_thumbnail() {
    if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) {
        return;
    }

    if ( is_singular() ) :
        ?>
        <div class="post-thumbnail">
            <?php the_post_thumbnail(); ?>
        </div>
        <?php
    else :
        ?>
        <a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
            <?php
            the_post_thumbnail(
                'post-thumbnail',
                array(
                    'alt' => the_title_attribute( array( 'echo' => false ) ),
                )
            );
            ?>
        </a>
        <?php
    endif;
}

zalbi_posted_on()

Displays formatted post date. Location: inc/template-tags.php:14
function zalbi_posted_on() {
    $time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';
    if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
        $time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s">%4$s</time>';
    }

    $posted_on = sprintf(
        esc_html_x( 'Posted on %s', 'post date', 'zalbi' ),
        '<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'
    );

    echo '<span class="posted-on">' . $posted_on . '</span>';
}

zalbi_posted_by()

Displays post author with link to archive. Location: inc/template-tags.php:43
function zalbi_posted_by() {
    $byline = sprintf(
        esc_html_x( 'by %s', 'post author', 'zalbi' ),
        '<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>'
    );

    echo '<span class="byline"> ' . $byline . '</span>';
}

zalbi_entry_footer()

Displays categories, tags, comments, and edit links. Location: inc/template-tags.php:59
function zalbi_entry_footer() {
    // Categories (posts only)
    if ( 'post' === get_post_type() ) {
        $categories_list = get_the_category_list( esc_html__( ', ', 'zalbi' ) );
        if ( $categories_list ) {
            printf( '<span class="cat-links">' . esc_html__( 'Posted in %1$s', 'zalbi' ) . '</span>', $categories_list );
        }

        // Tags
        $tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'zalbi' ) );
        if ( $tags_list ) {
            printf( '<span class="tags-links">' . esc_html__( 'Tagged %1$s', 'zalbi' ) . '</span>', $tags_list );
        }
    }

    // Comments link
    if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
        echo '<span class="comments-link">';
        comments_popup_link();
        echo '</span>';
    }

    // Edit link
    edit_post_link();
}

Creating Custom Template Parts

Example: Content Part for Custom Post Type

Create template-parts/content-hinchable.php:
<?php
/**
 * Template part for displaying hinchables in archive
 */
?>

<article id="post-<?php the_ID(); ?>" <?php post_class( 'product-card' ); ?>>
    <a href="<?php the_permalink(); ?>">
        <?php the_post_thumbnail( 'medium_large' ); ?>
    </a>
    
    <div class="card-content">
        <?php
        $tag_color = get_field('etiqueta_color');
        $medidas = get_field('medidas');
        $capacidad = get_field('capacidad');
        ?>
        
        <span class="card-tag <?php echo esc_attr( $tag_color ); ?>">
            <?php echo esc_html( get_field('categoria_nombre') ); ?>
        </span>
        
        <h3 class="card-title">
            <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
        </h3>
        
        <ul class="card-specs">
            <li><i class="fas fa-ruler-combined"></i> <?php echo esc_html( $medidas ); ?></li>
            <li><i class="fas fa-users"></i> <?php echo esc_html( $capacidad ); ?></li>
        </ul>
    </div>
</article>

Loading Custom Template Part

In archive-hinchable.php:
<?php
if ( have_posts() ) :
    while ( have_posts() ) :
        the_post();
        get_template_part( 'template-parts/content', 'hinchable' );
    endwhile;
endif;
?>

Best Practices

  • Use content-{type}.php pattern
  • Match post type slugs for automatic loading
  • Use descriptive names: content-event, not content-1

Common Modifications

Remove Post Metadata

In template-parts/content.php:21-29, comment out:
<?php // if ( 'post' === get_post_type() ) : ?>
    <!-- <div class="entry-meta">
        <?php
        // zalbi_posted_on();
        // zalbi_posted_by();
        ?>
    </div> -->
<?php // endif; ?>

Change Excerpt Length

Add to functions.php:
function zalbi_custom_excerpt_length( $length ) {
    return 20; // Number of words
}
add_filter( 'excerpt_length', 'zalbi_custom_excerpt_length', 999 );

Add Custom Wrapper

In any template part:
<article <?php post_class( 'my-custom-class' ); ?>>
    <!-- content -->
</article>
post_class() automatically adds WordPress classes plus your custom ones.

Passing Variables to Template Parts

Use get_template_part() with set_query_var():
// Set variable
set_query_var( 'card_style', 'compact' );
get_template_part( 'template-parts/content', 'product' );

// In template-parts/content-product.php
$card_style = get_query_var( 'card_style', 'default' );
Or use the modern approach (WordPress 5.5+):
get_template_part( 
    'template-parts/content', 
    'product',
    array( 'card_style' => 'compact' )
);

// In template part
$args = wp_parse_args( $args, array( 'card_style' => 'default' ) );

Build docs developers (and LLMs) love