web-dev-qa-db-fra.com

Modèle de page.php dynamique pour les types d'articles personnalisés

J'ai quelques types de messages personnalisés enregistrés. J'aimerais afficher tous les "articles" de chaque type d'article personnalisé sur sa propre page. Ces pages doivent être visibles dans le menu de navigation.

Ce serait bien de n'avoir qu'un seul modèle page-custom.php pour un modèle de page pour chaque type de publication personnalisée. Est-il possible de créer quelque chose comme ça?

1
Pieter Goosen

REVISIT: 2 février 2016

Le code original avait de nombreux problèmes

  • Les données n'ont pas été désinfectées et validées, ce qui peut entraîner de graves problèmes de sécurité

  • Certaines parties étaient répétitives

  • Un peu brouillon et parfois difficile à lire

  • Certaines sections ne fonctionnaient que partiellement

  • Globals utilisés qui est vraiment diabolique

C'est pourquoi j'ai revisité cette réponse et mis à jour le code afin de résoudre les problèmes ci-dessus. Le code est maintenant plus propre, plus sûr et plus facile à lire et à déboguer. Assurez-vous de le vérifier dans la section ORIGINAL REPONSE

Avant de passer à la section originale ORIGINAL REPONSE , je souhaite ajouter une alternative qui, à mon avis, est un peu préférable.

VOIE ALTERNATIVE

Il s’agit d’une solution alternative simple qui n’implique pas de modèles personnalisés (, sauf peut-être un content.php) ni la modification de modèles. Tout ce que vous devez faire c'est

  • créer une nouvelle page avec le modèle de page de votre choix

  • créer une partie de modèle content.php dans l'une de ces parties si votre thème ne les a pas disponibles par défaut

  • ajoutez le code suivant et votre fait

    $query = new PreGetPostsForPages(
        251,       // Page ID we will target
        'content', //Template part which will be used to display posts, name should be without .php extension 
        true,      // Should get_template_part support post formats
        false,     // Should the page object be excluded from the loop
        [          // Array of valid arguments that will be passed to WP_Query/pre_get_posts
            'post_type'      => 'post', 
            'posts_per_page' => 2
        ] 
    );
    $query->init(); 
    

La classe PreGetPostsForPages peut être trouvée dans ma réponse ici et une explication détaillée sur la façon de l'utiliser

RÉPONSE ORIGINALE

Si vous examinez la hiérarchie des modèles , les types d'articles personnalisés sont généralement affichés dans les modèles d'archives. La hiérarchie normale des modèles ne prévoit pas que les modèles de type page.php soient utilisés pour afficher les types de publication personnalisés par défaut.

Le problème avec les modèles d'archive est qu'ils ne sont pas automatiquement ajoutés au menu de navigation par défaut et la création d'un menu personnalisé pour créer des liens n'est pas toujours le moyen le plus pratique.

Pour y parvenir, utilisez WP_Query pour créer une requête personnalisée pour la boucle afin d'inclure les types de publication personnalisés. WP_Query possède un paramètre de type post_type qui est utilisé pour appeler les types de publication .

Il faut donc modifier les éléments suivants pour que cela fonctionne:

Tout d'abord, créez un modèle personnalisé page.php

Pour créer le page.php personnalisé, vous devez copier le page.php de votre thème et le renommer en quelque chose comme page-cpt.php. Maintenant, ouvrez-le et changez la boucle. Pour répondre à cette question, j'ai utilisé le thème par défaut vingt-quatre. Supprimer tout le contenu du modèle et le remplacer par ce code

EDIT Je suis revenu pour changer le code. Le code précédent utilisait les éléments suivants dans la requête personnalisée

global $post;
$tmp_post = $post;
$wp_query= null;
$wp_query = new WP_Query();
$wp_query->query( $args );

qui se traduisent également par query_posts, qui ne devrait jamais être utilisé. Donc, je modifie le code en conséquence pour exécuter une instance appropriée de WP_Query. Voici le code édité

