web-dev-qa-db-fra.com

Comment ajouter une partie de modèle de contenu personnalisé pour un type d'article personnalisé sur une requête principale à l'aide d'un plugin

J'ai un type de message personnalisé paper défini dans mon plugin WordPress que je montre avec les messages standard dans la requête principale via:

function add_custom_post_types_to_query( $query ) {
    if ( is_home() && $query->is_main_query() )
        $query->set( 'post_type', array( 'post', 'paper' ) );
    // As was pointed out by Ihor Vorotnov this return is not necessary. 
    // return $query;
}
add_action( 'pre_get_posts', 'add_custom_post_types_to_query' );

J'ai également pu enregistrer un modèle single-paper.php personnalisé à partir du répertoire du plugin pour mon type de message via:

function get_custom_post_type_single_template( $single_template ) {
     global $post;

     if ( $post->post_type == 'paper' ) {
          $single_template = dirname( __FILE__ ) . '/single-paper.php';
     }
     return $single_template;
}
add_filter( 'single_template', 'get_custom_post_type_single_template' );

J'aimerais faire quelque chose de similaire pour le modèle content-____.php utilisé par mon thème (onepress) afin de contrôler le mode d'affichage de mes publications dans la requête principale.

Le index.php du thème dit même:

<?php /* Start the Loop */ ?>
<?php while ( have_posts() ) : the_post(); ?>

<?php

    /*
     * Include the Post-Format-specific template for the content.
     * If you want to override this in a child theme, then include a file
     * called content-___.php (where ___ is the Post Format name) and that will be used instead.
     */
    get_template_part( 'template-parts/content', get_post_format() );
    ?>

<?php endwhile; ?>

mais je préférerais ne pas implémenter de thème enfant pour cela et conserver tout le code lié au type de publication personnalisé dans le plug-in.

Existe-t-il un moyen d'ajouter un filtre tel que get_template_part( 'template-parts/content', get_post_format() ); utilise un modèle personnalisé fourni par mon plug-in pour les publications paper et le modèle standard du thème pour les publications normales?

J'ai essayé différentes variantes du code que j'ai utilisé ci-dessus pour le 'single_template', mais en vain.

6
cgogolin

Contexte

Malheureusement, get_template_part() function n'a pas de filtre approprié pour obtenir ce que vous voulez. Il est possible d'utiliser le crochet d'action get_template_part_{$slug} pour injecter des parties de modèle. Toutefois, sans aucune modification apportée à votre thème ni à un thème enfant, la partie de modèle d'origine sera quand même ajoutée. De cette façon, vous ne pourrez pas remplacer les éléments de gabarit existants.

Cependant, vous pourrez obtenir le résultat souhaité en suivant l'une des options ci-dessous:


Option 1: Utilisez les classes CSS par défaut:

Si vous ne souhaitez que modifier le style du type de message personnalisé paper, vous pouvez simplement utiliser la classe CSS générée par WordPress. Tout thème standard dans WordPress générera les classes CSS $post_type et type-{$post_type} pour le contenu de la publication. Par exemple, le type d'article personnalisé paper aura paper & type-paper classes CSS et post général aura post et type-post classes CSS. De plus, la page d'accueil aura home classe CSS dans le corps. Donc, pour cibler les entrées paper dans la page d'accueil, vous pouvez utiliser les règles CSS suivantes:

body.home .type-paper {
    /* Custom CSS for paper entries in the home page */
}

Option 2: Modifier les classes CSS:

Si les classes CSS par défaut ne vous suffisent pas, vous pouvez également modifier (ajouter/supprimer) des classes CSS à l'aide du hook post_class filter de votre plugin. Comme ça:

add_filter( 'post_class', 'paper_post_class' );
function paper_post_class( $class ) {
    if ( get_post_type() === 'paper' && is_home() ) {

        // remove these classes
        $remove = array( 'css-class-to-remove', 'another-class-to-remove' );
        $class = array_diff( $class, $remove );

        // add these classes
        $add = array( 'custom-paper', 'my-paper-class' );
        $class = array_merge( $add, $class );
    }
    return $class;
}

Ainsi, vous pourrez supprimer les classes CSS non souhaitées pour les entrées paper et ajouter les nouvelles classes CSS souhaitées pour les entrées paper sans modifier les fichiers de thème. Utilisez ensuite ces classes CSS pour modifier le style des entrées paper selon vos besoins.


Option 3: Modifier le modèle et les parties du modèle

Si le changement de style souhaité n'est pas possible en ciblant uniquement les classes CSS, vous pouvez également modifier les parties du modèle à partir de votre plug-in. Toutefois, étant donné que le remplacement de parties de modèle ajoutées par get_template_part() n'est pas possible à l'aide de points d'ancrage, vous devez modifier le modèle de manière à pouvoir modifier l'appel get_template_part() à partir du plug-in.

Pour ce faire, vous pouvez cibler votre fonction de hook pre_get_posts et utiliser le hook template_include filter pour modifier le modèle de page d’accueil, comme suit:

