đơn - {$ post_type} - {slug} .php cho các loại bài đăng tùy chỉnh


20

Phần yêu thích của tôi trong hệ thống phân cấp mẫu Wordpress là khả năng tạo nhanh các tệp mẫu cho các trang bằng sên, mà không phải chỉnh sửa trang trong Wordpress để chọn mẫu.

Hiện tại chúng tôi có thể làm điều này:

trang- {sên} .php

Nhưng tôi muốn có thể làm điều này:

đơn- {post_type} - {slug} .php

Vì vậy, ví dụ, trong một loại bài đăng được gọi review, tôi có thể tạo mẫu cho bài đăng có tên "Đánh giá tuyệt vời của tôi" tạisingle-review-my-great-review.php

Có ai đã thiết lập điều này trước đây? single-{post_type}-{slug}.php


Không bao giờ sử dụng một thiết lập như vậy trước đây, nhưng nếu nó quá phức tạp, tại sao không chỉ tạo một tệp mẫu và liên kết nó với đánh giá trong câu hỏi.
Shane

WP 3.4 tự động tìm nạp single-{post_type}-{slug}.php, vì vậy nâng cấp lên WP 3.4 là một tùy chọn khác.
vào

Câu trả lời:


19

A) Cơ sở trong lõi

Như bạn có thể thấy trong phần giải thích Phân cấp mẫu Codex , single-{$post_type}.phpđã được hỗ trợ.


B) Mở rộng hệ thống phân cấp cốt lõi

Bây giờ có một số bộ lọc và móc bên trong /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • AND: một bộ lọc cụ thể bên trong get_query_template( $type, ... )có tên:"$type}_template"

B.1) Cách thức hoạt động

  1. Trong tệp trình tải mẫu, mẫu được tải bởi một truy vấn var / wp_query có điều kiện : is_*().
  2. Các điều kiện sau đó kích hoạt (trong trường hợp mẫu "đơn"): is_single() && $template = get_single_template()
  3. Điều này dẫn tới sau đó get_query_template( $type, $templates ), nơi $typesingle
  4. Sau đó, chúng tôi có "{$type}_template"bộ lọc

C) Giải pháp

Vì chúng tôi chỉ muốn mở rộng cấu trúc phân cấp với một mẫu được tải trước"single-{$object->post_type}.php" mẫu thực tế , chúng tôi sẽ chặn cấu trúc phân cấp và thêm mẫu mới vào đầu mảng mẫu.

// 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 );

LƯU Ý: (Nếu bạn muốn sử dụng một cái gì đó không phải là sên đối tượng mặc định) Bạn sẽ phải điều chỉnh $slugtheo cấu trúc permalink của mình. Chỉ cần sử dụng bất cứ điều gì bạn cần từ toàn cầu (object) $post.

Vé Trac

Vì cách tiếp cận trên hiện không được hỗ trợ (bạn chỉ có thể lọc đường dẫn được định vị tuyệt đối theo cách này), đây là danh sách các vé trac:


Tôi muốn kiểm tra điều này, nhưng có vẻ như thiếu một cái gì đó trong dòng add_filter của bạn ở cuối.
supertrue

@supertrue Bắt tốt. :) Tìm thấy một thiếu khác )trong bộ lọc. Đã sửa. Có thể bạn muốn trao đổi dấu gạch ngang với một gạch dưới trước khi sên bên trong mẫu. Chỉ để cho hậu tố nổi bật hơn khi nhìn qua các mẫu.
kaiser

Gây ra lỗi này trên trang web: Cảnh báo: Array_unshift () [function.array-unshift]: Đối số đầu tiên phải là một mảng trong [dòng chứa mảng_unshift]
supertrue

Ok, nhưng sau đó một cái gì đó khác đang chặn các mẫu cốt lõi. Các chức năng hoạt động tốt và $templateslà một mảng. Xem các chức năng cốt lõi trong pastebin này (không có ngày hết hạn). Hãy chắc chắn rằng bạn đã kiểm tra điều này với một bản cài đặt không có plugin và chủ đề mặc định. Sau đó kích hoạt từng cái một và xem nếu lỗi vẫn xảy ra.
kaiser

Vâng, tôi đã gỡ lỗi này và tôi nhận được đường dẫn tuyệt đối cuối cùng của mẫu tìm thấy đầu tiên trở lại dưới dạng chuỗi. Tôi sẽ phải nói chuyện với một số nhà phát triển cốt lõi về điều này, trước khi thay đổi câu trả lời. Ngoài ra: Tôi đã trộn lẫn một cái gì đó: slugchỉ có sẵn cho các điều khoản và phân loại. Bạn nên thay thế $post->post_namebằng những gì phù hợp với cấu trúc permalink của bạn. Hiện tại không có cách nào để tự động làm điều này cho tất cả các trường hợp với việc truy xuất và thay thế đường dẫn tùy thuộc vào quy tắc perma struct và viết lại của bạn. Mong đợi một bản cập nhật khác.
kaiser

