最近准备写个插件需要在主题中添加一个模板!因为早主题的目录中添加模板是侵入式的修改,不利于以后的维护和升级或者更换主题都会存在麻烦!怎么办??看下面实例代码就知道
<?php
//此代码需要在wordpress中运行
//可以保存插件使用
//加载自定义页面模板
//作者:http://www.wpexplorer.com/wordpress-page-templates-plugin/
//GITHUB:https://github.com/wpexplorer/page-templater
class PageTemplater {
/**
* 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(
'template-page.php' => '自定义模板',
);
}
/**
* 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' ) );
?>
下面是英文原文
Add Page Templates to WordPress with a Plugin
Have you ever wanted to create your own page templates, but not had access to the theme itself? I, as a WordPress plugin author, have found this problem to be particularly annoying when developing my plugins. Thankfully the solution is quite simple! I’m going to take you quickly through the few lines of code which you will need to dynamically create WordPress Page Templates directly through PHP.
Inspiration for this article and the genius behind the code solution comes from Tom McFarlin: I am using my edited version of his original code, which you can find on his GitHub. I have kept his commenting in (as well as adding some of my own) as I find it very helpful in explaining what is going on – I couldn’t have said it any better myself!
You can find the code in its entirety and an example plugin at the very bottom of this post.
Shall we begin?
THE CODE
We will create our PHP function using a PHP Class. For those of you who aren’t well versed with PHP Classes, a Class is defined as an object which contains a collection of functions and variables which are working together. Check out the PHP.net Introduction for more details about the syntax and theory.
Our wrapper will only need 3 variables:
- The Plugin Slug: This is simply used as a unique identifier for the plugin.
- Class Instance: As we are adding an instance of this class to WordPress’ head, we’d better store it.
- Template Array: As you can probably guess, this is an array holding the template names and titles.
Here they are in 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;
Get Class Instance
As I said previously, we’ll be adding an instance of our class to the WordPress header using the add_filter() function. Therefore we will need a method which will return (or create) this instance for us.
For this, we will need a simple method, which will be called ‘get_instance’. Check it out below;
/**
* Returns an instance of this class.
*/
public static function get_instance() {
if( null == self::$instance ) {
self::$instance = new PageTemplater();
}
return self::$instance;
}
This will be the method called when our class is added to the WordPress head using ‘add_action()’.
WordPress Filters
Now we’ve sorted out the ‘get_instance’ method, we need to sort out what happens when it is actually instantiated.
We will use WordPress’s inbuilt add_filter() function to add an instance of our class into key points along the WordPress initialisation timeline. Using this method we will insert our page templates’ data into relevant slots, such as telling WordPress what file to use as a template when the page is called, and the title to display on the dropdown menu on the Page Editor.
For this we need to use the ‘__construct’ method (this will be run when the class is instantiated).
/**
* 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',
);
}
There are 4 different things going on here (ignoring ‘ $this->templates = array();’, which is just preparing the variable for use);
- Lines 9 – 13: This filter is adding the ‘register_project_templates’ to the ‘page_attributes_dropdown_pages_args’ hook. This is populating the WordPress cache with our new templates, ‘tricking’ WordPress into believing that the page template files actually exist in the template directory. This adds the page templates to the dropdown list on the page attributes meta box in the page editor.
- Lines 16 – 20: Here we are doing essentially the same as the previous code block, except this time we are adding our page template (if selected) to the saved post data as well.
- Lines 23 – 28: This filter is adding the ‘template_include’ to the ‘view_project_template’ hook. This is a very important function; this tells WordPress where your page template file actually is. WordPress will use the path provided by this to render the final page.
- Lines 31 – 34: Although this is simple, it is very important. This is where you specify the page templates you want to be added, and the path relative to the file where the page template file is ( eg. ‘something.php’ ). I’ve included one example (which will be used in the example plugin). Check out below for a general example:
$this->templates = array(
'FILE_PATH_AND_NAME' => 'TEMPLATE_TITLE',
'awesome-template.php' => 'Awesome',
'templates/organised-template.php' => 'Organised',
);
(Eat, Sleep,) Code, Repeat as necessary.
register_project_templates()
I’ve alluded to this method previously; let’s see what it actually does.
Essentially, the purpose of this method is to manipulate WordPress’s cache, inserting the relevant data about our page templates at the right places. Have a look at the code first, and I’ll talk you through it afterwards.
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;
}
Right then. Line 4 is the first place to look. As you may have guessed, we are generating a ‘cache key’. This will be used as a unique identifier for our page template data. Using the md5() function simply creates a unique string identifier to avoid any conflicts.
Next, on line 8, we are searching for and retrieving the page template cache (if it exists already): this will return an array of paths and titles. On lines 9-11 we check to see if there was any output from the cache query. If yes, great. If not, create a local array to hold the data we will be merging into the cache.
The next step is crucial. On line 14 we delete the existing page template cache. Don’t worry, no data is lost – it is stored in the $templates variable.
On line 18 we merge the existing page templates cache with our new entries, and on line 22 we re-insert the whole page template cache into WordPress’s system.
Simple!
view_project_template ()
We’re now onto our final method; this is where we tell WordPress where the real page template file is.
/**
* Checks if the template is assigned to the page
*/
public function view_project_template( $template ) {
// Get global post
global $post;
// Return template if post is empty
if ( ! $post ) {
return $template;
}
// Return default template if we don't have a custom one defined
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
return $template;
}
Ok then, this method will be checking against the global $post variable (line 6). It checks to see if a page template ( ‘_wp_page_template’ ) has been set for the post (meaning it must be a page). If not, then never mind – non-pages can’t have page templates.
Line 16 specifies the location of the page template file. As I have set out above, it checks for the specified page template file in the root directory of your plugin. (This can be easily changed though; see below.)
// Just changing the page template path
// WordPress will now look for page templates in the subfolder 'templates',
// instead of the root
$file = plugin_dir_path(__FILE__). 'templates/' .get_post_meta(
$post->ID, '_wp_page_template', true
);
After this, on lines 21 – 24, we have just a little bit of validation which checks if the file actually exists. If yes, awesome! If not, oh dear… You will most likely get a PHP error message if WordPress can’t find the template file, or even a blank screen. If any of these symptoms sounds familiar, just check the template file path by printing the $file variable to the screen.
If you plan to use this code commercially (which you are free to do – my version of the code comes with no license, hence you are free to do with it as you please), I truly recommend investing some time in error handling for maximum reliability.
That is that. With our class completed, there is only one thing left to do – add it to the WordPress head.
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );
Congrats if you made it all the way through! I hope you found what I had to say useful, and you benefit from it in the future!
ENTIRE CODE
<?php
/*
Plugin Name: Page Template Plugin : 'Good To Be Bad'
Plugin URI: http://hbt.io/
Version: 1.0.1
Author: Harri Bell-Thomas
Author URI: http://hbt.io/
*/
class PageTemplater {
/**
* 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 ) {
// Get global post
global $post;
// Return template if post is empty
if ( ! $post ) {
return $template;
}
// Return default template if we don't have a custom one defined
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
return $template;
}
}
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );
THE PLUGIN
You can also download the full code as a plugin on Github.
POST EDITOR CLOSEUP
Here’s a close up of the plugin in action. See the page template added under Page Attributes?