
本文教你用单一函数在商品列表页和单商品页自动显示“new”徽章,支持按创建时间动态判断,并可灵活排除特定产品分类(如 sale),避免重复钩子与逻辑冗余。
本文教你用单一函数在商品列表页和单商品页自动显示“new”徽章,支持按创建时间动态判断,并可灵活排除特定产品分类(如 sale),避免重复钩子与逻辑冗余。
在 WooCommerce 主题开发中,为新品添加视觉标识(如 “N E W” 徽章)是提升用户感知的有效方式。但若分别在列表页(woocommerce_before_shop_loop_item_title)和单商品页(woocommerce_single_product_summary)编写两套逻辑,不仅代码冗余,后期维护也易出错。本文提供一套复用性强、扩展性好、语义清晰的解决方案。
✅ 统一函数 + 多钩子:一次定义,多处生效
核心思路是:将徽章渲染逻辑封装为独立函数,并通过多个 add_action() 挂载到不同位置。WooCommerce 的钩子机制天然支持这种解耦设计:
function new_badge_shop_page() {
global $product;
// 【关键】排除指定分类(如 'sale'、'clearance' 等)
// 注意:has_term() 第三个参数必须传入 product ID(整型),不可省略
if ( has_term( array( 'sale', 'clearance', 'discontinued' ), 'product_cat', $product->get_id() ) ) {
return;
}
$newness_days = 270; // 新品有效期:270 天(约 9 个月)
$created = strtotime( $product->get_date_created() );
// 判断是否在新品时效范围内
if ( time() - ( 60 * 60 * 24 * $newness_days ) ' . esc_html__( 'N E W', 'woocommerce' ) . '';
}
}
// 同时挂载到商品列表页(优先级 3)和单商品页(优先级 9,确保在标题后显示)
add_action( 'woocommerce_before_shop_loop_item_title', 'new_badge_shop_page', 3 );
add_action( 'woocommerce_single_product_summary', 'new_badge_shop_page', 9 );
? 为什么
has_term()原写法失败?
你之前使用的!has_term('sale')缺少两个关键点:
1️⃣has_term()默认作用于当前全局$post,而 WooCommerce 循环中$product对象需显式传入 ID;
2️⃣ 第二个参数'product_cat'必须明确指定分类法(taxonomy),否则可能误判;
3️⃣ 推荐使用数组传入多个分类 slug,便于后续扩展。
?️ 样式建议(CSS 示例)
徽章默认会紧贴产品图/标题左上角,建议添加基础样式以提升可读性与美观度:
.itsnew {
position: absolute;
top: 12px;
left: 12px;
background-color: #e74c3c;
color: white;
font-size: 12px;
font-weight: bold;
padding: 4px 8px;
letter-spacing: 1px;
text-transform: uppercase;
border-radius: 2px;
z-index: 10;
}
/* 确保徽章在图片上方显示(尤其在 loop item 中)*/
.woocommerce ul.products li.product,
.woocommerce div.product {
position: relative;
}
⚠️ 注意事项与最佳实践
- ✅ 始终使用
esc_html__():保障翻译兼容性与 XSS 安全; - ✅
$product->get_id()不可替换为$product->ID:后者在某些上下文(如 REST API 或自定义查询)中可能为空或不准确; - ✅ 时间计算推荐改用
strtotime()+date_i18n()更健壮(进阶可选):$created_date = $product->get_date_created(); if ( $created_date && $created_date->getTimestamp() > strtotime( "-{$newness_days} days" ) ) { ... } - ❌ 避免在循环中执行数据库查询(本方案无此问题,因
has_term()和get_date_created()均基于已加载对象); - ? 如需支持“仅对特定分类显示徽章”,只需将
if ( has_term(...) ) return;改为白名单模式:if ( ! has_term( array( 'new-arrivals', 'featured' ), 'product_cat', $product->get_id() ) ) { return; }
通过以上实现,你获得了一个轻量、可靠、易于维护的新品徽章系统——无需复制函数、无需重复判断逻辑,且具备清晰的业务隔离(分类过滤)与良好的可扩展性。










