single-{$post_type}-{slug}.php pentru tipuri personalizate de postări

2 feb. 2012, 18:36:50
Vizualizări: 16K
Voturi: 22

Partea mea preferată din ierarhia de template-uri WordPress este posibilitatea de a crea rapid fișiere de template pentru pagini după slug, fără a fi nevoie să editezi pagina în WordPress pentru a selecta un template.

În prezent putem face asta:

page-{slug}.php

Dar aș dori să pot face acest lucru:

single-{post_type}-{slug}.php

Astfel încât, de exemplu, pentru un post type numit review, să pot crea un template pentru un post numit "Recenzia mea minunată" în single-review-recenzia-mea-minunata.php

A mai configurat cineva acest lucru? single-{post_type}-{slug}.php

2
Comentarii

Nu am folosit niciodată o astfel de configurare înainte, dar dacă este prea complicată, de ce să nu creezi pur și simplu un fișier șablon și să-l asociezi cu recenzia în cauză.

Shane Shane
2 feb. 2012 18:53:50

WP 3.4 preia automat single-{post_type}-{slug}.php, așadar actualizarea la WP 3.4 este o altă opțiune.

yitwail yitwail
29 iul. 2012 20:56:33
Toate răspunsurile la întrebare 6
12
20

A) Baza în Nucleu

După cum puteți vedea în Codex explicația despre Ierarhia de Șabloane, single-{$post_type}.php este deja suportat.


B) Extinderea Ierarhiei Nucleare

Acum există, din fericire, niște filtre și hook-uri în /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • ȘI: un filtru specific în interiorul get_query_template( $type, ... ) numit: "$type}_template"

B.1) Cum funcționează

  1. În fișierul încărcătorului de șabloane, șablonul este încărcat printr-o condițională de query var/wp_query: is_*().
  2. Condiționala declanșează apoi (în cazul unui șablon "single"): is_single() && $template = get_single_template()
  3. Aceasta declanșează apoi get_query_template( $type, $templates ), unde $type este single
  4. Apoi avem filtrul "{$type}_template"

C) Soluția

Deoarece noi doar vrem să extindem ierarhia cu un șablon care este încărcat înainte de șablonul actual "single-{$object->post_type}.php", vom intercepta ierarhia și vom adăuga un nou șablon la începutul array-ului de șabloane.

// Extinde ierarhia
function add_posttype_slug_template( $templates )
{

    $object = get_queried_object();

    // Nou 
    $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
    // Ca în nucleu
    $templates[] = "single-{$object->post_type}.php";
    $templates[] = "single.php";

    return locate_template( $templates );    
}
// Acum adăugăm filtrul la hook-ul potrivit
function intercept_template_hierarchy()
{
    add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
}
add_action( 'template_redirect', 'intercept_template_hierarchy', 20 );

NOTĂ: (Dacă doriți să folosiți altceva decât slug-ul implicit al obiectului) Va trebui să ajustați $slug în funcție de structura permalink-urilor. Pur și simplu folosiți orice aveți nevoie din globalul (object) $post.

Tichete Trac

Deoarece abordarea de mai sus nu este în prezent suportată (puteți filtra doar calea absolută localizată în acest fel), iată o listă de tichete trac:

2 feb. 2012 19:25:45
Comentarii

Vreau să testez asta, dar se pare că lipsește ceva în linia ta add_filter de la final.

supertrue supertrue
2 feb. 2012 22:45:04

@supertrue Bună observație. :) Am găsit un alt ) lipsă în interiorul filtrului. Am remediat. Poate ai vrea să înlocuiești liniuța cu o subliniere înainte de slug în interiorul șablonului. Doar pentru a face sufixul să iasă în evidență mai bine când te uiți peste șabloane.

kaiser kaiser
3 feb. 2012 00:01:12

Cauzează această eroare pe tot site-ul: Avertisment: array_unshift() [function.array-unshift]: Primul argument ar trebui să fie un array în [linia care conține array_unshift]

supertrue supertrue
4 feb. 2012 02:02:30

Ok, dar atunci altceva interceptează șabloanele de bază. Funcția funcționează corect și $templates este un array. Vezi funcțiile de bază în acest pastebin (fără dată de expirare). Asigură-te că testezi asta cu o instalare fără plugin-uri și cu tema implicită. Apoi activează unul câte unul și vezi dacă eroarea mai apare.

kaiser kaiser
4 feb. 2012 02:47:49

Da, am depanat asta și am primit înapoi calea absolută finală a primului șablon găsit ca șir de caractere. Va trebui să vorbesc cu un dezvoltator de bază despre asta, înainte de a modifica răspunsul. De asemenea: am amestecat ceva: slug este disponibil doar pentru termeni și taxonomii. Ar trebui să înlocuiești $post->post_name cu ceea ce se potrivește cu structura ta de permalink-uri. În prezent, nu există nicio modalitate de a face asta automat pentru toate cazurile prin preluarea și înlocuirea căii în funcție de structura ta de permalink-uri și regulile de rescriere. Așteaptă o altă actualizare.

