single - {$ post_type} - {slug} .php per tipi di post personalizzati


20

La mia parte preferita della gerarchia dei modelli di Wordpress è la possibilità di creare rapidamente file di modelli per pagine tramite slug, senza dover modificare la pagina in Wordpress per selezionare un modello.

Attualmente possiamo farlo:

PAGE- {slug} .php

Ma vorrei poterlo fare:

singolo {post_type} - {slug} .php

In modo che, ad esempio, in un tipo di post chiamato review , potessi creare un modello per un post chiamato "La mia recensione" susingle-review-my-great-review.php

Qualcuno l'ha già impostato? single-{post_type}-{slug}.php


Non ho mai usato una tale configurazione prima, ma se è troppo complicata, perché non creare semplicemente un file modello e associarlo alla recensione in questione.
Shane,

WP 3.4 recupera automaticamente single-{post_type}-{slug}.php, quindi l'aggiornamento a WP 3.4 è un'altra opzione.
yitwail,

Risposte:


19

A) La base nel nucleo

Come puoi vedere nella spiegazione della Gerarchia dei modelli di codice , single-{$post_type}.phpè già supportato.


B) Estensione della Gerarchia di base

Ora ci sono volentieri alcuni filtri e ganci all'interno /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • E: un filtro specifico all'interno get_query_template( $type, ... )denominato:"$type}_template"

B.1) Come funziona

  1. All'interno del file del caricatore di modello, il modello viene caricato da una query var / WP_Query condizionale: is_*().
  2. Viene quindi attivato il condizionale (nel caso di un modello "singolo"): is_single() && $template = get_single_template()
  3. Questo innesca poi get_query_template( $type, $templates ), dove $typeèsingle
  4. Quindi abbiamo il "{$type}_template"filtro

C) La soluzione

Poiché vogliamo solo estendere la gerarchia con un modello che viene caricato prima del "single-{$object->post_type}.php"modello effettivo , intercetteremo la gerarchia e aggiungeremo un nuovo modello all'inizio dell'array dei modelli.

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

NOTA: (Se si desidera utilizzare qualcosa di diverso dalla lumaca di oggetti predefinita), è necessario regolare in $slugbase alla struttura del permalink. Usa tutto ciò di cui hai bisogno dal mondo (object) $post.

Biglietti Trac

Dato che l'approccio sopra non è attualmente supportato (puoi solo filtrare il percorso assoluto individuato in questo modo), ecco un elenco di ticket trac:


Voglio provarlo, ma sembra che manchi qualcosa nella tua riga add_filter alla fine.
Supertrue

@supertrue Buona cattura. :) Trovato un altro mancante )all'interno del filtro. Fisso. Forse vuoi scambiare il trattino con una sottolineatura prima della lumaca all'interno del modello. Solo per far risaltare meglio il suffisso quando si guardano i modelli.
Kaiser

Causa questo errore nel sito: Avviso: array_unshift () [function.array-unshift]: il primo argomento dovrebbe essere un array in [riga contenente array_unshift]
supertrue

Ok, ma qualcos'altro sta intercettando i template di base. La funzione funziona bene ed $templatesè un array. Vedi le funzioni principali in questo pastebin (nessuna data di scadenza). Assicurati di provare questo con un'installazione senza plugin e il tema predefinito. Quindi attivare uno dopo l'altro e vedere se l'errore si verifica ancora.
Kaiser

Sì, ho eseguito il debug di questo e ottengo il percorso assoluto finale del primo modello trovato come stringa. Dovrò parlarne con qualche sviluppatore principale prima di modificare la risposta. Inoltre: ho confuso qualcosa: slugè disponibile solo per termini e tassonomie. È necessario sostituire $post->post_namecon ciò che si adatta alla struttura del permalink. Attualmente non c'è modo di farlo automaticamente per tutti i casi con il recupero e la sostituzione del percorso in base alla propria struttura permanente e alle regole di riscrittura. Aspettati un altro aggiornamento.
Kaiser

