13

I want to add page templates to a theme directly from the plugin. The idea is that the template would show up in the dropdown under Page Attributes, and all the code would need to be in the plugin.

Any tips on how to achieve that ?

8 Answers 8

15

You can use the theme_page_templates filter to add templates to the dropdown list of page templates like this:

function wpse255804_add_page_template ($templates) {
    $templates['my-custom-template.php'] = 'My Template';
    return $templates;
    }
add_filter ('theme_page_templates', 'wpse255804_add_page_template');

Now WP will be searching for my-custom-template.php in the theme directory, so you will have to redirect that to your plugin directory by using the page_template filter like this:

function wpse255804_redirect_page_template ($template) {
    if ('my-custom-template.php' == basename ($template))
        $template = WP_PLUGIN_DIR . '/mypluginname/my-custom-template.php';
    return $template;
    }
add_filter ('page_template', 'wpse255804_redirect_page_template');

Read more about this here: Add custom template page programmatically

2
  • perfect ! that does it exactly.
    – smartcat
    Feb 9, 2017 at 15:53
  • 4
    since 4.7 version of wordpress, above code will not work. change this line from 'if ('my-custom-template.php' == basename ($template))' to $post = get_post(); $page_template = get_post_meta( $post->ID, '_wp_page_template', true ); if ('my-custom-template.php' == basename ($page_template )) Dec 9, 2017 at 9:47
5

This is a combination of the above answer and the above comments which ended up working for me.

The function to add the plugin to the list of available templates:

function wpse255804_add_page_template ($templates) {
    $templates['my-custom-template.php'] = 'My Template';
    return $templates;
    }
add_filter ('theme_page_templates', 'wpse255804_add_page_template');


The function to point the template to the appropriate directory within the plugin:

function wpse255804_redirect_page_template ($template) {
    $post = get_post();
    $page_template = get_post_meta( $post->ID, '_wp_page_template', true );
    if ('my-custom-template.php' == basename ($page_template))
        $template = WP_PLUGIN_DIR . '/mypluginname/my-custom-template.php';
    return $template;
    }
add_filter ('page_template', 'wpse255804_redirect_page_template');
2

Thanks for the help. I changed the code a little to work with the current WordPress version. Also changed it to support more than one custom template.

I bet there is a better way of doing this but it worked for me.

/**
 * Load Template with Plugin
 */
function yourname_add_page_template ($templates) {
    $templates['page-one.php'] = 'title here One';
    $templates['page-two.php'] = 'title here Two';
    $templates['page-three.php'] = 'title here Three';
    return $templates;
}
add_filter ('theme_page_templates', 'yourname_add_page_template');

function yourname_redirect_page_template ($template) {
    $post = get_post();
    $page_template = get_post_meta( $post->ID, '_wp_page_template', true );
    if ('page-one.php' == basename ($page_template)) {
        $template = WP_PLUGIN_DIR . '/pluginname/templates/page-one.php';
        return $template;
    }
    elseif ('page-two.php' == basename ($page_template)) {
        $template = WP_PLUGIN_DIR . '/pluginname/templates/page-two.php';
        return $template;
    }
    elseif ('page-three.php' == basename ($page_template)) {
        $template = WP_PLUGIN_DIR . '/pluginname/templates/page-three.php';
        return $template;
    }
}
add_filter ('page_template', 'yourname_redirect_page_template');

1
  • You're missing a return $template if it didn't match any of page-one/two/three
    – Rup
    Nov 4, 2022 at 0:46
0

From the codex:

<?php 
   $templates = get_page_templates();
   foreach ( $templates as $template_name => $template_filename ) {
       echo "$template_name ($template_filename)<br />";
   }
?>

You get then use the current templates and programmatically add them to whatever you wish.

0
0

The below code snippet is very well thought out, it will try to look for a template in the plugin and if it can't find it there it will try to get it from the theme.

define( 'MY_PLUGIN_DIR', plugin_dir_path( __FILE __ ) );
define( 'MY_PLUGIN_TEMPLATE_DIR', MY_PLUGIN_DIR . '/templates/' );

add_filter( 'template_include', 'ibenic_include_from_plugin', 99 );

function ibenic_include_from_plugin( $template ) {

    $new_template = '';

    $provided_template_array = explode( '/', $template );

    // This will give us archive.php
    $new_template = end( $provided_template_array );

    // Define single and archive template for custom post type 'portfolio'
    if( is_singular('portfolio') ) {
        $new_template = 'single-portfolio.php';
    }

    if( is_post_type_archive( 'portfolio' ) ) {
        $new_template = 'archive-portfolio.php';
    }

    $plugin_template = MY_PLUGIN_TEMPLATE_DIR . $new_template;

    if( file_exists( $plugin_template ) ) {
    return $plugin_template;
    }

    return $template;
}

Source: https://www.ibenic.com/include-or-override-wordpress-templates/

0

Now that WordPress supports using what was traditionally referred to as Page Templates with other post types, it seems like an updated example that works for posts and custom post types as well as pages might be helpful.

