Skip to content

自定义文章类型

什么是自定义文章类型?

自定义文章类型(Custom Post Types,CPT)允许你创建 WordPress 默认文章和页面之外的内容类型。

内置内容类型

类型说明是否有存档页
Post博客文章
Page静态页面
Attachment媒体文件
Revision修订版本
Navigation Menu导航菜单项

自定义文章类型的应用场景

  • 作品集 - 展示设计/开发作品
  • 产品 - 电商网站产品
  • 案例研究 - 客户案例
  • 食谱 - 美食博客
  • 视频 - 视频库
  • 评价/评测 - 产品评测
  • 员工 - 团队成员介绍

注册自定义文章类型

基本代码

php
<?php
// functions.php 或插件文件

function my_custom_post_types() {
    // 注册自定义文章类型
    register_post_type('portfolio', array(
        'labels' => array(
            'name'               => '作品集',
            'singular_name'      => '作品',
            'add_new'           => '添加新作品',
            'add_new_item'      => '添加新作品',
            'edit_item'         => '编辑作品',
            'new_item'          => '新作品',
            'view_item'         => '查看作品',
            'search_items'      => '搜索作品',
            'not_found'         => '未找到作品',
            'not_found_in_trash'=> '回收站中未找到作品',
            'parent_item_colon' => '父级作品:',
        ),
        'hierarchical'        => false,
        'description'         => '我们的项目作品集',
        'public'              => true,
        'show_ui'             => true,
        'show_in_menu'        => true,
        'show_in_nav_menus'   => true,
        'show_in_admin_bar'   => true,
        'menu_position'       => 5,
        'menu_icon'           => 'dashicons-portfolio',
        'capability_type'     => 'post',
        'supports'            => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
        'taxonomies'          => array('category', 'post_tag'),
        'has_archive'         => true,
        'rewrite'             => array('slug' => 'portfolio'),
        'query_var'           => true,
        'show_in_rest'        => true,  // 古腾堡编辑器支持
    ));
}
add_action('init', 'my_custom_post_types');

完整参数说明

php
<?php
register_post_type('post_type_name', array(
    // === 标签 (Labels) ===
    'labels' => array(
        'name'                     => '名称',
        'singular_name'            => '单数名称',
        'add_new'                  => '添加',
        'add_new_item'             => '添加新项目',
        'edit_item'                => '编辑',
        'new_item'                 => '新项目',
        'view_item'                => '查看',
        'view_items'               => '查看所有',
        'search_items'             => '搜索',
        'not_found'                => '未找到',
        'not_found_in_trash'       => '回收站中未找到',
        'parent_item_colon'        => '父级:',
        'all_items'                => '所有项目',
        'archives'                 => '存档',
        'attributes'               => '属性',
        'insert_into_item'         => '插入到',
        'uploaded_to_this_item'    => '上传到这个',
        'featured_image'           => '特色图片',
        'set_featured_image'       => '设置特色图片',
        'remove_featured_image'    => '移除特色图片',
        'use_featured_image'       => '使用特色图片',
        'menu_name'                => '菜单名称',
    ),
    
    // === 公开性 (Public) ===
    'public'                => true,        // 对管理员和前端可见
    'show_ui'               => true,        // 在后台显示 UI
    'show_in_nav_menus'     => true,        // 在导航菜单中显示
    'show_in_admin_bar'     => true,        // 在后台工具栏显示
    'exclude_from_search'    => false,       // 从搜索结果中排除
    'publicly_queryable'    => true,        // 允许公共查询
    'can_export'            => true,        // 允许导出
    
    // === 层级 ===
    'hierarchical'          => false,       // true=页面样式, false=文章样式
    
    // === UI ===
    'capability_type'       => 'post',      // 权限类型
    'menu_position'         => null,        // 菜单位置
    'menu_icon'             => null,        // 菜单图标 (Dashicons)
    'register_meta_box_cb'  => null,        // 注册 Meta Box 的回调
    
    // === 功能支持 ===
    'supports' => array(
        'title',                 // 标题
        'editor',                // 内容编辑器
        'author',                // 作者
        'thumbnail',             // 特色图片
        'excerpt',               // 摘要
        'trackbacks',            // 引用
        'custom-fields',         // 自定义字段
        'comments',              // 评论
        'revisions',             // 修订版本
        'page-attributes',       // 页面属性 (顺序)
        'post-formats',          // 文章格式
    ),
    
    // === 分类法 ===
    'taxonomies'            => array(),     // 关联的分类法
    
    // === 永久链接 ===
    'permalink_epmask'       => 'EP_PERMALINK',
    'rewrite' => array(
        'slug'                  => 'custom-slug',
        'with_front'            => true,
        'feeds'                 => true,
        'pages'                 => true,
        'ep_mask'               => EP_PERMALINK,
    ),
    'query_var'              => true,        // 查询变量名
    'show_in_rest'          => true,        // REST API 支持 (Gutenberg)
    
    // === 其他 ===
    '_builtin'              => false,        // 是否为内置类型
    '_edit_link'            => 'post.php?post=%d',
));

