Skip to main content
Easily create better & faster websites with the Total WordPress Theme Learn More
(opens a new tab)
Tutorials

Add Page Templates to WordPress with a Plugin

Update: The code has been updated recently to work on WordPress 4.7+

Have you ever wanted to create your own page templates, but not had access to the theme itself? I, as a WordPress plugin author, have found this problem to be particularly annoying when developing my plugins. Thankfully the solution is quite simple! I’m going to take you quickly through the few lines of code which you will need to dynamically create WordPress Page Templates directly through PHP.

Inspiration for this article and the genius behind the code solution comes from Tom McFarlin: I am using my edited version of his original code, which you can find on his GitHub. I have kept his commenting in (as well as adding some of my own) as I find it very helpful in explaining what is going on – I couldn’t have said it any better myself!

You can find the code in its entirety and an example plugin at the very bottom of this post.

Shall we begin?

The Code

We will create our PHP function using a PHP Class. For those of you who aren’t well versed with PHP Classes, a Class is defined as an object which contains a collection of functions and variables which are working together. Check out the PHP.net Introduction for more details about the syntax and theory.

Our wrapper will only need 3 variables:

  1. The Plugin Slug: This is simply used as a unique identifier for the plugin.
  2. Class Instance: As we are adding an instance of this class to WordPress’ head, we’d better store it.
  3. Template Array: As you can probably guess, this is an array holding the template names and titles.

Here they are in code:

class PageTemplater {

		/**
         * A Unique Identifier
         */
		 protected $plugin_slug;

        /**
         * A reference to an instance of this class.
         */
        private static $instance;

        /**
         * The array of templates that this plugin tracks.
         */
        protected $templates;

Get Class Instance

As I said previously, we’ll be adding an instance of our class to the WordPress header using the add_filter() function. Therefore we will need a method which will return (or create) this instance for us.

For this, we will need a simple method, which will be called ‘get_instance’. Check it out below;

/**
 * Returns an instance of this class. 
 */
public static function get_instance() {

	if( null == self::$instance ) {
		self::$instance = new PageTemplater();
	} 

	return self::$instance;

}

This will be the method called when our class is added to the WordPress head using ‘add_action()’.

WordPress Filters

Now we’ve sorted out the ‘get_instance’ method, we need to sort out what happens when it is actually instantiated.

We will use WordPress’s inbuilt add_filter() function to add an instance of our class into key points along the WordPress initialisation timeline. Using this method we will insert our page templates’ data into relevant slots, such as telling WordPress what file to use as a template when the page is called, and the title to display on the dropdown menu on the Page Editor.

For this we need to use the ‘__construct’ method (this will be run when the class is instantiated).

/**
 * Initializes the plugin by setting filters and administration functions.
 */
private function __construct() {

	$this->templates = array();

	// Add a filter to the attributes metabox to inject template into the cache.
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {

		// 4.6 and older
		add_filter(
			'page_attributes_dropdown_pages_args',
			array( $this, 'register_project_templates' )
		);

	} else {

		// Add a filter to the wp 4.7 version attributes metabox
		add_filter(
			'theme_page_templates', array( $this, 'add_new_template' )
		);

	}

	// Add a filter to the save post to inject out template into the page cache
	add_filter(
		'wp_insert_post_data', 
		array( $this, 'register_project_templates' ) 
	);

	// Add a filter to the template include to determine if the page has our 
	// template assigned and return it's path
	add_filter(
		'template_include', 
		array( $this, 'view_project_template') 
	);

	// Add your templates to this array.
	$this->templates = array(
		'goodtobebad-template.php' => 'It\'s Good to Be Bad',
	);

}

There are 4 different things going on here (ignoring ‘ $this->templates = array();’, which is just preparing the variable for use);

  1. Lines 9 – 13: This filter is adding the ‘register_project_templates’ to the ‘page_attributes_dropdown_pages_args’ hook. This is populating the WordPress cache with our new templates, ‘tricking’ WordPress into believing that the page template files actually exist in the template directory. This adds the page templates to the dropdown list on the page attributes meta box in the page editor.
  2. Lines 16 – 20: Here we are doing essentially the same as the previous code block, except this time we are adding our page template (if selected) to the saved post data as well.
  3. Lines 23 – 28: This filter is adding the ‘template_include’ to the ‘view_project_template’ hook. This is a very important function; this tells WordPress where your page template file actually is. WordPress will use the path provided by this to render the final page.
  4. Lines 31 – 34: Although this is simple, it is very important. This is where you specify the page templates you want to be added, and the path relative to the file where the page template file is ( eg. ‘something.php’ ). I’ve included one example (which will be used in the example plugin). Check out below for a general example:
$this->templates = array(
	'FILE_PATH_AND_NAME'               => 'TEMPLATE_TITLE',
	'awesome-template.php'             => 'Awesome',
	'templates/organised-template.php' => 'Organised',
);

(Eat, Sleep,) Code, Repeat as necessary.

register_project_templates()

I’ve alluded to this method previously; let’s see what it actually does.

Essentially, the purpose of this method is to manipulate WordPress’s cache, inserting the relevant data about our page templates at the right places. Have a look at the code first, and I’ll talk you through it afterwards.

public function register_project_templates( $atts ) {

	// Create the key used for the themes cache
	$cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );

