Add custom template page programmatically

I’m trying to add template page from a plugin,and my template page is in this plugin folder.Is this posible?Here is my code:

 global $user_ID;
    $new_post = array(
        'post_title' => 'Test Template Page',
        'post_content' => 'Some text',
        'post_status' => 'publish',
        'post_date' => date('Y-m-d H:i:s'),
        'post_author' => $user_ID,
        'post_type' => 'page',
        'post_category' => array(0)
    );
    $post_id = wp_insert_post($new_post);
    if (!$post_id) {
        wp_die('Error creating template page');
    } else {
        update_post_meta($post_id, '_wp_page_template', 'tp-file.php');
    }

tp-file.php is my custom template page.When I put that file into the my-theme folder,it works fine,but I want to do this with file from plugin folder so I don’t have to force users to copy that file from plugin folder to template folder.
Is this possible?Any idea?

Related posts

Leave a Reply

3 comments

  1. The article linked is on the right track, but i’ll make it more simple for you.. 😉

    add_filter( 'page_template', 'catch_plugin_template' );
    
    function catch_plugin_template( $template ) {
        if( 'tp-file.php' == basename( $template ) )
            $template = WP_PLUGIN_DIR . '/yourpluginname/tp-file.php';
        return $template;
    }
    

    The filter basically looks to see if your special page template is set for the current page, if it is, updates the path to point at your plugins template instead.

    Just be sure the path is right, else you’ll be seeing include errors… 🙂

    Follow-up #1

    Ok first problem is that WordPress validates any template set as a page template, ie. it checks to see if the file is in the theme folder, and is a valid template file, if not it skips past it and includes a more generic template, like page.php …

    However, this doesn’t change the fact that the meta field still holds the value of your custom template, and also is_page_template( 'tp-file.php' ) will correctly return true if used in place of my previous conditional statement, eg..

    // Filter page template
    add_filter('page_template', 'catch_plugin_template');
    
    // Page template filter callback
    function catch_plugin_template($template) {
        // If tp-file.php is the set template
        if( is_page_template('tp-file.php') )
            // Update path(must be path, use WP_PLUGIN_DIR and not WP_PLUGIN_URL) 
            $template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
        // Return
        return $template;
    }
    

    NOTE: I’ve switched the code to use WP_PLUGIN_DIR as the WP_PLUGIN_URL constant is not suitable for paths… (includes must use a path, not a URL).

    One issue, and this really isn’t something you can fix, is that when viewing the page from the admin area, when editting the page, the template won’t be listed as the active template, and saving changes could of course change the active template. There’s much we can do there, the page template dropdown is generated from a function that scans theme files, there’s no hooks in place that i can see that would allows us to extend the list with plugin templates.

    Personally what i’d suggest, as a work-around would be to save an additional meta field with every page that created using your special plugin page, then add a hook onto save_post or wp_insert_post_data and check if this meta field exists, if it does, also check the page template is set to tp-file.php, and if not, update it to tp-file.php. The additional meta field would just be a flag so to speak, to indicate which pages need to have your plugin template attached.

    Here’s your plugin working in it’s most basic form(yes i tested)… 🙂

    <?php
    /*
      Plugin Name: TP Test Plugin
      Plugin URI: 
      Description: TP Test Plugin
      Version: 1.0.0
      Author: 
      Author URI: 
    */
    
    global $wp_version;
    
    if( version_compare( $wp_version, "2.9", "<" ) )
        exit( 'This plugin requires WordPress 2.9 or newer. <a href="http://codex.wordpress.org/Upgrading_WordPress">Please update!</a>' );
    
    // Add callback to admin menu
    add_action('admin_menu', 'create_tp_menu');
    
    // Callback to add menu items
    function create_tp_menu() {
        add_management_page('TP Test', 'TP Test', 'manage_options', 'tp-teste', 'wp_tp_test_fnc' );
    }
    
    function wp_tp_test_fnc() {
    
        //include('tp-form-file.php');
    
        if( !empty( $_POST['tp_name'] ) ) {
            $tp_name = $_POST['tp_name'];
    
            global $user_ID;
            $new_post = array(
                'post_title' => $tp_name,
                'post_content' => 'Some text',
                'post_status' => 'publish',
                'post_date' => date('Y-m-d H:i:s'),
                'post_author' => $user_ID,
                'post_type' => 'page',
            );
            $post_id = wp_insert_post($new_post);
    
            if( !$post_id )
                wp_die('Error creating template page');
            else
                update_post_meta( $post_id, '_wp_page_template', 'tp-file.php' );
            /*
            $pt = get_page_templates();
    
            $pt['TP file test'] = WP_PLUGIN_URL . '/tp-test/tp-file.php';
    
            echo "<pre>";
            print_r($pt);
            echo "</pre>";
            */
        }   
        ?>
        <fieldset style="margin: 50px 100px;background-color: #cccccc;padding: 30px;border: 1px solid #ccc">
             <legend style="background-color: #ccccff;padding: 20px;font-weight: bold;font-size: 18px">Create Template Page</legend>
             <form name="frm_main" action="" method="POSt">
                  <input class="text" type="text" name="tp_name" size="50" />
                  <br />
                  <input class="button" type="submit" value="Create Template Page" name="btn_submit" />
             </form>
        </fieldset>
        <?php
    
    }
    
    
    // Filter page template
    add_filter('page_template', 'catch_plugin_template');
    
    // Page template filter callback
    function catch_plugin_template($template) {
        // If tp-file.php is the set template
        if( is_page_template('tp-file.php') )
            // Update path(must be path, use WP_PLUGIN_DIR and not WP_PLUGIN_URL) 
            $template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
        // Return
        return $template;
    }
    

    Hope that helps clear things up.. 🙂

  2. The page_template filter is deprecated now. (http://adambrown.info/p/wp_hooks/hook/page_template)

    Try using single_template (or archive_template for archive templates) instead.

    Based on @t31os’s answer:

    // Filter page template
    add_filter('single_template', 'catch_plugin_template');
    
    // Page template filter callback
    function catch_plugin_template($template) {
        // If tp-file.php is the set template
        if( is_page_template('tp-file.php') )
            // Update path(must be path, use WP_PLUGIN_DIR and not WP_PLUGIN_URL) 
            $template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
        // Return
        return $template;
    }
    
  3. One issue, and this really isn’t something you can fix, is that when
    viewing the page from the admin area, when editting the page, the
    template won’t be listed as the active template, and saving changes
    could of course change the active template. There’s much we can do
    there, the page template dropdown is generated from a function that
    scans theme files, there’s no hooks in place that i can see that would
    allows us to extend the list with plugin templates.

    Actually I found a hook in another thread that does exactly that:

    WordPress: Can you programmatically create page templates?

    I am pasting the code here for convenience:

    CONST CUSTOM_PAGE_TEMPLATES = array(
      array('slug' => 'home', 'label' => 'Home'),
      array('slug' => 'content-page', 'label' => 'Content Page'),
      array('slug' => 'ordering', 'label' => 'Ordering'),
      array('slug' => 'reviews', 'label' => 'Reviews')
    ); 
    
    /**
     * Add file-less page templates to the page template dropdown 
     */
    add_filter('theme_page_templates', function($page_templates, $wp_theme, $post) {
      foreach(CUSTOM_PAGE_TEMPLATES as $template) {
        // Append if it doesn't already exists
        if (!isset($page_templates[$template['slug']])) {
          $page_templates[$template['slug']] = $template['label'];
        }
      }
      return $page_templates;
    }, PHP_INT_MAX, 3);
    

    Hope that helps someone.