单个-{$ post_type}-{slug} .php用于自定义帖子类型


20

我最喜欢的Wordpress 模板层次结构部分是能够快速地为页面创建模板文件,而无需在Wordpress中编辑页面以选择模板。

我们目前可以这样做:

页面-{slug} .php

但我希望能够做到这一点:

single- {post_type}-{slug} .php

这样,例如,在名为的帖子类型中review,我可以为位于以下位置的名为“我的伟大评论”的帖子制作模板single-review-my-great-review.php

有人设置过吗? single-{post_type}-{slug}.php


以前从未使用过这样的设置,但是如果它太复杂了,为什么不制作一个模板文件并将其与相关评论关联。
Shane

WP 3.4自动获取single-{post_type}-{slug}.php,因此升级到WP 3.4是另一种选择。
yitwail

Answers:


19

A)核心基础

正如您在Codex模板层次结构说明中所看到的那样single-{$post_type}.php已经支持。


B)扩展核心层次结构

现在很高兴里面有一些过滤器和挂钩/wp-includes/template-loader.php

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • AND:内部get_query_template( $type, ... )名为的特定过滤器:"$type}_template"

B.1)如何运作

  1. 在模板加载器文件中,模板由条件var / wp_query查询加载is_*()
  2. 然后触发条件(如果使用“单个”模板): is_single() && $template = get_single_template()
  3. 那么这会触发get_query_template( $type, $templates ),这里$typesingle
  4. 然后我们有"{$type}_template"过滤器

C)解决方案

因为我们想要与得到一个模板延长层次之前加载实际的"single-{$object->post_type}.php"模板,我们将拦截层级,并添加一个新的模板,模板阵列的开始。

// Extend the hierarchy
function add_posttype_slug_template( $templates )
{

    $object = get_queried_object();

    // New 
    $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
    // Like in core
    $templates[] = "single-{$object->post_type}.php";
    $templates[] = "single.php";

    return locate_template( $templates );    
}
// Now we add the filter to the appropriate hook
function intercept_template_hierarchy()
{
    add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
}
add_action( 'template_redirect', 'intercept_template_hierarchy', 20 );

注意:(如果要使用默认对象子弹以外的其他东西),则必须$slug根据永久链接结构进行调整。只需使用全球所需的任何东西即可(object) $post

火车票

由于目前尚不支持上述方法(您只能以这种方式过滤绝对定位的路径),因此以下是跟踪单的列表:


我想对此进行测试,但看来您的add_filter行最后缺少一些内容。
supertrue 2012年

@supertrue好抓住。:) )在过滤器中发现另一个丢失的东西。固定。也许您想在模板内的嵌条之前用下划线替换破折号。只是为了在查看模板时使后缀更好地突出显示。
kaiser 2012年

在整个网站上导致此错误:警告: array_unshift()[function.array-unshift]:第一个参数应该是[包含array_unshift的行]中的数组
supertrue 2012年

好的,但是接下来其他事情正在拦截核心模板。该函数可以正常工作,并且$templates是一个数组。请参阅此pastebin中的核心功能(无有效期)。确保使用不带插件和默认主题的安装进行测试。然后一个接一个地激活,看看错误是否仍然出现。
kaiser 2012年

是的,我调试了这个,我得到了第一个找到的模板的最终绝对路径作为字符串。在更改答案之前,我将不得不与一些核心开发人员进行讨论。另外:我混合了一些内容:slug仅适用于术语和分类法。您应该替换$post->post_name为适合您的永久链接结构的内容。当前,尚无办法根据您的永久结构和重写规则在所有情况下自动执行此操作来检索和替换路径。期待另一个更新。
kaiser 2012年

4

在“ 模板层次结构”图像之后,我看不到这样的选项。

因此,我将如何处理:

解决方案1(我认为最好)

制作模板文件并将其关联到审阅

 <?php
 /*
 Template Name: My Great Review
 */
 ?>

将模板php文件添加到主题目录中,它将作为模板选项出现在帖子的编辑页面中。

解决方案2

这可以使用template_redirect钩子来实现。