<?php
/**
 * Template Name: Custom Post Type Page
 */
get_header(); ?>

<?php
    //See if we have any values
    $post_meta   = get_post_meta( $post->ID,false );

    $posttype    = isset( $post_meta['_cpt_post_type'] )   ? $post_meta['_cpt_post_type'][0]   : 1;
    $page_title  = isset( $post_meta['_cpt_page_title'] )  ? $post_meta['_cpt_page_title'][0]  : '';
    $posts_title = isset( $post_meta['_cpt_posts_title'] ) ? $post_meta['_cpt_posts_title'][0] : '';
    $orderby     = isset( $post_meta['_cpt_order_by'] )    ? $post_meta['_cpt_order_by'][0]    : 'date';
    $asc         = isset( $post_meta['_cpt_asc'] )         ? $post_meta['_cpt_asc'][0]         : 'DESC';
    $post_count  = isset( $post_meta['_cpt_post_count'] )  ? $post_meta['_cpt_post_count'][0]  : get_option('posts_per_page');

?>  
<div id="main-content" class="main-content">

    <div id="primary" class="content-area">
        <div id="content" class="site-content" role="main">

    <!-- Page Title -->
    <?php if( $page_title ) { ?>
        <article id="posts-title">
            <header class="entry-header">
                <h2 class="entry-title"><?php echo $page_title; ?></h2>
            </header><!-- .entry-header -->
        </article><!-- #posts-title -->
    <?php } ?>

        <?php the_post(); ?>
        <?php global $post;
        if( $post->post_content || $page_title ) : ?>
        <div class="entry-content">
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <?php if( $posts_title ) : ?>
                    <header class="entry-header">
                        <h1 class="entry-title"><?php echo $posts_title; ?></h1>
                    </header><!-- .entry-header -->

                <?php endif; ?>
            <?php if( $post->post_content ) : ?>    
                <div class="entry-content">
                    <?php the_content(); ?>
                    <?php wp_link_pages( ['before' => '<div class="page-link"><span>' . __( 'Pages:' ) . '</span>', 'after' => '</div>'] ); ?>
                </div><!-- .entry-content -->
                <footer class="entry-meta">

                </footer><!-- .entry-meta -->
            <?php endif; ?>
            </article><!-- #post-<?php the_ID(); ?> -->
        </div>  
        <?php endif; ?>

<?php 
/**-----------------------------------------------------------------------------
 *
 *  Start our custom query to display custom post type posts
 *
*------------------------------------------------------------------------------*/

        $args = [
            'post_type'           => $posttype,
            'posts_per_page'      => $post_count,
            'paged'               => $paged,
            'order'               => $asc,
            'ignore_sticky_posts' => 1,
        ];
        $cpt_query = new WP_Query($args);

        // Output
        if ( $cpt_query->have_posts() ) :

            // Start the Loop.
            while ( $cpt_query->have_posts() ) {
                $cpt_query->the_post(); 

                    get_template_part( 'content', get_post_format() );

            }

            if ( function_exists( 'pietergoosen_pagination' ) )
                pietergoosen_pagination();  

                wp_reset_postdata();

        } else {

                get_template_part( 'content', 'none' );

        } ?>


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

    <?php get_sidebar( 'content' ); ?>

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

<?php
get_footer();

Le premier morceau de code est utilisé pour appeler les paramètres de la base de données. Ceci sera défini via une metabox dans le back-end lors de la création d'une nouvelle page dans l'écran de l'éditeur de page. Le code important ici est constitué par les arguments de WP_Query.

$args = [
    'post_type'           => $posttype,
    'posts_per_page'      => $post_count,
    'paged'               => $paged,
    'order'               => $asc,
    'ignore_sticky_posts' => 1,
];

