讨厌成为坏消息的承担者,但WordPress至少在v3.0 中将页面模板功能硬编码为“页面”帖子类型(在将来的版本中可能会更改,但是我不知道有具体的措施可以更改它)因此,这是我极少数尝试弄清楚如何在不破坏内核的情况下解决问题的机会之一。
我想出的解决方案是基本上从WordPress核心复制相关代码并将其修改为我们的需求。这是步骤(行号来自v3.0.1):
复制page_attributes_meta_box()
535行的功能/wp-admin/includes/meta-boxes.php
并进行修改以适合。
编写一个代码add_meta_boxes
钩子,以添加在#1中创建的metabox。
复制get_page_templates()
166行的功能/wp-admin/includes/theme.php
并进行修改以适合。
复制page_template_dropdown()
功能的第2550行/wp-admin/includes/template.php
并修改以适合。
将帖子模板添加到您的主题。
编写一个save_post
钩子,以便在保存时存储帖子模板文件名。
编写一个single_template
挂钩,以启用相关帖子的帖子模板的加载。
现在继续吧!
1.复制page_attributes_meta_box()
功能
作为第一步,您需要复制第page_attributes_meta_box()
535行的函数,/wp-admin/includes/meta-boxes.php
而我选择了重命名它post_template_meta_box()
。由于您只要求页面模板,因此我省略了用于指定父帖子和指定顺序的代码,这使代码更加简单。我还选择为此使用postmeta,而不是尝试重用page_template
对象属性,以避免由于无意的耦合而导致的潜在不兼容性。所以这是代码:
function post_template_meta_box($post) {
if ( 'post' == $post->post_type && 0 != count( get_post_templates() ) ) {
$template = get_post_meta($post->ID,'_post_template',true);
?>
<label class="screen-reader-text" for="post_template"><?php _e('Post Template') ?></label><select name="post_template" id="post_template">
<option value='default'><?php _e('Default Template'); ?></option>
<?php post_template_dropdown($template); ?>
</select>
<?php
} ?>
<?php
}
2.编码一个add_meta_boxes
钩子
下一步是使用add_meta_boxes
挂钩添加metabox :
add_action('add_meta_boxes','add_post_template_metabox');
function add_post_template_metabox() {
add_meta_box('postparentdiv', __('Post Template'), 'post_template_meta_box', 'post', 'side', 'core');
}
3.复制get_page_templates()
功能
我认为只有在区分页面模板和帖子模板时才有意义,因此需要get_post_templates()
基于的get_page_templates()
第166行的功能/wp-admin/includes/theme.php
。但是,代替使用Template Name:
标记的页面模板使用此功能,Post Template:
而是使用标记,您可以在下面看到。
我还过滤掉了functions.php
(不确定该如何get_page_templates()
正确地工作,但是无论如何!)的检查。剩下的唯一事情就是更改对该词的引用,page
以post
确保以后的维护可读性:
function get_post_templates() {
$themes = get_themes();
$theme = get_current_theme();
$templates = $themes[$theme]['Template Files'];
$post_templates = array();
if ( is_array( $templates ) ) {
$base = array( trailingslashit(get_template_directory()), trailingslashit(get_stylesheet_directory()) );
foreach ( $templates as $template ) {
$basename = str_replace($base, '', $template);
if ($basename != 'functions.php') {
// don't allow template files in subdirectories
if ( false !== strpos($basename, '/') )
continue;
$template_data = implode( '', file( $template ));
$name = '';
if ( preg_match( '|Post Template:(.*)$|mi', $template_data, $name ) )
$name = _cleanup_header_comment($name[1]);
if ( !empty( $name ) ) {
$post_templates[trim( $name )] = $basename;
}
}
}
}
return $post_templates;
}
4.复制page_template_dropdown()
功能
类似地,page_template_dropdown()
从第2550行复制/wp-admin/includes/template.php
以创建post_template_dropdown()
并简单地将其更改为调用get_post_templates()
:
function post_template_dropdown( $default = '' ) {
$templates = get_post_templates();
ksort( $templates );
foreach (array_keys( $templates ) as $template )
: if ( $default == $templates[$template] )
$selected = " selected='selected'";
else
$selected = '';
echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
endforeach;
}
5.添加帖子模板
下一步是添加用于测试的帖子模板。使用Post Template:
第3步中提到的标记single.php
从您的主题复制到,single-test.php
并添加以下注释标头(请确保在其中进行了修改,single-test.php
以便您可以看出它正在加载而不是single.php
):
/**
* Post Template: My Test Template
*/
完成步骤1至5的操作后,您可以看到“帖子模板”元框出现在帖子编辑器页面上:
(来源:mikeschinkel.com)
6.编码一个save_post
钩子
既然您已经准备好了编辑器,那么当用户单击“发布”时,需要将页面模板文件名实际保存为postmeta。这是该代码:
add_action('save_post','save_post_template',10,2);
function save_post_template($post_id,$post) {
if ($post->post_type=='post' && !empty($_POST['post_template']))
update_post_meta($post->ID,'_post_template',$_POST['post_template']);
}
7.编码一个single_template
钩子
最后,您实际上需要让WordPress使用新的帖子模板。您可以通过single_template
为已分配了一个帖子的那些帖子钩住并返回所需的模板名称来做到这一点:
add_filter('single_template','get_post_template_for_template_loader');
function get_post_template_for_template_loader($template) {
global $wp_query;
$post = $wp_query->get_queried_object();
if ($post) {
$post_template = get_post_meta($post->ID,'_post_template',true);
if (!empty($post_template) && $post_template!='default')
$template = get_stylesheet_directory() . "/{$post_template}";
}
return $template;
}
就是这样!
注意,我并没有考虑到自定义文章类型,只post_type=='post'
。我认为处理自定义帖子类型需要区分不同的帖子类型,虽然不是很困难,但我在这里没有尝试过。