맞춤 게시물 유형에 대한 single-{$ post_type}-{slug} .php


20

Wordpress 템플릿 계층 에서 내가 가장 좋아하는 부분은 템플릿 을 선택하기 위해 Wordpress에서 페이지를 편집 할 필요없이 슬러그로 페이지에 대한 템플릿 파일을 빠르게 만들 수 있다는 것입니다.

우리는 현재 이것을 할 수 있습니다 :

page- {slug} .php

그러나 나는 이것을 할 수 있기를 원합니다.

single- {post_type}-{slug} .php

예를 들어이라는 게시물 유형에서 review'My Great 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

답변:


19

A) 핵심의 기초

Codex Template Hierarchy 설명 에서 볼 수 있듯이 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 )$type입니다single
  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.

트랙 티켓

위의 접근 방식은 현재 지원 되지 않으므로 (이 방법으로 절대 경로 만 필터링 할 수 있음) trac 티켓 목록은 다음과 같습니다.


이것을 테스트하고 싶지만 끝에 add_filter 줄에 누락 된 것처럼 보입니다.
supertrue

@supertrue 좋은 캐치. :) )필터 내부에 다른 부분이 없습니다 . 결정된. 템플릿 내부의 슬러그 앞에 대시를 밑줄로 바꾸고 싶을 수도 있습니다. 템플릿을 살펴볼 때 접미사가 더 잘 보이도록하기 위해서입니다.
kaiser

사이트 전체에서이 오류가 발생합니다. 경고 : array_unshift () [function.array-unshift] : 첫 번째 인수는 [
line_

좋아, 그러나 다른 무언가가 핵심 템플릿을 가로 채고 있습니다. 이 기능은 제대로 작동 $templates하며 배열입니다. 이 pastebin 의 핵심 기능을 참조하십시오 (만료 날짜 없음). 플러그인 이 없는 설치 및 기본 테마로 이를 테스트해야합니다 . 그런 다음 서로를 활성화하고 오류가 계속 발생하는지 확인하십시오.
카이저

네, 이것을 디버깅했습니다. 첫 번째 발견 된 템플릿의 최종 절대 경로를 문자열로 다시 얻습니다. 답변을 변경하기 전에 핵심 개발자에게 이야기해야합니다. 또한 : 나는 무언가를 섞었습니다 : slug용어와 분류법에서만 사용할 수 있습니다. $post->post_name퍼머 링크 구조에 맞는 것으로 바꿔야 합니다. 현재 영구 구조 및 재 작성 규칙에 따라 경로를 검색하고 바꾸는 모든 경우에 대해 자동으로이 작업을 수행 할 수있는 방법이 없습니다. 다른 업데이트가 필요합니다.
카이저

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 필자가 필요하지 않은 경우 내가 따라온 모든 튜토리얼에 있어야 했으므로 제거하겠습니다.
Shane

1
@kaiser : exit()기본 템플릿을로드하지 못하게합니다.
scribu

해결 방법 1은 게시물이 아닌 페이지에만 작동합니다.
IXN

2

4 년 전의 최고 답변은 더 이상 작동하지 않지만 WordPress 코덱 은 해결책이 있습니다 .

<?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가 자동으로 사용합니다. 'tax-serendipity'는 첫 번째 앨범 분류 용어의 슬러그입니다.

참고로 'single_template'필터 후크는
/wp-includes/theme.php에 선언되어 있습니다 .get_query_template()

샘플 코드에 대해 Kaiser에게 감사합니다.

건배, 그레고리


안녕하세요 그렉-WPSE에 오신 것을 환영합니다. 후속 답변이 아닌 질문에 대한 답변으로 답변을 게시하십시오. 기존 답변에 의해 답변되지 않고 의견에 비해 너무 큰 질문이있는 경우 다른 질문을여십시오 :)
Stephen Harris

1
문자열 / 배열 질문이 제거되었습니다 :-)
Gregory

1
"샘플 코드에 대해 Kaiser에게 감사합니다." - 천만에요.
카이저

그것은 당신을 위해 작동합니까? 우선, 코드에서 '$ template'에 주석을 달아서는 안됩니다. 그리고 '$ album_tax [0]-> slug'대신에 '$ object-> post_name'이 있어야한다고 생각하지 않습니까?
gregmatys

$ template 줄을 수정했습니다. 고맙습니다. $ object-> post_name? 아니. 게시물의 슬러그를 반환하지만 게시물이 연결된 앨범의 슬러그가 필요합니다.
Gregory

0

Brians 코드를 업데이트 한 결과 드롭 다운 상자를 사용하지 않을 때 "default"템플릿 옵션이 wp_page_template에 저장되어 default라는 템플릿을 찾게되었습니다. 이 변경 사항은 저장시 "default"옵션 만 확인하고 대신 포스트 메타를 삭제합니다 (템플릿 옵션을 기본값으로 다시 변경 한 경우 유용함)

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

if (esc_attr ($ _ POST [ '_ wp_page_template']) === "default") :
    delete_post_meta ($ post_id, '_wp_page_template');
다른 :
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST [ '_ wp_page_template']));
엔디 프;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.