在functions.php文件中:

 function my_redirect()
 {
      global $post;

      if( get_post_type( $post ) == "my_cpt" && is_single() )
      {
           if( file_exists( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' ) )
           {
                include( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' );
                exit;
           }
      }
 }
 add_action( 'template_redirect', 'my_redirect' );

编辑

添加file_exists支票


你为什么在exit;那里?
kaiser 2012年

@kaiser一定在我当时遵循的任何教程中,如果没有必要,我将其删除。
Shane

1
@kaiser:exit()防止加载默认模板是必需的。
scribu 2012年

解决方案1仅适用于页面,不适用于帖子。
IXN 2015年

2

最佳答案(来自4年前)不再起作用,但是WordPress Codex 在此处提供了解决方案

<?php
function add_posttype_slug_template( $single_template )
{
    $object = get_queried_object();
    $single_postType_postName_template = locate_template("single-{$object->post_type}-{$object->post_name}.php");
    if( file_exists( $single_postType_postName_template ) )
    {
        return $single_postType_postName_template;
    } else {
        return $single_template;
    }
}
add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
?>

1

使用页面模板

可伸缩性的另一种方法是将页面模板下拉功能复制到page自定义帖子类型的帖子类型上。

可重用代码

代码重复不是一个好习惯。超时会导致代码库严重膨胀,从而使开发人员难以管理。与其为每个子弹创建一个模板,不如说您将需要一个可以重用的一对多模板,而不是一对一的模板后模板。

代码

# Define your custom post type string
define('MY_CUSTOM_POST_TYPE', 'my-cpt');

/**
 * Register the meta box
 */
add_action('add_meta_boxes', 'page_templates_dropdown_metabox');
function page_templates_dropdown_metabox(){
    add_meta_box(
        MY_CUSTOM_POST_TYPE.'-page-template',
        __('Template', 'rainbow'),
        'render_page_template_dropdown_metabox',
        MY_CUSTOM_POST_TYPE,
        'side', #I prefer placement under the post actions meta box
        'low'
    );
}

/**
 * Render your metabox - This code is similar to what is rendered on the page post type
 * @return void
 */
function render_page_template_dropdown_metabox(){
    global $post;
    $template = get_post_meta($post->ID, '_wp_page_template', true);
    echo "
        <label class='screen-reader-text' for='page_template'>Page Template</label>
            <select name='_wp_page_template' id='page_template'>
            <option value='default'>Default Template</option>";
            page_template_dropdown($template);
    echo "</select>";
}

/**
 * Save the page template
 * @return void
 */
function save_page_template($post_id){

    # Skip the auto saves
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    elseif ( defined( 'DOING_AJAX' ) && DOING_AJAX )
        return;
    elseif ( defined( 'DOING_CRON' ) && DOING_CRON )
        return;

    # Only update the page template meta if we are on our specific post type
    elseif(MY_CUSTOM_POST_TYPE === $_POST['post_type'])
        update_post_meta($post_id, '_wp_page_template', esc_attr($_POST['_wp_page_template']));
}
add_action('save_post', 'save_page_template');


/**
 * Set the page template
 * @param string $template The determined template from the WordPress brain
 * @return string $template Full path to predefined or custom page template
 */
function set_page_template($template){
    global $post;
    if(MY_CUSTOM_POST_TYPE === $post->post_type){
        $custom_template = get_post_meta($post->ID, '_wp_page_template', true);
        if($custom_template)
            #since our dropdown only gives the basename, use the locate_template() function to easily find the full path
            return locate_template($custom_template);
    }
    return $template;
}
add_filter('single_template', 'set_page_template');

这是一个较晚的答案,但是我认为这将是有价值的,因为据我所知,网络上尚无人记录这种方法。希望这可以帮助某人。


1

就我而言,我具有“专辑”分类法链接的“专辑”和“曲目”自定义帖子类型。我希望能够根据专辑的分类法为专辑和曲目帖子使用不同的“单一”模板。

基于上面Kaiser的回答,我编写了这段代码。它运作良好。
注意。我不需要add_action()。

// Add an additional template option to the template hierarchy
add_filter( 'single_template', 'add_albumtrack_taxslug_template', 10, 1 );
function add_albumtrack_taxslug_template( $orig_template_path )
{
    // at this point, $orig_template_path is an absolute located path to the preferred single template.

    $object = get_queried_object();

    if ( ! (
        // specify another template option only for Album and Track post types.
        in_array( $object->post_type, array( 'gregory-cpt-album','gregory-cpt-track' )) &&
        // check that the Album taxonomy has been registered.
        taxonomy_exists( 'gregory-tax-album' ) &&
        // get the Album taxonomy term for the current post.
        $album_tax = wp_get_object_terms( $object->ID, 'gregory-tax-album' )
        ))
        return $orig_template_path;

    // assemble template name
    // assumption: only one Album taxonomy term per post. we use the first object in the array.
    $template = "single-{$object->post_type}-{$album_tax[0]->slug}.php";
    $template = locate_template( $template );
    return ( !empty( $template ) ? $template : $orig_template_path );
}

现在,我可以创建名为single-gregory-cpt-track-tax-serendipity.php的模板,并且single-gregory-cpt-album-tax-serendipity.php和WP将自动使用它们;“税收偶然性”是第一个“专辑”分类法术语的标语。

作为参考,“ single_template”过滤器挂钩在以下
位置声明:/wp-includes/theme.php:get_query_template()

感谢Kaiser提供的示例代码。

干杯,格雷戈里


嗨,格雷格-欢迎来到WPSE。请仅将答案发布为问题的答案,而不是后续问题。如果您有一个现有答案无法回答的问题,且太大而无法发表评论,请打开另一个问题:)
Stephen Harris

1
字符串/数组问题已删除:-)
Gregory

1
“感谢Kaiser提供示例代码。” - 别客气。
kaiser 2012年

对你起作用吗?首先,'$ template'不应在您的代码中被注释..我认为,代替'$ album_tax [0]-> slug'应该有'$ object-> post_name',不是吗?
gregmatys 2013年

修复了$ template行。谢谢。$ object-> post_name?没有。那会返回帖子的内容,但是我需要帖子链接到的相册的内容。
2013年

0

更新Brians代码后,我发现当不使用下拉框时,“默认”模板选项被保存到wp_page_template中,这导致它尝试查找名为default的模板。此更改仅在保存时检查选项“ default”,然后删除帖子元(如果您将模板选项更改为默认值,则很有用)

elseif(MY_CUSTOM_POST_TYPE === $ _POST ['post_type']){

if(esc_attr($ _ POST ['_ wp_page_template'])===“默认”):
    delete_post_meta($ post_id,'_wp_page_template');
其他:
    update_post_meta($ post_id,'_wp_page_template',esc_attr($ _ POST ['_ wp_page_template']));;
万一;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.