kaiser kaiser
4 feb. 2012 03:19:40

Ți-am lăsat o versiune funcțională - totuși, aceasta nu este satisfăcătoare (copierea/inserarea array-ului de bază și apoi adăugarea lui din nou într-o funcție personalizată).

kaiser kaiser
4 feb. 2012 03:27:01

acest lucru nu pare să aibă niciun efect... partea finală este corectă? Nu văd intercept_template_hierarchy apelat nicăieri. Schimbarea ultimului add_posttype_slug_template în intercept_template_hierarchy a rezultat în Eroare fatală: operatorul [] nu este suportat pentru șiruri

supertrue supertrue
7 feb. 2012 04:59:47

@supertrue Da, aceasta este o problemă. Pur și simplu nu funcționează. Deja vorbesc cu un dezvoltator de bază pentru a include acest lucru în ciclul 3.4. Revino în câteva zile și readaugă această întrebare cu un comentariu aici. Mulțumesc. Notă laterală: Nucleul se comportă extrem de stupid în acest punct, deoarece array-ul de șabloane nu este filtrat, ci calea șablonului localizată în schimb. Consider că aceasta este de fapt o defect.

kaiser kaiser
7 feb. 2012 05:47:49

@supertrue Discuția a început deja. Așteaptă un update în zilele următoare. Dacă nu va fi un update, atunci poate un ticket trac :P

kaiser kaiser
7 feb. 2012 12:54:09

@supertrue Dominik Schilling (cunoscut și sub numele de Ocean90) s-a alăturat unora dintre tichete. Așteptați progrese în versiunea 3.4.

kaiser kaiser
10 feb. 2012 17:19:06

@kaiser soluția ta arată foarte bine, dar nu funcționează ($templates nu este un array în cazul meu… primesc eroare fatală). Există vreo șansă să o faci să funcționeze?

gregmatys gregmatys
18 nov. 2013 14:54:38

@gregmatys Te rog să citești ultimul paragraf "Tichete Trac".

kaiser kaiser
18 nov. 2013 15:00:35
Arată celelalte 7 comentarii
4

Urmând imaginea Ierarhiei de Șabloane, nu văd o astfel de opțiune.

Deci, iată cum aș proceda:

Soluția 1 (cea mai bună în opinia mea)

Crează un fișier de șablon și asociază-l cu recenzia

 <?php
 /*
 Template Name: Recenzia mea grozavă
 */
 ?>

Adăugând fișierul php cu șablon în directorul temei tale, acesta va apărea ca o opțiune de șablon în pagina de editare a articolului.

Soluția 2

Aceasta ar putea fi probabil realizată folosind hook-ul template_redirect.

În fișierul 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' );

EDITARE

Am adăugat verificarea file_exists

2 feb. 2012 19:06:21
Comentarii

De ce folosești exit; acolo?

kaiser kaiser
2 feb. 2012 20:26:36

@kaiser Probabil a fost în tutorialul pe care l-am urmat la vremea respectivă, dacă nu este necesar îl voi elimina.

Shane Shane
2 feb. 2012 21:48:04

@kaiser: exit() este necesar pentru a preveni încărcarea șablonului implicit.

scribu scribu
3 feb. 2012 02:30:35

Soluția 1 va funcționa doar pentru pagini, nu și pentru articole.

IXN IXN
7 nov. 2015 14:18:56
0

Cel mai bun răspuns (de acum 4 ani) nu mai funcționează, dar codex-ul WordPress are soluția aici:

<?php
/**
 * Adaugă un template personalizat bazat pe slug-ul postului și tipul de post
 */
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 );
?>
9 iun. 2016 23:39:00
5

În cazul meu, am tipuri de postări personalizate Album și Track legate printr-o taxonomie Album. Am dorit să pot folosi șabloane Single diferite pentru postările Album și Track în funcție de taxonomia lor Album.

Bazat pe răspunsul lui Kaiser de mai sus, am scris acest cod. Funcționează bine.
Notă. Nu am avut nevoie de add_action().

// Adaugă o opțiune suplimentară de șablon în ierarhia de șabloane
add_filter( 'single_template', 'add_albumtrack_taxslug_template', 10, 1 );
function add_albumtrack_taxslug_template( $orig_template_path )
{
    // în acest moment, $orig_template_path este o cale absolută către șablonul single preferat.

    $object = get_queried_object();

    if ( ! (
        // specifică o altă opțiune de șablon doar pentru tipurile de postări Album și Track.
        in_array( $object->post_type, array( 'gregory-cpt-album','gregory-cpt-track' )) &&
        // verifică dacă taxonomia Album a fost înregistrată.
        taxonomy_exists( 'gregory-tax-album' ) &&
        // obține termenul taxonomiei Album pentru postul curent.
        $album_tax = wp_get_object_terms( $object->ID, 'gregory-tax-album' )
        ))
        return $orig_template_path;

    // asamblează numele șablonului
    // presupunere: doar un termen de taxonomie Album per post. folosim primul obiect din array.
    $template = "single-{$object->post_type}-{$album_tax[0]->slug}.php";
    $template = locate_template( $template );
    return ( !empty( $template ) ? $template : $orig_template_path );
}

