single - {$ post_type} - {slug} .php dla niestandardowych typów postów


20

Moją ulubioną częścią hierarchii szablonów Wordpress jest możliwość szybkiego tworzenia plików szablonów dla stron przez ślimak, bez konieczności edytowania strony w Wordpress, aby wybrać szablon.

Obecnie możemy to zrobić:

page- {slug} .php

Ale chciałbym móc to zrobić:

single- {post_type} - {slug} .php

Na przykład w typie posta o nazwie reviewMógłbym utworzyć szablon dla postu o nazwie „Moja wielka recenzja” pod adresemsingle-review-my-great-review.php

Czy ktoś już to skonfigurował? single-{post_type}-{slug}.php


Nigdy wcześniej nie korzystałem z takiej konfiguracji, ale jeśli jest ona zbyt skomplikowana, po prostu utwórz plik szablonu i skojarz go z recenzją.
Shane

WP 3.4 automatycznie pobiera single-{post_type}-{slug}.php, więc uaktualnienie do WP 3.4 to kolejna opcja.
yitwail

Odpowiedzi:


19

A) Baza w rdzeniu

Jak widać w objaśnieniu hierarchii szablonów kodeksu , single-{$post_type}.phpjest już obsługiwane.


B) Rozszerzenie podstawowej hierarchii

Teraz chętnie są w środku filtry i haczyki /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • ORAZ: określony filtr get_query_template( $type, ... )o nazwie:"$type}_template"

B.1) Jak to działa

  1. Wewnątrz pliku ładowarki szablonu, szablon zostanie załadowany przez kwerendy var / wp_query warunkowe: is_*().
  2. Następnie uruchamiane są warunki warunkowe (w przypadku „pojedynczego” szablonu): is_single() && $template = get_single_template()
  3. To uruchamia wtedy get_query_template( $type, $templates ), gdzie $typejestsingle
  4. Następnie mamy "{$type}_template"filtr

C) Rozwiązanie

Jak tylko chcemy przedłużyć hierarchię z jednego szablonu, który zostanie załadowany przed faktycznym "single-{$object->post_type}.php"szablonu, będziemy przechwytywać hierarchię i dodać nowy szablon do początku tablicy szablonów.

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

UWAGA: (Jeśli chcesz użyć czegoś innego niż domyślny ślimak obiektów) Będziesz musiał dostosować się $slugdo swojej struktury permalink. Po prostu użyj tego, czego potrzebujesz od globalnego (object) $post.

Bilety na Trac

Ponieważ powyższe podejście jest obecnie nie są obsługiwane (można filtrować tylko bezwzględną ścieżkę znajdujący ten sposób), oto lista biletów trac:


Chcę to przetestować, ale wygląda na to, że na końcu brakuje czegoś w linii add_filter.
supertrue

@supertrue Good catch. :) Znaleziono kolejny brak )w filtrze. Naprawiony. Może chcesz zamienić kreskę z podkreśleniem przed ślimakiem w szablonie. Po prostu, aby przyrostek wyróżniał się lepiej podczas przeglądania szablonów.
kaiser

Powoduje ten błąd w całej witrynie: Ostrzeżenie: array_unshift () [function.array-unshift]: Pierwszym argumentem powinna być tablica w [wierszu zawierającym array_unshift]
supertrue

Ok, ale coś innego przechwytuje podstawowe szablony. Funkcja działa dobrze i $templatesjest tablicą. Zobacz podstawowe funkcje w tej pastebin (bez daty ważności). Upewnij się, że przetestujesz to z instalacją bez wtyczek i domyślnym motywem. Następnie aktywuj jeden po drugim i sprawdź, czy błąd nadal występuje.
kaiser

Tak, debugowałem to i otrzymuję ostatnią ścieżkę bezwzględną pierwszego znalezionego szablonu z powrotem jako ciąg. Będę musiał porozmawiać o tym z jakimś głównym programistą, zanim zmienię odpowiedź. Ponadto: coś pomieszałem: slugjest dostępne tylko dla warunków i taksonomii. Powinieneś zastąpić $post->post_nametym, co pasuje do twojej struktury permalink. Obecnie nie ma możliwości automatycznego wykonania tego we wszystkich przypadkach z pobieraniem i zastępowaniem ścieżki w zależności od reguł perma struct i przepisywania. Spodziewaj się kolejnej aktualizacji.
kaiser

4

