用于定制帖子类型的Dynamic Page.php模板

时间:2014-04-03 作者:Pieter Goosen

我注册了几个自定义的帖子类型。我想在自己的页面上显示每个自定义帖子类型的所有“帖子”,并且这些页面必须在导航菜单中可见。

如果只有一个就好了page-custom.php 模板作为每个自定义帖子类型的页面模板。有可能创造出这样的东西吗?

1 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

回访:2016年2月2日,原始代码有许多问题

未对数据进行清理和验证,这可能导致严重的安全问题

有些部分是重复的

有点凌乱,有时难以阅读

一些部门只起到了部分作用

使用globals真的很邪恶

这就是为什么我重新审视这个答案并更新代码以解决上述问题的原因。代码现在更干净、更安全、更易于阅读和调试。确保在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 可以找到类in my answer here 以及如何使用它的详细说明

原始答案,如果您查看template hierarchy, 自定义帖子类型通常显示在存档模板上。普通模板层次结构不提供page.php 默认情况下,用于显示自定义帖子类型的类型模板。

存档模板的问题是,它们不会自动添加到默认的导航菜单中,创建自定义菜单来创建链接并不总是最方便的方式。

这里的方法是使用WP_Query 为循环创建自定义查询以包括自定义帖子类型。WP_Query 祝你好运post_type 用于调用的类型参数post types.

因此,需要对以下内容进行修改以实现此目的:

首先,创建自定义page.php 样板

创建自定义page.php 你需要复制你的主题page.php 并将其重命名为page-cpt.php. 现在打开它并更改循环。为了回答这个问题,我使用了默认的214主题。删除模板中的所有内容,并将其替换为以下代码

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调用的,并在后端的自定义元框中进行设置

其次,创建custom meta box

创建新页面并在“页面属性”元框中选择“自定义帖子类型页面”时,此元框将显示在“页面”屏幕中。

将以下内容添加到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

这段代码所做的是注册和显示元框,将选项添加到元框中,并将选项存储到db中,以便在page-cpt.php 样板

现在,您可以创建一个新页面,并根据需要调用该页面。在“页面属性”中,选择“自定义帖子类型页面”和“发布”页面。自定义帖子类型选项的元框现在将显示在“发布”元框的上方,并将显示所有当前可用的自定义帖子类型。选择并设置需要显示的选项,然后单击“更新”。您的页面现在将显示您选择的自定义帖子类型中的帖子,并且您的页面将在导航栏中可见。

您可以在此基础上添加更多功能,或者更改代码以同样的方式显示类别或分类。希望这有帮助

结束

相关推荐

为自定义字段创建Metabox

我使用自定义字段将视频添加到WordPress帖子的视频格式中。我想知道是否有任何方法可以在post editor中为特定的自定义字段创建一个元框(如摘录或其他内容)。只需要一个文本区域来添加iframe代码。例如,自定义字段是嵌入视频。