Cela décidera quels types de messages personnalisés seront affichés, messages par page et l'ordre des messages. Tous ces paramètres sont appelés à partir de la base de données et sont définis dans la boîte méta personnalisée du back-end

Deuxièmement, créez une méta-boîte personnalisée

Cette métabox sera affichée dans l'écran "Page" lorsqu'une nouvelle page est créée et que "Page de type de publication personnalisée" est sélectionné dans la boîte à méta "Attributs de page".

Ajoutez les éléments suivants dans votre fichier functions.php ou dans le fichier de fonctions personnalisées

<?php
add_action( 'admin_init', function ()
{   
    $post_id = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
    if ( $post_id ) {
        // Get the current page template
        $post_meta = get_post_meta( $post_id );

        // Make sure that we only target our desired template
        if (    isset ( $post_meta['_wp_page_template'][0] )
             && 'page-cpt.php' === $post_meta['_wp_page_template'][0] 
        ) {
            add_meta_box(
                'cpt_meta_box', 
                __( 'Page of post from a given custom post type' ), 
                'cpt_metabox_options', 
                'page', 
                'side', 
                'core'
            );
        } else {
            if( isset( $meta['_cpt_post_type'][0] ) ) {
                $meta_value_array = [
                    '_cpt_post_type',
                    '_cpt_page_title',
                    '_cpt_posts_title',
                    '_cpt_order_by',
                    '_cpt_asc',
                    '_cpt_post_count'
                ];
                foreach ( $meta_value_array as $value ) 
                    cpt_helper_update_post_meta( $post_id, $value, '' );

                remove_meta_box( 'cpt_meta_box', 'page', 'side' );
            }
        }
    }
    add_action( 'save_post',  'cpt_update_post_meta_box' );
});

function get_cpt_order_by_list()
{   
    // Set the sort order
    $sort = [
        [
            'DESC' => [
                    'value' => 'DESC',
                    'label' => 'Descending'
                ],
            'ASC'  => [
                    'value' => 'ASC',
                    'label' => 'Ascending'
                ],
        ]
    ];      

    // Create an array of values to order the posts by
    $order_list = [
        [
            'none'          => [
                    'value' => 'none',
                    'label' => 'None'
                ],
            'id'            => [
                    'value' => 'ID',
                    'label' => 'Post ID'
                ],
            'author'        => [
                    'value' => 'author',
                    'label' => 'Author'
                ],
            'title'         => [
                    'value' => 'title',
                    'label' => 'Post Title'
                ],
            'date'          => [
                    'value' => 'date', 
                    'label' => 'Post Date'
                ],
            'modified'      => [
                    'value' => 'modified',
                    'label' => 'Modified Date'
                ],
            'parent'        => [
                    'value' => 'parent',
                    'label' => 'Parent Post'
                ],
            'Rand'          => [
                    'value' => 'Rand',
                    'label' => 'Random'
                ],
            'comment_count' => [
                    'value' => 'comment_count',
                    'label' => 'Comment Count'
                ],
            'menu_order'    => [
                    'value' => 'menu_order',
                    'label' => 'Menu Order'
                ],
        ]
    ];

    return $list = array_merge( $sort, $order_list );
}

