arrow_back
Back

WordPress templates: hierarchy, the loop, and integrating a layout

Andrew Dorokhov Andrew Dorokhov schedule 3 min read
menu_book Table of Contents

The main reference on the subject is the open_in_new Theme Development handbook.

Splitting a layout into parts

The repeating top of the page goes into header.php and is included with:

<?php get_header(); ?>

The bottom of the page goes into footer.php:

<?php get_footer(); ?>

Required hook calls

Two calls must be present in every theme, otherwise plugins won’t be able to inject their styles and scripts.

Inside the head container:

<?php wp_head(); ?>

Right before the closing body tag:

<?php wp_footer(); ?>

Paths and site information

Get the URL of the theme directory:

echo get_template_directory_uri();

Usage example:

<img src="<?= get_template_directory_uri(); ?>/images/logo.png" alt="" />

Information about the site:

bloginfo( 'name' );     // prints the value
get_bloginfo( 'name' ); // returns the value

// Available parameters:
// name
// description
// url
// admin_email
// charset
// version
// language
// stylesheet_url
// stylesheet_directory

For the site URL prefer the dedicated function instead of bloginfo():

// Use this:
home_url();

// Instead of:
bloginfo( 'url' );
get_bloginfo( 'url' );

The page title

Always use wp_title() rather than printing a static title: it adds the contextual information for 404 pages, search results, archive pages and so on.

<title><?php wp_title(); ?></title>
// Prints: " &raquo; Page Title"

The first parameter is the separator, so passing an empty string removes it:

<title><?php wp_title( '' ); ?></title>
// Prints: "  Page Title"

The variant I normally use — the site name and tagline on the front page, and the page title everywhere else:

<title><?= is_front_page()
    ? get_bloginfo( 'name' ) . ' - ' . get_bloginfo( 'description' )
    : trim( wp_title( '', false ) ); ?></title>

The loop

The loop is the block that walks through the posts prepared by the main query:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    ...
<?php endwhile; endif; ?>

Functions available inside the loop:

<?php the_ID(); ?>
<?php the_permalink(); ?>
<?php the_title(); ?>
<?php the_author(); ?>
<?php the_time( 'F jS, Y' ); ?>
<?php the_content(); ?>

Modifying the loop

query_posts() replaces the main query before the loop runs:

query_posts( 'category_name=special_cat&posts_per_page=10' );

if ( have_posts() ) : while ( have_posts() ) : the_post();
    ...
endwhile; endif;

The arguments can also be passed as an array, which is easier to read:

query_posts( [ 'category_name' => $category->slug ] );

The full list of arguments is documented in the open_in_new WP_Query parameters .

Note that query_posts() overwrites the main query, so for any secondary listing on the page create a separate WP_Query object instead.

The template hierarchy

Every page needs a template, and WordPress has a fixed list of file names it looks for. The template hierarchy answers a single question:

What template file will WordPress use when a certain type of page is displayed?

The open_in_new hierarchy diagram shows the whole resolution order.

A typical task

Say we have a page listing the team members, and each member also needs their own page, both with custom templates. There are two ways to solve it.

Option 1 — pages. Create a page with the slug clients and a template for it named page-clients.php. Create an arbitrary custom template, e.g. client.php, and select it when creating a page for each member. The listing page can then output all members if they are made children of the current page.

Option 2 — a custom post type. Register a separate post type (for example client) alongside posts and pages. The listing then lives in archive-client.php and every member gets single-client.php automatically. This is usually the cleaner option.

Checking the current template

is_front_page()
is_home()
code

Need Help with Development?

Happy to help — reach out via the contacts or go straight to my Upwork profile.

work View Upwork Profile arrow_forward
Next Article

WordPress theme structure: required files, style.css header, screenshot

arrow_forward