/*
    Plugin Name: Example Plugin Templates
    Plugin URI: 
    Description: Load page(or post type) templates from a plugin
    Version: 0.1
    Requires at least: 6.0
    Requires PHP: 7
    Author: t31os
    Author URI: 
    License: GPL v2 or later
    License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
namespace t31os\Plugin;

if( !defined('ABSPATH') )
    exit;

class Plugin_Templates {
    
    private $types;
    private $args;
    private $folder;
    private $templates = [
         'template-name-1.php' => 'Plugin Template 1'
        ,'template-name-2.php' => 'Plugin Template 2'
        ,'template-name-3.php' => 'Plugin Template 3'
    ];
    
    public function __construct() {
        // Hook late so plugins/themes have time to register post types
        add_action( 'init', [$this, 'on_init'], 5000 );
    }
    public function on_init() {
        
        // Filter hooks, because why not!
        $this->args      = apply_filters( 'my_plugin_template_type_args', [ 'public' => true ] );
        $this->folder    = apply_filters( 'my_plugin_template_directory', __DIR__ . '/templates/' );
        $this->templates = apply_filters( 'my_plugin_template_file_list', $this->templates );
        // Set the post types 
        $this->types     = get_post_types( $this->args );
        
        // We don't use page templates with attachments
        unset( $this->types['attachment'] );
        
        // Add custom files to template list
        add_filter( 'theme_templates', [$this,'add_plugin_templates'], 1000, 4 );
        
        // If page is one of the types
        if( isset( $this->types['page'] ) )
            add_filter( 'page_template', [$this,'set_plugin_page_template'], 1000, 3 );
        
        // And deal with other post types
        add_filter( 'single_template', [$this,'set_plugin_type_template'], 1000, 3 );   
    }
    public function add_plugin_templates( $post_templates, $obj, $post, $post_type ) {
        
        if( !isset( $this->types[$post_type] ) )
            return $post_templates;
        
        foreach( $this->templates as $file => $name )
            $post_templates[$file] = $name;
        
        return $post_templates;
    }
    private function is_plugin_template( $file ) {
        return (bool) isset( $this->templates[$file] ) && file_exists( $this->folder . $file );
    }
    public function set_plugin_page_template( $template, $type, $templates ) {
        
        if( !isset( $templates[0] ) )
            return $template;
        
        if( $this->is_plugin_template( $templates[0] ) )
            return $this->folder . $templates[0];
        
        return $template;
    }
    public function set_plugin_type_template( $template, $type, $templates ) {
        
        if( !isset( $templates[0] ) || 'single' !== $type )
            return $template;
        
        if( $this->is_plugin_template( $templates[0] ) )
            return $this->folder . $templates[0];
        
        return $template;
    }
    // Simple function for debugging / checking values
    private function pre( $s ) {
        printf( '<pre>%s</pre>', print_r( $s, true ) );
    }
}
new Plugin_Templates;

I tried not to be too abstract and keep the logic fairly simple, any problems, add a comment.

0

Here's an update for 2022: Below this code will add a template to the page template list and register it within your plugin files

// ------------register page template to page template lists------------
function register_custom_template_list ($templates) {
  // ------------register template display name to file name------------
  $templates['my-template.php'] = 'My Template Name';
  // ------------return page template list with new addition------------
  return $templates;
}
// ------------hook page template to page template lists------------
add_filter('theme_page_templates', 'register_custom_template_list');

// ------------register page template to file------------
function render_custom_template_archive ($template) {
  // ------------get currently edited page attributes------------
  $post = get_post();
  $page_template = get_post_meta( $post->ID, '_wp_page_template', true );
  // ------------check if selected template is for custom template------------
  if (basename ($page_template) == 'my-template.php'){
    // ------------register page template file to page------------
    $template = dirname(__DIR__).'/path_to/my-template.php';
    // ------------render custom template content template------------
    return $template;
  } else {
    // ------------return selected template if custom template is not selected------------
    return $template;
  }
}
// ------------hook page template to file------------
add_filter('page_template', 'render_custom_template_archive');
4
  • That looks like TKEz's answer. What's different?
    – Rup
    Nov 4, 2022 at 0:45
  • @Rup I've commented the code to make the difference a bit clearer. The major difference is on the last part of "render_custom_template_archive". The else statement ensures that other page templates can be loaded as well. The accepted answer/TKEz's answer broke my WP site and caused all pages to render my custom template. I had to completely reset the site to get it working (Thankfully it was a testing site).
    – sallycakes
    Nov 4, 2022 at 17:01
  • They should both work fine as-is, unless you add in extra braces. Both functions end with return $template which will be run whether the condition is true or not.
    – Rup
    Nov 5, 2022 at 17:19
  • @Rup if you look at TKEz's answer; his return statement is only on the inside of the if statement, which caused issues on my site
    – sallycakes
    Nov 5, 2022 at 20:32
-4
<?php load_template( $_template_file, $require_once ) ?>

That is from the very 1st google search results for "load template from plugin". Please make an effort to find the answers yourself before asking here.

2
  • If you don't want the theme or child theme to be able to override the plugin template then just use require($template)
    – mrben522
    Feb 9, 2017 at 13:41
  • 3
    Ofcourse I've seen that on google. I don't think you understood my question. I want the template to show up in the Page Attributes dropdown, so the user can choose it when creating/editing a page.
    – smartcat
    Feb 9, 2017 at 13:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.