Créer une page d'archive personnalisée pour un type de publication personnalisé dans un plugin

11

J'écris un plugin qui crée un type de publication personnalisé nommé "my_plugin_lesson":

$args = array (
    'public' => true,
    'has_archive' => true,
    'rewrite' => array('slug' => 'lessons', 'with_front' => false)
);
register_post_type ('my_plugin_lesson', $args);

Le type de publication personnalisé a une archive et l'URL de l'archive est:

http://example.com/lessons

Je veux personnaliser l'apparence de cette archive; Je veux lister les articles sous forme de tableau, plutôt que les archives standard des articles de blog WordPress. Je comprends qu'un modèle d'archive personnalisé pourrait être créé dans le thème en créant le archive-my_plugin_lesson.phpfichier; cependant, j'aimerais que le plugin fonctionne avec n'importe quel thème.

Comment puis-je modifier le contenu de la page d'archive sans ajouter ou modifier des fichiers de thème?

Edit: je comprends que je pourrais utiliser le archive_templatecrochet du filtre. Cependant, tout cela ne fait que remplacer le modèle de thème, qui doit encore être spécifique au thème. Par exemple, à peu près tous les modèles de thème aura besoin des get_header, get_sidebaret des get_footerfonctions, mais ce que l'identifiant du contenu devrait <div>être? C'est différent dans chaque thème.

Ce que je voudrais faire, c'est remplacer le contenu lui-même par mon propre contenu et l'utiliser à la place de la page d'archive pour mon type de publication personnalisé.

Ben Miller - Souvenez-vous de Monica
la source

Réponses:

12

Ce dont vous avez besoin est d'accrocher le template_includefiltre et de charger sélectivement votre modèle dans le plugin.

Comme bonne pratique, si vous prévoyez de distribuer votre plugin, vous devriez vérifier si archive-my_plugin_lesson.php(ou peut-être myplugin/archive-lesson.php) existe dans le thème, sinon utiliser la version du plugin.

De cette façon, il est facile pour les utilisateurs de remplacer le modèle via un thème (ou un thème enfant) sans modifier le code du plugin.

C'est la méthode utilisée par les plugins populaires, par exemple WooCommmerce, juste pour dire un nom.

add_filter('template_include', 'lessons_template');

function lessons_template( $template ) {
  if ( is_post_type_archive('my_plugin_lesson') ) {
    $theme_files = array('archive-my_plugin_lesson.php', 'myplugin/archive-lesson.php');
    $exists_in_theme = locate_template($theme_files, false);
    if ( $exists_in_theme != '' ) {
      return $exists_in_theme;
    } else {
      return plugin_dir_path(__FILE__) . 'archive-lesson.php';
    }
  }
  return $template;
}

Plus d'informations sur le Codex pour

gmazzap
la source
Cela remplace toujours le fichier de modèle du thème, non? Qu'est-ce que je mets dans le fichier archive-lesson.php de mon plugin? Il faudrait que ce soit différent pour travailler avec chaque thème. Même les «Vingt» thèmes par défaut ne sont pas d'accord sur les conteneurs div / section qui entourent le contenu.
Ben Miller - Souvenez-vous de Monica
7

Vous pouvez utiliser le archive_templatehook pour traiter le contenu du modèle d'archive d'un thème, en utilisant le schéma ci-dessous, mais vous ne pourrez évidemment traiter qu'une fraction des thèmes, étant donné qu'un modèle peut essentiellement contenir n'importe quelle chose ancienne .

Le schéma consiste à charger le modèle dans une chaîne ( $tpl_str) dans le archive_templatefiltre, à remplacer votre contenu, à inclure la chaîne (à l'aide de l'astuce eval( '?>' . $tpl_str );), puis à renvoyer un fichier vide de sorte que includedans "wp-includes / template-loader.php" devient un no-op.

Vous trouverez ci-dessous une version piratée du code que j'utilise dans un plugin, qui cible les modèles "classiques" qui utilisent get_template_partet est plus concerné par le traitement de modèles uniques que d'archive, mais devrait vous aider à démarrer. La configuration est que le plugin a un sous-répertoire appelé "modèles" qui contient un fichier vierge ("null.php") et des modèles de contenu (par exemple "content-single-posttype1.php", "content-archive-postype1.php") ainsi qu'un modèle de repli "single.php" pour le cas unique, et utilise une version personnalisée get_template_partqui ressemble à ce répertoire.

define( 'MYPLUGIN_FOLDER', dirname( __FILE__ ) . '/' );
define( 'MYPLUGIN_BASENAME', basename( MYPLUGIN_FOLDER ) );

add_filter( 'single_template', 'myplugin_single_template' );
add_filter( 'archive_template', 'myplugin_archive_template' );

