向结账表单添加WooCommerce自定义结账字段,可以使用插件WooCommerce checkout manager或者filter:woocommerce_checkout_fields,本文介绍的方法非上述两种,而是使用woocommerce_form_field()函数在订单备注之后添加自定义结账字段,并将字段显示在订单详情、订单邮件和后台中的方法。
2021年10月更新:WooCommerce自定义结账字段(2021)
代码测试环境和使用方法
WordPress 3.9.1 + WooCommerce 2.1.2 + 主题Twentytwelve
所有代码放在主题的functions.php中执行,每段代码后面的图片为改代码的执行效果。
目录
代码段1 – 在订单备注后添加WooCommerce自定义结账字段
注意在最开头输出了带有my_custom_section class的div,可以用该class修改这个区域的样式,突出该区域。
/**
* 代码段1 - 在订单备注后添加自定义选项
*/
function my_custom_checkout_section( $checkout ){
// $checkout stores all checkout fields
// Section starts, output wrapper or header
echo '<div class="my_custom_section">';
// Create a select field
$options = array(
'只工作日送货' => '只工作日送货',
'只双休日送' => '只双休日送货',
'工作日、双休日均可送货' => '工作日、双休日均可送货'
);
woocommerce_form_field("my_custom_field_1", array(
'type' => 'select',
'class' => array('form-row-wide my_custom_field'),
'label' => '送货时间: ',
'options' => array( '' => '-----选择送货时间-----') + $options,
'required' => true
), $checkout->get_value( 'my_custom_field_1' ) );
echo '</div>';
}
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_section' );
代码段2 – 验证自定义字段
虽然第一步中强调了required=true,但只是改变了长相,真正的验证还得自己来。这里只验证是否有值。
/**
* 代码段2 - 验证自定义字段
*
* required=true只改变了长相,验证还得自己写代码
*/
function my_custom_checkout_field_process(){
global $woocommerce;
if( empty($_POST['my_custom_field_1']) )
$woocommerce->add_error( '<strong>请选择送货时间</strong>' );
}
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process' );
代码段3 – 存储自定义字段的值
用户选择后还要把值存到订单中方便以后查询。order的本质是post,所以order meta就是post meta,用update_post_meta存储,用get_post_meta查询。
/**
* 代码段3 - 存储自定义字段的值
*
* 如果和用户属性相关,存到usermeta表里,否则存在order meta(postmeta)里即可
*/
function my_custom_checkout_field_save( $order_id ){
// custom field名称,最前面的下划线的作用是使该custom field在后台不可见,必须通过自定义程序显示
$ordermeta_name = '_my_custom_field_1';
// 将送货时间存到订单的custom field里
if( !empty($_POST['my_custom_field_1'] ) )
update_post_meta( $order_id, $ordermeta_name, wc_clean( $_POST['my_custom_field_1'] ) );
}
add_action('woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_save' );代码段4.1-4.3 – 在成功下单页面不同位置显示结账字段的值
提供三个位置显示,一般只需要选择其中一个即可。
代码段4.1 – 在订单详情之后,customer details之前显示
/**
* 代码段4.1 - 在order-received页面显示自定义字段的值
*
* 在订单详情之后,customer details之前显示
*/
function my_custom_field_display_on_order_received( $order ){
$my_custom_field_1 = get_post_meta( $order->id, '_my_custom_field_1', true );
if( !empty($my_custom_field_1) ){
echo '<h2>送货时间</h2>';
echo '<p><strong>送货时间:</strong>' .$my_custom_field_1. '</p>';
}
}
add_action('woocommerce_order_details_after_order_table', 'my_custom_field_display_on_order_received' );代码段4.2 – 在产品列表后显示
/**
* 代码段4.2在产品列表后显示
*
* 在tbody内、产品列表后显示
*/
function my_custom_field_display_after_product_list( $order ){
$my_custom_field_1 = get_post_meta( $order->id, '_my_custom_field_1', true );
if( !empty($my_custom_field_1) ){
?>
<tr><td>送货时间</td><td><?php echo $my_custom_field_1; ?></td></tr>
<?php
}
}
add_action( 'woocommerce_order_items_table', 'my_custom_field_display_after_product_list' );
代码段4.3 – 在配送方式前面显示
/**
* 代码段4.3 - 在配送方式前面显示
*
* 在tfoot内、shipping方式前显示
*/
function my_custom_field_display_before_shipping( $total_rows, $order ){
$my_custom_field_1 = get_post_meta( $order->id, '_my_custom_field_1', true );
$new_total_rows = array();
if( !empty($my_custom_field_1) ){
$new_row['my_custom_field_1'] = array(
'label' => '送货时间:',
'value' => $my_custom_field_1
);
// Insert $new_row after shipping field
$total_rows = array_merge( array_splice( $total_rows,0,2), $new_row, $total_rows );
}
return $total_rows;
}
add_filter( 'woocommerce_get_order_item_totals', 'my_custom_field_display_before_shipping', 10, 2 );
代码段5 – 在订单邮件中显示
若选择代码段4.2将字段加入订单详情页面,则字段也会自动加到邮件中,就不需要代码段5了。
/**
* 代码段5 - 在email中显示
*
* 在email的订单详情表格之后显示
* 若使用woocommerce_get_order_item_totals添加字段,
* 无需下面的代码,就可以在订单详情表格里显示
*
* $sent_to_admin - 为true表示该邮件发送给管理员
*/
function my_custom_field_order_email( $order, $sent_to_admin ){
$my_custom_field_1 = get_post_meta( $order->id, '_my_custom_field_1', true );
if( !empty($my_custom_field_1) ){
echo '<h3>送货时间</h3>';
echo "<p>送货时间: $my_custom_field_1 </p>";
if( $sent_to_admin ) {
echo '这是发给管理员的通知邮件';
}
}
}
add_action( 'woocommerce_email_after_order_table', 'my_custom_field_order_email', 10, 2 );
代码段6 – 在后台订单详情中显示
/**
* 代码段6 - 在后台订单详情中显示自定义字段
*/
function my_custom_field_admin_info( $order ){
$my_custom_field_1 = get_post_meta( $order->id, '_my_custom_field_1', true );
if( !empty($my_custom_field_1) ){
echo '<h4>送货时间</h4>';
echo "<p>$my_custom_field_1</p>";
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'my_custom_field_admin_info' );
代码段2执行不成功。
排错过程如下:
1、Chrome控制台报:wp-admin/admin-ajax.php?action=woocommerce_checkout 500 (Internal Server Error)。
2、查看apache的error.log,报:PHP Fatal error: Call to undefined method WooCommerce::add_error()
3、确信代码是加在了主题下的functions.php文件下
4、倒腾半天,借鉴wp-content\plugins\woocommerce\includes\class-wc-checkout.php里面的wc_add_notice()函数格式将代码2改为如下:
function my_custom_checkout_field_process(){
//global $woocommerce; 此句注释
if( empty($_POST['my_custom_field_1']) )
//$woocommerce->add_error( '请选择送货时间' ); 此句注释
wc_add_notice( '送货时间 ' . __( 'is a required field.', 'woocommerce' ), 'error' ); //添加此句
}
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process' );
我是php小白,因此错误原因不明,望站长释疑,谢谢!
报错含义是该函数未定义,因为woocommerce 2.1移除了add_error函数,换成了wc_add_notice,使用方法是
wc_add_notice( $message, ‘error’ ),你把add_error都替换掉试试。
明白了原因,谢谢你的回复:)
写得非常好!读完之后原理也懂了,效果也直观。感谢分享!
怎么增加多个这种自定义字段呢?
把代码里那个字段复制一下,换个ID就行了啊
你好 ,博主
请问我想在给顾客的回复中调用他的 Last name 用该怎么写呢 非常感激··
你具体要在哪里调用?WooCommerce的Order是一个custom post type,而last name是custom field,存储在wp_postmeta表里。所以用get_post_meta可以获取。
也可以用woocommerce的Order API,在已知ID的情况下调用new WC_Order( $order_id )
如果直接在邮件里,还有其他API可以用,所以要具体情况具体分析。
Sola您好,
想請問有沒有可能在wc的結帳欄位增加驗證boolean的值呢?
如果這個是true,就可以結帳付款
如果不行,就return false並且無法送出訂單。
例如台灣想要驗證身分證的話,所輸入的號碼需要符合一些規則,
提供一個php檔案:
//************** // 身份證檢查 //************** function checkNick($id){ //建立字母分數陣列 $head = array('A'=>1,'I'=>39,'O'=>48,'B'=>10,'C'=>19,'D'=>28, 'E'=>37,'F'=>46,'G'=>55,'H'=>64,'J'=>73,'K'=>82, 'L'=>2,'M'=>11,'N'=>20,'P'=>29,'Q'=>38,'R'=>47, 'S'=>56,'T'=>65,'U'=>74,'V'=>83,'W'=>21,'X'=>3, 'Y'=>12,'Z'=>30); //建立加權基數陣列 $multiply = array(8,7,6,5,4,3,2,1); //檢查身份字格式是否正確 if (ereg("^[a-zA-Z][1-2][0-9]+$",$id) && strlen($id) == 10){ //切開字串 $len = strlen($id); for($i=0; $i<$len; $i++){ $stringArray[$i] = substr($id,$i,1); } //取得字母分數 $total = $headPoint[array_shift($stringArray)]; //取得比對碼 $point = array_pop($stringArray); //取得數字分數 $len = count($stringArray) for($j=0; $j<$len; $j++){ $total += $stringArray[$j]*$multiply[$j]; } //檢查比對碼 if (($total%10 == 0 )?0:10-$total%10 != $point) { return false; } else { return true; } } else { return false; } }謝謝您的幫忙
chenghsuan
参考下本文的代码段2 验证自定义字段。
这里所有表单值都存储在$_POST里,你可以随意验证,如果验证不通过,调用
$woocommerce->add_error( ‘错误信息’ );
剩下的woocommerce会负责处理。
你说的布尔值应该是结果,不是表现。身份证号用text field就可以,在验证函数里调用checkNick函数检查,如果返回值为false,调用$woocommerce->add_error,为true就不管它。
請問能夠更改這些自定義項目的排列位置嗎?
謝謝~
可以啊,改变每一项在php数组里的位置。
謝謝您的回應
請問是依照這個修改嗎?
http://docs.woothemes.com/document/hooks/
例如
add_action( ‘woocommerce_after_order_notes’, ‘my_custom_checkout_section’ );
改成
add_action( ‘woocommerce_after_checkout_billing_form’, ‘my_custom_checkout_section’ );
這樣嗎?
謝謝
你说的是改变所有项目的显示位置啊,那是要改action,但不是所有的都能用,必须是带有$checkout参数的action,你试一下就知道了
我的意思是:
如果就以這篇文章的範例來說
如果我要把”选择送货时间” 改成擺到 ” Billing details “的最下面
我需要改哪些參數呢?
謝謝你
用你说的woocommerce_after_checkout_billing_form应该可以吧,你没试过吗
成功了,謝謝您。 :D
有没办法,把客户地址,公司地址,镇/市 *,统统都去掉啊。只留邮箱。我用来卖虚拟产品,简单一些的好,
同好。有方法结论没?
简洁大气上档次的博客啊。请问主题是自己做的么?
twentytwelve改的
woocommerce用信用卡付款的话一般用什么方式?就是输入卡片信息直接能付款的,不用让客户再注册第三方支付平台什么的
从phpbbchina 搜索缩略图问题关键字到—–小猪网站遇到缩略图问题—-我几经尝试虽然没有成功—-遂想换换脑子,看看猪网站到底是怎么回事吧—-发现N年无更新,注册用户未满200人,但仍开放着,膜拜!—-遂翻阅到该博客—-读了几篇博文后。。。。
发现楼主是技术型的Freelancer,再次膜拜!
留个印记 :)
那网站是养猪的时候弄的,现在猪定型了,品种也弄明白了,动力没了,于是网站也荒废了。话说你遇到啥缩略图问题了?
哈哈,你的爱好真是广泛啊,不过确实挺另类的 😀
我遇到缩略图的问题,第二天睡足觉后,又查资料+多番改动,最终解决了 :)
以后得常来你这里走走学习了,Good luck
Thank you!
可惜不知道这些代码片段放在哪个文件中。。。。囧
开头不就写了么