tunggal - {$ post_type} - {slug} .php untuk jenis posting khusus

20

Bagian favorit saya dari hierarki templat Wordpress adalah kemampuan untuk dengan cepat membuat file templat untuk halaman dengan siput, tanpa harus mengedit halaman di Wordpress untuk memilih templat.

Saat ini kami dapat melakukan ini:

halaman- {slug} .php

Tetapi saya ingin dapat melakukan ini:

single- {post_type} - {slug} .php

Jadi, misalnya, dalam jenis posting yang disebut review, saya dapat membuat templat untuk posting yang disebut "My Great Review" disingle-review-my-great-review.php

Adakah yang sudah mengatur ini sebelumnya? single-{post_type}-{slug}.php

supertrue
sumber
Belum pernah menggunakan pengaturan seperti itu sebelumnya, tetapi jika terlalu rumit, mengapa tidak hanya membuat file templat dan mengaitkannya dengan ulasan yang dimaksud.
Shane
WP 3.4 diambil secara otomatis single-{post_type}-{slug}.php, jadi meningkatkan ke WP 3.4 adalah pilihan lain.
yitwail

Jawaban:

19

A) Basis di Inti

Seperti yang Anda lihat di penjelasan Codex Template Hierarchy, single-{$post_type}.phpsudah didukung.


B) Memperluas Hirarki inti

Sekarang dengan senang hati ada beberapa filter dan kait di dalamnya /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • DAN: filter khusus di dalam get_query_template( $type, ... )bernama:"$type}_template"

B.1) Cara kerjanya

  1. Di dalam file loader Template, template akan dimuat oleh query var / WP_Query kondisional: is_*().
  2. Kondisional kemudian memicu (dalam kasus templat "tunggal"): is_single() && $template = get_single_template()
  3. Hal ini memicu kemudian get_query_template( $type, $templates ), di mana $typeadalahsingle
  4. Lalu kita memiliki "{$type}_template"filter

C) Solusinya

Karena kami hanya ingin memperluas hierarki dengan satu templat yang dimuat sebelum"single-{$object->post_type}.php" templat yang sebenarnya , kami akan mencegat hierarki dan menambahkan templat baru ke awal larik templat.

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

CATATAN: (Jika Anda ingin menggunakan sesuatu selain dari objek standar siput) Anda harus menyesuaikan $slugsesuai dengan permalink-struktur Anda. Cukup gunakan apa pun yang Anda butuhkan dari global (object) $post.

Tiket Trac

Karena pendekatan di atas saat ini tidak didukung (Anda hanya dapat memfilter jalur lokasi absolut dengan cara ini), berikut adalah daftar tiket trac:

kaisar
sumber
Saya ingin menguji ini, tetapi sepertinya ada sesuatu yang hilang di baris add_filter Anda di akhir.
supertrue
@supertrue Tangkapan bagus. :) Menemukan satu lagi yang hilang )di dalam filter. Tetap. Mungkin Anda ingin menukar tanda hubung dengan garis bawah sebelum siput di dalam templat. Hanya untuk membiarkan sufiks menonjol dengan lebih baik ketika melihat di atas templat.
kaiser
Penyebab kesalahan ini di seluruh situs: Peringatan: array_unshift () [function.array-unshift]: Argumen pertama harus berupa array di [baris yang mengandung array_unshift]
supertrue
Ok, tapi kemudian ada sesuatu yang mencegat template inti. Fungsi ini berfungsi dengan baik dan $templatesmerupakan array. Lihat fungsi inti dalam pastebin ini (tidak ada tanggal kedaluwarsa). Pastikan Anda mengujinya dengan pemasangan tanpa plugin dan tema default. Kemudian aktifkan satu demi satu dan lihat apakah kesalahan masih terjadi.
kaiser
Ya, saya men-debug ini dan saya mendapatkan path absolut terakhir dari template yang ditemukan kembali sebagai string. Saya harus berbicara dengan beberapa pengembang inti tentang ini, sebelum mengubah jawabannya. Juga: Saya mencampuradukkan sesuatu: slughanya tersedia untuk persyaratan dan taksonomi. Anda harus mengganti $post->post_namedengan yang sesuai dengan struktur permalink Anda. Saat ini tidak ada cara untuk melakukan ini secara otomatis untuk semua kasus dengan mengambil dan mengganti path tergantung pada perma struct Anda dan aturan penulisan ulang. Harapkan pembaruan lainnya.
kaiser
4

