一个工业配件站,产品页要列型号、功率、接口、认证,访客按功率区间筛,暂时不结账。上线前先要定的是这些型号存成 catalog_item 还是 WooCommerce 的 product,模板好不好看反而在后面。两者都能做出列表页,差别在数据落在哪里、查询怎么写、以后接不接交易。
需要做的事 | 自定义文章类型 | WooCommerce 商品 |
|---|---|---|
只展示、询价 | 用 | 也能做,但会带上商品、购物车、订单的概念 |
价格、库存、购物车、订单 | 要自己补 | 已有对应字段和流程 |
变体(颜色、尺寸、型号) | 自己建关系或子文章 | 内置变体文章类型 |
查询入口 |
|
|
REST |
| WooCommerce REST API 和 Store API |
以后转交易 | 要把字段、分类、URL 映射过去 | 一开始就在商品模型里 |
自定义文章类型的本体在 wp_posts:标题、正文、摘要、状态、别名、父级、排序都在这里。自定义字段在 wp_postmeta,分类和标签在 wp_terms、wp_term_taxonomy、wp_term_relationships。register_post_meta() 不会给数据库加列,它做的是声明字段类型、REST 暴露和清理回调;值仍然按 key-value 存在 wp_postmeta。
WooCommerce 的商品也是 wp_posts 里的 product,但多了商品类型、属性、变体、价格、库存这些语义。简单商品和变体是不同文章类型,产品分类走 product_cat,标签走 product_tag,属性常见为 pa_* 分类法。价格、库存状态等还会进入 WooCommerce 自己维护的 lookup 表,供商品列表和筛选用。订单、优惠券、税率、配送这些数据由 WooCommerce 管理,不需要你在 CPT 上重造。
下面这段注册一个目录文章类型、两个分类法和两个字段。可以放进自建插件,也可以临时放进主题的 functions.php:
add_action('init', function () {
register_post_type('catalog_item', [
'label' => '产品目录',
'public' => true,
'show_in_rest' => true,
'has_archive' => true,
'rewrite' => ['slug' => 'catalog', 'with_front' => false],
'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'],
'menu_icon' => 'dashicons-products',
]);
register_taxonomy('catalog_category', ['catalog_item'], [
'label' => '目录分类',
'public' => true,
'hierarchical' => true,
'show_in_rest' => true,
'rewrite' => ['slug' => 'catalog-category'],
]);
register_taxonomy('catalog_brand', ['catalog_item'], [
'label' => '品牌',
'public' => true,
'hierarchical' => false,
'show_in_rest' => true,
'rewrite' => ['slug' => 'catalog-brand'],
]);
register_post_meta('catalog_item', 'catalog_model', [
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function () {
return current_user_can('edit_posts');
},
]);
register_post_meta('catalog_item', 'catalog_power_w', [
'type' => 'number',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => function ($value) {
return is_numeric($value) ? (float) $value : 0;
},
'auth_callback' => function () {
return current_user_can('edit_posts');
},
]);
});字段名不要用 _price、_sku、_stock_status 这类 WooCommerce 已经占用的 key。以后真要迁到商品模型,少一层命名冲突。
目录页对搜索引擎输出结构化数据这件事,可以自己按字段拼 JSON-LD,也可以交给插件。AumViso 是 AumCreate 做的免费插件(AumViso),做的是 schema 结构化数据、sitemap、meta、内链和 llms.txt 这几块。上面把型号、品牌、功率定义成独立字段,这一步的价值就在这儿:字段拆得清楚,schema 里的属性才有东西可填。
CPT 的查询就是 WP_Query。分类用 tax_query,数值区间用 meta_query,排序用 orderby。下面按目录分类取一页,按功率从低到高排:
$paged = max(1, get_query_var('paged') ?: get_query_var('page'));
$args = [
'post_type' => 'catalog_item',
'post_status' => 'publish',
'posts_per_page' => 12,
'paged' => $paged,
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'catalog_category',
'field' => 'slug',
'terms' => ['power-supply'],
],
],
'meta_query' => [
'relation' => 'AND',
[
'key' => 'catalog_power_w',
'value' => [100, 500],
'compare' => 'BETWEEN',
'type' => 'NUMERIC',
],
],
'orderby' => [
'meta_value_num' => 'ASC',
'title' => 'ASC',
],
'meta_key' => 'catalog_power_w',
];
$q = new WP_Query($args);
if ($q->have_posts()) {
while ($q->have_posts()) {
$q->the_post();
$model = get_post_meta(get_the_ID(), 'catalog_model', true);
$power = get_post_meta(get_the_ID(), 'catalog_power_w', true);
echo '<article>';
the_title('<h2>', '</h2>');
echo '<p>' . esc_html($model) . ' / ' . esc_html($power) . 'W</p>';
the_excerpt();
echo '</article>';
}
wp_reset_postdata();
}meta_query 会 JOIN wp_postmeta。筛选条件一多,SQL 里会出现多次 JOIN,字段值又是长文本,数值比较要显式写 type 为 NUMERIC。如果目录有十几个筛选维度,先跑 EXPLAIN 看执行计划,再决定要不要把规格拆到单独的表或搜索索引里。
WooCommerce 这边用 wc_get_products(),它返回 WC_Product 对象,价格、库存、商品类型、可见性这些条件由商品查询层处理:
$page = max(1, get_query_var('paged') ?: get_query_var('page'));
$products = wc_get_products([
'status' => 'publish',
'limit' => 12,
'page' => $page,
'category' => ['power-supply'],
'stock_status' => 'instock',
'orderby' => 'price',
'order' => 'ASC',
'return' => 'objects',
]);
foreach ($products as $product) {
if (! $product instanceof WC_Product) {
continue;
}
echo '<article>';
echo '<h2><a href=\'' . esc_url($product->get_permalink()) . '\'>' . esc_html($product->get_name()) . '</a></h2>';
echo wp_kses_post($product->get_price_html());
echo '<p>' . esc_html($product->get_sku()) . '</p>';
echo '</article>';
}category 传的是产品分类别名,不是分类显示名。直接写 WP_Query 查 product 也能取到文章,但商品可见性、库存状态、价格排序这些条件要自己补,容易和 WooCommerce 的查询层不一致。
如果后面要程序化创建商品,用 CRUD 比直接插 wp_posts 稳:
$product = new WC_Product_Simple();
$product->set_name('示例型号');
$product->set_status('publish');
$product->set_regular_price('199');
$product->set_sku('DEMO-001');
$product->save();只做目录时,CPT 的字段和模板都可控,前台列表、详情页、参数筛选都能按自己的结构写。风险在以后接交易:商品 ID、分类、字段、图片、URL 都要映射到 WooCommerce 的商品模型,旧链接还要做 301。迁移时至少固定 SKU,把分类和品牌映射到 product_cat 或自定义分类法,把价格、库存、单位这些字段写清楚对应关系,再跑一遍列表页和筛选页的回归。
一开始就用 WooCommerce 商品,后面加价格、库存、变体、优惠券、订单、支付、发货会顺一些;代价是后台多出购物车、结账、订单这些概念,数据表也更多。只做展示时,可以把加购和结账入口收起来,但数据模型仍然是商品模型。
产品参数很多时,两种模型都会遇到同一个问题:把所有规格塞进一个序列化字段,查询很难写。把常用筛选字段拆成独立 meta 或独立分类法,把长文本参数留在详情页,后面加筛选条件时不用重做数据层。
只做目录、询价、资料下载,短期不接在线支付,用自定义文章类型就够,字段和模板都由自己控制。
需要价格、库存、变体、优惠券、订单、支付、发货,用 WooCommerce 商品,不要在 CPT 上模拟交易流程。
现在只展示、但半年后大概率要卖,可以直接上 WooCommerce 商品;如果先用 CPT,至少把 SKU、分类、字段映射写进设计里,别等迁移时才发现字段对不上。
产品参数多、筛选维度复杂,先把规格拆成可查询的结构,再选 catalog_item 还是 product。目录站的技术债通常落在字段和查询上。
目录本身好搭,难的是目录之外的匹配逻辑:按多个维度联合筛选、访客输入一个型号返回自家等效型号、或者要和 ERP 的型号表对上。这部分自己写要先估工期。这类定制开发 AumCreate 接,$1,500 起,流程是填需求表、报价、付 50% 开工、验收付尾款,价格以官网为准。
定制开发的范围和交付方式写在 AumCreate 服务页。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。