single - {$ post_type} - {slug} .php สำหรับประเภทโพสต์ที่กำหนดเอง


20

ส่วนที่ฉันชอบในลำดับชั้นของเทมเพลต Wordpress คือความสามารถในการสร้างไฟล์เทมเพลตสำหรับหน้าอย่างรวดเร็วโดยใช้ทากโดยไม่ต้องแก้ไขหน้าใน Wordpress เพื่อเลือกเทมเพลต

ขณะนี้เราสามารถทำสิ่งนี้:

page- {} กระสุน .php

แต่ฉันอยากจะทำสิ่งนี้:

เดียว {post_type} - {} กระสุน .php

ตัวอย่างเช่นในประเภทโพสต์ที่เรียกว่าreviewฉันสามารถสร้างเทมเพลตสำหรับโพสต์ที่เรียกว่า "My Great Review" ที่single-review-my-great-review.php

มีใครตั้งค่านี้มาก่อนหรือไม่ single-{post_type}-{slug}.php


ไม่เคยใช้การตั้งค่าแบบนี้มาก่อน แต่ถ้ามันซับซ้อนเกินไปทำไมไม่เพียงสร้างไฟล์เทมเพลตและเชื่อมโยงกับการตรวจสอบที่เป็นปัญหา
เชน

WP 3.4 ดึงข้อมูลโดยอัตโนมัติsingle-{post_type}-{slug}.phpดังนั้นการอัพเกรดเป็น WP 3.4 เป็นอีกตัวเลือกหนึ่ง
yitwail

คำตอบ:


19

A) ฐานในแกนกลาง

อย่างที่คุณเห็นในคำอธิบายลำดับชั้นเทมเพลตCodexsingle-{$post_type}.phpได้รับการสนับสนุนแล้ว


B) การขยายลำดับชั้นของแกนหลัก

ตอนนี้เรามีตัวกรองและตะขออยู่ภายใน/wp-includes/template-loader.phpด้วยความยินดี

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • และ: ตัวกรองเฉพาะภายใน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ตามโครงสร้าง Permalink ของคุณ (object) $postใช้เพียงแค่สิ่งที่คุณต้องการจากทั่วโลก

ตั๋ว Trac

เนื่องจากวิธีการข้างต้นไม่ได้รับการสนับสนุน (คุณสามารถกรองเส้นทางที่อยู่แบบสัมบูรณ์ได้ด้วยวิธีนี้) นี่คือรายการตั๋ว trac:


ฉันต้องการทดสอบสิ่งนี้ แต่ดูเหมือนว่ามีบางสิ่งขาดหายไปในบรรทัด add_filter ของคุณในตอนท้าย
supertrue

@supertrue จับได้ดี :) พบอีกอย่างหนึ่งที่ขาดหายไป)ในตัวกรอง แก้ไขแล้ว. บางทีคุณอาจต้องการเปลี่ยนเส้นประด้วยการขีดเส้นใต้ก่อนทากที่อยู่ภายในแม่แบบ เพียงเพื่อให้คำต่อท้ายโดดเด่นกว่าเมื่อมองดูเทมเพลต
ไกเซอร์

ทำให้เกิดข้อผิดพลาดนี้ทั่วทั้งไซต์: คำเตือน: array_unshift () [function.array-unshift]: อาร์กิวเมนต์แรกควรเป็นอาร์เรย์ใน [บรรทัดที่มี array_unshift]
supertrue

ตกลง แต่อย่างอื่นก็มีการขัดขวางเทมเพลตหลัก ฟังก์ชั่นใช้งานได้ดีและ$templatesเป็นอาร์เรย์ ดูฟังก์ชั่นหลักในpastebin นี้ (ไม่มีวันหมดอายุ) ตรวจสอบให้แน่ใจว่าคุณทดสอบสิ่งนี้ด้วยการติดตั้งโดยไม่ต้องใช้ปลั๊กอินและชุดรูปแบบเริ่มต้น จากนั้นเปิดใช้งานกันและดูว่าข้อผิดพลาดยังคงเกิดขึ้น
ไกเซอร์

