Obtenir le nom du fichier de modèle actuel

58

J'ai trouvé ceci pour afficher le nom actuel du fichier utilisé dans le modèle:

function get_template_name () {
    foreach ( debug_backtrace() as $called_file ) {
        foreach ( $called_file as $index ) {
            if ( !is_array($index[0]) AND strstr($index[0],'/themes/') AND !strstr($index[0],'footer.php') ) {
                $template_file = $index[0] ;
            }
        }
    }
    $template_contents = file_get_contents($template_file) ;
    preg_match_all("Template Name:(.*)\n)siU",$template_contents,$template_name);
    $template_name = trim($template_name[1][0]);
    if ( !$template_name ) { $template_name = '(default)' ; }
    $template_file = array_pop(explode('/themes/', basename($template_file)));
    return $template_file . ' > '. $template_name ;
}

Source: obtenir le nom du modèle de page sur une page

Cela fonctionne assez bien, sauf que dans le backend, dans la boîte de sélection du modèle, je reçois cette entrée supplémentaire laide:

capture d'écran

Quelqu'un a-t-il une idée de comment résoudre ce problème? Je ne sais même pas pourquoi cette fonction est appelée dans le backend. Existe-t-il une fonction conditionnelle du type is_frontend(): peut-être que cela résoudrait le problème?

Chodorowicz
la source
2
@chodorowicz - Bien que je m'arrête un peu avant d'appeler la sélection de functions.phpbogue, je suis tout à fait d'accord avec votre idée. Pour aggraver les choses, j'ai scanné le code principal de WordPress et trouvé environ 5 endroits où il aurait pu y avoir un crochet pour vous permettre de gérer ce problème, mais je n'en ai trouvé aucun. Je suggère de poster un billet sur core.trac.wordpress.org .
MikeSchinkel
@MikeSchinkel - merci pour le commentaire, mais ne template_includeraccrochez pas , qui t31os suggéré, résoudre le problème? Ou peut-être je vous ai mal compris.
Chodorowicz
1
@MikeSchinkel - il a déjà un correctif :) core.trac.wordpress.org/ticket/16689
chodorowicz
1
J'ai créé un nouveau plugin pour afficher le modèle actuel. Vérifiez-le sur wordpress.org/extend/plugins/display-template-name
4
^ ie. vous avez pris le code de ma réponse et l'avez intégré dans un plugin. Et vous avez fait tout cela sans donner aucun crédit à l'origine, ni moi-même ni le stack stackchange ... sympa ...: /
t31os

Réponses:

69

Vous pouvez définir une variable globale au cours du template_includefiltre, puis vérifier ultérieurement ce vairable global pour voir quel modèle a été inclus.

Naturellement, vous ne voudriez pas avoir le chemin complet avec le fichier, je vous recommande donc de tronquer jusqu'au nom du fichier à l'aide de la basenamefonction PHP .

Exemple de code:
Deux fonctions, une pour définir la globale, une pour l'appeler.

add_filter( 'template_include', 'var_template_include', 1000 );
function var_template_include( $t ){
    $GLOBALS['current_theme_template'] = basename($t);
    return $t;
}

function get_current_template( $echo = false ) {
    if( !isset( $GLOBALS['current_theme_template'] ) )
        return false;
    if( $echo )
        echo $GLOBALS['current_theme_template'];
    else
        return $GLOBALS['current_theme_template'];
}

Vous pouvez ensuite appeler get_current_templateoù vous en avez besoin dans les fichiers de thème, en notant que cela doit naturellement se produire après le template_includedéclenchement de l' action (vous n'aurez pas à vous en préoccuper si l'appel est effectué à l'intérieur d'un fichier de modèle).

En ce qui concerne les modèles de page, il ne faut pas is_page_template()oublier que cela n’aidera que dans le cas des modèles de page (une fonction beaucoup moins intéressante ).

Informations sur les fonctions utilisées ou référencées ci-dessus:

t31os
la source
Impressionnant! Je savais qu'il devait y avoir un moyen plus simple.
Racl101
Un à ajouter en haut de ma liste de fonctions de débogage.
Jules
24

apparemment cela suffit:

add_action('wp_head', 'show_template');
function show_template() {
    global $template;
    echo basename($template);
}

ou juste l'utiliser directement dans le template (j'ai tendance à faire écho dans footer.php dans un commentaire HTML)

