通常情况下,我不会遵循米洛提供的这样一个强有力的答案。既然我已经为另一个项目编写了这段代码,我想我会与大家分享。
下面的代码完成了米洛在回答中总结的所有内容,我之前已经成功地将其移植到各个项目中。
以下是发生的事情的备忘单:
1) 钩住“add\\u meta\\u box”操作,在编辑屏幕上呈现一个新的自定义meta框(本机“page”帖子类型除外)。
2) 钩住“admin\\u menu”操作以删除现有的“Page Attributes”元框(本机“Page”帖子类型上的除外)。
3) 构建自定义元框以替换本机“页面属性”元框的功能。这包括用于定义已初始化的任何自定义帖子类型的父级、模板和顺序的字段。
4) 钩住“save\\u post”操作,将模板选择保存在post meta中。
5) 钩住“single\\u template”过滤器以加载自定义模板,而不是默认的WordPress模板。
以下是供您使用的全功能复制/粘贴:
/** Custom Post Type Template Selector **/
function cpt_add_meta_boxes() {
$post_types = get_post_types();
foreach( $post_types as $ptype ) {
if ( $ptype !== \'page\') {
add_meta_box( \'cpt-selector\', \'Attributes\', \'cpt_meta_box\', $ptype, \'side\', \'core\' );
}
}
}
add_action( \'add_meta_boxes\', \'cpt_add_meta_boxes\' );
function cpt_remove_meta_boxes() {
$post_types = get_post_types();
foreach( $post_types as $ptype ) {
if ( $ptype !== \'page\') {
remove_meta_box( \'pageparentdiv\', $ptype, \'normal\' );
}
}
}
add_action( \'admin_menu\' , \'cpt_remove_meta_boxes\' );
function cpt_meta_box( $post ) {
$post_meta = get_post_meta( $post->ID );
$templates = wp_get_theme()->get_page_templates();
$post_type_object = get_post_type_object($post->post_type);
if ( $post_type_object->hierarchical ) {
$dropdown_args = array(
\'post_type\' => $post->post_type,
\'exclude_tree\' => $post->ID,
\'selected\' => $post->post_parent,
\'name\' => \'parent_id\',
\'show_option_none\' => __(\'(no parent)\'),
\'sort_column\' => \'menu_order, post_title\',
\'echo\' => 0,
);
$dropdown_args = apply_filters( \'page_attributes_dropdown_pages_args\', $dropdown_args, $post );
$pages = wp_dropdown_pages( $dropdown_args );
if ( $pages ) {
echo "<p><strong>Parent</strong></p>";
echo "<label class=\\"screen-reader-text\\" for=\\"parent_id\\">Parent</label>";
echo $pages;
}
}
// Template Selector
echo "<p><strong>Template</strong></p>";
echo "<select id=\\"cpt-selector\\" name=\\"_wp_page_template\\"><option value=\\"default\\">Default Template</option>";
foreach ( $templates as $template_filename => $template_name ) {
if ( $post->post_type == strstr( $template_filename, \'-\', true) ) {
if ( isset($post_meta[\'_wp_page_template\'][0]) && ($post_meta[\'_wp_page_template\'][0] == $template_filename) ) {
echo "<option value=\\"$template_filename\\" selected=\\"selected\\">$template_name</option>";
} else {
echo "<option value=\\"$template_filename\\">$template_name</option>";
}
}
}
echo "</select>";
// Page order
echo "<p><strong>Order</strong></p>";
echo "<p><label class=\\"screen-reader-text\\" for=\\"menu_order\\">Order</label><input name=\\"menu_order\\" type=\\"text\\" size=\\"4\\" id=\\"menu_order\\" value=\\"". esc_attr($post->menu_order) . "\\" /></p>";
}
function save_cpt_template_meta_data( $post_id ) {
if ( isset( $_REQUEST[\'_wp_page_template\'] ) ) {
update_post_meta( $post_id, \'_wp_page_template\', $_REQUEST[\'_wp_page_template\'] );
}
}
add_action( \'save_post\' , \'save_cpt_template_meta_data\' );
function custom_single_template($template) {
global $post;
$post_meta = ( $post ) ? get_post_meta( $post->ID ) : null;
if ( isset($post_meta[\'_wp_page_template\'][0]) && ( $post_meta[\'_wp_page_template\'][0] != \'default\' ) ) {
$template = get_template_directory() . \'/\' . $post_meta[\'_wp_page_template\'][0];
}
return $template;
}
add_filter( \'single_template\', \'custom_single_template\' );
/** END Custom Post Type Template Selector **/
我在这里所做的唯一假设是,模板遵循以下命名约定最佳实践:
posttype-templatename.php
例如,您可以在主题中使用以下命名约定为“事件”自定义帖子类型定义一些自定义模板:
event-standard.php
event-allday.php
event-recurring.php
此代码足够聪明,只允许将“事件”模板应用于事件帖子类型。换句话说,一个名为“section video.php”的模板永远不会对事件帖子类型可见。该模板将作为选项显示在“Section”帖子类型上。
要删除此功能,只需从上述代码中删除条件逻辑:
if ( $post->post_type == strstr( $template_filename, \'-\', true) ) { }