Build classic and block WordPress themes from scratch: the template hierarchy, The Loop, the_title() and the_content(), template parts, menus, the Customizer, child themes and theme.json.
Lessons
get_template_part() loads a reusable chunk of template from a file such as template-parts/content.php, so the markup for "one post in a list" is written once and shared by the blog, archives and search results.
Without template parts, index.php, archive.php and search.php each contain an identical <article> block inside their Loop. Change the design of a post card and you must remember to change it in three places.
Create template-parts/content.php:
<?php
/**
* Template part: one post inside a list.
*/
?>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'post-card' ); ?>>
<?php if ( has_post_thumbnail() ) : ?>
<a class="post-card__image" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
<?php the_post_thumbnail( 'medium_large' ); ?>
</a>
<?php endif; ?>
<header class="post-card__header">
<?php the_title( sprintf( '<h2 class="post-card__title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?>
<?php gdc_starter_posted_on(); ?>
</header>
<div class="post-card__excerpt">
<?php the_excerpt(); ?>
</div>
</article>And use it from any Loop:
<?php while ( have_posts() ) : the_post(); ?>
<?php get_template_part( 'template-parts/content' ); ?>
<?php endwhile; ?>The part runs inside the Loop, so every template tag in it — the_title(), the_permalink() — describes the current post automatically.
get_template_part( $slug, $name ) looks for {$slug}-{$name}.php first and falls back to {$slug}.php. That gives you a mini template hierarchy:
<?php
// Posts load template-parts/content-post.php, pages content-page.php,
// and any other type falls back to template-parts/content.php.
get_template_part( 'template-parts/content', get_post_type() );
// Or vary by post format: content-video.php, content-quote.php ...
get_template_part( 'template-parts/content', get_post_format() );Since WordPress 5.5, a third argument passes an array that arrives in the part as $args. Use it instead of global variables:
<?php
// In archive.php
get_template_part(
'template-parts/content',
'card',
array(
'show_excerpt' => true,
'heading' => 'h3',
)
);<?php
// In template-parts/content-card.php
$args = wp_parse_args(
$args,
array(
'show_excerpt' => false,
'heading' => 'h2',
)
);
$tag = in_array( $args['heading'], array( 'h2', 'h3', 'h4' ), true ) ? $args['heading'] : 'h2';
?>
<article <?php post_class( 'card' ); ?>>
<<?php echo tag_escape( $tag ); ?> class="card__title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</<?php echo tag_escape( $tag ); ?>>
<?php if ( $args['show_excerpt'] ) : ?>
<?php the_excerpt(); ?>
<?php endif; ?>
</article>wp_parse_args() fills in defaults for anything the caller left out. The heading tag is checked against a fixed list before it is used, and tag_escape() strips anything that is not a valid tag name on output — two layers, so a typo or a bad value can never inject markup.
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
<?php endwhile; ?>
<?php else : ?>
<?php get_template_part( 'template-parts/content', 'none' ); ?>
<?php endif; ?>Tip:get_template_part()searches the child theme first, then the parent. That makes every part you create an override point: a child theme can replace justcontent-card.phpand nothing else.
index.php into template-parts/content.php.content-page.php and load parts with get_post_type() as the name.content-none.php with a search form and use it in the else branch.In accordance with Section 6 & Section 7 of the DPDP Act 2023, third-party analytics and marketing trackers are strictly gated behind your affirmative consent. You may withdraw consent at any time under Section 6(4).
Essential for session authentication (ci_session), Cross-Site Request Forgery security (csrf_cookie_name), and Cloudflare DDoS/bot prevention. Cannot be disabled.
Gated under DPDP Section 7. Allows Google Analytics 4 (Google Consent Mode v2) to measure aggregate, anonymized tool usage.
Enables browser local storage to preserve your theme selection (dark/light mode) and code editor layout between visits.
Used to display developer sponsorships and native tool partner notices.