10

I've been looking around for the past couple hours for a way to create a custom page template from within a plugin but haven't had any luck yet.

What I am specifically trying to do is add an option to the list of available page templates when editing a page, and not using some other method like if( is_page( 'page-slug' ) ) { /* etc */ }

Is there a global variable I can modify to do this?

Edit:

I'm using this code currently, based on the link @m0r7if3r gave me in a comment, the problem is it will run this function when viewing the page, but not when editing the page (to populate the dropdown list with the page templates):

class JW_SiteGrader {

    private static $instance;

    private function __construct() {


        add_action( 'template_redirect', array( &$this, 'sitegrader_template_redirect' ), 20 );

    }

    public static function getInstance() {

        // Return the class data in a Singleton fashion
        if (self::$instance == null)
            self::$instance = new JW_SiteGrader();
        return self::$instance;

    }

    public function sitegrader_template_redirect() {

        add_filter( 'page_template', array( &$this, 'sitegrader_page_template' ), 10, 1 );

    }

    public function locate_plugin_template( $template_names, $load = false, $require_once = true ) {

        if ( !is_array( $template_names ) )
            return '';

        $located = '';

        $this_plugin_dir = WP_PLUGIN_DIR . '/' . str_replace( basename( __FILE__ ), '', plugin_basename( __FILE__ ) );

        foreach ( $template_names as $template_name ) {

            if ( !$template_name )
                continue;

            if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {

                $located = STYLESHEETPATH . '/' . $template_name;
                break;

            } else if ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) {

                $located = TEMPLATEPATH . '/' . $template_name;
                break;

            } else if ( file_exists( $this_plugin_dir .  $template_name ) ) {

                $located =  $this_plugin_dir . $template_name;
                break;

            }

        }

        if ( $load && '' != $located )
            load_template( $located, $require_once );

        return $located;
    }

    public function sitegrader_page_template( $template ) {

        $object = get_queried_object();

        if ( 'page' == $object->post_type ) {

            // New 
            $templates[] = "page-sitegrader.php";
            // Like in core
            $templates[] = "page-{$object->post_type}.php";
            $templates[] = "page.php";

            return locate_template( $templates );  

        }

        // return apply_filters('page_template', $template);
        return $template;
    }

}

Edit 2:

It seems that this functionality will be released in a future update, I read quite a few trac tickets about this and there has been some discussion but no real answer (hoping for 3.4). Will list trac tickets URLs here in a bit.

Edit 3:

The code above works, BUT, the only issue I'm having at this point is there's no template being added to the dropdown list when editing/adding a new page. I'm trying a few things and will update my question soon.

7
  • 2
    Have you tried something like this?
    – mor7ifer
    Feb 13, 2012 at 16:21
  • @m0r7if3r (If you try that, please leave a message how it worked out - Thanks!)
    – kaiser
    Feb 14, 2012 at 1:59
  • @kaiser I tried the code he recommended, the only missing link is to get the meta box to add the template to the dropdown list (as far as I know!).
    – Jared
    Feb 14, 2012 at 17:26
  • @Jared Look at this answer by me to a similar Q and the related trac tickets on the bottom of the a. Ad your code) If it's not showing on every page, then you're using the wrong hooks to run the instance. Which hooks are you using?
    – kaiser
    Feb 14, 2012 at 21:41
  • @kaiser I'm using the page_template hook, the code above in my edit is what's currently being used. Do I need to use the template_redirect hook and then add the page_template filter in there?
    – Jared
    Feb 14, 2012 at 22:22

6 Answers 6

4

Filters? Anyone?

There's no filter there to help: page_template_dropdown($template); is used to build the drop down and it's not filterable.

Sneaking into the Templates Array?

To build the drop downs contents, the core meta box uses get_page_templates(). From inside, the function looks like the following:

$themes = get_themes();
$theme = get_current_theme();
$templates = $themes[$theme]['Template Files'];

But when looking into get_themes(); then there seams to be no possibility to intercept the list of templates. Further more we have the problem, that there's no chance to get a template from outside the themes directory…

...Faking a Theme!

The theory and it's drawbacks…

You can use register_theme_directory() to add an additional theme directory where you can place templates. So the easiest thing would be to register your plugin as themes folder too:

// Register during init hook:
register_theme_directory( plugin_dir_path( __FILE__ ).'templates' );

Note: This is where I'm not sure if it will work.