function cpt_metabox_options()
{
    $post_id = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
    if ( !$post_id )
        return;

    // Make sure the current user have the edit_page ability
    if ( !current_user_can( 'edit_post', $post_id ) )
        return;

    // Get the current page template
    $template_file = get_post_meta( $post_id, '_wp_page_template', true );

    // Make sure that we only target our desired template
    if ( 'page-cpt.php' !== $template_file ) 
        return;

    // Get all the post meta values and sanitize/validate them
    $post_meta = get_post_meta( $post_id );

    $filters = [
        '_cpt_post_type'   => [
            'filter'       => FILTER_SANITIZE_STRING,
            'default'      => ''
        ],
        '_cpt_page_title'  => [
            'filter'       => FILTER_SANITIZE_STRING,
            'default'      => ''
        ],
        '_cpt_posts_title' => [
            'filter'       => FILTER_SANITIZE_STRING,
            'default'      => ''
        ],
        '_cpt_order_by'    => [
            'filter'       => FILTER_SANITIZE_STRING,
            'default'      => 'ID'
        ],
        '_cpt_asc'         => [
            'filter'       => FILTER_SANITIZE_STRING,
            'default'      => 'DESC'
        ],
        '_cpt_post_count'  =>  [
            'filter'       => FILTER_VALIDATE_INT,
            'default'      => get_option( 'posts_per_page' )
        ],
    ];  

    foreach ( $filters as $key=>$value ) {
        if ( !array_key_exists( $key, $post_meta  ) ) {
            $post_meta[$key][0] = $value['default'];
        } else {
            $post_meta[$key][0] = filter_var( $post_meta[$key][0], $value['filter'], $value['default'] );
        }
    }
    ?>

    <!-- Sart the meta boxes -->
    <div class="inside">

        <p>
            <label>
                <strong><?php _e( 'Page Title' ); ?></strong>
            </label>
        </p>    
        <input id="_cpt_page_title" name="_cpt_page_title" type="text" style="width: 98%;" value="<?php echo $post_meta['_cpt_page_title'][0]; ?>"/>    

        <p>
            <label>
                <strong><?php _e( 'Post Title' ); ?></strong>
            </label>
        </p>    
        <input id="_cpt_posts_title" name="_cpt_posts_title" type="text" style="width: 98%;" value="<?php echo $post_meta['_cpt_posts_title'][0]; ?>"/>

        <p>
            <label>
                <strong><?php _e( 'Custom Post Type' ); ?></strong>
            </label>
        </p>
        <select id="_cpt_post_type" name="_cpt_post_type">
            <?php 
                //Custom Post Type List
            $args = [
                'public'   => true,
                '_builtin' => false
            ];

            $output = 'names'; // names or objects, note names is the default
            $operator = 'and'; // 'and' or 'or'

            $post_types = get_post_types( $args, $output, $operator ); 

            foreach ( $post_types  as $post_type ) {
                $selected = ( $post_type == $post_meta['_cpt_post_type'][0] ) ? ' selected = "selected" ' : '';

                $option = '<option '.$selected .'value="'. $post_type;
                $option = $option .'">';
                $option = $option .$post_type;
                $option = $option .'</option>';
                echo $option;
            } //endforeach;
            ?>
        </select>

        <?php 
        if ( function_exists( 'get_pop_order_by_list' ) ) {
            $list = get_pop_order_by_list();
            ?>
            <p>
                <label>
                    <strong><?php _e( 'Sort by' )?></strong>
                </label>
            </p>
            <select id="_cpt_order_by" name="_cpt_order_by">
                <?php 
                foreach ( $list[0] as $output ) {
                    $selected = ( $output['value'] == $post_meta['_cpt_order_by'][0] ) ? ' selected = "selected" ' : '';

                    $option = '<option '.$selected .'value="' . $output['value'];
                    $option = $option .'">';
                    $option = $option .$output['label'];
                    $option = $option .'</option>';
                    echo $option;
                } //endforeach;
                ?>
            </select>   

            <p>
                <label>
                    <strong><?php _e( 'Order' )?><strong>
                </label>
            </p>
            <select id="_cpt_asc" name="_cpt_asc">
                <?php 
                foreach ( $list[1] as $output ) {
                    $selected = ( $output['value'] == $post_meta['_cpt_asc'][0] ) ? ' selected = "selected" ' : '';

                    $option = '<option '.$selected .'value="' . $output['value'];
                    $option = $option .'">';
                    $option = $option .$output['label'];
                    $option = $option .'</option>';
                    echo $option;
                } //endforeach;
                ?>
            </select>

            <?php
        }
        ?>
        <p>
            <label>
                <strong><?php _e( 'Posts per Page' ); ?><strong>
            </label>
        </p>
        <input id="_cpt_post_count" name="_cpt_post_count" type="text" value="<?php echo $post_meta['_cpt_post_count'][0]; ?>" size="3" />

    </div>
    <!-- End page of posts meta box -->
    <?php
}