	// Retrieve the cache list. 
	// If it doesn't exist, or it's empty prepare an array
	$templates = wp_get_theme()->get_page_templates();
	if ( empty( $templates ) ) {
		$templates = array();
	} 

	// New cache, therefore remove the old one
	wp_cache_delete( $cache_key , 'themes');

	// Now add our template to the list of templates by merging our templates
	// with the existing templates array from the cache.
	$templates = array_merge( $templates, $this->templates );

	// Add the modified cache to allow WordPress to pick it up for listing
	// available templates
	wp_cache_add( $cache_key, $templates, 'themes', 1800 );

	return $atts;

}

Right then. Line 4 is the first place to look. As you may have guessed, we are generating a ‘cache key’. This will be used as a unique identifier for our page template data. Using the md5() function simply creates a unique string identifier to avoid any conflicts.

Next, on line 8, we are searching for and retrieving the page template cache (if it exists already): this will return an array of paths and titles. On lines 9-11 we check to see if there was any output from the cache query. If yes, great. If not, create a local array to hold the data we will be merging into the cache.

The next step is crucial. On line 14 we delete the existing page template cache. Don’t worry, no data is lost – it is stored in the $templates variable.

On line 18 we merge the existing page templates cache with our new entries, and on line 22 we re-insert the whole page template cache into WordPress’s system.

Simple!

view_project_template ()

We’re now onto our final method; this is where we tell WordPress where the real page template file is.

/**
 * Checks if the template is assigned to the page
 */
public function view_project_template( $template ) {
	
	// Get global post
	global $post;

	// Return template if post is empty
	if ( ! $post ) {
		return $template;
	}

	// Return default template if we don't have a custom one defined
	if ( !isset( $this->templates[get_post_meta( 
		$post->ID, '_wp_page_template', true 
	)] ) ) {
		return $template;
	} 

	$file = plugin_dir_path(__FILE__). get_post_meta( 
		$post->ID, '_wp_page_template', true
	);

	// Just to be safe, we check if the file exist first
	if ( file_exists( $file ) ) {
		return $file;
	} else {
		echo $file;
	}

	// Return template
	return $template;

}

Ok then, this method will be checking against the global $post variable (line 6). It checks to see if a page template ( ‘_wp_page_template’ ) has been set for the post (meaning it must be a page). If not, then never mind – non-pages can’t have page templates.

Line 16 specifies the location of the page template file. As I have set out above, it checks for the specified page template file in the root directory of your plugin. (This can be easily changed though; see below.)

// Just changing the page template path
// WordPress will now look for page templates in the subfolder 'templates',
// instead of the root
$file = plugin_dir_path(__FILE__). 'templates/' .get_post_meta( 
	$post->ID, '_wp_page_template', true 
);

After this, on lines 21 – 24, we have just a little bit of validation which checks if the file actually exists. If yes, awesome! If not, oh dear… You will most likely get a PHP error message if WordPress can’t find the template file, or even a blank screen. If any of these symptoms sounds familiar, just check the template file path by printing the $file variable to the screen.

If you plan to use this code commercially (which you are free to do – my version of the code comes with no license, hence you are free to do with it as you please), I truly recommend investing some time in error handling for maximum reliability.

That is that. With our class completed, there is only one thing left to do – add it to the WordPress head.

add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );

Congrats if you made it all the way through! I hope you found what I had to say useful, and you benefit from it in the future!

Entire Code

Bellow is the entire code for the plugin for easy copy and paste.

<?php
/*
Plugin Name: Page Template Plugin : 'Good To Be Bad'
Plugin URI: http://www.wpexplorer.com/wordpress-page-templates-plugin/
Version: 1.1.0
Author: WPExplorer
Author URI: http://www.wpexplorer.com/
*/

class PageTemplater {

	/**
	 * A reference to an instance of this class.
	 */
	private static $instance;

	/**
	 * The array of templates that this plugin tracks.
	 */
	protected $templates;

	/**
	 * Returns an instance of this class. 
	 */
	public static function get_instance() {

		if ( null == self::$instance ) {
			self::$instance = new PageTemplater();
		} 

		return self::$instance;

	} 

