single - {$ post_type} - {slug} .php für benutzerdefinierte Beitragstypen

20

Mein Lieblingsteil der Wordpress- Vorlagenhierarchie ist die Möglichkeit, schnell Vorlagendateien für Seiten per Slug zu erstellen, ohne die Seite in Wordpress bearbeiten zu müssen, um eine Vorlage auszuwählen.

Das können wir derzeit tun:

page- {slug} .php

Das möchte ich aber können:

single- {post_type} - {slug} .php

So reviewkönnte ich zum Beispiel in einem Beitragstyp namens "My Great Review" unter eine Vorlage für einen Beitrag mit dem Namen "My Great Review" erstellensingle-review-my-great-review.php

Hat das schon mal jemand eingerichtet? single-{post_type}-{slug}.php

supertrue
quelle
Nie zuvor ein solches Setup verwendet, aber wenn es zu kompliziert ist, erstellen Sie einfach eine Vorlagendatei und verknüpfen Sie sie mit der betreffenden Überprüfung.
Shane
WP 3.4 wird automatisch abgerufen single-{post_type}-{slug}.php, daher ist ein Upgrade auf WP 3.4 eine weitere Option.
Yitwail

Antworten:

19

A) Die Basis im Kern

Wie Sie in der Erklärung zur Codex- Vorlagenhierarchie sehen können, single-{$post_type}.phpwird dies bereits unterstützt.


B) Erweiterung der Kernhierarchie

Jetzt sind gerne ein paar Filter und Haken drin /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • UND: ein bestimmter Filter innerhalb mit dem get_query_template( $type, ... )Namen:"$type}_template"

B.1) Wie es funktioniert

  1. In der Vorlage Loader - Datei, wird die Vorlage durch eine geladene Abfrage var / wp_query bedingt: is_*().
  2. Die Bedingung löst dann aus (im Fall einer "einzelnen" Vorlage): is_single() && $template = get_single_template()
  3. Dies löst dann aus get_query_template( $type, $templates ), wo $typeistsingle
  4. Dann haben wir den "{$type}_template"Filter

C) Die Lösung

Da wir nur die Hierarchie mit einer Vorlage erweitern möchten, wird vor dem Laden der aktuellen "single-{$object->post_type}.php"Vorlage, werden wir die Hierarchie abfangen und eine neue Vorlage zu Beginn des Vorlagen - Array hinzuzufügen.

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

HINWEIS: (Wenn Sie etwas anderes als den Standardobjekt-Slug verwenden möchten), müssen Sie die Einstellungen $slugentsprechend Ihrer Permalink-Struktur vornehmen. Verwenden Sie einfach alles, was Sie von der globalen benötigen (object) $post.

Trac Karten

Da der oben beschriebene Ansatz derzeit nicht unterstützt wird (Sie können nur den absolut lokalisierten Pfad auf diese Weise filtern), finden Sie hier eine Liste der Trac-Tickets:

Kaiser
quelle
Ich möchte dies testen, aber es sieht so aus, als ob am Ende etwas in Ihrer Zeile add_filter fehlt.
supertrue
@supertrue Guter Fang. :) )Im Filter fehlt ein weiteres . Fest. Vielleicht möchten Sie den Gedankenstrich mit einer Unterstreichung vor dem Slug in der Vorlage austauschen. Nur um das Suffix besser hervorzuheben, wenn Sie sich die Vorlagen ansehen.
Kaiser
Ursachen dieser Fehler über site: Warning: array_unshift () [function.array-unshift]: Das erste Argument ein Array in sein sollte [Zeile mit array_unshift]
supertrue
Ok, aber dann fängt etwas anderes die Kernvorlagen ab. Die Funktion funktioniert einwandfrei und $templatesist ein Array. Siehe die Kernfunktionen in diesem Pastebin (kein Ablaufdatum). Stellen Sie sicher, dass Sie dies mit einer Installation ohne Plugins und dem Standarddesign testen . Aktivieren Sie dann nacheinander und prüfen Sie, ob der Fehler weiterhin auftritt.
Kaiser
Ja, ich habe dieses debuggt und bekomme den endgültigen absoluten Pfad der ersten gefundenen Vorlage als String zurück. Ich muss mit einem Kernentwickler darüber sprechen, bevor ich die Antwort ändere. Außerdem: Ich habe etwas verwechselt: slugist nur für Begriffe und Taxonomien verfügbar. Sie sollten das ersetzen, $post->post_namewas zu Ihrer Permalink-Struktur passt. Derzeit gibt es keine Möglichkeit, dies automatisch für alle Fälle zu tun, indem der Pfad abhängig von Ihrer Permastruktur und den Umschreiberegeln abgerufen und ersetzt wird. Erwarten Sie ein weiteres Update.
Kaiser
4

Nach dem Bild der Vorlagenhierarchie sehe ich keine solche Option.

Also hier ist, wie ich vorgehen würde:

