adding custom page template from plugin

22,997

Solution 1

Here is my code solution for adding page templates from a Wordpress plugin (inspired by Tom McFarlin).

This is designed for a plugin (the template files are searched for in the root directory of the plugin). These files are also in exactly the same format as if they were to be included directly in a theme. This can be changed if desired - check out my full tutorial http://www.wpexplorer.com/wordpress-page-templates-plugin/ for greater detail on this solution.

To customise, simply edit the following code block within the __construct method;

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

Full 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;


    /**
     * 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.
            add_filter(
                'page_attributes_dropdown_pages_args',
                 array( $this, 'register_project_templates' ) 
            );


            // 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 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 ) {

            global $post;

            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;

    } 


} 

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

Check out my tutorial on this for more info.

http://www.wpexplorer.com/wordpress-page-templates-plugin/

I hope this helps you in what you want to do :)

Solution 2

I actually was able to talk to a developer friend of mine after revising the code quite a bit.

Here it is...

<?php

    register_activation_hook( __FILE__, 'create_uploadr_page' );

    function create_uploadr_page() {

        $post_id = -1;

        // Setup custom vars
        $author_id = 1;
        $slug = 'event-photo-uploader';
        $title = 'Event Photo Uploader';

        // Check if page exists, if not create it
        if ( null == get_page_by_title( $title )) {

            $uploader_page = array(
                    'comment_status'        => 'closed',
                    'ping_status'           => 'closed',
                    'post_author'           => $author_id,
                    'post_name'                     => $slug,
                    'post_title'            => $title,
                    'post_status'           => 'publish',
                    'post_type'                     => 'page'
            );

            $post_id = wp_insert_post( $uploader_page );


            if ( !$post_id ) {

                    wp_die( 'Error creating template page' );

            } else {

                    update_post_meta( $post_id, '_wp_page_template', 'custom-uploadr.php' );

            }
        } // end check if

    }

    add_action( 'template_include', 'uploadr_redirect' );
    function uploadr_redirect( $template ) {

        $plugindir = dirname( __FILE__ );

        if ( is_page_template( 'custom-uploadr.php' )) {

            $template = $plugindir . '/templates/custom-uploadr.php';
        }

        return $template;

    }

?>

Solution 3

I'm providing a general solution for those that want to add a template to a post from the their plugin. Use the single_template filter.

<?php
  add_filter( 'single_template', 'add_custom_single_template', 99 );

  function add_custom_single_template( $template ) {
    return plugin_dir_path( __FILE__ ) . 'path-to-page-template-inside-plugin.php';
  }
?>

Also, if you want to use the template in a specific post type, then:

<?php
  add_filter( 'single_template', 'add_custom_single_template', 99 );

  function add_custom_single_template( $template ) {
    if ( get_post_type() == 'post-type-name'; ) {
      return plugin_dir_path( __FILE__ ) . 'path-to-page-template-inside-plugin.php';
    }

    return $template;
  }
?>
Share:
22,997
Designer 17
Author by

Designer 17

A beginning WordPress theme designer/developer.

Updated on January 15, 2020

Comments

  • Designer 17
    Designer 17 over 4 years

    I'm working on building my first plugin for wordpress and am needing it to dynamically add a custom page for a login screen among other things.

    The only thing I've been able to find that's anywhere near what I'm needing is here: WP - Use file in plugin directory as custom Page Template? & Possible to add Custom Template Page in a WP plugin?, but they're still not quite what I'm looking for.

    Here is the code that I currently have running in my plugin...

    // Add callback to admin menu
    add_action( 'template_redirect', 'uploadr_redirect' );
    
    // Callback to add menu items
    function uploadr_redirect() {
    
    global $wp;
    $plugindir = dirname( __FILE__ );
    
    // A Specific Custom Post Type
    if ( $wp->query_vars["post_type"] == 'uploadr' ) {
    
        $templatefilename = 'custom-uploadr.php';
    
        if ( file_exists( TEMPLATEPATH . '/' . $templatefilename )) {
    
            $return_template = TEMPLATEPATH . '/' . $templatefilename;
    
        } else {
    
            $return_template = $plugindir . '/themefiles/' . $templatefilename;
    
        }
    
        do_theme_redirect( $return_template );
    
    }
    
    }
    
    
    function do_theme_redirect( $url ) {
    
        global $post, $wp_query;
    
        if ( have_posts ()) {
    
            include( $url );
            die();
    
        } else {
    
            $wp_query->is_404 = true;
    
        }
    
    }
    

    Using this would require that my client create new page... what I'm needing is for the pluging to auto create a custom page (with a customized path, meaning .com/custompathhere) using a template file from the plugin folder, which will then contain all actions the plugin performs.

    Note: This plugin is designed to run on one page, therefore reducing load-time and etc.

    Thanks in advance!

  • Pranav Singh
    Pranav Singh about 10 years
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.
  • Michael
    Michael over 3 years
    Hi, thanks for the suggestion, I am trying to make this work but I am not successful. I created a page programmatically, do I need to set a specific template for that page? How does that work? The doc says "It will replace the template used whenever the "single" template is called." what is the "single" template exactly?
  • jolvera
    jolvera over 3 years
    @Michael It refers to a Single Post Template, i.e., single.php. I think you want to do a Page Template,
  • Michael
    Michael over 3 years
    oh so what you added won't work with pages? Isn't "page" a post type, though?
  • Michael
    Michael over 3 years
    Does this still work for you? I copied both 2 files in my plugin but I don't see the template.
  • Michael
    Michael over 3 years
    Actually I was able to make it work. How to set the template to a page programmatically, though? I create a page with wp_insert_post and set it using 'page_template' => 'goodtobebad-template.php' but the created page is not using it.