	/**
	 * Initializes the plugin by setting filters and administration functions.
	 */
	private function __construct() {

		$this->templates = array();


		// Add a filter to the attributes metabox to inject template into the cache.
		if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {

			// 4.6 and older
			add_filter(
				'page_attributes_dropdown_pages_args',
				array( $this, 'register_project_templates' )
			);

		} else {

			// Add a filter to the wp 4.7 version attributes metabox
			add_filter(
				'theme_page_templates', array( $this, 'add_new_template' )
			);

		}

		// Add a filter to the save post to inject out template into the page cache
		add_filter(
			'wp_insert_post_data', 
			array( $this, 'register_project_templates' ) 
		);


		// Add a filter to the template include to determine if the page has our 
		// template assigned and return it's path
		add_filter(
			'template_include', 
			array( $this, 'view_project_template') 
		);


		// Add your templates to this array.
		$this->templates = array(
			'goodtobebad-template.php' => 'It\'s Good to Be Bad',
		);
			
	} 

	/**
	 * Adds our template to the page dropdown for v4.7+
	 *
	 */
	public function add_new_template( $posts_templates ) {
		$posts_templates = array_merge( $posts_templates, $this->templates );
		return $posts_templates;
	}

	/**
	 * Adds our template to the pages cache in order to trick WordPress
	 * into thinking the template file exists where it doens't really exist.
	 */
	public function register_project_templates( $atts ) {

		// Create the key used for the themes cache
		$cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );

		// Retrieve the cache list. 
		// If it doesn't exist, or it's empty prepare an array
		$templates = wp_get_theme()->get_page_templates();
		if ( empty( $templates ) ) {
			$templates = array();
		} 

		// New cache, therefore remove the old one
		wp_cache_delete( $cache_key , 'themes');

		// Now add our template to the list of templates by merging our templates
		// with the existing templates array from the cache.
		$templates = array_merge( $templates, $this->templates );

		// Add the modified cache to allow WordPress to pick it up for listing
		// available templates
		wp_cache_add( $cache_key, $templates, 'themes', 1800 );

		return $atts;

	} 

	/**
	 * Checks if the template is assigned to the page
	 */
	public function view_project_template( $template ) {
		
		// Get global post
		global $post;

		// Return template if post is empty
		if ( ! $post ) {
			return $template;
		}

		// Return default template if we don't have a custom one defined
		if ( ! isset( $this->templates[get_post_meta( 
			$post->ID, '_wp_page_template', true 
		)] ) ) {
			return $template;
		} 

		$file = plugin_dir_path( __FILE__ ). get_post_meta( 
			$post->ID, '_wp_page_template', true
		);

		// Just to be safe, we check if the file exist first
		if ( file_exists( $file ) ) {
			return $file;
		} else {
			echo $file;
		}

		// Return template
		return $template;

	}

} 
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );

The Plugin

You can also download the full code as a plugin on Github.

Post Editor Closeup

Here’s a close up of the plugin in action. See the page template added under Page Attributes?

GTBB1