菜单图标参考

使用 WordPress Dashicons:

php
// 常用图标
'dashicons-portfolio'      // 作品集
'dashicons-products'       // 产品
'dashicons-testimonial'    // 评价
'dashicons-admin-custom'   // 自定义图标
'dashicons-book'          // 书籍
'dashicons-money'         // 金钱
'dashicons-calendar'      // 日历
'dashicons-video'         // 视频

创建分层自定义文章类型

类似于页面,可以有父级和子级:

php
<?php
register_post_type('documentation', array(
    'labels' => array(
        'name'               => '文档',
        'singular_name'      => '文档',
    ),
    'hierarchical'        => true,          // 重要:启用层级
    'supports'            => array(
        'title', 
        'editor', 
        'page-attributes',  // 支持父级选择
        'thumbnail'
    ),
    'rewrite' => array('slug' => 'docs'),
));

创建存档页模板

archive-{post_type}.php

php
<?php
/**
 * 作品集存档页模板
 */
get_header(); ?>

<main class="portfolio-archive">
    <header class="archive-header">
        <h1>我们的作品</h1>
        <p>浏览我们完成的项目</p>
    </header>
    
    <?php
    // 分类过滤
    $terms = get_terms('portfolio_category');
    if ($terms): ?>
        <div class="portfolio-filters">
            <button class="filter-btn active" data-filter="all">全部</button>
            <?php foreach ($terms as $term): ?>
                <button class="filter-btn" data-filter="<?php echo $term->slug; ?>">
                    <?php echo $term->name; ?>
                </button>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>
    
    <div class="portfolio-grid">
        <?php 
        // 循环输出作品
        while (have_posts()): the_post();
            // 获取分类
            $terms = get_the_terms(get_the_ID(), 'portfolio_category');
            $term_class = $terms ? implode(' ', wp_list_pluck($terms, 'slug')) : '';
        ?>
            <article class="portfolio-item <?php echo $term_class; ?>">
                <a href="<?php the_permalink(); ?>">
                    <?php if (has_post_thumbnail()): ?>
                        <div class="item-image">
                            <?php the_post_thumbnail('medium_large'); ?>
                        </div>
                    <?php endif; ?>
                    
                    <div class="item-content">
                        <h2><?php the_title(); ?></h2>
                        
                        <?php if (has_excerpt()): ?>
                            <p><?php the_excerpt(); ?></p>
                        <?php endif; ?>
                        
                        <?php if ($terms): ?>
                            <div class="item-categories">
                                <?php foreach ($terms as $term): ?>
                                    <span class="category-tag"><?php echo $term->name; ?></span>
                                <?php endforeach; ?>
                            </div>
                        <?php endif; ?>
                    </div>
                </a>
            </article>
        <?php endwhile; ?>
    </div>
    
    <?php the_posts_pagination(); ?>
</main>

<?php get_footer(); ?>

创建单页模板

single-{post_type}.php

php
<?php
/**
 * 作品集单页模板
 */
get_header(); ?>

<main class="portfolio-single">
    <?php while (have_posts()): the_post(); ?>
        <article id="portfolio-<?php the_ID(); ?>">
            
            <!-- 特色图片 -->
            <?php if (has_post_thumbnail()): ?>
                <div class="portfolio-hero">
                    <?php the_post_thumbnail('full'); ?>
                </div>
            <?php endif; ?>
            
            <div class="portfolio-content">
                <!-- 标题 -->
                <header class="portfolio-header">
                    <h1><?php the_title(); ?></h1>
                    
                    <!-- 元信息 -->
                    <div class="portfolio-meta">
                        <?php
                        $client = get_post_meta(get_the_ID(), 'client_name', true);
                        $year = get_post_meta(get_the_ID(), 'project_year', true);
                        $url = get_post_meta(get_the_ID(), 'project_url', true);
                        ?>
                        
                        <?php if ($client): ?>
                            <div class="meta-item">
                                <strong>客户:</strong> <?php echo esc_html($client); ?>