Acum pot crea șabloane numite single-gregory-cpt-track-tax-serendipity.php și single-gregory-cpt-album-tax-serendipity.php iar WP le va folosi automat; 'tax-serendipity' este slug-ul pentru primul termen al taxonomiei Album.

pentru referință, cârligul de filtrare 'single_template' este declarat în:
/wp-includes/theme.php: get_query_template()

Mulțumesc lui Kaiser pentru codul exemplu.

Toate cele bune, Gregory

18 apr. 2012 09:46:11
Comentarii

Salut Greg - bun venit pe WPSE. Te rog să postezi răspunsuri doar ca răspunsuri la întrebări - nu ca întrebări suplimentare. Dacă ai o întrebare care nu este răspunsă de un răspuns existent și este prea complexă pentru un comentariu, te rog să deschizi o altă întrebare :)

Stephen Harris Stephen Harris
18 apr. 2012 18:07:19

întrebarea despre string/array a fost eliminată :-)

Gregory Gregory
18 apr. 2012 19:04:13

"Mulțumesc Kaiser pentru exemplul de cod." - Cu plăcere.

kaiser kaiser
23 oct. 2012 16:01:37

funcționează pentru tine? în primul rând, '$template' nu ar trebui să fie comentat în codul tău.. și cred că în loc de '$album_tax[0]->slug' ar trebui să fie '$object->post_name', nu-i așa?

gregmatys gregmatys
18 nov. 2013 16:14:14

am rezolvat linia cu $template. mulțumesc. $object->post_name? nu. asta ar returna slug-ul postării, dar eu am nevoie de slug-ul albumului cu care postarea este legată.

Gregory Gregory
19 nov. 2013 01:21:10
0

Folosește șabloane de pagini

O altă abordare pentru scalabilitate ar fi să duplicăm funcționalitatea dropdown-ului de șabloane de pagini de pe tipul de postare page pentru tipul tău de postare personalizat.

Cod Reutilizabil

Duplicarea în cod nu este o practică bună. În timp, poate cauza o umflare severă a unei baze de cod, ceea ce poate face foarte dificil pentru un dezvoltator să o gestioneze. În loc să creezi un șablon pentru fiecare slug individual, cel mai probabil vei avea nevoie de un șablon one-to-many care poate fi reutilizat, în loc de unul one-to-one post-to-șablon.

Codul

# Definește șirul tipului tău de postare personalizat
define('MY_CUSTOM_POST_TYPE', 'my-cpt');

/**
 * Înregistrează meta box-ul
 */
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', #Prefer plasarea sub meta box-ul acțiunilor postării
        'low'
    );
}

/**
 * Randarea meta box-ului - Acest cod este similar cu cel randat pe tipul de postare page
 * @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'>Șablon Pagină</label>
            <select name='_wp_page_template' id='page_template'>
            <option value='default'>Șablon Implicit</option>";
            page_template_dropdown($template);
    echo "</select>";
}

/**
 * Salvează șablonul paginii
 * @return void
 */
function save_page_template($post_id){

    # Sari peste salvările automate
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    elseif ( defined( 'DOING_AJAX' ) && DOING_AJAX )
        return;
    elseif ( defined( 'DOING_CRON' ) && DOING_CRON )
        return;

    # Actualizează meta-ul șablonului paginii doar dacă suntem pe tipul nostru specific de postare
    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');


/**
 * Setează șablonul paginii
 * @param string $template Șablonul determinat de WordPress
 * @return string $template Calea completă către șablonul predefinit sau personalizat al paginii
 */
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)
            #deoarece dropdown-ul nostru oferă doar numele de bază, folosește funcția locate_template() pentru a găsi cu ușurință calea completă
            return locate_template($custom_template);
    }
    return $template;
}
add_filter('single_template', 'set_page_template');

Acesta este un răspuns puțin târziu, dar am considerat că ar fi valoros deoarece nimeni pe internet nu a documentat această abordare, din câte știu. Sper că acest lucru îi va ajuta pe cineva.

13 oct. 2012 09:29:41
0

Actualizare pentru codul lui Brian, am descoperit că atunci când caseta derulantă nu era utilizată, opțiunea "default" pentru șablon era salvată în wp_page_template, ceea ce determina sistemul să încerce să găsească un șablon numit default. Această modificare verifică doar dacă opțiunea este "default" la salvare și șterge meta-ul postului în schimb (util dacă ai schimbat opțiunea de șablon înapoi la 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');
else :
    update_post_meta($post_id, '_wp_page_template', esc_attr($_POST['_wp_page_template']));
endif;
}
29 mai 2014 21:20:33