<?php global $template; echo basename($template); ?>
Chodorowicz
la source
1
Cela ne fonctionnera pas avec get-template-part juste pour que vous sachiez qu'il ne montre que single.php (par exemple) et pas le fichier dans
lequel
Oui c'est vrai. Pour obtenir le nom du fichier inclus, vous devrez probablement utiliser quelque chose comme ceciecho __FILE__;
chodorowicz
c'est très bien, par exemple dans les cas où vous modifiez le modèle par défaut sans l'affecter à une publication dans le backoffice. Par exemple, en utilisant des itinéraires personnalisés et le filtre template_include. Je vous remercie.
Luca Reghellin
Comment pourrais-je faire cela dans une boucle? J'essaie de générer l'URL sur une page de chaque fichier de modèle.
JacobTheDev
@JacobTheDev peut-être utiliser echo __FILE__- parce que cela ne fonctionnera pas, il affiche uniquement le modèle initial principal
chodorowicz
17

Entre les fonctions WP natives telles que get_template_part () et le langage PHP natif, le moyen le plus fiable de voir les fichiers de thèmes utilisés consiste à extraire la liste de tous les fichiers inclus et à filtrer ce qui n'appartient pas au thème (ou aux thèmes lorsque les combinaisons parent et enfant sont utilisées) :

$included_files = get_included_files();
$stylesheet_dir = str_replace( '\\', '/', get_stylesheet_directory() );
$template_dir   = str_replace( '\\', '/', get_template_directory() );

foreach ( $included_files as $key => $path ) {

    $path   = str_replace( '\\', '/', $path );

    if ( false === strpos( $path, $stylesheet_dir ) && false === strpos( $path, $template_dir ) )
        unset( $included_files[$key] );
}

var_dump( $included_files );
Rarst
la source
9

Un ajout (plus de code doux) à d'autres réponses ici.

Nom du modèle

Pour obtenir simplement le nom du modèle de page actuel , utilisez la ligne suivante.

is_page() AND print get_page_template_slug( get_queried_object_id() );

Nom de fichier

Lorsque vous souhaitez simplement faire écho au nom du fichier de modèle actuel , procédez comme suit:

Edit: Voici la nouvelle version du plugin encapsulée dans une classe. Il affiche à la fois le nom du fichier de modèle actuel et le nom du fichier de hiérarchie de modèles dans le point d'arrêt situé au bas de la page.

Ce que le plugin vous dit:

  • Le modèle provient-il du parent du thème enfant / actuel?
  • Le modèle est-il servi à partir d'un sous-dossier? Si oui: vous dit le nom
  • Le nom du fichier modèle.

Copiez simplement le code suivant dans un fichier et nommez-le wpse10537_template_info.php, chargez-le dans le répertoire de vos plugins et activez-le.

<?php
/** Plugin Name: (#10537) »kaiser« Get Template file name */

if ( ! class_exists( 'wpse10537_template_name' ) )
{
    add_action( 'plugins_loaded', array( 'wpse10537_template_name', 'init' ) );

class wpse10537_template_name
{
    protected static $instance;

    public $stack;

    public static function init()
    {
        is_null( self :: $instance ) AND self :: $instance = new self;
        return self :: $instance;
    }

    public function __construct()
    {
        if ( is_admin() )
            return;

        add_action( 'wp', array( $this, 'is_parent_template' ), 0 );
        add_action( 'wp', array( $this, 'get_template_file' ) );
        add_action( 'template_include', array( $this, 'get_template_name' ) );
        add_action( 'shutdown', array( $this, 'get_template_name' ) );
    }

    public function get_template_name( $file )
    {
        if ( 'template_include' === current_filter() )
        {
            $this->to_stack(
                 "Template file"
                ,basename( $file )
            );
            return $file;
        }

        // Return static var on echo call outside of filter
        if (
            current_user_can( 'manage_options' )
            AND defined( 'WP_DEBUG' )
            AND WP_DEBUG 
        )
            return print implode( " &ndash; ", $this->stack );
    }

    public function get_template_file()
    {
        if ( ! is_post_type_hierarchical( get_post_type() ) )
            return;

        $slug = get_page_template_slug( get_queried_object_id() );
        if ( ! strstr( $slug, "/" ) )
            return $this->to_stack( "Template", $slug );

        $this->to_stack(
             "Subdirectory"
            ,strstr( $slug, "/", true )
        );

        $this->to_stack(
             "Template (in subdirectory)"
            ,str_replace( "/", "", strstr( $slug, "/" ) )
        );
    }

    public function is_parent_template()
    {
        if ( ! is_null( wp_get_theme()->parent ) )
            return $this->to_stack( 'from parent theme' );

        $this->to_stack( 'from current/child theme' );
    }

    public function to_stack( $part, $item = '' )
    {
        $this->stack[] = "{$part}: {$item}";
    }
} // END Class wpse10537_template_name

} // endif;

