web-dev-qa-db-ja.com

カスタム投稿タイプの動的page.phpテンプレート

カスタム投稿タイプがいくつか登録されています。各カスタム投稿タイプのすべての「投稿」を独自のページに表示したいのですが、これらのページはナビゲーションメニューに表示されている必要があります。

各カスタム投稿タイプのページテンプレートに関して、page-custom.phpテンプレートが1つだけあるのは素晴らしいことです。このようなものを作ることは可能ですか?

1
Pieter Goosen

再訪:2016年2月2日

元のコードには多くの問題がありました

  • 重大なセキュリティ問題につながる可能性があるデータがサニタイズおよび検証されていない

  • いくつかの部分は繰り返しました

  • 少し面倒で読みにくい

  • 一部のセクションは部分的にしか機能していませんでした

  • 本当に邪悪な中古グローバル

上記の問題を解決するために私がこの回答を再検討し、コードを更新したのはそのためです。コードは、よりクリーンで、より安全で、そして読みやすくそしてデバッグしやすくなりました。必ずORIGINAL ANSWERセクションでチェックしてください。

元のORIGINAL ANSWERセクションに進む前に、もう少し使いやすいと思う代替手段を追加したいと思います。

別の方法

これは、カスタムテンプレート(content.phpを除く)やテンプレートの変更を伴わない直接的な代替ソリューションです。あなたがする必要があるのはただ

  • あなたが望む任意のページテンプレートで新しいページを作成する

  • あなたのテーマがデフォルトでこれらを利用できない場合、そのようなテンプレートパーツのcontent.phpテンプレートパーツを作成します

  • 次のコードを追加すれば完了です。

    $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(); 
    

PreGetPostsForPagesクラスは ここに私の答えで そしてそれを使用する方法に関する詳細な説明もあります。

もともとの答え

テンプレート階層 を見ると、カスタム投稿タイプは通常アーカイブテンプレートに表示されます。通常のテンプレート階層では、デフォルトでカスタム投稿タイプを表示するために使用されるpage.phpタイプのテンプレートは用意されていません。

アーカイブテンプレートの問題は、デフォルトのナビゲーションメニューに自動的に追加されないことです。また、リンクを作成するためのカスタムメニューを作成することが、必ずしも最も便利な方法とは限りません。

ここへ行く方法は WP_Query を使ってカスタム投稿タイプを含めるためのループのためのカスタムクエリを作成することです。 WP_Queryには、 post types を呼び出すために使用されるpost_type typeパラメータがあります。

したがって、これを機能させるには、以下を変更する必要があります。

まず、カスタムのpage.phpテンプレートを作成します

カスタムのpage.phpを作成するには、テーマのpage.phpをコピーしてpage-cpt.phpのような名前に変更する必要があります。それを開き、ループを変更してください。この答えのために、私はデフォルトの14のテーマを使いました。テンプレート内のすべてのものを削除して、このコードに置き換えます

EDITコードを変更するために戻ってきました。前のコードでは、カスタムクエリで次のコードを使用していました。

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

これはquery_postsにも変換されますが、決して使用しないでください。そのため、WP_Queryの適切なインスタンスを実行するようにコードを変更します。これが編集したコードです。

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

最初のコードは、dbから設定を呼び出すために使用されます。これは、ページエディタ画面で新しいページを作成するときにバックエンドのメタボックスを介して設定されます。ここで重要なコードはWP_Queryの引数です。

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

これにより、どのカスタム投稿タイプが表示されるか、ページごとの投稿数、および投稿の順序が決まります。これらの設定はすべてdbから呼び出され、バックエンドのカスタムメタボックスに設定されます。

次に、 カスタムメタボックスを作成します

このメタボックスは、新しいページが作成され、[ページ属性]メタボックスで[カスタム投稿タイプページ]が選択されたときに[ページ]画面に表示されます。

functions.phpまたはカスタム関数ファイルに以下を追加します。

<?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

このコードがすることは、メタボックスを登録して表示し、メタボックスにオプションを追加し、page-cpt.phpテンプレートで使用するためにオプションをdbに格納することです。

これで移動して新しいページを作成し、そのページを好きなように呼び出すことができます。 [ページ属性]で、[カスタム投稿タイプページ]と[公開]ページを選択します。カスタム投稿タイプオプションのメタボックスは、「公開」メタボックスの上に表示され、現在利用可能なすべてのカスタム投稿タイプが表示されます。表示する必要があるオプションを選択して設定し、[更新]をクリックします。あなたのページはあなたが選択したカスタム投稿タイプからの投稿を表示し、あなたのページはナビゲーションバーに表示されます。

これにさらに機能を追加することも、同じ方法でカテゴリまたは分類法を表示するようにコードを変更することもできます。この助けを願っています

3
Pieter Goosen