ใช่ฉันแก้จุดบกพร่องนี้ฉันได้รับเส้นทางที่แน่นอนสุดท้ายของแม่แบบที่พบครั้งแรกกลับมาเป็นสตริง ฉันจะต้องคุยกับผู้พัฒนาหลักเกี่ยวกับเรื่องนี้ก่อนที่จะแก้ไขคำตอบ นอกจากนี้: ฉันผสมบางอย่างเข้าด้วยกัน: slugใช้ได้เฉพาะกับข้อกำหนดและ taxonomies คุณควรแทนที่$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 ต้องเป็นกวดวิชาใดก็ตามที่ฉันตามมาในเวลานั้นหากไม่จำเป็นฉันจะลบออก
เชน

1
@kaiser: exit()จำเป็นเพื่อป้องกันการโหลดเทมเพลตเริ่มต้น
scribu

โซลูชันที่ 1 จะใช้งานได้กับหน้าเท่านั้นไม่ใช่โพสต์
IXN

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ประเภทโพสต์สำหรับประเภทโพสต์ที่คุณกำหนดเอง

รหัสนำมาใช้ใหม่

การทำสำเนาในโค้ดไม่ใช่วิธีปฏิบัติที่ดี การทำงานล่วงเวลาอาจทำให้ bloat รุนแรงถึง codebase เมื่อนั้นทำให้นักพัฒนาจัดการยากมาก แทนที่จะสร้างเทมเพลตสำหรับกระสุนแต่ละอันคุณมักจะต้องมีเทมเพลตแบบหนึ่งต่อหลายที่สามารถนำมาใช้ซ้ำได้แทนที่จะเป็นเทมเพลตแบบตัวต่อตัว

รหัส

# 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

ในกรณีของฉันฉันมีอัลบั้มและติดตามชนิดโพสต์ที่กำหนดเองที่เชื่อมโยงโดย taxonomy ของอัลบั้ม ฉันต้องการที่จะใช้เทมเพลต Single ที่แตกต่างกันสำหรับโพสต์อัลบั้มและแทร็กขึ้นอยู่กับอนุกรมวิธานของอัลบั้ม

ตามคำตอบของไกเซอร์ฉันเขียนรหัสนี้ มันใช้งานได้ดี
บันทึก. ฉันไม่ต้องการ 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 สำหรับตัวอย่างโค้ด

ไชโยเกรกอรี่


สวัสดี Greg - ยินดีต้อนรับสู่ WPSE โปรดโพสต์คำตอบเพื่อเป็นคำตอบสำหรับคำถามเท่านั้นไม่ใช่คำถามติดตาม หากคุณมีคำถามที่ไม่ได้รับคำตอบจากคำตอบที่มีอยู่และใหญ่เกินไปสำหรับความคิดเห็นโปรดเปิดคำถามอื่น :)
สตีเฟ่นแฮร์ริส

1
คำถามสตริง / อาร์เรย์ได้ถูกลบออก :-)
เกรกอรี่

1
"ขอบคุณ Kaiser สำหรับโค้ดตัวอย่าง" - ยินดีต้อนรับ
ไกเซอร์

มันได้ผลสำหรับคุณ ก่อนอื่นเลย '$ template' ไม่ควรใส่ความคิดเห็นในรหัสของคุณ .. และฉันคิดว่าแทนที่จะเป็น '$ album_tax [0] -> กระสุน' ควรมี '$ object-> post_name' ใช่ไหม?
gregmatys

แก้ไขบรรทัด $ template ขอขอบคุณ. $ วัตถุ> POST_NAME? ไม่ ที่จะส่งคืนกระสุนของโพสต์ แต่ฉันต้องการกระสุนของอัลบั้มที่เชื่อมโยงกับโพสต์
เกรกอรี่

0

อัปเดตสำหรับรหัส Brians ฉันพบว่าเมื่อไม่ได้ใช้ช่องแบบเลื่อนลงตัวเลือกแม่แบบ "เริ่มต้น" ได้ถูกบันทึกลงใน wp_page_template ซึ่งเป็นสาเหตุให้พยายามค้นหาแม่แบบที่เรียกว่าเป็นค่าเริ่มต้น การเปลี่ยนแปลงนี้จะตรวจสอบตัวเลือก "เริ่มต้น" เมื่อบันทึกและลบเมตาโพสต์แทน (มีประโยชน์หากคุณเปลี่ยนตัวเลือกเทมเพลตกลับไปเป็นค่าเริ่มต้น)

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']));
endif;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.