web-dev-qa-db-fra.com

Modèle de page en tant qu'archive de type publication personnalisée

Mon objectif est d’utiliser le slug www.domain.com/resources par un Modèle de page plutôt que/ Archive Page , et d’avoir une publication CPT unique, telle que www.domain.com/resources/post.

Je pensais que la solution fonctionnerait:

J'ai créé une nouvelle page dans Wordpress et lui ai donné un modèle de page personnalisé. J'enregistre également mon type de message personnalisé comme suit. Portez une attention particulière à has_archive et rewrite :

function bb_resources() {
    register_post_type( 'resources', array(
            'labels' => array(
                    'name' => 'Resources',
                    'singular_name' => 'Resource',
            ),
            'taxonomies' => array('resources_cat'),
            'public' => true,
            'has_archive' => false,
            'show_ui' => true,
            'supports' => array( 'title', 'editor' ),
            'rewrite' => array('slug'=>'resources', 'with_front'=>false),
    ) );
}

Cela crée toutefois un 404 sur les pages à publication unique.

Je suis perplexe, s'il vous plaît aviser!

6
wackerfuss

Depuis WordPress version 4.4, le hook 'theme_page_templates' permet de définir des modèles de page arbitraires.

Cela signifie qu'il est possible d'afficher des valeurs arbitraires dans le menu "Modèle de page" de l'écran de modification de page et qu'une fois sélectionnée, la valeur sera stockée dans la méta de modèle de page de la page.

Cela signifie que vous pouvez créer "automatiquement" un modèle de page pour n'importe lequel des CPT enregistrés.

Modèles de page d'installation

Le code ressemblerait à ceci:

add_action( 'current_screen', function( \WP_Screen $screen ) {
    if( 'page' !== $screen->id || 'post' !== $screen->base ) {
        return;
    }

    // retrieve CPT objects with archive
    $types = get_post_types( ['has_archive' => true], 'objects' );

    // store CPT slug and labels in an array
    $menu = array();
    foreach( $types as $cpt ) {
        $menu[ $cpt->name ] = 'Archive: ' . $cpt->label;
    }

    // merge with page templates
    $menu and add_filter(
        'theme_page_templates',
        function( array $templates ) use ( $menu ) {
            $templates = array_merge( $templates, $menu );
            return $templates;
        }
    );
} );

Lorsque ce code est en place, en supposant que vous avez enregistré un type de publication resources avec has_archive défini sur true, lorsque vous créez ou modifiez une page, vous verrez dans le menu "Modèle de page" un modèle de page nommé Archive: Resources.

Vous pouvez choisir ce modèle lors de la création d'une page, que vous souhaitez utiliser pour afficher vos publications resources.

Rediriger l'accès direct à la page

Étant donné que cette page est une archive de plus d'une page, vous pouvez utiliser du code pour rediriger les utilisateurs vers les archives du CPT lors de l'accès à la page:

add_action( 'template_redirect', function() {
    if( is_page_template() ) {

        // current page templates
        $template = get_page_template_slug( get_queried_object_id() );

        // array of CPT names, filtering the ones with archives
        $types = get_post_types( array( 'has_archive' => true ), 'names' );

        // if the current template is one of the CPT, redirect
        if( in_array( $template, $types, true ) ) {
            wp_safe_redirect( get_post_type_archive_link( $template ) );
            exit();
        }
    }
} );

Obtenir les données de la page

Vous voudrez probablement utiliser le contenu et le titre de cette page lors de la lecture de l'article.

Écrivons donc une fonction qui vous permet d’obtenir la page d’un type de message spécifique.

function get_archive_page( $post_type = '' ) {

    // if no CPT given, let's use the current main query to get it
    if( ! $post_type ) {
        global $wp_query;
        $query_var = ( array ) $wp_query->get( 'post_type' );
        $post_type = reset($query_var);
    }

    // if we have a valid post type
    if( post_type_exists( $post_type ) ) {

        // let's query the first page that has a page template
        // named after the the post type
        $posts = get_posts( array(
            'post_type'      => 'page',
            'post_status'    => 'publish',
            'posts_per_page' => 1,
            'orderby'        => 'menu_order',
            'order'          => 'ASC',
            'meta_query' => array( array( 
                'key'   => '_wp_page_template',
                'value' => $post_type
            ) )
        ) );

        // if we have results, return first (and only) post object
        if( $posts ) {
            return reset($posts);
        }
    }
}

Vous pouvez utiliser la fonction ci-dessus pour écrire deux fonctions supplémentaires pour obtenir le titre et le contenu de la page:

