Technote

Themes & plugins Practical

Series Child theme development in practice Part 3 of 8

Template parts: give shared markup a single owner

Duplicated markup always drifts. You fix one copy, the other stays wrong, and nobody notices until the two screens disagree.

You build a post card for the archive screen. Days later the search results need the same card, so you copy the markup across. At that moment you have created two sources of truth. The problem does not appear now; it appears two months later when you add a badge to the card and only fix one of them.

This class of breakage is silent. No error, no warning, and unless somebody views both screens side by side, nothing reveals it. So the goal is not to fix the drift but to make drift impossible.

Give the markup one owner

get_template_part() puts a fragment of markup in its own file and calls it wherever it is needed. The fragment becomes the single owner, and screen templates merely invoke it.

<?php
// The same call from archive.php, search.php, anywhere
while ( have_posts() ) :
    the_post();
    get_template_part( 'template-parts/card', 'note' );
endwhile;

The second argument names a variant. The call above looks for template-parts/card-note.php first and falls back to template-parts/card.php. That gives you a base plus variants almost for free.

The child theme rule applies here too. Fragments go through locate_template(), so a copy in the child wins over the parent. To change a single fragment of a parent theme, copy just that one file across.

Duplication is not billed on the day you copy — it is billed on the day you edit

Pass data as arguments

Fragments often need slightly different values per call site. The old approach was to set a global before the call and read it inside, which forces the fragment to know about its caller and kills reuse. Pass an array as the third argument instead and read it as $args.

<?php
get_template_part( 'template-parts/card', 'note', [
    'heading' => 'h3',
    'compact' => true,
] );

// inside template-parts/card-note.php
$heading = $args['heading'] ?? 'h2';
$compact = ! empty( $args['compact'] );

Keeping the defaults inside the fragment is the important half. Call sites that pass nothing still work, and the fragment stays self-contained.

What should not become a template part

get_template_part() echoes rather than returns. So when you find yourself wanting the result as a string and reaching for output buffering, treat that urge as a signal: this wants to be a function. Returning strings is not a template fragment’s job.

There is an opposite failure too. Extracting markup that appears on exactly one screen — and always will — means you now open two files to understand one page. The criterion is reuse, not length.

Deciding whether to extract — the bottom three want a different tool

Finding markup you already duplicated is simple: pick one distinctive class name and search the whole theme for it. If the same class appears in more than one template, that is your extraction candidate.

How we run structural clean-up work is published step by step on our process page, and further reading on theme structure lives in the Themes & plugins archive.

Next part

With markup tidy, the stylesheet side is next. The following part covers wiring up an SCSS build, and the argument that never quite dies in WordPress themes: do you commit the compiled output?

More on this topic

All technotes

Themes & plugins Practical

Decide the editable regions before you design them

A design the CMS cannot express stays up for negotiation long after it ships. Deciding what editors may change, first, removes the negotiation entirely.

Designers 6 min read

Themes & plugins Practical

Icon fonts, SVG sprites or inline SVG?

All three draw the same picture on screen. What differs is how many colours you can use, what assistive technology hears, and how many icons actually ship to…

Designers 10 min read

₩270,000 · Join the program