</div>
                        <?php endif; ?>
                        
                        <?php if ($year): ?>
                            <div class="meta-item">
                                <strong>年份:</strong> <?php echo esc_html($year); ?>
                            </div>
                        <?php endif; ?>
                        
                        <?php if ($url): ?>
                            <div class="meta-item">
                                <strong>链接:</strong> 
                                <a href="<?php echo esc_url($url); ?>" target="_blank">
                                    访问网站
                                </a>
                            </div>
                        <?php endif; ?>
                    </div>
                </header>
                
                <!-- 项目画廊 -->
                <?php
                $gallery = get_post_meta(get_the_ID(), 'project_gallery', true);
                if ($gallery && is_array($gallery)): ?>
                    <div class="portfolio-gallery">
                        <h2>项目展示</h2>
                        <div class="gallery-grid">
                            <?php foreach ($gallery as $image_id): ?>
                                <div class="gallery-item">
                                    <?php echo wp_get_attachment_image($image_id, 'large'); ?>
                                </div>
                            <?php endforeach; ?>
                        </div>
                    </div>
                <?php endif; ?>
                
                <!-- 内容 -->
                <div class="portfolio-description">
                    <?php the_content(); ?>
                </div>
            </div>
            
            <!-- 导航 -->
            <nav class="portfolio-navigation">
                <div class="nav-previous">
                    <?php previous_post_link('%link', '← 上一个项目'); ?>
                </div>
                <div class="nav-next">
                    <?php next_post_link('%link', '下一个项目 →'); ?>
                </div>
            </nav>
            
            <!-- 相关作品 -->
            <?php
            $related = new WP_Query(array(
                'post_type' => 'portfolio',
                'posts_per_page' => 3,
                'post__not_in' => array(get_the_ID()),
                'tax_query' => array(
                    array(
                        'taxonomy' => 'portfolio_category',
                        'field' => 'term_id',
                        'terms' => wp_get_post_terms(get_the_ID(), 'portfolio_category', array('fields' => 'ids')),
                    ),
                ),
            ));
            
            if ($related->have_posts()): ?>
                <section class="related-portfolio">
                    <h3>相关作品</h3>
                    <div class="related-grid">
                        <?php while ($related->have_posts()): $related->the_post(); ?>
                            <a href="<?php the_permalink(); ?>">
                                <?php the_post_thumbnail('thumbnail'); ?>
                                <span><?php the_title(); ?></span>
                            </a>
                        <?php endwhile; ?>
                    </div>
                </section>
            <?php 
            endif;
            wp_reset_postdata();
            ?>
        </article>
    <?php endwhile; ?>
</main>

<?php get_footer(); ?>

自定义文章类型查询

WP_Query 方法

php
<?php
// 查询自定义文章类型
$args = array(
    'post_type'      => 'portfolio',
    'posts_per_page' => 10,
    'orderby'        => 'date',
    'order'          => 'DESC',
);

// 条件过滤
$args = array(
    'post_type'      => 'portfolio',
    'posts_per_page' => -1,  // 获取全部
    'post_status'    => 'publish',
    'meta_key'       => 'project_year',
    'meta_value'     => '2024',
    'meta_compare'   => '>=',
);

// 分类过滤
$args = array(
    'post_type'      => 'portfolio',
    'tax_query'      => array(
        array(
            'taxonomy' => 'portfolio_category',
            'field'    => 'slug',
            'terms'    => 'web-design',
        ),
    ),
);

$query = new WP_Query($args);
?>

<?php if ($query->have_posts()): ?>
    <?php while ($query->have_posts()): $query->the_post(); ?>
        <!-- 输出内容 -->
    <?php endwhile; ?>
    <?php wp_reset_postdata(); ?>
<?php endif; ?>

使用 pre_get_posts 钩子

php
<?php
// 在存档页面包含自定义文章类型
function add_portfolio_to_home($query) {
    if (!is_admin() && $query->is_main_query()) {
        if (is_home()) {
            $query->set('post_type', array('post', 'portfolio'));
        }
    }
}
add_action('pre_get_posts', 'add_portfolio_to_home');

高级用法

Flush Rewrite Rules

创建或更新自定义文章类型后,需要刷新永久链接:

php
<?php
// 方法 1: 保存永久链接设置页面
// 方法 2: 激活主题时
function my_rewrite_flush() {
    my_custom_post_types();  // 重新注册
    flush_rewrite_rules();    // 刷新规则
}
add_action('after_switch_theme', 'my_rewrite_flush');

// 方法 3: 激活插件时
register_activation_hook(__FILE__, function() {
    my_custom_post_types();
    flush_rewrite_rules();
});

自定义列

php
<?php
// 后台列表添加自定义列
function set_custom_columns($columns) {
    $columns['portfolio_client'] = '客户';
    $columns['portfolio_year'] = '年份';
    $columns['thumbnail'] = '缩略图';
    return $columns;
}
add_filter('manage_portfolio_posts_columns', 'set_custom_columns');

function custom_column_content($column, $post_id) {
    switch ($column) {
        case 'portfolio_client':
            echo get_post_meta($post_id, 'client_name', true);
            break;
        case 'portfolio_year':
            echo get_post_meta($post_id, 'project_year', true);
            break;
        case 'thumbnail':
            if (has_post_thumbnail()) {
                echo get_the_post_thumbnail($post_id, array(60, 60));
            }
            break;
    }
}
add_action('manage_portfolio_posts_custom_column', 'custom_column_content', 10, 2);

下一步

基于 WordPress官方文档 构建