Śledząc obrazie Hierarchia szablonów nie widzę takiej opcji.

Oto, jak bym to zrobił:

Rozwiązanie 1 (najlepsze według mnie)

Utwórz plik szablonu i powiąż go z recenzją

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

Dodając szablonowy plik php do katalogu motywów, pojawi się on jako opcja szablonu na stronie edycji posta.

Rozwiązanie 2

Można to prawdopodobnie osiągnąć za pomocą template_redirecthaka.

W pliku 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' );

EDYTOWAĆ

Dodano file_existsczek


Dlaczego exit;tam jesteś
kaiser

@kaiser Musiałem być w tym samym tutorialu, który wtedy podjąłem, jeśli nie będzie to konieczne, usunę go.
Shane

1
@kaiser: Jest exit()to konieczne, aby zapobiec ładowaniu domyślnego szablonu.
scribu

Rozwiązanie 1 będzie działać tylko dla stron, a nie dla postów.
IXN

2

Najlepsza odpowiedź (sprzed 4 lat) już nie działa, ale kodeks WordPress ma tutaj rozwiązanie :

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

Użyj szablonów stron

Innym podejściem do skalowalności byłoby zduplikowanie funkcji rozwijania szablonu strony pagedla typu postu dla niestandardowego typu postu.

Kod wielokrotnego użytku

Powielanie kodu nie jest dobrą praktyką. Praca w godzinach nadliczbowych może powodować poważne wzdęcia w bazie kodu, co utrudnia programistom zarządzanie. Zamiast tworzyć szablon dla każdego ślimaka, najprawdopodobniej będziesz potrzebować szablonu jeden do wielu, który może być ponownie użyty zamiast jednego do jednego post-to-template.

Kod

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

To trochę spóźniona odpowiedź, ale pomyślałem, że będzie cenna, ponieważ nikt w sieci nie udokumentował tego podejścia, o ile wiem. Mam nadzieję, że to komuś pomoże.


1

W moim przypadku mam niestandardowe typy wpisów Album i Śledź połączone taksonomią Albumu. Chciałem móc korzystać z różnych szablonów Single dla postów Album i Track w zależności od ich taksonomii albumu.

Na podstawie powyższej odpowiedzi Kaiser napisałem ten kod. To dobrze działa.
Uwaga. Nie potrzebowałem add działań ().

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

Mogę teraz tworzyć szablony o nazwach single-gregory-cpt-track-tax-serendipity.php i single-gregory-cpt-album-tax-serendipity.php, a WP użyje ich automatycznie; „podatność na zerwanie” jest ślimakiem pierwszego terminu taksonomii albumu.

w celach informacyjnych deklaracja filtru „single_template” jest zadeklarowana w:
/wp-includes/theme.php:get_query_template()

Dziękuję Kaiser za przykładowy kod.

Pozdrawiam, Gregory


Cześć Greg - witamy w WPSE. Proszę zamieszczać odpowiedzi tylko jako odpowiedzi na pytania - nie odpowiadać na pytania. Jeśli masz pytanie, na które nie ma odpowiedzi, i jest ono zbyt duże, aby je skomentować, otwórz kolejne pytanie :)
Stephen Harris

1
pytanie dotyczące łańcucha / tablicy zostało usunięte :-)
Gregory,

1
„Dziękuję Kaiser za przykładowy kod”. - Nie ma za co.
kaiser

Czy Ci to pasuje? po pierwsze, „$ template” nie powinien być komentowany w twoim kodzie… i myślę, że zamiast „$ album_tax [0] -> ślimak” powinno być „$ object-> post_name”, prawda?
gregmatys,

naprawiono wiersz szablonu $. Dziękuję Ci. $ object-> post_name? Nie. zwróciłoby to informację o postie, ale potrzebuję informacji o albumie, z którym jest on powiązany.
Gregory

0

Zaktualizowałem kod Briansa. Odkryłem, że kiedy nie było rozwijanego pola, opcja „domyślnego” szablonu była zapisywana w wp_page_template, co spowodowało, że próbował znaleźć szablon o nazwie default. ta zmiana sprawdza tylko opcję „domyślną” podczas zapisywania i zamiast tego usuwa meta post (przydatne, jeśli zmieniono opcję szablonu z powrotem na domyślną)

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

if (esc_attr ($ _ POST ['_ wp_page_template']) === „default”):
    delete_post_meta ($ post_id, '_wp_page_template');
inaczej:
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template']));
endif;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.