function myplugin_single_template( $template ) {
    static $using_null = array();

    // Adjust with your custom post types.
    $post_types = array( 'posttype1', );

    if ( is_single() || is_archive() ) {
        $template_basename = basename( $template );
        // This check can be removed.
        if ( $template == '' || substr( $template_basename, 0, 4 ) == 'sing' || substr( $template_basename, 0, 4 ) == 'arch' ) {
            $post_type = get_post_type();
            $slug = is_archive() ? 'archive' : 'single';
            if ( in_array( $post_type, $post_types ) ) {
                // Allow user to override.
                if ( $single_template = myplugin_get_template( $slug, $post_type ) ) {
                    $template = $single_template;
                } else {
                    // If haven't gone through all this before...
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        if ( $template && ( $content_template = myplugin_get_template( 'content-' . $slug, $post_type ) ) ) {
                            $tpl_str = file_get_contents( $template );
                            // You'll have to adjust these regexs to your own case - good luck!
                            if ( preg_match( '/get_template_part\s*\(\s*\'content\'\s*,\s*\'' . $slug . '\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'content\'\s*,\s*get_post_format\s*\(\s*\)\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'content\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'[^\']+\'\s*,\s*\'' . $slug . '\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE ) ) {
                                $using_null[$slug][$post_type] = true;
                                $tpl_str = substr( $tpl_str, 0, $matches[0][1] ) . 'include \'' . $content_template . '\'' . substr( $tpl_str, $matches[0][1] + strlen( $matches[0][0] ) );
                                // This trick includes the $tpl_str.
                                eval( '?>' . $tpl_str );
                            }
                        }
                    }
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        // Failed to parse - look for fall back template.
                        if ( file_exists( MYPLUGIN_FOLDER . 'templates/' . $slug . '.php' ) ) {
                            $template = MYPLUGIN_FOLDER . 'templates/' . $slug . '.php';
                        }
                    } else {
                        // Success! "null.php" is just a blank zero-byte file.
                        $template = MYPLUGIN_FOLDER . 'templates/null.php';
                    }
                }
            }
        }
    }
    return $template;
}

function myplugin_archive_template( $template ) {
    return myplugin_single_template( $template );
}

La coutume get_template_part:

/*
 * Version of WP get_template_part() that looks in theme, then parent theme, and finally in plugin template directory (sub-directory "templates").
 * Also looks initially in "myplugin" sub-directory if any in theme and parent theme directories so that plugin templates can be kept separate.
 */
function myplugin_get_template( $slug, $part = '' ) {
    $template = $slug . ( $part ? '-' . $part : '' ) . '.php';

    $dirs = array();

    if ( is_child_theme() ) {
        $child_dir = get_stylesheet_directory() . '/';
        $dirs[] = $child_dir . MYPLUGIN_BASENAME . '/';
        $dirs[] = $child_dir;
    }

    $template_dir = get_template_directory() . '/';
    $dirs[] = $template_dir . MYPLUGIN_BASENAME . '/';
    $dirs[] = $template_dir;
    $dirs[] = MYPLUGIN_FOLDER . 'templates/';

    foreach ( $dirs as $dir ) {
        if ( file_exists( $dir . $template ) ) {
            return $dir . $template;
        }
    }
    return false;
}

Pour être complet, voici la solution de remplacement "single.php", qui utilise la coutume get_template_part:

<?php
get_header(); ?>

    <div id="primary" class="content-area">
        <div id="content" class="clearfix">
            <?php while ( have_posts() ) : the_post(); ?>

            <?php if ( $template = myplugin_get_template( 'content-single', get_post_type() ) ) include $template; else get_template_part( 'content', 'single' ); ?>

                <?php
                    // If comments are open or we have at least one comment, load up the comment template
                    if ( comments_open() || '0' != get_comments_number() ) :
                        comments_template();
                    endif;
                ?>

            <?php endwhile; ?>

        </div><!-- #content -->
    </div><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>
bonger
la source
1

J'ai réfléchi à la même question, et c'est la solution hypothétique que j'ai trouvée:

  • Dans le plugin, créez un shortcode qui sort votre boucle d'archive comme vous le souhaitez.
  • Lors de la création du type de publication personnalisé, n'activez pas l'option «archive».
  • Ajoutez une feuille de style qui contrôle tous les styles de votre contenu de boucle.

Lors de l'activation du plugin, créez une page en utilisant wp_insert_post avec le nom étant le type de publication et le contenu étant le shortcode.

Vous pouvez fournir des options dans le shortcode pour des considérations de style supplémentaires, ou ajouter des classes au conteneur de publication pour faire correspondre les styles spécifiques ou personnalisés au thème. L'utilisateur peut également ajouter du contenu supplémentaire avant / après la boucle en modifiant la page.

SkyShab
la source
Bien que je ne sois pas l'OP, je cherchais une solution au même problème. J'ai suivi votre solution hypotétique et je peux maintenant confirmer qu'elle fonctionne aussi dans la pratique.
Lucio Crusca
Hé bien! Heureux que cela ait été utile pour quelqu'un. J'avais complètement oublié ça.
SkyShab
0

Vous pouvez utiliser le filtre single_template. Un exemple de base tiré du Codex :

function get_custom_post_type_template($single_template) {
     global $post;

     if ($post->post_type == 'my_post_type') {
          $single_template = dirname( __FILE__ ) . '/post-type-template.php';
     }
     return $single_template;
}

add_filter( "single_template", "get_custom_post_type_template" );
Eyal
la source
Je pense que le crochet de filtre pour un modèle d'archive est archive_template, mais je ne pense pas que cela fonctionnera pour ce que j'essaie de faire. J'ai édité ma question avec plus d'informations.
Ben Miller - Souvenez-vous de Monica