web-dev-qa-db-fra.com

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

J'écris un plugin qui crée un type de post 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 cette archive est:

http://example.com/lessons

Je veux personnaliser l'apparence de cette archive. Je souhaite répertorier les publications dans un format de tableau plutôt que dans les archives de publication de blog WordPress standard. Je comprends qu’un modèle d’archive personnalisé pourrait être créé dans le thème en créant le fichier archive-my_plugin_lesson.php; 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 hook archive_template filter. Cependant, cela ne fait que remplacer le modèle de thème, qui doit toujours être spécifique à un thème. Par exemple, à peu près tous les modèles de thème auront besoin des fonctions get_header, get_sidebar et get_footer, mais quel devrait être l'identifiant du contenu <div>? C'est différent dans chaque thème.

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

7
Ben Miller

Ce dont vous avez besoin, c'est de crocheter le filtre template_include et de charger sélectivement votre modèle dans le plugin.

À titre de bonne pratique, si vous envisagez de distribuer votre plug-in, vous devez vérifier si archive-my_plugin_lesson.php (ou peut-être myplugin/archive-lesson.php) existe dans le thème, sinon utilisez la version du plug-in.

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

8
gmazzap

Vous pouvez utiliser le hook archive_template 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 jamais traiter qu'une fraction des thèmes, étant donné qu'un modèle peut contenir n'importe quel ancien chose.

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

Ci-dessous, une version piratée du code que j'utilise dans un plugin, qui cible les modèles "classiques" qui utilisent get_template_part et est plus concernée par le traitement de modèles uniques que par l'archive, mais devrait vous aider à démarrer. La configuration est que le plugin a un sous-répertoire appelé "templates" qui contient un fichier vide ("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 individuel et utilise une version personnalisée de get_template_part qui apparaît dans 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 );
}

Le get_template_part personnalisé:

/*
 * 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 repli "single.php", qui utilise le get_template_part personnalisé:

<?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(); ?>
6
bonger

J'ai réfléchi à la même question et voici la solution hypothétique que j'ai proposé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 du contenu de votre boucle.

Lors de l'activation du plug-in, créez une page à l'aide de wp_insert_post, avec le nom correspondant au type de publication et le contenu au shortcode.

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

1
SkyShab

Vous pouvez utiliser le filtre single_template. Un exemple de base pris 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" );
0
Eyal