Mettre à jour: Le code a été mis à jour récemment pour fonctionner sur WordPress 4.7+

Avez-vous déjà voulu créer vos propres modèles de page, mais n’avez pas eu accès au thème lui-même? En tant qu’auteur de plugins WordPress, j’ai trouvé ce problème particulièrement ennuyeux lors du développement de mes plugins. Heureusement, la solution est assez simple! Je vais vous expliquer rapidement les quelques lignes de code dont vous aurez besoin pour créer dynamiquement des modèles de page WordPress directement via PHP.

L’inspiration pour cet article et le génie derrière la solution de code vient de Tom McFarlin: J’utilise ma version modifiée de son code d’origine, que vous pouvez trouver sur son GitHub. J’ai gardé ses commentaires (ainsi que l’ajout de mes propres commentaires) car je le trouve très utile pour expliquer ce qui se passe – je n’aurais pas pu le dire mieux moi-même!

Vous pouvez trouver le code dans son intégralité et un exemple de plugin tout en bas de cet article.

Allons-nous commencer?

LE CODE

Nous allons créer notre fonction PHP en utilisant une classe PHP. Pour ceux d’entre vous qui ne connaissent pas bien les classes PHP, une classe est définie comme un objet qui contient une collection de fonctions et de variables qui fonctionnent ensemble. Vérifiez Introduction à PHP.net pour plus de détails sur la syntaxe et la théorie.

Notre wrapper n’aura besoin que de 3 variables:

  1. Le plugin Slug: Ceci est simplement utilisé comme identifiant unique pour le plugin.
  2. Instance de classe: Comme nous ajoutons une instance de cette classe à la tête de WordPress, nous ferions mieux de la stocker.
  3. Tableau de modèles: Comme vous pouvez probablement le deviner, il s’agit d’un tableau contenant les noms et titres des modèles.

Les voici en code:

class PageTemplater {

        /**
         * A Unique Identifier
         */
         protected $plugin_slug;

        /**
         * A reference to an instance of this class.
         */
        private static $instance;

        /**
         * The array of templates that this plugin tracks.
         */
        protected $templates;

Obtenir une instance de classe

Comme je l’ai dit précédemment, nous ajouterons une instance de notre classe à l’en-tête WordPress en utilisant le add_filter () fonction. Par conséquent, nous aurons besoin d’une méthode qui retournera (ou créera) cette instance pour nous.

Pour cela, nous aurons besoin d’une méthode simple, qui s’appellera ‘get_instance’. Vérifiez-le ci-dessous;

/**
 * Returns an instance of this class. 
 */
public static function get_instance() {

    if( null == self::$instance ) {
        self::$instance = new PageTemplater();
    } 

    return self::$instance;

}

Ce sera la méthode appelée lorsque notre classe sera ajoutée à la tête WordPress en utilisant ‘add_action ()’.

Filtres WordPress

Maintenant que nous avons trié la méthode ‘get_instance’, nous devons trier ce qui se passe lorsqu’elle est réellement instanciée.

Nous utiliserons l’intégration de WordPress add_filter () pour ajouter une instance de notre classe en points clés le long de la chronologie d’initialisation de WordPress. En utilisant cette méthode, nous insérerons les données de nos modèles de page dans les emplacements appropriés, comme indiquer à WordPress quel fichier utiliser comme modèle lorsque la page est appelée et le titre à afficher dans le menu déroulant de l’éditeur de page.

Pour cela, nous devons utiliser le ‘__construction’ méthode (elle sera exécutée lorsque la classe sera instanciée).

/**
 * Initializes the plugin by setting filters and administration functions.
 */
private function __construct() {

    $this->templates = array();

    // Add a filter to the attributes metabox to inject template into the cache.
    if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {

        // 4.6 and older
        add_filter(
            'page_attributes_dropdown_pages_args',
            array( $this, 'register_project_templates' )
        );

    } else {

        // Add a filter to the wp 4.7 version attributes metabox
        add_filter(
            'theme_page_templates', array( $this, 'add_new_template' )
        );

    }

    // Add a filter to the save post to inject out template into the page cache
    add_filter(
        'wp_insert_post_data', 
        array( $this, 'register_project_templates' ) 
    );

    // Add a filter to the template include to determine if the page has our 
    // template assigned and return it's path
    add_filter(
        'template_include', 
        array( $this, 'view_project_template') 
    );

    // Add your templates to this array.
    $this->templates = array(
        'goodtobebad-template.php' => 'It's Good to Be Bad',
    );

}

Il y a 4 choses différentes qui se passent ici (en ignorant ‘$ this-> templates = array ();’, qui prépare juste la variable pour l’utilisation);

