需求是我要在上圖的地方多增加一個 checkbox:
本想用 JS 硬幹,但爬了一下原始碼發現有 product_type_options
這個勾點可以使用,寫法跟 WooCommerce Setting API 滿像的,一樣是用一個關聯陣列包含欄位 id、label、description 跟 default 預設值:
private static function get_product_type_options() {
return apply_filters(
'product_type_options',
array(
'virtual' => array(
'id' => '_virtual',
'wrapper_class' => 'show_if_simple',
'label' => __( 'Virtual', 'woocommerce' ),
'description' => __( 'Virtual products are intangible and are not shipped.', 'woocommerce' ),
'default' => 'no',
),
'downloadable' => array(
'id' => '_downloadable',
'wrapper_class' => 'show_if_simple',
'label' => __( 'Downloadable', 'woocommerce' ),
'description' => __( 'Downloadable products give access to a file upon purchase.', 'woocommerce' ),
'default' => 'no',
),
)
);
}
搞定介面後要處理資料寫入的部分,有 woocommerce_admin_process_product_object
這個勾點可以使用,看他的寫法是用 $product
物件的 set_props
方法來儲存,於是我就依樣畫葫蘆用 set_props
來寫入我自己的值,結果搞了老半天一直寫不進去,去爬了 set_props 的實作,發現到我新增的值是不能用它寫入的:
$errors = $product->set_props(
array(
'sku' => isset( $_POST['_sku'] ) ? wc_clean( wp_unslash( $_POST['_sku'] ) ) : null,
'purchase_note' => isset( $_POST['_purchase_note'] ) ? wp_kses_post( wp_unslash( $_POST['_purchase_note'] ) ) : '',
'downloadable' => isset( $_POST['_downloadable'] ),
'virtual' => isset( $_POST['_virtual'] ),
'featured' => isset( $_POST['_featured'] ),
'catalog_visibility' => isset( $_POST['_visibility'] ) ? wc_clean( wp_unslash( $_POST['_visibility'] ) ) : null,
...
)
);
public function set_props( $props, $context = 'set' ) {
$errors = false;
foreach ( $props as $prop => $value ) {
try {
/**
* Checks if the prop being set is allowed, and the value is not null.
*/
if ( is_null( $value ) || in_array( $prop, array( 'prop', 'date_prop', 'meta_data' ), true ) ) {
continue;
}
$setter = "set_$prop";
if ( is_callable( array( $this, $setter ) ) ) {
$this->{$setter}( $value );
}
} catch ( WC_Data_Exception $e ) {
if ( ! $errors ) {
$errors = new WP_Error();
}
$errors->add( $e->getErrorCode(), $e->getMessage() );
}
}
return $errors && count( $errors->get_error_codes() ) ? $errors : true;
}
最後跑去翻 $prdouct
物件的其他方法,找到跟訂單物件一樣的 update_meta_data
才能正確寫入,雖然理論上也是可以使用 update_post_meta
來處理,而且 $product
物件目前還沒看到資料表要拆分出來的消息,但避免日後需要另外修改,就還是乖乖用 update_meta_data
來實作:
// 新增介面
add_filter( 'product_type_options', 'add_my_setting' );
function add_onepage_checkout_setting( $options ) {
$options['my_type_option'] = array(
'id' => '_my_type_option',
'wrapper_class' => '',
'label' => __( 'my_type_option', 'woocommerce' ),
'description' => __( 'my_type_option_desc', 'woocommerce' ),
'default' => 'no',
);
return $options;
}
// 儲存值
add_action( 'woocommerce_admin_process_product_object', 'save_product_type_setting' );
function save_product_type_setting( $product ) {
$product->update_meta_data( 'my_type_option', ! empty( $_POST['_my_type_option'] ) ? 'yes' : 'no' );
}