function get_archive_page_title( $post_type = '' ) {
    $page = get_archive_page( $post_type );

    return ( $page ) ? get_the_title( $page ) : '';
}    

function get_archive_page_content( $post_type = '' ) {
    $page       = get_archive_page( $post_type );
    $content    = '';

    if( $page ) {
        setup_postdata( $page );
        ob_start();
            the_content();
        $content = ob_get_clean();
        wp_reset_postdata();
    }

    return $content;
}

function the_archive_page_title() {
    echo get_archive_page_title();
}

function the_archive_page_content() {
    echo get_archive_page_content();
}

Les noms de fonctions doivent indiquer clairement ce qu’ils font.

Vous pouvez également écrire des fonctions telles que get_archive_page_meta() si vous avez besoin de champs personnalisés.

Dans le modèle d'archive

Maintenant, dans le modèle archive.php (ou dans le archive-resources.php), vous pouvez utiliser les fonctions ci-dessus pour afficher le titre et le contenu de la page d'archive.

Cela ressemblera à quelque chose comme:

<h1><?php the_archive_page_title(); ?></h1>

<div><?php the_archive_page_content(); ?></div>

<?php
    while( have_posts() ) : the_post();
        // loop stuff here
    endwhile;
?>

De cette façon, votre URL d’archive CPT sera example.com/resources/ et votre seule URL CPT sera example.com/resources/post-name/ comme vous le souhaitez.

Dans le même temps, vous pourrez écrire du contenu et un titre (et des champs personnalisés, si vous le souhaitez) spécifiques au type de publication.

En outre, considérez que cette méthode est réutilisable pour tout type de publication que vous avez ou pourriez utiliser à l'avenir.

10
gmazzap

gmazzap 's réponse est génial! Je voudrais juste ajouter que depuis la version 4.1, deux nouvelles fonctions s’adaptent parfaitement à ce cas d’utilisation: the_archive_title et the_archive_description . Pour les thèmes qui utilisent déjà ceux-ci (comme Twenty Fifteen), vous pouvez ignorer la dernière partie où vous modifiez le modèle de thème et le faire à la place:

Ajouter des données via des filtres

add_filter( 'get_the_archive_title', function( $title ) {
    if( is_post_type_archive() ) {   
        $page  = get_archive_page( $post_type );    // Function Found in @gmazzap's answer
        $title = $page ? get_the_title( $page ) : $title;
    }

    return $title;
} );

add_filter( 'get_the_archive_description', function( $content ) {
    if( is_post_type_archive() ) {
        $page    = get_archive_page( $post_type );  // Function Found in @gmazzap's answer
        $content = '';

        if( $page ) {
            setup_postdata( $page );
            ob_start();
                the_content();
            $content = ob_get_clean();
            wp_reset_postdata();
        }

        $content = ( $content !== '' ) ? get_the_title( $page ) : $content;
    }

    return $content;
} );
2
kraftner

Après avoir lu les deux réponses précédentes, ma propre méthode pour ce faire est résolument celle de l'homme des cavernes, mais je la partagerai quand même car, même si elle n'est pas aussi robuste, sa configuration est incroyablement facile. Il est également très simple pour les auteurs de contenu de savoir où éditer le contenu "général" pour une archive donnée dans une structure de site largement basée sur des pages/style CMS.

Pour un post_type appelé region, je l'enregistrerais avec une page WP réelle appelée regions.

Créez un modèle appelé page-regions.php (ou la stratégie que vous souhaitez utiliser pour le connecter à cette page) et créez une boucle personnalisée pour extraire tous les post_types de la région. Si vous utilisez des parties de modèle pour vos modèles, il est assez facile d'inclure l'en-tête de page et le corps principal afin que votre code reste DRY. C'est aussi très facile à personnaliser car il y a toujours ce post_type. :)

Avec cela, les URL seront légèrement différentes de ce que vous avez demandé:

http://example.com/regions pour la page avec les articles d'archive et
http://example.com/region/africa ou
http://example.com/region/asia pour une vue CPT unique.

Mais pour moi, /region/africa est en réalité plus logique que /regions/africa bien que cela puisse être motivé par le fait de travailler sur des sites Rails/Cakephp où c'est la norme. /region à lui seul finit par être une archive post_type = region (selon la manière dont vous avez configuré le post_type) sans le contenu de la vue d'ensemble de la page, mais je ne crée pas de lien. Si les internautes de la barre d'URL y parviennent, pas de problème.

Bonus léger et secondaire: vous pouvez créer l'URL de la page de synthèse/d'archives à votre guise, par exemple /regions-of-the-world.

0
Will