4

Seguendo l' immagine della Gerarchia dei modelli , non vedo questa opzione.

Quindi ecco come lo farei:

Soluzione 1 (la migliore secondo me)

Crea un file modello e associalo alla recensione

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

Aggiungendo il file modello php nella directory del tuo tema, sembrerebbe un'opzione modello nella pagina di modifica del tuo post.

Soluzione 2

Questo potrebbe probabilmente essere ottenuto usando l' template_redirecthook.

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

MODIFICARE

Aggiunto file_existscontrollo


Perché ci sei exit;?
Kaiser

@kaiser Deve essere stato in qualunque tutorial che ho seguito in quel momento, se non è necessario lo rimuoverò.
Shane,

1
@kaiser: exit()è necessario per impedire il caricamento del modello predefinito.
scribu,

La soluzione 1 funzionerà solo per le pagine, non per i post.
IXN,

2

La risposta migliore (di 4 anni fa) non funziona più, ma il codice WordPress ha la soluzione qui :

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

Usa modelli di pagina

Un altro approccio per la scalabilità sarebbe duplicare la funzionalità a discesa del modello di pagina sul pagetipo di post per il tipo di post personalizzato.

Codice riutilizzabile

La duplicazione nel codice non è una buona pratica. Gli straordinari possono causare un forte gonfiore a una base di codice quando poi rende molto difficile la gestione da parte di uno sviluppatore. Invece di creare un modello per ogni singola lumaca, molto probabilmente avrai bisogno di un modello uno-a-molti che può essere riutilizzato anziché uno-a-uno post-modello.

Il codice

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

Questa è una risposta un po 'tardiva, ma ho pensato che sarebbe stato prezioso dal momento che nessuno sul web ha documentato questo approccio per quanto ne so. Spero che questo aiuti qualcuno.


1

Nel mio caso, ho i tipi di post personalizzati Album e Track collegati da una tassonomia dell'album. Volevo essere in grado di utilizzare diversi modelli Single per i post Album e Track a seconda della tassonomia dell'album.

Sulla base della risposta di Kaiser sopra, ho scritto questo codice. Funziona bene.
Nota. Non avevo bisogno di 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 );
}

Ora posso creare template chiamati single-gregory-cpt-track-tax-serendipity.php e single-gregory-cpt-album-tax-serendipity.php e WP li userà automaticamente; 'tax-serendipity' è la lumaca del primo termine di tassonomia dell'album.

come riferimento, l'hook del filtro 'single_template' è dichiarato in:
/wp-includes/theme.php:get_query_template()

Grazie Kaiser per il codice di esempio.

Saluti, Gregorio


Ciao Greg, benvenuto in WPSE. Si prega di pubblicare le risposte solo come risposte alle domande, non di dare seguito alle domande. Se hai una domanda a cui non è stata data risposta ed è troppo grande per un commento, per favore apri un'altra domanda :)
Stephen Harris,

1
la domanda stringa / matrice è stata rimossa :-)
Gregory,

1
"Grazie Kaiser per il codice di esempio." - Prego.
Kaiser

Per te funziona? prima di tutto, '$ template' non dovrebbe essere commentato nel tuo codice .. e penso che invece di '$ album_tax [0] -> slug' dovrebbe esserci '$ object-> post_name', non è vero?
Gregregat

riparata la linea $ template. grazie. $ object-> POST_NAME? no. che restituirebbe la lumaca del post, ma ho bisogno della lumaca dell'album a cui è collegato il post.
Gregorio,

0

Aggiornamento per il codice Brians, ho scoperto che quando la casella a discesa non veniva utilizzata, l'opzione del modello "predefinito" veniva salvata in wp_page_template, il che gli faceva provare a trovare un modello chiamato predefinito. questa modifica controlla solo l'opzione "default" durante il salvataggio ed elimina invece la meta meta (utile se hai ripristinato l'opzione template di 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');
altro :
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template']));
finisci se;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.