将模板应用到自定义帖子类型

时间:2015-10-05 作者:Dimitrov

今天,我有一个客户希望为其中的每个页面和部分使用自定义模板。我建议Laravel定制sh3t,但他想要WordPress,因为它似乎更容易主控(不是根据我的经验)。

..到目前为止还不错。我有点困惑。

所以我决定我的父实体是页面,所以我可以对每个页面应用不同的模板。然后我在这一页中有一个部分,它不应该是硬核的。用户应该能够选择节布局(模板),并在当前页面中删除或重新排序节。最后,我有帖子,因为它们是网站中最小的实体。帖子将被呈现为引导中的列(col-md-2、col-lg-6等)。。

我决定创建一个自定义帖子类型,将其用作一个部分,但后来我了解到,帖子类型不能有模板,只有页面可以有模板。到目前为止,这影响了我的计划,我花了5个小时研究解决方案(没有出口)。所以我需要另一种策略来实现这一点。我需要两个实体的模板。

有人能提出这个问题的解决方案吗?(我给你买杯啤酒!)

EDIT:

要创建我自己的自定义帖子类型,我使用wordpress中名为“自定义帖子类型UI”的插件,当然还有另一种方法,将一个简短的代码片段粘贴到函数中。php文件,但我这里不讨论这个问题。

4 个回复
最合适的回答,由SO网友:dswebsme 整理而成

通常情况下,我不会遵循米洛提供的这样一个强有力的答案。既然我已经为另一个项目编写了这段代码,我想我会与大家分享。

下面的代码完成了米洛在回答中总结的所有内容,我之前已经成功地将其移植到各个项目中。

以下是发生的事情的备忘单:

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) ) {  }

SO网友:Landing on Jupiter

从WordPress 4.7开始,已经为自定义帖子类型提供了对多个模板的支持。

为了使模板可用于自定义帖子类型,请将此标题添加到模板文件的元部分:

Template Post Type: post, foo, bar 
例如,我们假设您的自定义帖子类型标记为“my\\u events”,您希望为页面和自定义帖子类型提供一个名为“Fullwidth”的模板。

This:

/**
 * Template Name: Fullwidth
 * 
 * Template Description...
 **/

Becomes This:

/**
 * Template Name: Fullwidth
 * Template Post Type: page, my_events
 * 
 * Template Description...
 **/
More Info: Post Type Templates in 4.7 来自WordPress Core

SO网友:SUM1

我知道这是一个老问题,但我想补充一下,是什么帮助我将模板应用于自定义帖子类型。

我手动(使用自己的插件)而不是使用Custom Post Type UI 插件。

插件的代码如下所示:

<?php
/**
 * Plugin Name: [Your post type plugin]
 */

defined(\'ABSPATH\') or die(\'\'); // Prevents access to the file through its URL in the browser

function yourPostTypeFunction() {
    register_post_type(\'your-post-type\', array(
            \'labels\'=>array(
                \'name\'=>__(\'Post type pages\'),
                \'singular_name\'=>__(\'Post type page\')
            ),
            \'description\'=>\'Your description\',
            \'public\'=>true,
            \'hierarchical\'=>true, // Allows parent–child relationships
            \'show_in_rest\'=>true,
            \'supports\'=>array( // Features the post type should support
                \'title\',
                \'editor\',
                \'thumbnail\',
                \'revisions\',
                \'page-attributes\' /* Necessary to show the metabox for setting parent–child
relationships if you are not using the \'Template Post Type\' header field method */
            ),
            \'has_archive\'=>true,
        )
    );
}
add_action(\'init\', \'yourPostTypeFunction\');

function CPTFlushPermalinks() {
    yourPostTypeFunction();
    flush_rewrite_rules();
}
register_activation_hook(__FILE__, \'CPTFlushPermalinks\');

?>
请参见here 有关的所有选项的详细信息register_post_type() (为什么会有flush_rewrite_rules() 最后)。许多设置为默认值,您无需添加。

对我来说重要的是\'hierarchical\' 已设置为true\'supports\' 包括\'page-attributes\'.

之后,我创建了模板文件。代码如下所示:

<?php
/*
 * Template Name: [Your template]
 */

// ... page content (mostly copied from page.php)

?>

注意我是如何省略了post-WordPress-4.7“Template Post Type“字段?这是因为此字段用于允许特定帖子类型在“页面属性”元框中查看模板。列出的帖子类型将能够在其页面属性元框中选择模板。(如果这样做,则不需要\'page-attributes\' 支持您的帖子类型–metabox将自动创建。)没有它,只有“页面”类型的帖子才能在其“页面属性”元框中选择不同的模板。

这不是我想要的,因为我希望我的模板能够立即应用到所有具有post类型的页面。这是通过将模板命名为“single-[post type name].php”来实现的。

下面列出了可用于其他目的的其他命名方案here.

这将适用于post类型的单个页面。我不知道小节,就像最初问的问题一样;在这里,您可能需要在其他模板中使用条件语句,例如“if (\'your-post-type\' === get_post_type()) { ...“。

您可以通过“模板名称”字段自由重命名自定义模板,而不影响任何页面。如果要重命名文件,可以这样做,但必须进入数据库,搜索文件名并将实例重命名为新名称。

此外Post Type Switcher 插件有助于在帖子类型之间切换帖子,包括批量切换。它无缝地为我工作,没有bug。

dswebsme\'s 在WordPress允许非“页面”在“页面属性”框中选择自定义模板之前,答案是一个合适的答案。

SO网友:Milo

自定义帖子类型可以有可选的模板,您只需自己实现即可。WordPress在内部处理页面帖子类型的方法是,将模板slug保存到帖子元数据中,然后在前端加载模板时,根据the hierarchy.

基本流程是add a meta box 自定义帖子类型,以便用户选择模板(可能使用get_page_templates 创建列表)。

第二步是add a filter to single_template 在前端查看选定模板时加载该模板。

如果你查看核心文件wp-includes/template.phpwp-includes/post-template.php, 您可以查看WordPress使用的代码(以及过滤器的应用位置),并根据您的需要进行调整。get_queried_object 将为您提供对象的post_type 在过滤器中,以及使您能够获取帖子元数据的ID。

编辑-

下面是post 加载元键中任何内容的post类型my_template (如whatever.php). 您可以通过创建一篇新文章并使用本机自定义字段元框在该键下输入文件名来测试它。您可以为自定义类型修改此选项(更改\'post\'), 以及您用来存储和命名文件的任何方案。

function wpd_post_type_template( $template ){
    $object = get_queried_object();
    if( ! empty( $object->post_type )
        && \'post\' == $object->post_type
        && $slug = get_post_meta( $object->ID, \'my_template\', true ) ){
        if( $custom_template = locate_template( $slug, false ) ){
            $template = $custom_template;
        }
    }
    return $template;
}
add_filter( \'single_template\', \'wpd_post_type_template\' ) ;

相关推荐

Templates for Mobile Site

是否有任何内置方法可以根据浏览器大小显示不同的模板(即移动设备检测)?我做了一些研究,我能找到的只是大量插件,它们的功能远远超出了我的需要。我基本上只需要一种方法,将移动目录添加到我的主题中,并为移动用户显示该主题。