网站开发

WooCommerce 二次开发:8 个最常见的定制需求怎么实现

WooCommerce 插件装好,产品上架,能下单了。然后客户开始提需求:

  • 「价格能不能显示成『询价』而不是数字?」
  • 「能不能批量下单不要走购物车?」
  • 「订单邮件能不能加上我们的银行账号?」

这些需求插件未必有,或者要买付费版。其实大部分用几十行代码就能解决。

下面这 8 个是我实际做得最多的,按出现频率排序。

先说三件事,能省你很多时间

1. 所有代码放子主题或 Code Snippets,不要改插件文件

WooCommerce 更新很频繁,改插件文件等于每次更新都要重改一遍。

2. WooCommerce 的模板也可以覆盖

和子主题机制一样,在主题里建 /woocommerce/ 目录,放同名模板文件就能覆盖。改结构用它,改数据用钩子。

3. 优先用钩子,其次才覆盖模板

钩子不会因为版本更新失效,模板文件可能变。能用钩子解决就不要覆盖模板。

需求 1:隐藏价格,改成「询价」

B2B 外贸站非常常见——很多产品不适合直接标价。

// 未登录用户看不到价格
add_filter( 'woocommerce_get_price_html', function( $price, $product ) {
    if ( ! is_user_logged_in() ) {
        return '<a href="/contact">登录查看价格</a>';
    }
    return $price;
}, 10, 2 );

// 或者完全隐藏价格,只显示询价按钮
add_filter( 'woocommerce_get_price_html', function( $price ) {
    return '<span class="ask-price">请联系我们询价</span>';
});

注意:只改显示是不够的。如果产品仍有价格数据,懂技术的人能从页面源码或 REST API 拿到。要真正隐藏,需要把产品类型改成「外部/分组」或者用插件单独处理。

同时隐藏加购按钮

remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );

需求 2:产品页加自定义字段(比如「起订量」「交货期」)

用 ACF 插件(推荐,不用写代码)

装 Advanced Custom Fields,建字段组,绑定到「产品」,然后填值。前台显示:

add_action( 'woocommerce_single_product_summary', function() {
    $moq = get_field( 'moq' );
    if ( $moq ) {
        echo '<p>起订量:' . esc_html( $moq ) . ' 件</p>';
    }
}, 25 );

不用插件的原生做法

// 后台加字段
add_action( 'woocommerce_product_options_general_product_data', function() {
    woocommerce_wp_text_input( array(
        'id'          => '_moq',
        'label'       => '起订量(MOQ)',
        'placeholder' => '例如 500',
    ) );
});

// 保存
add_action( 'woocommerce_process_product_meta', function( $post_id ) {
    if ( isset( $_POST['_moq'] ) ) {
        update_post_meta( $post_id, '_moq', sanitize_text_field( $_POST['_moq'] ) );
    }
});

字段名前加下划线 _ 表示「隐藏的自定义字段」,不会在后台自定义字段列表里显示。

需求 3:修改订单邮件内容

最常加的东西:银行账号、预计发货时间、客服联系方式。

方法一:覆盖邮件模板(适合大改)

复制 /wp-content/plugins/woocommerce/templates/emails/customer-processing-order.php
到 /wp-content/themes/你的主题/woocommerce/emails/customer-processing-order.php,然后改。

方法二:用钩子追加内容(适合加一小段)

add_action( 'woocommerce_email_order_meta', function( $order, $sent_to_admin, $plain_text ) {
    if ( $plain_text ) return;
    echo '<h3>付款方式</h3>';
    echo '<p>银行:XXX Bank<br>账号:123456789<br>SWIFT:XXXXXX</p>';
}, 10, 3 );

$sent_to_admin 可以判断这封邮件是发给客户还是发给管理员,避免银行账号出现在管理员邮件里。

需求 4:批量询价替代购物车

很多 B2B 站不需要在线支付,只需要「客户选一堆产品 → 提交询价单 → 销售跟进」。

两种实现思路:

  • 简单方案:装询价插件(YITH Request a Quote、Product Enquiry 等),把加购按钮换成「加入询价单」
  • 自定义方案:用 WooCommerce 的订单系统,创建一个「询价」状态的订单,不走支付流程

自定义方案的核心代码:

// 注册一个自定义订单状态「待报价」
add_action( 'init', function() {
    register_post_status( 'wc-quoted', array(
        'label'                     => '待报价',
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop( '待报价 (%s)', '待报价 (%s)' ),
    ) );
});

add_filter( 'wc_order_statuses', function( $statuses ) {
    $statuses['wc-quoted'] = '待报价';
    return $statuses;
});

需求 5:按数量阶梯定价

「买 100 个 10 美元,买 1000 个 8 美元」——B2B 标配。