function cpt_update_post_meta_box( $post_id )
{
    // Make sure we have a valid $_POST method
    if ( !$_POST )
        return;

    // Make sure the current user have the edit_page ability
    if ( !current_user_can( 'edit_page', $post_id ) )
        return;

    // Get the current page template
    $template_file = get_post_meta( $post_id, '_wp_page_template', true );

    // Make sure that we only target our desired template
    if ( 'page-cpt.php' !== $template_file ) 
        return;

    // Do nothing on auto save, just bail
    if (    defined( 'DOING_AUTOSAVE' ) 
         && DOING_AUTOSAVE 
    )
        return;

    $args = [
        '_cpt_post_type'    => [
                               'filter' => FILTER_SANITIZE_STRING,
                               'default' => ''
                           ],   
        '_cpt_page_title'   => [
                               'filter' => FILTER_SANITIZE_STRING,
                               'default' => ''
                           ],
        '_cpt_posts_title'  => [
                               'filter' => FILTER_SANITIZE_STRING,
                               'default' => ''
                           ],
        '_cpt_order_by'     => [
                               'filter'  => FILTER_SANITIZE_STRING,
                               'default' => 'date'
                           ],
        '_cpt_asc'          => [
                               'filter'  => FILTER_SANITIZE_STRING,
                               'default' => 'DESC'
                           ],
        '_cpt_post_count'   => [
                               'filter'  => FILTER_VALIDATE_INT,
                               'default' => get_option( 'posts_per_page' )
                           ],  
    ];  

    $meta = filter_input_array( INPUT_POST, $args );

    if ( !$meta )
        return;

    // Loop throught the array and update meta values
    foreach ( $meta as $k=>$v ) 
        cpt_helper_update_post_meta( $post_id, $k, $v );
}   

function cpt_helper_update_post_meta( $post_id = '', $key = '', $data = '' ) 
{
    // Make sure we have valid values, if not, return false
    if ( !$post_id
         || !$key
    )
        return false;

    // Sanitize and validate values
    $post_id = filter_var( $post_id, FILTER_VALIDATE_INT    );
    $key     = filter_var( $key,     FILTER_SANITIZE_STRING );
    $data    = filter_var( $data,    FILTER_SANITIZE_STRING );

    // Get the  post meta values
    $post_meta = get_post_meta( $post_id, $key, true );

    if(    $data
        && $post_meta != $data
    ) {
        update_post_meta( $post_id, $key, $data );
    } 

    if (    $post_meta 
         && !$data
    ) {
        delete_post_meta( $post_id, $key );
    }
}

Metabox

Le but de ce code est d’enregistrer et d’afficher la boîte de métadonnées, d’ajouter les options à la métabox et de les stocker dans la base de données à utiliser dans le modèle page-cpt.php.

Vous pouvez maintenant créer une nouvelle page et appeler la page comme vous le souhaitez. Dans les "Attributs de page", sélectionnez "Page Type de publication personnalisée" et "Publier" votre page. La métabox pour les options de types de publication personnalisée apparaîtra maintenant au-dessus de la métabox "Publier" et affichera tous les types de publication personnalisés disponibles. Sélectionnez et définissez les options à afficher, puis cliquez sur "Mettre à jour". Votre page affichera maintenant les messages du type de message personnalisé que vous avez sélectionné et votre page sera visible dans la barre de navigation.

Vous pouvez ajouter plus de fonctionnalités à cela ou changer le code pour afficher les catégories ou les taxonomies de la même manière. J'espère que cette aide

3
Pieter Goosen