Mengikuti gambar Templat Hirarki , saya tidak melihat opsi seperti itu.

Jadi, inilah cara saya melakukannya:

Solusi 1 (Terbaik menurut saya)

Buat file template dan kaitkan ke review

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

Menambahkan file php template di direktori tema Anda, itu akan muncul sebagai opsi template di halaman edit posting Anda.

Solusi 2

Ini mungkin bisa dicapai menggunakan template_redirecthook.

Dalam file 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' );

EDIT

Menambahkan file_existscek

Shane
sumber
Kenapa kamu exit;disana?
kaiser
@kaiser Pasti ada dalam tutorial apa pun yang saya ikuti pada saat itu, jika tidak perlu saya akan menghapusnya.
Shane
1
@kaiser: Hal exit()ini diperlukan untuk mencegah pemuatan templat default.
scribu
Solusi 1 hanya akan berfungsi untuk halaman, bukan posting.
IXN
2

Jawaban teratas (dari 4 tahun lalu) tidak lagi berfungsi, tetapi kodeks WordPress memiliki solusinya di sini :

<?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 );
?>
skladany
sumber
1

Gunakan Templat Halaman

Pendekatan lain untuk skalabilitas adalah menduplikasi fungsionalitas drop-down templat halaman pada pagejenis posting untuk jenis posting kustom Anda.

Kode yang dapat digunakan kembali

Duplikasi dalam kode bukanlah praktik yang baik. Lembur itu dapat menyebabkan mengasapi parah ke basis kode ketika kemudian membuatnya sangat sulit bagi pengembang untuk mengelola. Alih-alih membuat templat untuk setiap siput tunggal, Anda kemungkinan besar akan membutuhkan templat satu-ke-banyak yang dapat digunakan kembali alih-alih satu-ke-satu pasca-ke-templat.

Kode

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

Ini sedikit jawaban yang terlambat, tetapi saya pikir ini akan berharga karena tidak ada seorang pun di web yang mendokumentasikan pendekatan ini sejauh yang saya tahu. Semoga ini bisa membantu seseorang.

Brian Fegter
sumber
1

Dalam kasus saya, saya memiliki Album dan Lacak jenis kiriman khusus yang ditautkan oleh taksonomi Album. Saya ingin dapat menggunakan template tunggal yang berbeda untuk Album dan Lacak posting tergantung pada taksonomi Album mereka.

Berdasarkan jawaban Kaiser di atas, saya menulis kode ini. Itu bekerja dengan baik.
Catatan. Saya tidak memerlukan 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 );
}

Sekarang saya dapat membuat templat bernama single-gregory-cpt-track-tax-serendipity.php dan single-gregory-cpt-album-tax-serendipity.php dan WP akan menggunakannya secara otomatis; 'tax-serendipity' adalah siput untuk istilah taksonomi Album pertama.

untuk referensi, kait filter 'single_template' dinyatakan di:
/wp-includes/theme.php:get_query_template()

Terima kasih Kaiser untuk kode sampel.

Salam, Gregory

Gregory
sumber
Hai Greg - selamat datang di WPSE. Harap hanya mengirim jawaban sebagai jawaban atas pertanyaan - bukan menindaklanjuti pertanyaan. Jika Anda memiliki pertanyaan yang tidak dijawab oleh jawaban yang ada dan terlalu besar untuk dikomentari, silakan buka pertanyaan lain :)
Stephen Harris
1
pertanyaan string / array telah dihapus :-)
Gregory
1
"Terima kasih, Kaiser untuk kode sampel." - Sama-sama.
kaiser
apakah itu bekerja untukmu? pertama-tama, '$ template' tidak boleh dikomentari dalam kode Anda .. dan saya pikir alih-alih '$ album_tax [0] -> slug' harus ada '$ object-> post_name', bukan?
gregmatys
memperbaiki baris $ template. Terima kasih. $ object-> post_name? tidak. itu akan mengembalikan siput pos, tapi saya perlu siput album yang terhubung dengan pos.
Gregory
0

Pembaruan untuk kode Brians, saya menemukan bahwa ketika kotak dropdown tidak digunakan opsi template "default" disimpan ke wp_page_template yang menyebabkannya mencoba dan menemukan template yang disebut default. perubahan ini hanya memeriksa opsi "default" saat menyimpan dan menghapus meta pos sebagai gantinya (berguna jika Anda mengubah opsi templat kembali ke 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');
lain :
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template']));
berakhir jika;
}
Menandai
sumber