Ce plugin peut aussi fonctionner comme MU-Plugin.

Vous pouvez ensuite simplement appeler wpse10537_get_template_name()à tout moment (dans un modèle de thème, par exemple). Cela évite d'encombrer l'espace de noms global.

kaiser
la source
1
template_redirectne passe rien, je pense que vous confondez avec template_include. Je voudrais aussi vérifier si à l'intérieur du filtre au lieu de si statique var rempli. Si un code décide d'exécuter du temps supplémentaire, il peut détruire des choses.
Rarst
@Rarst Done / Fixed. Merci pour l'allusion et en soulignant le nom du filtre.
Kaiser
5

Le nom du modèle est stocké dans la table postmeta, il vous suffit donc de le placer quelque part dans votre boucle:

$template = get_post_meta( $post->ID, '_wp_page_template', true );
echo "Template: " . $template;
Simon Blackbourn
la source
2
Oui, je suis au courant, mais le problème est que cela ne fonctionne que lorsqu'une page a un modèle défini. La chose cool sur le code que je posté est qu'il vous dira si la page en cours utilise front-page.php, index.php, single.php, page.phpou tout autre fichier. Votre code affiche le nom du modèle uniquement pour les pages avec un modèle de page personnalisé.
Chodorowicz
ah, désolé - mon incompréhension de votre question.
Simon Blackbourn
@SimonBlackbourn C'est une aide pour mon besoin. Merci.
KarSho
3

Cela ne répond pas à toutes les questions du PO, mais le code ci-dessous est certainement plus élégant que les expressions régulières et l'analyse du fichier modèle lui-même.

Si vous êtes sur une page utilisant un modèle de page et que vous souhaitez obtenir le nom du modèle de page (c'est-à-dire: le nom lisible par l'homme que vous avez défini dans les commentaires en haut de votre fichier PHP de modèle), vous pouvez utiliser cette petite pépite:

if ( is_page() && $current_template = get_page_template_slug( get_queried_object_id() ) ){
    $templates = wp_get_theme()->get_page_templates();
    $template_name = $templates[$current_template];
}

Je voulais obtenir le nom du modèle parce que j'en avais vraiment marre des noms de classe ridicules que la fonction intégrée de WordPress body_classcrée lorsque vous utilisez un modèle. Heureusement, il y a un crochet de filtre à la toute fin de cette fonction pour vous permettre d'ajouter également vos propres noms de classe. Voici mon filtre. J'espère que quelqu'un le trouvera utile:

add_filter( 'body_class', 'gs_body_classes', 10, 2 );
function gs_body_classes( $classes, $class ){
    if ( is_page() && $current_template = get_page_template_slug( get_queried_object_id() ) ){
        $templates = wp_get_theme()->get_page_templates();
        $template_name = str_replace( " ", "-", strtolower( $templates[$current_template] ) );

        $classes[] = $template_name;
    }

    return $classes;
}

Ce filtre prend ce que vous avez nommé votre modèle de page, remplace les espaces par des tirets et met tout en minuscule pour qu'il ressemble à toutes les autres classes WordPress.

Tom Auger
la source
0

Il y a un problème avec la preg_match_allligne. Essayez ceci à la place:

preg_match_all("/Template Name:(.*)\n/siU",$template_contents,$template_name);

En outre, vous pouvez utiliser if (!is_admin()) { .... }pour exécuter des choses sur le front-end uniquement.