function add_custom_post_types_to_query( $query ) {
    if ( is_home() && $query->is_main_query() ) {
        $query->set( 'post_type', array( 'post', 'paper' ) );

        // now also change the home page template, but only when this condition matches
        add_filter( 'template_include', 'wpse258844_custom_template', 999 );
    }
}
add_action( 'pre_get_posts', 'add_custom_post_types_to_query' ); 

Ensuite, utilisez le code suivant (modifiez-le selon vos besoins):

// for better file management, use a separate "theme-{$theme_name_slug}" directory within your plugin directory
// so if the active theme name is "OnePress", the directory name will be "theme-onepress"
// This will save you a ton of headache if you change the theme,
// as different themes may use different function calls within the templates, which other themes may not have
define( 'wpse258844_TEMPLATE_DIR', plugin_dir_path( __FILE__ ) . sprintf( 'theme-%s/', sanitize_title( wp_get_theme() ) ) );

function wpse258844_custom_template( $template ) {
    // this file will replace your homepage template file
    $index_paper = wpse258844_TEMPLATE_DIR . 'custom-home.php';

    // file_exists() check may need clearing stat cache if you change file name, delete the file etc.
    // Once you are done, comment out or remove clearstatcache(); in production
    clearstatcache();

    if ( file_exists( $index_paper ) ) {
        $template = $index_paper;
    }
    return $template;
}

function wpse258844_get_template_part( $slug, $name = null ) {
    if( get_post_type() === 'paper' ) {

        // just to be consistant with get_template_part() function
        do_action( "get_template_part_{$slug}", $slug, $name );

        $located = '';
        $name = (string) $name;

        // file_exists() check may need clearing stat cache if you change file name, delete the file etc.
        // Once you are done, comment out or remove clearstatcache(); in production
        clearstatcache();

        if ( '' !== $name && file_exists( wpse258844_TEMPLATE_DIR . "{$slug}-{$name}.php" ) ) {
            $located = wpse258844_TEMPLATE_DIR . "{$slug}-{$name}.php";
        }
        else if ( file_exists( wpse258844_TEMPLATE_DIR . "{$slug}.php" ) ) {
            $located = wpse258844_TEMPLATE_DIR . "{$slug}.php";
        }

        if ( '' != $located ) {
            load_template( $located, false );
            return;
        }
    }

    get_template_part( $slug, $name );
}

Une fois que vous avez le code ci-dessus dans votre plugin (lisez les commentaires dans le code):

  1. Créez un nouveau répertoire dans votre répertoire de plug-in pour conserver les fichiers de modèle de thème, par exemple. theme-onepress. Cela vous aidera dans l’avenir si vous souhaitez tester les modifications de conception avec un thème différent (je suppose que c’est l’objet principal de tous ces problèmes;)).

  2. Dans le nouveau répertoire theme-onepress, créez un fichier nommé custom-home.php. Copiez le modèle de code de page d'accueil de votre thème (il peut s'agir de index.php, ou home.php ou de tout ce que votre thème utilise pour le modèle de page d'accueil).

  3. Maintenant, dans custom-home.php, changez tous les appels de get_template_part en wpse258844_get_template_part. Pas besoin de changer le paramètre, seulement le nom de la fonction. La fonction wpse258844_get_template_part() dans le code ci-dessus est identique à la fonction get_template_part() et revient au comportement par défaut si une partie de modèle personnalisée n'est pas trouvée dans le répertoire theme-{$theme_name_slug} (par exemple, theme-onepress) de votre plugin.

  4. Enfin, remplacez le fichier pièce modèle que vous vouliez remplacer dans le répertoire theme-{$theme_name_slug} de votre plugin.

    Par exemple, si l'appel d'origine était get_template_part( 'template-parts/content', get_post_format() ) et que vous souhaitez remplacer le modèle content.php, placez simplement un fichier nommé content.php dans le répertoire theme-onepress/template-parts de votre plugin. Cela signifie que le répertoire theme-onepress se comportera comme un thème enfant pour les parties de modèle - c’est-à-dire un simple remplacement immédiat.

7
Fayaz

créez votre propre fonction pour cela:

function get_template_part_custom($content_name) {
     global $post;
     //its paper type?
     if ($post->post_type == 'paper') {
         //get template-parts/content-paper.php
         get_template_part( 'template-parts/content', $content_name );
     }else{
         //fallback to the default
         get_template_part( 'template-parts/content', get_post_format($post) );
     }
}

utilisez-le comme ceci:

get_template_part_custom('paper');

si le message est du type paper, il essaiera de charger un fichier appelé content-paper.php dans un dossier appelé template-parts dans le dossier du thème racine. Si le fichier n'existe pas, il essaiera de charger content.php. Vérifiez le template-hierarchy , je ne pense pas que vous deviez enregistrer votre modèle single-paper.php, WordPress le récupérera pour vous.

EDIT:

Pour charger un template depuis un plugin:

//load a custom file from the plugin
add_filter( 'template_include', 'return_our_template');

//Returns template file
function return_our_template( $template ) {

    // Post ID
    $post_id = get_the_ID();

    // For all other Types that arent ours
    if ( get_post_type( $post_id ) != 'paper' ) {
        return $template;
    }

    // Else use our custom template
    if ( is_single() ) {
        return get_custom_template( 'single' );
    }

}

//Get the custom template if is set
function get_custom_template( $template ) {

    // Get the slug
    $template_slug = rtrim( $template, '.php' );
    $template = $template_slug . '.php';

    // Check if a custom template exists in the theme folder, if not, load the plugin template file
    if ( $theme_file = locate_template( array( 'plugin_template/' . $template ) ) ) {
        $file = $theme_file;
    }
    else {
        //here path to '/single-paper.php'
        $file = PATH_TO_YOUR_BASE_DIR . $template;
    }
    //create a new filter so the devs can filter this
    return apply_filters( 'filter_template_' . $template, $file );
}
0
David Lee

Autant que je sache d'après le code source, vous ne pouvez pas filtrer get_template_part() comme vous le feriez normalement. S'il vous plaît voir ce fil pour certaines solutions.

0
Ihor Vorotnov

Voici un autre "hack" pour réaliser ce qui était demandé:

On peut utiliser le post format (à ne pas confondre avec le post type!) Pour utiliser un modèle personnalisé pour un type d'article personnalisé. Rappelez-vous la ligne

get_template_part( 'template-parts/content', get_post_format() );

dans le index.php décrit dans la question. Grâce à cette construction, la plupart des thèmes standard chargent différents modèles en fonction du post format.

On peut prétendre que toutes les publications d'un type de publication personnalisé donné, par exemple paper, ont un certain format de publication, disons aside en appelant

set_post_format( $post_id, 'aside' )

pendant la fonction accrochée au crochet 'save_post' et en ajoutant quelque chose comme

function paper_format_terms( $terms, $post_id, $tax ) {
    if ( 'post_format' === $tax && empty( $terms ) && 'paper' === get_post_type( $post_id ) ) {
        $aside = get_term_by( 'slug', 'post-format-aside', $tax );
        $terms = array( $aside );
    }
    return $terms;
}
add_filter( 'get_the_terms', 'paper_format_terms', 10, 3 );

au crochet 'get_the_terms'.

On ne peut pas définir de formats de publication personnalisés, mais il existe généralement au moins un format de publication qui n’est utilisé pour rien d’autre. Le format "à part" peut être un bon choix.

Un thème standard recherchera alors le modèle .../template-parts/content-aside.php, chaque fois qu’il rencontrera une publication paper. Il ne reste plus qu'à installer un modèle approprié dans le répertoire du thème de manière à ce qu'il ne soit ni écrasé ni supprimé lors de la mise à jour du thème (nous souhaitons conserver tout le code contenu dans le plugin!). Ceci peut être fait en plaçant un modèle approprié dans le champ content-aside.php dans le répertoire des plugins et en le reliant à `'upgrader_process_complete' comme suit

function install_aside_template_on_upgrade( $upgrader_object, $options ) {
    if ($options['type'] == 'theme' ) {
        $content_aside = plugin_dir_path( __FILE__ ) . 'content-aside.php';
        $template_parts_content_aside = get_stylesheet_directory() . '/template-parts/content-aside.php';

        copy($content_aside, $template_parts_content_aside);
    }
}
add_action( 'upgrader_process_complete', 'install_aside_template_on_upgrade',10, 2);

De cette manière, le content-aside.php est copié dans le répertoire du thème après chaque mise à jour du thème.

Gardez à l'esprit que c'est un bidonville assez terrible et qu'il peut avoir des effets secondaires indésirables! Pourtant, je pensais que cela pouvait être utile à certains ...

0
cgogolin

Bien qu’il ne s’agisse pas d’une réponse exacte à la question telle qu’elle a été publiée, il existe un autre moyen assez propre et simple d’obtenir un résultat similaire qui, je suppose, sera la solution optimale optimale pour de nombreuses personnes se retrouvant sur cette page. Pour moi, les exigences ont légèrement changé après avoir posé cette question, ce qui m'a permis de choisir cette solution à la fin.

Au lieu d'utiliser un thème personnalisé, dans de nombreux cas, il suffit de changer ce qu'un type de message personnalisé renvoie lorsque le modèle du thème appelle the_excerpt(). Ceci peut être réalisé en s’accrochant au filtre 'the_excerpt' comme suit:

function paper_get_the_excerpt ($content) {
    global $post;
    $post_id = $post->ID;
    if ( get_post_type($post_id) === 'paper' ) {
        [do whatever you want with $content]
    }
    return $content;
}
add_filter( 'the_excerpt', 'paper_get_the_excerpt' );

Nice, propre et simple et permet presque autant de flexibilité que de changer le modèle.

0
cgogolin