web-dev-qa-db-fra.com

single - {$ post_type} - {slug} .php pour les types de publication personnalisés

Ma partie préférée de la hiérarchie de Wordpress template est la possibilité de créer rapidement des fichiers de gabarit pour les pages par slug, sans avoir à modifier la page dans Wordpress pour sélectionner un gabarit.

Nous pouvons actuellement faire ceci:

page- {slug} .php

Mais j'aimerais pouvoir faire ceci:

single- {post_type} - {slug} .php

Ainsi, par exemple, dans un type de message appelé review, je pourrais créer un modèle pour un message appelé "My Great Review" à single-review-my-great-review.php

Quelqu'un a-t-il déjà organisé cela? single-{post_type}-{slug}.php

19
supertrue

A) La base en noyau

Comme vous pouvez le voir dans l'explication Codex Template Hierarchy, single-{$post_type}.php est déjà pris en charge.


B) Extension de la hiérarchie fondamentale

Maintenant, il y a volontiers des filtres et des crochets dans /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • ET: un filtre spécifique dans get_query_template( $type, ... ) nommé: "$type}_template"

B.1) Comment ça marche

  1. Dans le fichier du chargeur de modèles, le modèle est chargé par une requête conditionnelle var/wp_query: is_*().
  2. Le conditionnel se déclenche alors (dans le cas d'un modèle "unique"): is_single() && $template = get_single_template()
  3. Ceci déclenche alors get_query_template( $type, $templates ), où $type est single
  4. Ensuite, nous avons le filtre "{$type}_template"

C) La solution

Comme nous seulement voulons étendre la hiérarchie avec un modèle qui obtient chargé avant le modèle "single-{$object->post_type}.php" actuel, nous intercepterons la hiérarchie et ajouterons un nouveau modèle au début du tableau de modèles. .

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

NOTE: (Si vous voulez utiliser autre chose que le slug des objets par défaut), vous devrez ajuster $slug en fonction de votre structure de lien permanent. Utilisez simplement ce dont vous avez besoin dans le (object) $post global.

Billets Trac

Comme l'approche ci-dessus est actuellement not supportée (vous pouvez uniquement filtrer le chemin absolu de cette façon), voici une liste des tickets de traçage:

18
kaiser

Suivant l’image Template Hierarchy , je ne vois pas une telle option.

Alors voici comment je le ferais:

Solution 1 (Best à mon avis)

Créez un fichier modèle et associez-le à la révision

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

En ajoutant le modèle de fichier php dans votre répertoire de thème, il apparaîtrait comme une option de modèle dans la page d'édition de votre publication.

Solution 2

Ceci pourrait probablement être réalisé en utilisant template_redirect hook.

Dans le fichier 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' );

EDIT

Ajout du contrôle file_exists

3
Shane

La meilleure réponse (d'il y a 4 ans) ne fonctionne plus, mais le codex WordPress a la solution ici :

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

Utiliser les modèles de page

Une autre approche en matière d'évolutivité consisterait à dupliquer la fonctionnalité de liste déroulante de modèle de page sur le type d'article page pour votre type d'article personnalisé.

Code réutilisable

La duplication dans le code n'est pas une bonne pratique. Les heures supplémentaires peuvent causer de graves problèmes de saturation à une base de code, ce qui complique la gestion du développeur. Au lieu de créer un modèle pour chaque slug, vous aurez probablement besoin d'un modèle un-à-plusieurs qui peut être réutilisé au lieu d'un modèle un à un.

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

C'est une réponse un peu tardive, mais je pensais que ce serait utile, car personne sur le Web n'a documenté cette approche à ce que je sache. J'espère que cela aide quelqu'un.

1
Brian Fegter

Dans mon cas, les types de publication personnalisés Album et Suivi sont liés par une taxonomie d’Album. Je souhaitais pouvoir utiliser différents modèles Single pour les publications Album et Track en fonction de leur taxonomie.

Basé sur la réponse de Kaiser ci-dessus, j'ai écrit ce code. Ça marche bien.
Remarque. Je n'ai pas eu besoin de 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 );
}

Je peux maintenant créer des modèles nommés single-gregory-cpt-track-tax-serendipity.php et single-gregory-cpt-album-tax-serendipity.php et WP les utiliseront automatiquement; 'tax-serendipity' est la limace du premier terme de taxonomie de l'album.

pour référence, le hook de filtre 'single_template' est déclaré dans:
/wp-includes/theme.php: get_query_template()

Merci Kaiser pour l'exemple de code.

À la vôtre, Gregory

1
Gregory

Mise à jour pour le code Brians, j'ai constaté que lorsque le menu déroulant n'était pas utilisé, l'option de modèle "par défaut" était en cours d'enregistrement dans wp_page_template, ce qui l'avait amené à rechercher un modèle appelé par défaut. cette modification vérifie simplement l'option "par défaut" lors de l'enregistrement et supprime la méta de publication (utile si vous avez modifié l'option de modèle à sa valeur par défaut)

 elseif (MY_CUSTOM_POST_TYPE === $ _POST ['post_type']) {
 
 if (esc_attr ($ _ POST ['_ wp_page_template'])) === "défaut"): 
 delete_post_meta ($ post_id, '_wp_page_template'); 
 else: 
 update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template')), 
fin si;
}
0
Mark