Wyrfel
la source
Merci pour la suggestion, ils ne résolvent pas le problème, mais ils m'ont un peu orienté vers des solutions. Il se trouve que WP, lors de la création de la liste des modèles, cherche même à functions.phptrouver "/Template Name:(.*)\n/siU"et traite ainsi le functions.phpfichier en tant que modèle. Je pense que c'est un bogue WP, il ne devrait même pas regarder ce fichier. La solution: déplacez le fichier dans un sous-répertoire.
Chodorowicz
@chodorowicz: Ce n'est pas un bogue dans WP, c'est un bogue dans votre fonction.
Wyrfel
Donc, fondamentalement, WP vous interdit de mettre la chaîne "Nom du modèle:" (même en commentaire) dans le functions.phpfichier. Pour moi, personnellement, c’est un bug (petit, mais quand même) mais c’est le sujet de la discussion, je suppose. Je pense que vous ne pouvez pas dire que la fonction elle-même est un buggy.
Chodorowicz
WP ne vous interdit de rien faire. Mais WP ne vous promet pas non plus que vous pouvez boucler sur un debug_backtrace () pour savoir quel fichier de modèle vous utilisez. Ce n’est pas parce que vous l’avez trouvé sur un forum de support WP que le code est officiellement pris en charge. Comme vous pouvez le constater, votre fonction explicite explicitement footer.php. Vous pouvez également ajouter une autre condition excluant le fichier functions.php. BTW: votre fonction ne cherche pas Template Namedans chacun des fichiers, votre boucle est terminée bien avant.
Wyrfel
Le problème ne debug_backtrace()venait pas de - je peux supprimer tout le code et tout laisser preg_match_all("/Template Name..., ou même tout simplement // Template Name:et WP traite alors functions.phpcomme un fichier modèle, mais merci pour les commentaires - c'est un problème tellement unique que, comme vous dites, il n'est pas juste de dire c'est un bug. La solution t31os est propre et résout tout le problème. Salue.
Chodorowicz
0

Joue avec:

echo '<ul><li>'.implode('</li><li>', str_replace(str_replace('\\', '/', ABSPATH).'wp-content/', '', array_slice(str_replace('\\', '/', get_included_files()), (array_search(str_replace('\\', '/', ABSPATH).'wp-includes/template-loader.php', str_replace('\\', '/', get_included_files())) + 1)))).'</li></ul>';

Écrit à:

Comment savoir quelle page de modèle sert la page actuelle?

Si admin-bar stuffpath est affiché en haut, ou dans tout autre fichier, modifiez le nom template-loader.phpde fichier dans cette ligne de code en: quel que soit le nom de fichier que vous souhaitez interrompre.

si vous en avez besoin dans la barre d’administration, utilisez la bonne priorité (la plus ancienne) pour vous assurer qu’aucun fichier n’est entré à la fin de cette liste. Par exemple:

add_action('admin_bar_menu', 'my_adminbar_template_monitor', -5);

La priorité est de -5faire en sorte qu'elle soit chargée en premier. La clé est de rendre cette ligne au bon moment.

Il ne renvoie pas le fichier modèle "en cours", mais tout le fichier actuellement utilisé pour le chargement de page en cours. Peut-être "coupé" avec une logique de cette idée .

La get_included_files()"dernière" clé est le dernier fichier inclus enregistré, probablement le dernier modèle-fichier / -part utilisé dans le widget pied de page par la barre latérale ou quelque chose d'autre. Comme il se doit, les fichiers inclus dans la commande multiple ne sont pas réenregistrés / remplis à nouveau dans get_included_files ().

Autrement, l'intension doit être claire pour résoudre ce problème . Un fichier inclus ne peut pas se déclarer lui-même comme inclus tant qu'il n'a pas été inclus . Ensuite, il est probablement trop tard pour utiliser le scénario.

La plupart du "temps" que vous voudriez :

$template = get_current_loaded_template();
if($template == 'single-product.php') add_filter('the_title' ....
if($template == 'format-gallery.php') add_action('post_thumbnail' ....

Mais c’est impossible si le modèle est chargé en dehors de la méthode de base de Wordpress get_template_part. Re-concevez vos besoins à la place! Peut loop_start()- être , in_the_loop()et add_action('the_post')a la solution que vous souhaitez, pour modifier les données en fonction du modèle que vous allez charger pour chaque entrée d'une boucle.

Jonas Lundman
la source
-3
global $post;
$templateName = get_page_template_slug( $post->ID );
//echo $templateName;
var_dump( $templateName );
Shafi
la source