Adding items to page template dropdown on Page Edit Screen

I am developing a WP theme with MVC approach. It only have index.php, functions.php and styles.css on the parent directory. So, I do not want to place page templates on it rather then I want to programmatically provide them from View classes while functionality from edit screen stays the same.

Users need to have page templates select option on the edit screen. How do I successfully add Items to the template dropdown?

I tried to hook into theme_page_templates filter.

Example code:

add_filter( 'theme_page_templates', function($templates){

    $templates['my-page-template.php'] = "My Page Template";

    return $templates;

});

This does not work because of the use of array_intersect_assoc() on the filtered array, which removes the added page template item. I don’t understand why this function is used. It seems you can only remove page template from the list but can not add a new one using the given filter.

Is there any other way around?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I thought I would provide you with another approach. It is also a bit hackish, but it is general purpose and allows you to simply register the filename and label that you want to use, like so:

if ( class_exists( 'WPSE_196995_Page_Templates' ) ) {   
    WPSE_196995_Page_Templates::register_page_template(
        'My Page Template',
        'my-page-template.php'
    );
}

You could add the above code to your theme’s functions.php file.

To enable the above to actually work I implemented a self-contained class that could be used as a plugin or just copied into functions.php:

<?php   
/**
 * Plugin Name: WPSE 196995 Page Templates
 *
 * Class WPSE_196995_Page_Templates
 *
 * Allows registering page templates via code.
 */
class WPSE_196995_Page_Templates {

    static $registered_templates = array();

    static function on_load() {

        /**
         * Add registered page templates to 'page_template' cache.
         * @note This hook is called just before page templates are loaded
         */
        add_action( 'default_page_template_title', array( __CLASS__, '_default_page_template_title' ) );
    }

    /**
     * Register page templates
     *
     * @param string $label
     * @param string $filename
     */
    static function register_page_template( $label, $filename ) {

        self::$registered_templates[ $filename ] = $label;

    }

    /**
     * Add registered page templates to 'page_template' cache.
     *
     * @param string $title
     *
     * @return string mixed
     */
    static function _default_page_template_title( $title ) {

        /**
         * @var WP_Theme $theme
         */
        $theme = wp_get_theme();

        /**
         * Access the cache the hard way since WP_Theme makes almost everything private
         */
        $cache_hash = md5( $theme->get_stylesheet_directory() );

        /**
         * Get the page templates as the 'page_templates' cache will already be primed
         */
        $page_templates = wp_cache_get( $key = "page_templates-{$cache_hash}", $group = 'themes' );

        /**
         * Add in registered page templates
         */
        $page_templates += self::$registered_templates;

        /**
         * Now update the cache, which is what the get_page_templates() uses.
         */
        wp_cache_set( $key, $page_templates, $group, 1800 );

        /**
         * We are using this hook as if it were an action.
         * So do not modify $title, just return it.
         */
        return $title;

    }

}
WPSE_196995_Page_Templates::on_load();

The class provides the register_page_template() method, of course, but to actually add your page template it updates the value for 'page_templates' set in the object cache.

It is a bit hacky because WordPress made most methods and properties of the WP_Theme class private, but fortunately they used the publicly-accessible WordPress object cache to store the values. And by updating the object cache in the 'default_page_template_title' hook, which is called just before the page templates dropdown is generated and sent to the browser, we can get WordPress to display your page template(s), as you desired.

Method 2

Got around with a ugly hack :-/. I will update the answer If I go with jQuery later on. The solution still requires to have template files but code for the template file loads from the index.php

  1. I made a new template/ directory and put all page template there.
  2. All page templates are blank. We need it only for them to show up on the dropdown.
  3. Use template_include filter to redirect to index.php

Code

Blank Page Template Example

<?php
/*
Template Name: No Sidebar
 *
 * */

Filter

add_filter( 'template_include', function ($template ) {

    if ( !is_page_template()  )
        return $template;

    return locate_template( array( 'index.php' ), true );

}, 99);

I have created a trac ticket to allow adding templates via filter.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x