  1. Lignes 9 à 13: Ce filtre ajoute le ‘register_project_templates’ au hook ‘page_attributes_dropdown_pages_args’. Cela remplit le cache WordPress avec nos nouveaux modèles, «trompant» WordPress en lui faisant croire que les fichiers de modèle de page existent réellement dans le répertoire des modèles. Cela ajoute les modèles de page à la liste déroulante de la méta-boîte des attributs de page dans l’éditeur de page.
  2. Lignes 16 à 20: Ici, nous faisons essentiellement la même chose que le bloc de code précédent, sauf que cette fois, nous ajoutons également notre modèle de page (s’il est sélectionné) aux données de publication enregistrées.
  3. Lignes 23 à 28: Ce filtre ajoute le “template_include” au hook “view_project_template”. C’est une fonction très importante; cela indique à WordPress où se trouve réellement votre fichier de modèle de page. WordPress utilisera le chemin fourni par celui-ci pour rendre la page finale.
  4. Lignes 31 à 34: Bien que ce soit simple, c’est très important. C’est ici que vous spécifiez les modèles de page que vous souhaitez ajouter, et le chemin relatif au fichier où se trouve le fichier de modèle de page (par exemple ‘quelque chose.php’). J’ai inclus un exemple (qui sera utilisé dans l’exemple de plugin). Consultez ci-dessous pour un exemple général:
$this->templates = array(
    'FILE_PATH_AND_NAME'               => 'TEMPLATE_TITLE',
    'awesome-template.php'             => 'Awesome',
    'templates/organised-template.php' => 'Organised',
);

(Mangez, Dormez,) Code, Répétez si nécessaire.

register_project_templates ()

J’ai fait allusion à cette méthode précédemment; voyons ce qu’il fait réellement.

Essentiellement, le but de cette méthode est de manipuler le cache de WordPress, en insérant les données pertinentes sur nos modèles de page aux bons endroits. Jetez d’abord un coup d’œil au code, et je vous en parlerai ensuite.

public function register_project_templates( $atts ) {

    // Create the key used for the themes cache
    $cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );

    // Retrieve the cache list. 
    // If it doesn't exist, or it's empty prepare an array
    $templates = wp_get_theme()->get_page_templates();
    if ( empty( $templates ) ) {
        $templates = array();
    } 

    // New cache, therefore remove the old one
    wp_cache_delete( $cache_key , 'themes');

    // Now add our template to the list of templates by merging our templates
    // with the existing templates array from the cache.
    $templates = array_merge( $templates, $this->templates );

    // Add the modified cache to allow WordPress to pick it up for listing
    // available templates
    wp_cache_add( $cache_key, $templates, 'themes', 1800 );

    return $atts;

}

Bon alors. La ligne 4 est le premier endroit à regarder. Comme vous l’avez peut-être deviné, nous générons une «clé de cache». Il sera utilisé comme identifiant unique pour notre données de modèle de page. L’utilisation de la fonction md5 () crée simplement un identifiant de chaîne unique pour éviter tout conflit.

Ensuite, à la ligne 8, nous recherchons et récupérons le cache du modèle de page (s’il existe déjà): cela retournera un tableau de chemins et de titres. Aux lignes 9 à 11, nous vérifions s’il y avait une sortie de la requête de cache. Si oui, super. Sinon, créez un tableau local pour contenir les données que nous fusionnerons dans le cache.

La prochaine étape est cruciale. Sur la ligne 14 nous effacer le cache de modèle de page existant. Ne vous inquiétez pas, aucune donnée n’est perdue – elle est stockée dans la variable $ templates.

À la ligne 18, nous fusionnons le cache des modèles de page existants avec nos nouvelles entrées, et à la ligne 22, nous réinsérons le cache du modèle de page entier dans le système de WordPress.

Facile!

view_project_template ()

Nous sommes maintenant sur notre méthode finale; c’est là que nous indiquons à WordPress où se trouve le vrai fichier de modèle de page.

/**
 * Checks if the template is assigned to the page
 */
public function view_project_template( $template ) {
    
    // Get global post
    global $post;

    // Return template if post is empty
    if ( ! $post ) {
        return $template;
    }

    // Return default template if we don't have a custom one defined
    if ( !isset( $this->templates[get_post_meta( 
        $post->ID, '_wp_page_template', true 
    )] ) ) {
        return $template;
    } 

    $file = plugin_dir_path(__FILE__). get_post_meta( 
        $post->ID, '_wp_page_template', true
    );

    // Just to be safe, we check if the file exist first
    if ( file_exists( $file ) ) {
        return $file;
    } else {
        echo $file;
    }

    // Return template
    return $template;

}

Ok alors, cette méthode vérifiera la variable globale $ post (ligne 6). Il vérifie si un modèle de page (‘_wp_page_template’) a été défini pour le message (ce qui signifie qu’il doit s’agir d’une page). Sinon, tant pis – les non-pages ne peuvent pas avoir de modèles de page.

La ligne 16 spécifie l’emplacement du fichier de modèle de page. Comme je l’ai indiqué ci-dessus, il vérifie le fichier de modèle de page spécifié dans le répertoire racine de votre plugin. (Cela peut être facilement changé, voir ci-dessous.)