139 Comments
  1. AJ Clarke · 11 years ago

    I actually didn’t know how to do this and it’s going to come in handy for a new plugin I’m developing 😉 Thanks for being a contributor with us and sharing your knowledge 😉

    • Harri Bell-Thomas · 11 years ago

      Thanks AJ! Its great to be a part of such a great blog!

  2. Trisha Cupra · 11 years ago

    Nice! I’ve been wondering how to create a Page Template via a plugin. Saving this straight to Evernote for future reference.

    • Harri Bell-Thomas · 11 years ago

      I’m glad you’ve found this useful!

  3. bucurosul · 11 years ago

    Very nice code, simple end good…ten plus.

    • Harri Bell-Thomas · 11 years ago

      Thanks for the kind feedback 🙂

  4. Mark · 11 years ago

    Thanks – it helped me greatly.

  5. Karl · 11 years ago

    Do you have any updates for the registration of the page templates in the dropdown? I noticed that it deletes the list of templates provided by the theme, and only lists my custom plugin templates.

    • Harri Bell-Thomas · 11 years ago

      Hey there Karl,

      I’m sorry you are having this problem. I can see where this error is probably coming from, so I’ll have a look and try and find out what’s going awry!

      I’ll update the article and leave another reply here when I have more news and hopefully a solution.

      Thanks, Harri

      • Harri Bell-Thomas · 11 years ago

        I think I’ve figured it out – the problem lay in retrieving the pre-existing page template cache. I will update the post now, but if you would like to apply the fix manually, simply change;

        $templates = wp_cache_get( $cache_key, ‘themes’ ); (Line 92 in pagetemplater.php of the plugin) to

        $templates = wp_get_theme()->get_page_templates(); (This is probably a nicer solution in retrospect)

        I hope this fixes the problem 🙂

        P.S. Pretty proud of the 20 minute response time 😉

        • Karl · 11 years ago

          Thanks that worked great!

          • Harri Bell-Thomas · 11 years ago

            Glad to hear 🙂

  6. Yash · 11 years ago

    Very nice article, working for me !!!. I need to know how can i use this code to my plugin. I used this code to my plugin and then my SMS feature functionality is break. when i comment this file code the SMS feature is again working fine. Please tell me how to properly use this code to plugin.

    Thanks and regards,

    Yash

    • AJ Clarke · 11 years ago

      Sorry for the delay on this. We’ve updated the code if you want to check it out!

  7. Mohamed Hamad · 11 years ago

    I recently used this plugin/code in one of my own plugins and it worked fantastically. But now i’m noticing that the template added via this code is the only template available to choose from. Is there something to be updated to make this more current?

  8. Mohamed Hamad · 11 years ago

    never mind. i saw the solution posted. works great now

  9. Spence · 11 years ago

    This seems like a great idea and exactly what I need! I have downloaded the code, added my custom templates to: $this->templates = array(
    I have added ‘templates/’ to: $file = plugin_dir_path(__FILE__). ‘templates/’
    I can activate the plugin in my wp-admin but, it is not showing any of the templates in the page editor template drop-down. I have read and reread this article a and all I can find that Tom McFarlin has posted about this method and I still have the same problem.

    Does anyone have any ideas of what I might be doing wrong or know how I could figure it out?

    • Harri Bell-Thomas · 11 years ago

      Hello Spence,

      Sorry for the delay in replying. Could we possibly discuss this over on Github, as it’s easier to talk through code there.

      Thanks!
      Harri

      • Spence · 11 years ago

        Hello Harri,

        Thank you for the reply. I figured it out. Details are on the WordPress forms here.

        This method works really great! Thanks for all this helpful info.

        I did run into one bug that doesn’t stop it from working. It is something that would just be nice to figure out. I detail the minor problem in the WP post but I will explain it again here for anyone else following this.

        Using your great explanation and code above, the new templates that I have created show up nicely in the template drop-down in page editors. However, they do not show up in the list of pages under “Quick Edit” template drop-down options. It would be nice to have them show up in the “Quick Edit” options too, for connivance.

        I would be happy to continue this conversation on Github.

        • Spence · 11 years ago

          Hello again Harri,

          I got this bug worked out, that was not showing page templates in the “Quick Edit” options of the pages list. It was resolved here if you are interested.

          Thanks for posting this helpful info about this plugin method for page templates, it has been a big help.

          • AJ Clarke · 11 years ago

            Great, thanks for sharing Spence!

          • Harri Bell-Thomas · 11 years ago

            Thanks Spence – that is actually a really nice solution!

          • LittleBigThings · 9 years ago

            Another solution (to using the ‘wp_dropdown_pages’ filter as explained in the above link) is to hook the method ‘register_project_templates’ additionally to the filter ‘quick_edit_dropdown_pages_args’. This makes the templates appear in the Quick Edit dropdown menu, too. Just an alternative.

  10. Ruhul Amin · 11 years ago

    Thanks boss. It works great

  11. Mushtaq Ali · 11 years ago

    Great post. I am able to add template in the drop down however Template code does not works. Somehow wordpress can’t find this new templstr created by the plugin. Any help? Thanks

    • Harri Bell-Thomas · 11 years ago

      Hello Mushtaq,

      This is probably a problem with the path to the template file. Have you edited this line in your code?

      $file = plugin_dir_path(__FILE__). get_post_meta( $post->ID, ‘_wp_page_template’, true );

      If not, are you sure you have the template file in the root folder of your plugin. If yes, just double check that your new location matches where you keep the files.

      If none of the above works, then could you pop over to Github, as it’s easier for us to talk code there.

      Thanks!
      Harri

      • Mushtaq Ali · 11 years ago

        Hi, Thanks for the reply, I had changed the line as below :
        $file = plugin_dir_path( __FILE__ ) . ‘templates/’ . get_post_meta( $post->ID, ‘_wp_page_template’, true );

        Also I have kept the template file under myplugin/templates/mytemplate.php and pageTemplater.php in includes directory. The structure is as follows:

        myplugindir/myplugin.php
        myplugindir/includes/pageTemplater.php
        myplugindir/templates/template.php

        P.S: I am new to github, I really don’t know how to create comment/ issue. Thanks

        • Harri Bell-Thomas · 11 years ago

          That seems to be ok – what have you put for this;

          $this->templates = array(
          . . .
          );
          (Line 72) ?
          Harri

          • Mushtaq Ali · 11 years ago
            $this->templates = array(
            'mytemplate.php' => 'New Template',
            );
            
            • Harri Bell-Thomas · 11 years ago

              That is odd…
              Does mytemplate.php contain a valid Page Template declaration header?
              e.g;

              /*
               * Template Name: My Custom Page
               * Description: A Page Template with a darker design.
               */
              

              Harri

  12. Aamer Hussain Khan · 11 years ago

    This worked out perfectly for me. Thank you for the code! 🙂

  13. Craig Ralston · 11 years ago

    Awesome guide – I am having one issue and I can’t seem to narrow down where it is coming from. My template is being found and is working properly but above my header it is spitting out the file path to the template file. Any ideas what could be causing this? I have also read through all of the comments and made appropriate changes where needed and double checked issues others were having. Everything seems like it should be working properly, just not sure why the file path is being echo’d in the header.

    Thanks!

    • Sharon Murphy · 3 years ago

      Hi there! I’m wondering what your solution was, as I’m experiencing the same error (file path showing instead). Thanks 😊

    • Sharon Murphy · 3 years ago

      Never mind 😊 I figured it out. Anyone else, make sure you’re calling the right path FROM the right path.

      I had plugins_loaded.php inside a directory, and it was trying to call the template from inside the same directory. Solution:

      $file = plugin_dir_path(__FILE__) . ‘../templates/’ . get_post_meta( $post->ID, ‘_wp_page_template’, true );

      (see the 2 dots and slash in front of the file name). I hope that helps someone.

  14. Craig Ralston · 11 years ago

    Nevermind, found what I was doing wrong. Thanks!

    • AJ Clarke · 11 years ago

      Great, glad you got it working!

  15. Jeroen · 10 years ago

    Working like a charm. Nothing more to add !!! 🙂

  16. Vishal · 10 years ago

    Hello Harri,
    I want to create page template for frontend & this seems to be for admin section. Can you help me to tell how can i solve my requirement? Any suggestions.
    Thanks,
    Vishal

    • AJ Clarke · 10 years ago

      Hi Vishal,

      It’s the same thing. Have a look at the CODEX for creating the page template file.

  17. cyrusville · 10 years ago

    Thanks for the great tutorial. Is it possible to register a custom header template using the same approach? This should not appear on the drop down.

  18. opportunex · 10 years ago

    Awesome solution! Thanks. This is really going to be a big time saver 🙂 You Rock!

  19. Jim Douglas Mazabuel · 10 years ago

    Muchas muchas gracias! Una y otra vez lo digo, gracias por toda tu ayuda!

  20. Dario · 10 years ago

    Absolutely a great tutorial! Many thanks for it!

  21. Pixselig · 10 years ago

    First: thamk you verry much for your outstanding solution, Harri! It works perfect for me!

    But I have a little question:

    I am writting a PlugIn, this PlugIn injects different Page-Templates into a existing Theme. For this, I use your awesome code. It works perfect.
    But, i also want to enqueue a Script only on Pages who uses the injected Page-Templates.
    For this I use the WP-Function “is_page_template()” http://codex.wordpress.org/Function_Reference/is_page_template
    But it doesnt work, whatever data path I try.

    For better understanding whats going on, I output two diferent Parameters (WP-Functions) inside the Template.
    For the first “get_page_template_slug( $post->ID );”, I get the right name of the injected Page-Template back.
    But for the second “get_page_template(__FILE__);” I get the absolute path to the default Template inside the used Theme (page.php) back.

    So, I am a litte bit confused, dont know how to enqueue Scripts only on the injected Pagetemplates.

    Hope, you understand my bad english -> sorry for that!
    But if you have a question, i will answer!!
    If you need some Code-Snippets from me, i will post!!

    Thamks,
    Pixselig

  22. Pixselig · 10 years ago

    Sorry, for second post!
    I only want to say, that I got it to work!

    My brain was fried – the answer is very easy:
    “is_page_template()” can only be called afte the template has been loaded. So I had to add some wp-action:

    function check_for_template() {
       if ( is_page_template ( "xxx.php" ) {
          function add_template_scripts() {
             wp_register_script( 'template_script', ................ );
             wp_enqueue_script( 'template_script' );
          }
          add_action( 'wp_enqueue_scripts', 'add_template_scripts' );
       }
    }
    add_action('wp','check_for_template');

    This solution had nothing to do with the great code from Harri – its the common way to check for templates in WP-functions.

    Thanks twice Harri!
    Pixselig

    • AJ Clarke · 10 years ago

      Nice! Thanks for sharing.

    • Harri Bell-Thomas · 10 years ago

      Thanks for the solution, Pixselig!

  23. Robby · 10 years ago

    Any pointers on how to get this to work with a custom post? I’m creating the custom post via a plugin, and would like to include the archive and post template in the plugin.

    Thanks!

    • Anything Graphic · 8 years ago

      Plus one on the CPT and archive page template…

    • Anything Graphic · 8 years ago

      @Robby, what I ended up doing was making a normal page and using the Custom Archive Template page I made. Then I made set has_archive => false.

    • Leon · 8 years ago

      +1, would really like to know how to make this work with Custom Post Types and plugin-included templates

    • Plamen Kostadinov · 6 years ago

      You simply need to duplicate the line with the filter ‘theme_page_templates’ and update it with the custom post type slug, so for posts it would be ‘theme_post_templates’.

      • Andre Esteves Perrone · 3 years ago

        Awesome, thanks for the tip Plamen!

  24. Alexis Duran (@duranmla) · 10 years ago

    Thanks! It works perfectly for me. Nice help. @Robby I’m doing the same thing I would suggest you to include the class like:

    include_once('path/to/page-templater.php');

    into your main plugin file and it is all since:

    add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) ); // once the plugin is activated the class make its magic!!

    Regards!

  25. grn7 · 10 years ago

    Hi everyone,

    Thanks for this tutorial and comments.

    I’m new to wordpress plugins and not sure where exactly the add_action line should be placed. I’ve been placing it in a child theme header.php like this just before the wp_head…

    Can someone tell me if this is correct?

    • AJ Clarke · 10 years ago

      If you want to use the add_action function to add something to the head, you would create the function in functions.php and “hook” that function see the examples at the bottom of the CODEX. All that would be added in functions.php

      • grn7 · 10 years ago

        Thanks for this! Delighted it’s now working.

  26. Jürgen Schulze · 10 years ago

    Thank you.
    That was JUST what I needed.
    I am not a big fan of child themes and prefer to handle everything inside my own plugin

    • Harri Bell-Thomas · 10 years ago

      You’re welcome, Jürgen! That was exactly my thinking as well. Glad you found this useful 🙂
      Harri

  27. Tom · 10 years ago

    Hi, Thank you for the code.
    I’m using Genesis Framework and you allways have to use a child theme with Genesis as parent.

    The original code from Tom McFarlin seems to block the templates placed in the child, your code not – so it is perfect!

    • Harri Bell-Thomas · 10 years ago

      Thanks for the feedback, Tom! Really glad it’s working for you 🙂
      Harri

  28. Tapan Kumer Das · 10 years ago

    Hi, Thanks for sharing the code, I was searching for such a thing.

    • Harri Bell-Thomas · 10 years ago

      Glad I could help!

  29. gordielachance · 10 years ago

    You can also scan a directory for templates (so you don’t need to fill the $templates_array var) with this

    • Harri Bell-Thomas · 10 years ago

      Thanks for the tip! I’ll look at adding this into the class when I next get the chance 🙂
      Harri

  30. euprop · 10 years ago

    Hello, Thank you for the code. I’m not sure yet if this suits my needs and sorry if this post is unappropriate. I’m trying to get the code inside the file goodtobebad-template.php to appear in the page with the default template of my website. But when I sellect the custom template “It’s good to be bad” I only get the code in there and not the rest of the template. I’m I missing something or this plugin is not suitable to inject code into de page content within the the active template?

    Thank you.

    • Harri Bell-Thomas · 10 years ago

      Hello europop,

      You can get your theme’s header, footer and sidebar by calling the get_header(), get_footer() and get_sidebar() functions, allowing you to keep your theme’s general styling while still being able to customise the inner page content. Therefore I do think this is what you’re looking for for the problem you describe.

      For more information about what you can do with page templates, I’d recommend taking a look at the examples on the Codex.

      Let me know if you have any other questions either here or on Twitter (@harribellthomas),
      Harri

  31. Jared Kail · 10 years ago

    Thanks – exactly what I was looking for. Helped a ton.

    • Harri Bell-Thomas · 10 years ago

      Glad I could help!

  32. Joshua Mark · 10 years ago

    @Harri Bell-Thomas Thanks so much for this, it worked right out of the box. I used this to tie the PayPal API to wordpress actions. I may eventually build it out to generally do “charge for X” where X is publishing a post, submitting a gravity form, etc.

    Am I right in thinking that a page template is the best way to tie API’s to the WordPress framework? I’m used to MVC frameworks, so that seems like a janky hack. A page that isn’t meant to be accessed directly doesn’t feel very good.

    • Harri Bell-Thomas · 10 years ago

      Hi Joshua,

      It’s an interesting point you make, about it being a ‘hack’. I do agree with you somewhat, but the WordPress experience is built upon templates such as these, so it will be greatly different to MVC frameworks. I can assure you that using page templates is normal in WordPress development, specifically for themes.

      The implementation I talk about in this article can definitely be seen as a hack, as it hooks in to and amends the WordPress cache; it is done in the most semantically valid way though (and please do correct me if this isn’t the case 😉 ).

      If you want to discuss this further (I do find this argument extremely fascinating having triend my hand at Ruby-on-Rails) please feel free tweet me @harribellthomas to discuss this further.

      Thanks!
      Harri

  33. rahendz · 10 years ago

    This Article is Outstanding and worked as well, thanks clarke for this. But i wanna simple ask, since i using your code, my shortcode doesn’t work while using those page template from my developed plugins. Did you know why, or it’s just my mistakes? Anyone here has the same issue? thank before and sorry for my bad english.

    • Harri Bell-Thomas · 10 years ago

      Hi rahendz,

      I’d recommend looking at the do_shortcode() function. This can be used to execute shortcodes that aren’t currently being executed in your page.

      Hope this helps,
      Harri

  34. Nimesh Jain · 10 years ago

    Thank you so much. That was super easy.

    • Harri Bell-Thomas · 10 years ago

      Glad I could help you out!

  35. Kezz · 9 years ago

    This is something I’ve tried to do multiple times for soooo long. You’ve just solved the final piece of the puzzle on a major project for me. Thank you!!

  36. Lythande · 9 years ago

    Thank you !!!!!!

  37. Britta Weller · 9 years ago

    Thank you soooooooooo!!!

  38. Лого Дизайн · 9 years ago

    Thanks guys! just looking for that kind of plugin.

  39. reddo · 9 years ago

    Hey,

    Great plugin, helped me a lot, but I ran into a problem and I was wondering if there’s a workaround.

    The site I installed this plugin on uses W3Total cache and each time I update the page the template gets overriden by the default template.

    You have to save as draft again and publish it. This is the only way it’ll work.

    I’ve tried adding the page slug to w3tc’s page cache/advanced/”Never cache the following pages” but it didn’t work.

    Any suggestions?

    • AJ Clarke · 8 years ago

      Do you have the same issue when w3 is not enabled?

  40. iceberg11 · 9 years ago

    If you have multiple theme directories your get_theme_root() might not be correct so better to use this. Specially bedrock has this problem.

    ‘page_templates-‘ . md5( get_raw_theme_root( get_stylesheet() ) . ‘/’ . get_stylesheet() );

    • AJ Clarke · 9 years ago

      Thanks for the tip!

  41. Văn Nguyễn · 9 years ago

    Thanks! Nice Work!

  42. Rana Touqeer · 9 years ago

    Awesome work, thanks for uploading such a nice tutorial, it helped a lot..

  43. Dirk Argyle · 9 years ago

    Hey, I’ve got this problem with wordpress. I created a custom template independent to the my current theme. The problem is that I want plugins to work with it. So I use wp_head() in the head but it override my custom CSS files and break my custom template design. Can you point me to the right direction?

    • AJ Clarke · 9 years ago

      You have to use wp_head() if it’s causing issues with your template design, you probably have to tweak your CSS so it overrides correctly or use wp_dequeue_style to remove any css files you don’t want loaded for this page.

  44. Jason Jersey · 9 years ago

    Great solution. Only issue I see is if you are using a Custom Page Post Type (ie: post-new.php?post_type=landing ), the templates show when you create a page in the dropdown, but when you go back in and edit the page the templates dont show in the dropdown. Any idea’s?

  45. Belmar Santanilla Gutiérrez · 9 years ago

    Thanks, Great solution, actually I use this in my devs. But I have a question, the page template created don’t showing in the Advanced Custom Fields location by Page Template, any idea how fix that?

  46. Aj · 9 years ago

    Hi, great plugin. It’s just what I need. I see the template in the dropdown but when I select it for a page and save, it resets to the Default Template (or what was previously selected). If I copy the template to the themes folder, it works fine. Any suggestions?

  47. Robin Ferrari · 8 years ago

    Work fine for me but now i can’t select the template page with ACF.

    I try to add a rule location for a field groupe and the template page doesn’t appear.

    Any idea’s

  48. mai · 8 years ago

    Hi sir
    please if i used this i have to keep the plugin on my site?
    what if wordpress got updated will i need to come back here and update the plugin?
    i hope my question is clear, am new to deeper wordpress and learning everyday
    thanks a lot

    • AJ Clarke · 8 years ago

      Unless WordPress changes the way templates work you won’t have to update anything. If you created a plugin you should be able to update without issues. If you do run into any issues let me know so I can look and then update our code accordingly.

  49. Kakoma · 8 years ago

    Thanks for this. Very well explained

  50. little dream · 8 years ago

    not possible to add an issue to the github repo
    You should check if post exist in view_project_template

    • AJ Clarke · 8 years ago

      Good call, I will update the code on the post.

  51. Chris · 8 years ago

    Huge thanks for this AJ. The class works beautifully

  52. dxladner · 8 years ago

    Harri,

    I have just started to do some research as I am using two custom templates in a plugin and was wondering if this code works will work for the new WordPress 4.7. I just downloaded the WP 4.7 RC and I cannot get my templates to show up when creating a new page? Any help would be greatly appreciated.

    Thanks in advanced

    • AJ Clarke · 8 years ago

      Hey, if you check out the github repository it has been updated already to support WP 4.7

      • Britta · 8 years ago

        Thank you so much for this quick fix! Used this code for a while now and didn’t understand why it wouldn’t work on my new project.

      • Jon Schroeder · 8 years ago

        Thanks so much for posting the update; saved me on a project of my own that was affected by the change (where I need to register a page template in a plugin) at https://github.com/redblueconcepts/redblue-sections

        • AJ Clarke · 8 years ago

          Awesome!

      • Paul · 8 years ago

        What were the changes? I have a plugin using this on two sites, and I’d like to quickly update the code.

        • AJ Clarke · 8 years ago

          Hi Paul,

          If you go to the Github repository you can click on “History” to see all the changes that have been made to the code over time. You can also subscribe to be notified of any changes to the repository if you want.

  53. marcgott · 8 years ago

    4.7 upgrade broke it. I nearly flipped.. Then I upgraded from the git repo. Thanks for being on top of it and letting me keep my sanity.

  54. Robin · 8 years ago

    Super helpful tutorial and example code. Does exactly what I need for a client project. Thank you!

  55. Steven Britton · 8 years ago

    This plugin does not work: Copied and pasted code verbatim. No template dropdown appears, and when I force it to appear by adding a new page template to the theme folder (Twenty Seventeen) the template name(s) in this plugin do not appear in the list.

    • AJ Clarke · 8 years ago

      The code has been updated recently to fix issues with the latest version of WordPress (4.7) everything should be working now with the updated code.

  56. adriano · 8 years ago

    Stop running on wordpress version 4.7, could you help us?

    • AJ Clarke · 8 years ago

      We’ve updated the code to fix any issues with 4.7. In the future you may want to “subscribe” to the Github repository because we do push out updates there from time to time and you can also report any issues there and or pull-requests.

  57. Rob · 8 years ago

    I think this broke with wp 4.7, the templates still work but no longer show in the select list.

    • AJ Clarke · 8 years ago

      Please check out the updated code on Github. I will update the article right now as well 😉

      • JanaLEE · 8 years ago

        Amazing work! This helps me a lot! Thank you!

  58. Brian · 8 years ago

    Super neato…. if anyone is doing this for a custom post type follow Alexis Duran’s comment for the require once in main in your custom post type plugin file worked perfectly for my portfolio custom post type

  59. Chris · 8 years ago

    Much thanks for updating the code for WP 4.7+ compatibility. I was having some trouble with it, but hadn’t gotten around to working on it.

  60. Rodrigo Barreiros Muniz · 8 years ago

    Great post! Keep up the good work and congratulations!

  61. flipmortel · 8 years ago

    hi in my case that have remove the drop down menu of page template in my dashboard pages section

  62. Kevin Donnigan · 8 years ago

    Thank you for keeping this updated! I really appreciate it 🙂

    It stopped working with a new release of WP. I came back here and sure enough it works with the updated code you provided.

  63. aishahenderson · 8 years ago

    Thank you for updating for WP 4.7.x!

  64. zecka1213 · 8 years ago

    Thank’s a lot for the update !!!!

  65. rhinorck · 7 years ago

    This is exactly what I was looking for! Thank you very very much!!!

  66. Ragoub · 7 years ago

    Thank you so much, this code help Me ^^

  67. shebinleovincent · 7 years ago

    Thank you. This was extremely helpful.

  68. Indrek · 7 years ago

    I adapted this code with slight modifications as a composer package. Hope it helps someone. https://github.com/codelight-eu/wp-page-templates

    • Kyla · 7 years ago

      Cool! Thanks for sharing 😉

  69. Hardeep Asrani · 7 years ago

    This is exactly what I was looking for. Thanks for the great help, keep it up. 🙂

  70. sean · 6 years ago

    Excellent plugin thanks. I have a question is it possible to add some content to it like html and PHP and so on so that the page can follow the theme’s structure? Would appreciate the help!

  71. Radley Sustaire · 6 years ago

    Why wrap it in an object? It’s way easier to incorporate code into an existing plugin if it’s just plain functions. You can still throw it in your own object if you want.

    If anyone is interested, I re-wrote it this in about half the amount of code without objects, designed for just one template (but easy to add more):

    https://gist.github.com/RadGH/025b6c80187be200e05e6e89ad6fadfd

  72. Sybille · 6 years ago

    The update for 4.7 saved my life. Thanks a lot!

  73. Rob McClara · 5 years ago

    THANK YOU very much for this! Works like a charm. I have recently ventured into building plugins. The only thing I have not been able to figure out is how to include page templates in my plugins. Thanks, again.

  74. Kalahiri · 5 years ago

    Thanks! Exactly what I was looking for and it works like a charm on my WP 5.3.1. installation.

  75. Juan Molina · 5 years ago

    A ton of thanks to you. It works perfectly on WP 5.4 multisite

  76. Mateus Neves · 4 years ago

    Thanks ! This post helped me a lot. 🙂

  77. Samuel Asor · 4 years ago

    Wow, its 2020 and this code still works!

    Thanks Harri.

  78. khazra · 4 years ago

    Thank you Harri, this post was really useful for me

  79. Nathan Hoover · 3 years ago

    I’m kinda new to WordPress, Templates, Plugins, but I managed to get this to work. Thanks for the excellent code. One of the post that was really helpful, (and put on my light bulb), was the post regarding:

    $this->templates = array(
    . . .
    );

  80. Daniel · 3 years ago

    This is a great post. Saved me from adding post types for just lots of css/js for a plugin. Kudos and thanks!

  81. David · 9 months ago

    Great article Harri!
    I’ve been pounding this issue for days with no clear solution in the view until I found your article.
    You saved the day!!!
    Thanks,

Leave a Reply

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

Learn how your comment data is processed by viewing our privacy policy here.