it-swarm.com.de

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

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.

Wir können dies derzeit tun:

page- {slug} .php

Das möchte ich aber können:

single- {post_type} - {slug} .php

So könnte ich beispielsweise in einem Beitragstyp mit dem Namen review eine Vorlage für einen Beitrag mit dem Namen "My Great Review" unter single-review-my-great-review.php erstellen.

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

19
supertrue

A) Die Basis im Kern

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


B) Erweiterung der Kernhierarchie

Jetzt gibt es gerne ein paar Filter und Hooks im /wp-includes/template-loader.php.

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

B.1) Wie es funktioniert

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

C) Die Lösung

Da wir nur die Hierarchie mit einer Vorlage erweitern möchten, die vor der tatsächlichen "single-{$object->post_type}.php"-Vorlage geladen wird, werden wir die Hierarchie abfangen und eine neue Vorlage am Anfang des Vorlagen-Arrays hinzufü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) Sie müssen $slug entsprechend Ihrer Permalink-Struktur anpassen. Verwenden Sie einfach alles, was Sie brauchen, aus dem globalen (object) $post.

Trac Karten

Da der obige 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:

18
kaiser

Nach dem Template Hierarchy image 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_redirect hook 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' );

EDIT

file_exists check hinzugefügt

3
Shane

Die Top-Antwort (ab 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 );
?>
2
skladany

Verwenden Sie Seitenvorlagen

Ein weiterer Ansatz für die Skalierbarkeit besteht darin, die Dropdown-Funktion für Seitenvorlagen für den Beitragstyp page 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 für einen Entwickler sehr schwierig wird, 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.

1
Brian Fegter

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

1
Gregory

Beim Update für Brians-Code stellte ich fest, dass die "Standard" -Vorlagenoption in wp_page_template gespeichert wurde, wenn das Dropdown-Feld nicht verwendet 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'); 
 else: 
 update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _POST ['_wp_page_template'); 
 endif; 
} 
0
Mark