During plugin activation: Then you should place a style.css.php file inside your templates folder. This would allow you to add variables to your file. This variable would then be the parent theme. And the parent theme should simply be the currently active theme. Then update your active theme to your plugin.

Drawback #2: About the »Appearance« UI… Maybe add a note that this "Theme" is not meant to be used as actual Theme. I leave the rest of »Avoid activating this theme« stuff up to your imagination. Anyway: It should work.

Drawback #2: This trick will successfully avoid child themes. You're allowed to have one parent theme. Nothing more.

2
  • So I am guessing that there is no actual way to use custom page templates from any inactive theme, correct? I could register a theme directory but the templates however are not available for use unless that theme is active.
    – Jared
    Feb 15, 2012 at 21:21
  • 1
    Not really. It's just not supposed to be and therefore a lack of core. Have you tried the link to ipstenu above? I already tried going that route but ended in a dead way - with another solution. The best bet would be to follow the tickets, push & link them wherever you are. :/
    – kaiser
    Feb 15, 2012 at 22:34
2

As a suggestion for a potential work around have you considered using the WordPress file system to write a page template file from your plugin to your current active theme directory? Depending upon how much control you want over this process you can have your plugin write the file on activation and remove it on uninstall. Alternatively you could could create page template files dynamically from within your plugin UI using a form to pass certain values such as the page template name which is to appear in the dropdown box of the post edit screen. You could also in theory remove the page template from within your plugin UI at the click of a button and similarly add multiple templates for different purposes. There's a good post on using the file system over at Otto's blog. I don't have the link with me now but you can search for it.

I hope they release what you were intending to do by way of a hook in the next core release.

3
  • 1
    I had a method exactly like this working before but had many issues back when I tried it, because when a user would switch themes, it would not delete the template file and if they were to copy their active theme and put it on a different site, they would risk uploading a custom template file that would not work. I know there are several workarounds for that, but I really want this to be automatic. +1 for the suggestion though.
    – Jared
    Feb 22, 2012 at 20:29
  • 1
    Hi Jared, I was also concerned about the same issue. The only solution I could think to further extend this alternative method would be to have the plugin upon it's activation get the current theme's name then if a user deactivates/switches themes you can delete the template file from that theme and rewrite it to the newly activated theme. Take a look at this link where he created his own activation/deactivation hooks for checking themes. With a little extra code I feel this is do-able.
    – Adam
    Feb 23, 2012 at 15:12
  • Absolutely, I think that may work. I'll give it a go and post the results in my question. Thanks for the link, it helps!
    – Jared
    Feb 23, 2012 at 18:45
1

I took a browse through the source, and quite shockingly there doesn't look to be a way to do this! My suggested hack would be to add a second meta box with a theme override/second theme dropdown. Then hook into this filter:

# wp-includes/theme.php line 751 in 3.3.1:
return apply_filters( "{$type}_template", locate_template( $templates ) );

to return your theme file if it's been overridden. Of course, you'd want to only add_filter if it's the post you want.

If you wanted to be fancy, you could scrap the original box and re-create it (via filters of course, not modifying core code).

I'd also suggest adding a trac ticket requesting that functionality (if there isn't one already in there for it).

3
1

I have accomplished this in the past by removing the default page template metabox and then adding your own metabox. I had the new metabox use the built in get_page_templates and then added the others that I needed programatically. On a save it can can update the page template just like wordpress does.

1
  • Would you mind showing the full code? Currently it's only a rough concept. Thanks.
    – kaiser
    Mar 13, 2012 at 3:31
1

Check out the hook theme_page_templates, used by the get_page_templates function, filter added since 3.9 updated in 4.4:

apply_filters( 'theme_page_templates', $page_templates, $this, $post );
1
-2

A search result with DuckDuckGo add a wordpress page template turned up the answer for me on a wpmu.org page titled WordPress Custom Page Template Tutorial.

Essentially, inside the theme directory, wp-content/themes/your-theme, copy an existing page template to a new php file name of your choice. Edit the new file, taking care to change the magic "Template Name:" property value in the comment at the top of the file.

That was all there was to it. It is possible this is a feature that post-dates the question. I am using WP 3.5 with the twenty_eleven theme.

It is also possible that there are cleaner ways to extend a theme. Edits like this might be overwritten by theme updates. Mea Culpa.

1
  • I need a solution to add the template to the dropdown list from a plugin, not a theme. :(
    – Jared
    Jan 31, 2013 at 23:20

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.