在 WordPress 开发中,我们经常会遇到这样的需求:
- 使用自定义文章类型(CPT)如
case
展示项目或案例; - 希望每个内容的访问链接为
/case/123.html
或/case/my-slug.html
,符合静态页面结构; - 又希望访问
/case/
是一个由 Elementor 或 ACF 制作的普通页面(非 archive),可以自由编辑; - 而不使用任何插件,如 Permalink Manager Lite 等。
本文将一步步带你使用纯代码实现这个需求,避开 WordPress 的伪静态规则限制,打造一个 SEO 友好 + 灵活定制 + 100% 插件无依赖 的解决方案。
📌 最终目标 URL 结构如下
页面类型 | 示例 URL | 实现说明 |
---|---|---|
自定义页面 | /case/ |
使用 Elementor/ACF 自由编辑 |
单个文章页面 | /case/123.html 或 /case/slug.html |
自定义文章类型的单篇页面 |
❓ 为什么默认 WordPress 无法实现?
WordPress 中若你将 CPT 设置为 slug = case
,同时创建一个同名页面 case
,会产生路由冲突:
/case/
会优先匹配 CPT 的 archive;- 页面无法访问,返回 404;
- permalink 结构也无法使用
.html
。
即使你关闭了 has_archive
,WordPress 的 rewrite 规则仍然会保留 /case/
作为内部保留路径,仍无法用页面占用。
✅ 分步实现:不使用插件,手动实现目标 URL
第一步:注册自定义文章类型(避免 slug 冲突)
add_action('init', function () {
register_post_type('case', [
'label' => '案例',
'public' => true,
'has_archive' => false,
'rewrite' => [
'slug' => 'case-item', // 避免和页面 slug 冲突
'with_front' => false
],
'supports' => ['title', 'editor', 'thumbnail'],
]);
});
如果你用的是Custom Post Type UI 插件,设置效果如下
第二步:自定义单篇文章 permalink 为 .html
add_filter('post_type_link', function ($post_link, $post) {
if ($post->post_type === 'case') {
return home_url('/case/' . $post->ID . '.html');
}
return $post_link;
}, 10, 2);
第三步:添加 rewrite 规则支持 .html
解析
add_action('init', function () {
add_rewrite_rule(
'^case/([0-9]+)\.html$',
'index.php?post_type=case&p=$matches',
'top'
);
});
⚠️ 务必刷新固定链接: 后台 → 设置 → 固定链接 → 保存更改。
第四步:新建页面 /case/
并自由编辑
此时因为 has_archive
设置为 false,你可以:
- 在后台新建一个页面,slug 为
case
; - 使用 Elementor 进行布局;
- 或用 ACF 添加自定义字段;
- 页面地址即为
/case/
,不会和 CPT archive 冲突。
🎯 Bonus:将链接变为 /case/slug.html
而非 /case/ID.html
修改 post_type_link
:
add_filter('post_type_link', function ($post_link, $post) {
if ($post->post_type === 'case') {
return home_url('/case/' . $post->post_name . '.html');
}
return $post_link;
}, 10, 2);
添加 rewrite 规则:
add_action('init', function () {
add_rewrite_rule(
'^case/([^/]+)\.html$',
'index.php?case=$matches',
'top'
);
});
注册 query var:
add_filter('query_vars', function ($vars) {
$vars[] = 'case';
return $vars;
});
转换 slug 到文章对象:
add_action('pre_get_posts', function ($query) {
if (!is_admin() && $query->is_main_query() && get_query_var('case')) {
$slug = get_query_var('case');
$post = get_page_by_path($slug, OBJECT, 'case');
if ($post) {
$query->set('p', $post->ID);
$query->set('post_type', 'case');
$query->is_single = true;
$query->is_page = false;
}
}
});
📌 整体实现效果回顾
功能点 | 说明 |
---|---|
✅ 支持 .html 后缀 |
URL 如 /case/123.html 、/case/my-slug.html |
✅ 页面 /case/ 可编辑 |
Elementor、ACF 自由编辑,无 archive 冲突 |
✅ 无需插件 | 不依赖 Permalink Manager、Rewrite 插件等 |
✅ SEO 友好结构 | 自定义结构简洁清晰,利于爬虫索引 |
🛠 延伸建议
- 使用
single-case.php
模板自定义显示样式; - 若要添加分页、taxonomy 分类支持,可在 rewrite 规则中加入更多正则匹配;
- 若需求复杂,可以进一步封装成模块或插件。
✅ 结语
通过几段简单但灵活的代码,我们成功实现了:
- 保留
case
页面用于视觉构建与字段展示; - 所有案例链接为
.html
静态风格,利于 SEO; - 100% 无插件依赖,代码可控、可维护;
- 不再被 WordPress 的 rewrite 规则限制。
这就是 WordPress 可定制性的魅力所在。希望本文对你有所帮助!如果你也在构建主题或插件,欢迎留言交流。