// Just changing the page template path
// WordPress will now look for page templates in the subfolder 'templates',
// instead of the root
$file = plugin_dir_path(__FILE__). 'templates/' .get_post_meta( 
    $post->ID, '_wp_page_template', true 
);

Après cela, aux lignes 21 à 24, nous avons juste un petit peu de validation qui vérifie si le fichier existe réellement. Si oui, génial! Sinon, oh mon Dieu … Vous obtiendrez probablement un message d’erreur PHP si WordPress ne trouve pas le fichier modèle, ou même un écran vide. Si l’un de ces symptômes vous semble familier, vérifiez simplement le chemin du fichier modèle en imprimant la variable $ file à l’écran.

Si vous envisagez d’utiliser ce code dans le commerce (ce que vous êtes libre de faire – ma version du code est livrée sans licence, vous êtes donc libre de le faire à votre guise), je recommande vraiment d’investir un peu de temps dans la gestion des erreurs pour un maximum fiabilité.

C’est ça. Une fois notre cours terminé, il ne reste plus qu’une chose à faire: l’ajouter à la tête WordPress.

add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );

Félicitations si vous avez réussi tout le temps! J’espère que vous avez trouvé ce que j’avais à dire utile et que vous en bénéficierez à l’avenir!

CODE ENTIER

Voici le code complet du plugin pour un copier-coller facile.

<?php
/*
Plugin Name: Page Template Plugin : 'Good To Be Bad'
Plugin URI: http://www.wpexplorer.com/wordpress-page-templates-plugin/
Version: 1.1.0
Author: Themelocal
Author URI: http://www.wpexplorer.com/
*/

class PageTemplater {

    /**
     * A reference to an instance of this class.
     */
    private static $instance;

    /**
     * The array of templates that this plugin tracks.
     */
    protected $templates;

    /**
     * Returns an instance of this class. 
     */
    public static function get_instance() {

        if ( null == self::$instance ) {
            self::$instance = new PageTemplater();
        } 

        return self::$instance;

    } 

    /**
     * Initializes the plugin by setting filters and administration functions.
     */
    private function __construct() {

        $this->templates = array();


        // Add a filter to the attributes metabox to inject template into the cache.
        if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {

            // 4.6 and older
            add_filter(
                'page_attributes_dropdown_pages_args',
                array( $this, 'register_project_templates' )
            );

        } else {

            // Add a filter to the wp 4.7 version attributes metabox
            add_filter(
                'theme_page_templates', array( $this, 'add_new_template' )
            );

        }

        // Add a filter to the save post to inject out template into the page cache
        add_filter(
            'wp_insert_post_data', 
            array( $this, 'register_project_templates' ) 
        );


        // Add a filter to the template include to determine if the page has our 
        // template assigned and return it's path
        add_filter(
            'template_include', 
            array( $this, 'view_project_template') 
        );


        // Add your templates to this array.
        $this->templates = array(
            'goodtobebad-template.php' => 'It's Good to Be Bad',
        );
            
    } 

    /**
     * Adds our template to the page dropdown for v4.7+
     *
     */
    public function add_new_template( $posts_templates ) {
        $posts_templates = array_merge( $posts_templates, $this->templates );
        return $posts_templates;
    }

    /**
     * Adds our template to the pages cache in order to trick WordPress
     * into thinking the template file exists where it doens't really exist.
     */
    public function register_project_templates( $atts ) {

        // Create the key used for the themes cache
        $cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );

        // Retrieve the cache list. 
        // If it doesn't exist, or it's empty prepare an array
        $templates = wp_get_theme()->get_page_templates();
        if ( empty( $templates ) ) {
            $templates = array();
        } 

        // New cache, therefore remove the old one
        wp_cache_delete( $cache_key , 'themes');

        // Now add our template to the list of templates by merging our templates
        // with the existing templates array from the cache.
        $templates = array_merge( $templates, $this->templates );

        // Add the modified cache to allow WordPress to pick it up for listing
        // available templates
        wp_cache_add( $cache_key, $templates, 'themes', 1800 );

        return $atts;

    } 

    /**
     * Checks if the template is assigned to the page
     */
    public function view_project_template( $template ) {
        
        // Get global post
        global $post;

        // Return template if post is empty
        if ( ! $post ) {
            return $template;
        }

        // Return default template if we don't have a custom one defined
        if ( ! isset( $this->templates[get_post_meta( 
            $post->ID, '_wp_page_template', true 
        )] ) ) {
            return $template;
        } 

        $file = plugin_dir_path( __FILE__ ). get_post_meta( 
            $post->ID, '_wp_page_template', true
        );

        // Just to be safe, we check if the file exist first
        if ( file_exists( $file ) ) {
            return $file;
        } else {
            echo $file;
        }

        // Return template
        return $template;

    }

} 
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );

LE PLUGIN

Vous pouvez également télécharger le code complet sous forme de plugin sur Github.

CLOSEUP DE LA RÉDACTION

Voici un gros plan du plugin en action. Voir le modèle de page ajouté sous Attributs de page?

Share: