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?

2 Answers
2

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.

Leave a Reply

Your email address will not be published. Required fields are marked *