Lösung 1 (meiner Meinung nach am besten)

Erstellen Sie eine Vorlagendatei und ordnen Sie sie der Überprüfung zu

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

Wenn Sie die Vorlagen-PHP-Datei in Ihr Themenverzeichnis aufnehmen, wird sie als Vorlagenoption auf der Bearbeitungsseite Ihres Beitrags angezeigt.

Lösung 2

Dies könnte wahrscheinlich mit template_redirectHaken erreicht werden .

In der functions.php Datei:

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

BEARBEITEN

file_existsCheck hinzugefügt

Shane
quelle
Warum bist du exit;da?
Kaiser
@kaiser Muss in irgendeinem Tutorial gewesen sein, dem ich zu der Zeit gefolgt bin, wenn es nicht notwendig ist, werde ich es entfernen.
Shane
1
@kaiser: Das exit()ist notwendig, um das Laden der Standardvorlage zu verhindern.
Scribu
Lösung 1 funktioniert nur für Seiten, nicht für Posts.
IXN
2

Die Top-Antwort (seit 4 Jahren) funktioniert nicht mehr, aber der WordPress-Codex hat hier die Lösung :

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

Verwenden Sie Seitenvorlagen

Ein weiterer Ansatz für die Skalierbarkeit besteht darin, die Dropdown-Funktion für Seitenvorlagen für den pageBeitragstyp für Ihren benutzerdefinierten Beitragstyp zu duplizieren .

Wiederverwendbarer Code

Die Vervielfältigung von Code ist keine gute Praxis. Im Laufe der Zeit kann es zu einem starken Aufblähen der Codebasis kommen, wenn es dann für einen Entwickler sehr schwierig ist, damit umzugehen. Anstatt eine Vorlage für jeden einzelnen Slug zu erstellen, benötigen Sie höchstwahrscheinlich eine Eins-zu-Viele-Vorlage, die anstelle einer Eins-zu-Eins-Post-zu-Vorlage wiederverwendet werden kann.

Der Code

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

Dies ist eine etwas verspätete Antwort, aber ich dachte, es wäre wertvoll, da niemand im Web diesen Ansatz dokumentiert hat, soweit ich das beurteilen kann. Hoffe das hilft jemandem aus.

Brian Fegter
quelle
1

In meinem Fall sind die benutzerdefinierten Post-Typen "Album" und "Track" durch eine Album-Taxonomie verknüpft. Ich wollte in der Lage sein, abhängig von ihrer Albumtaxonomie verschiedene Einzelvorlagen für die Album- und Track-Posts zu verwenden.

Basierend auf Kaisers Antwort habe ich diesen Code geschrieben. Es läuft gut.
Hinweis. Ich habe die add_action () nicht benötigt.

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

Ich kann jetzt Vorlagen mit den Namen single-gregory-cpt-track-tax-serendipity.php und single-gregory-cpt-album-tax-serendipity.php erstellen und WP verwendet sie automatisch. 'tax-serendipity' ist der Slug für den ersten Begriff der Album-Taxonomie.

Als Referenz wird der Filter-Hook 'single_template' deklariert in:
/wp-includes/theme.php:get_query_template()

Vielen Dank Kaiser für den Beispielcode.

Prost, Gregory

Gregory
quelle
Hallo Greg - willkommen bei WPSE. Bitte posten Sie Antworten nur als Antwort auf die Fragen - nicht als Folgefragen. Wenn Sie eine Frage haben, die nicht durch eine vorhandene Antwort beantwortet wurde und zu groß für einen Kommentar ist, öffnen Sie bitte eine andere Frage :)
Stephen Harris
1
Die String / Array-Frage wurde entfernt :-)
Gregory
1
"Danke Kaiser für den Beispielcode." - Bitte.
Kaiser
funktioniert es bei dir Zunächst sollte '$ template' in Ihrem Code nicht kommentiert werden. Und ich denke, dass es anstelle von '$ album_tax [0] -> slug' '$ object-> post_name' geben sollte, nicht wahr?
Gregmatys
reparierte die $ Schablonenzeile. Danke dir. $ object-> post_name? Nein. Das würde den Slug des Posts zurückgeben, aber ich brauche den Slug des Albums, mit dem der Post verknüpft ist.
Gregory
0

Beim Update für Brians-Code stellte ich fest, dass bei Nichtverwendung des Dropdown-Felds die "Standard" -Vorlagenoption in wp_page_template gespeichert wurde, wodurch versucht wurde, eine Vorlage mit dem Namen "Standard" zu finden. Diese Änderung überprüft nur die Option "Standard" beim Speichern und löscht stattdessen das Post-Meta (nützlich, wenn Sie die Vorlagenoption wieder auf den Standard zurückgesetzt haben).

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

if (esc_attr ($ _ POST ['_ wp_page_template']) === "default"):
    delete_post_meta ($ post_id, '_wp_page_template');
sonst:
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template']));
endif;
}
Kennzeichen
quelle