免费方案:WooCommerce 的变体功能可以勉强实现,但体验差。更好的方式是装阶梯定价插件(WooCommerce Quantity Discounts、Dynamic Pricing 等)。

如果要自己实现,核心钩子是:

add_filter( 'woocommerce_product_get_price', function( $price, $product ) {
    $qty = WC()->cart->get_cart_item_quantities();
    // 根据购物车里的数量返回不同价格
    return $price;
}, 10, 2 );

提醒:价格逻辑涉及税费、优惠券、货币切换,自己写容易踩坑。商业场景建议直接用成熟插件,比自己维护划算。

需求 6:结账表单加自定义字段

比如「公司名称」「税号」「希望的交货日期」——B2B 场景非常常见。

add_filter( 'woocommerce_checkout_fields', function( $fields ) {
    $fields['billing']['billing_company_tax'] = array(
        'label'       => '公司税号',
        'placeholder' => '请输入税号',
        'required'    => false,
        'class'       => array( 'form-row-wide' ),
        'priority'    => 25,
    );
    return $fields;
});

// 保存到订单
add_action( 'woocommerce_checkout_update_order_meta', function( $order_id ) {
    if ( ! empty( $_POST['billing_company_tax'] ) ) {
        update_post_meta( $order_id, '_billing_company_tax',
            sanitize_text_field( $_POST['billing_company_tax'] ) );
    }
});

这样字段会显示在后台订单详情和邮件里(需要额外加代码显示在邮件)。

需求 7:限制最低起订量

add_filter( 'woocommerce_quantity_input_args', function( $args, $product ) {
    $args['min_value'] = 100;    // 最少 100
    $args['step']      = 100;    // 每次增加 100
    return $args;
}, 10, 2 );

// 加购时校验
add_filter( 'woocommerce_add_to_cart_validation', function( $passed, $product_id, $qty ) {
    if ( $qty < 100 ) {
        wc_add_notice( '本产品起订量为 100 件', 'error' );
        return false;
    }
    return $passed;
}, 10, 3 );

需求 8:订单自动同步到企业微信/钉钉

有新订单时推送通知到你的手机——这个对一个人运营的站非常实用。邮件通知你可能几小时后才看,即时推送是立刻知道。

add_action( 'woocommerce_new_order', function( $order_id ) {
    $order = wc_get_order( $order_id );
    $msg = sprintf(
        "新订单 #%s
金额:%s
客户:%s %s",
        $order->get_order_number(),
        $order->get_total(),
        $order->get_billing_first_name(),
        $order->get_billing_email()
    );

    wp_remote_post( 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的KEY', array(
        'headers' => array( 'Content-Type' => 'application/json' ),
        'body'    => json_encode( array(
            'msgtype' => 'text',
            'text'    => array( 'content' => $msg ),
        ) ),
    ) );
});

woocommerce_new_order 在订单创建时触发。改成 woocommerce_order_status_completed 则是完成时触发。

几个必须注意的坑

坑 1:模板覆盖了但 WooCommerce 更新后失效

WooCommerce 大版本更新时,模板文件结构可能变,你覆盖的旧模板会不兼容。

后台会提示「你的主题有过时的 WooCommerce 模板」——看到这个提示就要去检查更新。在 WooCommerce → 状态 → 工具 里能看到哪些文件过时了。

坑 2:价格过滤钩子冲突

woocommerce_get_price_html 和 woocommerce_product_get_price 是不同的东西:

  • 前者改显示的 HTML
  • 后者改实际的价格数值(影响购物车计算)

用错了会导致「显示一个价,结算另一个价」——这是很严重的问题。

坑 3:忘记转义输出

输出到页面的用户数据必须转义,否则有 XSS 风险:

echo esc_html( $value );     // 普通文本
echo esc_url( $url );        // 链接
echo esc_attr( $attr );      // HTML 属性

坑 4:在钩子里做耗时操作

比如 woocommerce_new_order 里同步调用外部 API,如果 API 慢,客户结账就会卡住。

正确做法:把耗时操作放到定时任务里异步执行,用 wp_schedule_single_event()。

最后:什么时候该找人做

上面这些,会 PHP 的人半小时能搞定一个。但如果你不懂代码,照着复制也有风险——一个语法错误就是白屏。

判断标准:

  • 改显示、加字段:可以自己试,先在测试站上试
  • 涉及价格计算、支付流程:别自己改,错了直接导致钱算错
  • 需要性能考虑的功能(比如几千个产品的批量处理):找专业的人

而且说实话,很多需求买个插件比写代码便宜——一个插件几十到几百块,你自己折腾的时间成本可能更高。先搜一下有没有现成插件,再决定要不要自己写。