4

Sau khi hình ảnh Template Hierarchy , tôi không thấy một tùy chọn như vậy.

Vì vậy, đây là cách tôi sẽ đi về nó:

Giải pháp 1 (Theo ý kiến ​​của tôi)

Tạo một tệp mẫu và liên kết nó với đánh giá

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

Thêm tệp php mẫu trong thư mục chủ đề của bạn, nó sẽ xuất hiện dưới dạng tùy chọn mẫu trong trang chỉnh sửa bài đăng của bạn.

Giải pháp 2

Điều này có thể có thể đạt được bằng cách sử dụng template_redirecthook.

Trong tệp tin.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' );

CHỈNH SỬA

Đã thêm file_existskiểm tra


Tại sao bạn exit;ở đó
kaiser

@kaiser Phải có trong bất kỳ hướng dẫn nào tôi đã làm theo vào thời điểm đó, nếu không cần thiết tôi sẽ xóa nó.
Shane

1
@kaiser: exit()Cần thiết để ngăn tải mẫu mặc định.
scribu

Giải pháp 1 sẽ chỉ hoạt động cho các trang, không phải bài viết.
IXN

2

Câu trả lời hàng đầu (từ 4 năm trước) không còn hoạt động nữa, nhưng codex WordPress có giải pháp ở đây :

<?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

Sử dụng mẫu trang

Một cách tiếp cận khác về khả năng mở rộng sẽ là sao chép chức năng thả xuống của mẫu trang trên pageloại bài đăng cho loại bài đăng tùy chỉnh của bạn.

Mã tái sử dụng

Sao chép trong mã không phải là một thực hành tốt. Làm thêm giờ nó có thể gây ra sự phình to nghiêm trọng cho một codebase khi đó làm cho nhà phát triển rất khó quản lý. Thay vì tạo một mẫu cho mỗi con sên, rất có thể bạn sẽ cần một mẫu một-nhiều có thể được sử dụng lại thay vì một-một-một-mẫu.

Mật mã

# 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');

Đây là một chút của một câu trả lời muộn, nhưng tôi nghĩ rằng nó sẽ có giá trị vì không ai trên web đã ghi lại cách tiếp cận này như tôi có thể nói. Mong rằng nó giúp ai đó thoát.


1

Trong trường hợp của tôi, tôi có các loại bài đăng tùy chỉnh Album và Theo dõi được liên kết bởi phân loại Album. Tôi muốn có thể sử dụng các mẫu Đơn khác nhau cho các bài đăng Album và Theo dõi tùy thuộc vào phân loại Album của họ.

Dựa trên câu trả lời của Kaiser ở trên, tôi đã viết mã này. Nó hoạt động tốt.
Chú thích. Tôi không cần 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 );
}

Bây giờ tôi có thể tạo các mẫu có tên là gregory-cpt-track-tax-serendipity.php và single-gregory-cpt-album-tax-serendipity.php và WP sẽ tự động sử dụng chúng; 'Serendipity' là sên cho thuật ngữ phân loại Album đầu tiên.

để tham khảo, hook bộ lọc 'single_template' được khai báo trong:
/wp-includes/theme.php:get_query_template()

Cảm ơn Kaiser về mã mẫu.

Chúc mừng, Gregory


Xin chào Greg - chào mừng bạn đến với WPSE. Vui lòng chỉ gửi câu trả lời dưới dạng câu trả lời cho các câu hỏi - không theo dõi câu hỏi. Nếu bạn có một câu hỏi không được trả lời bởi một câu trả lời hiện có và quá lớn cho một nhận xét, vui lòng mở một câu hỏi khác :)
Stephen Harris

1
câu hỏi chuỗi / mảng đã bị xóa :-)
Gregory

1
"Cảm ơn Kaiser vì mã mẫu." - Không có gì.
kaiser

Nó làm việc cho bạn? trước hết, '$ template' không nên được nhận xét trong mã của bạn .. và tôi nghĩ rằng thay vì '$ album_tax [0] -> slug' thì nên có '$ object-> post_name', phải không?
gregmatys

đã sửa lỗi dòng mẫu $. cảm ơn bạn. $ object-> post_name? Không. điều đó sẽ trả lại sên của bài đăng, nhưng tôi cần sên của album mà bài đăng được liên kết đến.
Gregory

0

Cập nhật mã Brians, tôi thấy rằng khi hộp thả xuống không được sử dụng, tùy chọn mẫu "mặc định" đã được lưu vào wp_page_template khiến nó phải thử và tìm một mẫu có tên mặc định. thay đổi này chỉ kiểm tra tùy chọn "mặc định" khi lưu và xóa meta bài đăng thay thế (hữu ích nếu bạn thay đổi tùy chọn mẫu trở về mặc định)

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

if (esc_attr ($ _ POST ['_ wp_page_template']) === "mặc định"):
    xóa_post_meta ($ post_id, '_wp_page_template');
khác:
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template']));
endif;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.