Posted on

Create a Custom Page Template for your Theme

The WordPress template system is very flexible, but sometimes you need a custom page template for your content. We’ll cover how to create a custom page template file so that the WordPress editor can pick it up. Then we’ll use the new template to implement a WordPress Main Loop.

When you extend a theme by creating a custom child theme, you effectively “inherit” the options and customisation options from the parent theme. This includes the page template files you can use to layout your page content. Most parent themes come with preset template options like:

  • “Full Width”
  • “Fixed Width”
  • “Full Width – Without sidebar”

…that sort of thing.

Select a Page Template in the Editor

For most of your content you’ll be fine, but occasionally you’ll want to do something a bit non-standard. For this mini-project, we’ll make a custom page template called “Brochure“.

Let’s Write some Code

In your custom child theme, create a new file called template-brochure.php and paste the following into it.

<?php
/**
 * Template Name: Brochure
 */

?><p>Our Brochure Template</p>

This is absolute bare-bones. By saving this file in your custom child theme’s folder, you can now edit any of your pages, select “Brochure” as the template, click Publish and then have a look.

If you go to view your page now, all you’ll see is this:

Bare-bones template

To make this new template actually do something useful, we need to add some standard WordPress functions to output things like the HTML header, links to CSS style sheets, the footer, the admin bar and other bits-and-bobs.

Adding some WordPress Structure

To support the standard WordPress headers, menus and footer, we need to make our PHP file look something like this…

<?php
/**
 * Template Name: Brochure
 */

get_header();
?>

<p>Our <strong>Brochure</strong> page template.</p>

<?php
get_footer();

importantNotice how we don’t end of the file with a closing PHP short tag “?>” – this is deliberate. The get_footer() function closes our document with a “</html>” closing tag. By not having a “?>” in our file, we reduce the risk of accidentally adding any extra characters to the document after the closing “</html>” – accidental trailing spaces or new-lines.

Take a look at the page and you should see that “Our Brochure page template.” is now sat nicely in our page’s styling.

We’re making progress, so now let’s look at the actual page content…

The WordPress Loop

The guts of almost every WordPress component is a loop. Whether it’s a page template, a menu, or a widget, a WordPress loop will iterate over a list of content items (posts/pages/products/etc), outputting HTML for each one.

Using the WordPress loop involves applying fairly standard logic…

  1. Create a query parameters array.
  2. Create a WP_Query object, based on your query parameters.
  3. If the query has any posts
    • Output some opening HTML.
    • For each post in the query’s results
      • Grab the next post available in the query’s results.
      • Output some post-specific content…
        • The Title.
        • Permalink.
        • Excerpt.
        • Content.
        • Whatever…
      • Output post footer bits-and-bobs, like comments.
    • Output some closing HTML.
    • Reset the WP loop post metadata.
  4. Else
    • Output a “no posts found” message.

Because we’re dealing with a page template file, WordPress has already set up the main loop for us. So we don’t have to execute steps 1 or 2, and we don’t need to reset the metadata at the end of the loop either.

Let’s update template-fullpage-app.php so it outputs our actual page content.

<?php
/**
 * Template Name: Brochure
 */

get_header();

// Output a breadcrumb trail if Yoast is installed.
if (function_exists('yoast_breadcrumb')) {
	yoast_breadcrumb('<p id="breadcrumbs">', '</p>');
}

// The sidebar will be specific to the parent theme you're using. Have a
// look at your parent theme's page.php to see where to call get_sidebar(),
// if you even want to call it. Maybe you don't want a sidebar?
// get_sidebar();

// The main WordPress loop.
if (have_posts()) {
	// Open any container HTML elements.
	echo '<div class="main brochure">';

	while (have_posts()) {
		// Grab the next post available in the query's results.
		the_post();

		// It's often useful to have access to the ID for this
		// piece of content.
		$post_id = get_the_ID();

		// Output the post-specific content here...
		// the_category(',');
		// the_excerpt();
		// the_meta();
		// ...
		the_title('<h1>', '</h1>');
		the_content();

		// Comment-out this next bit if you never want to see comments
		// with this page type.
		if (comments_open() || get_comments_number()) {
			comments_template();
		}
	}

	echo '</div>'; //.main .brochure
} else {
	printf('<p>%s</p>', __('No posts found', 'mywebsitetheme'));
}

get_footer();

To finish things off, the following bit of CSS can go into your child theme’s style.css file.

/**
 * Brochure
 */

.main.brochure {
	background-color: pink;
	border: 1em solid lightpink;
	padding: 2em;
	border-radius: 0.5em;
	box-shadow: 0.25em 0.25em 1em lightgrey;
}

.main.brochure h1 {
	padding-bottom: 0.5em;
	margin-bottom: 0.5em;
	border-bottom: 0.125em dashed #404040;
}

@media (min-width: 768px) {
	.main.brochure {
		margin: 4em auto 4em auto;
		width: 768px;
	}
}

This should be enough to get you up-and-running with a basic, but extendable, custom page template. It’s not going to win any design awards though 😐

Our custom page template for WordPress

So, instead of hacking around with PHP files in your child theme’s parent theme, you can just make a new template that’s specific to your requirements. It’s clean and portable code you can use in any of your WordPress projects.

We’ll do more interesting things with the WordPress loop in another tutorial, and remember that the main loop (like in a page) is slightly different than a WordPress loop used anywhere else (like for showing a list of posts in a custom widget).

Happy templating! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *