WooCommerce Custom Fields

WooCommerce has the ability to use custom fields in various locations within the checkout, user profile and add / manage order screens. Using custom fields and tying them together to create a simple workflow is key to managing orders and customers.

The following code example contains some basic logic to enable custom fields to be shown on the checkout, add / manage order screen, and the customer profile. It makes some assumptions about what how and when data should be saved so please customise it to fit your needs.

In summary, the code example creates 6 new custom fields that are displayed at various locations within the WordPress backend and checkout, these are as follows:

  1. VAT Number - The VAT number field is assigned to the checkout, customer profile, and add / manage order screen. This field is assigned to an order and if the customer checks Save Address it is assigned to their user profile.
  2. Position - Same as above
  3. Department - Same as above
  4. Switchboard Phone Number - Same as above
  5. Purchase Order Number - The purchase order number field is assigned to checkout and add / manage order screen. This field doesn't need to be saved to the user profile.
  6. Save Address Checkbox - This allows users to save their address at the checkout which then updates the custom fields in the their user profile. This is checked by default.

WooCommerce Custom User Profile Fields

WooCommerce Custom Checkout Fields

WooCommerce Custom Manage / Add Order Fields

Providing the above functionality means a customer can add their details to the custom fields featured on the checkout which will then be displayed on the manage order screen. By integrating with the 'Save Customer' functionality on the order screen a user order details can be saved to their profile, this is useful if a user has made a mistake during the order process and the order administrator needs to update their user profile without leaving the manage order screen. Likewise, it is also useful when creating manual orders as order administrators can update the custom user profile fields without leaving the add order screen. Further to this, clicking the 'load billing address' button when editing an order will load the custom user profile fields via an Ajax request.


//---------------------------------------------------------------
// WOOCOMMERCE
//---------------------------------------------------------------

///// CUSTOM FIELDS //////

//ADD CUSTOM USER FIELDS TO WOOCOMMERCE BILLING ADDRESS IN USER PROFILE
add_filter( 'woocommerce_customer_meta_fields' , 'user_profile_custom_fields' );
function user_profile_custom_fields( $fields ) {
	$fields['billing']['fields']['billing_vat_number'] = array(
		'label' => __( 'VAT Number', 'woocommerce' ),
		'description' => '',
	);
	$fields['billing']['fields']['billing_position'] = array(
		'label' => __( 'Position', 'woocommerce' ),
		'description' => '',
	);
	$fields['billing']['fields']['billing_department'] = array(
		'label' => __( 'Department', 'woocommerce' ),
		'description' => '',
	);
	$fields['billing']['fields']['billing_switchboard_phone_number'] = array(
		'label' => __( 'Switchboard Phone Number', 'woocommerce' ),
		'description' => '',
	);
	return $fields;
}

//ADD CUSTOM USER FIELDS TO ADMIN ORDER SCREEN
add_filter( 'woocommerce_admin_billing_fields' , 'order_admin_custom_fields' );
function order_admin_custom_fields( $fields ) {
	global $theorder;
	$fields['vat_number'] = array(
		'label' => __( 'VAT Number', '_billing_vat_number' ),
		'value'=> get_post_meta( $theorder->id, '_billing_vat_number', true ),
		'show'  => true,
		//'class'   => '',
		'wrapper_class' => 'form-field-wide',
		'style' => '',
		//'id' => '',
		//'type' => '',
		//'name' => '',
		//'placeholder' => '',
		//'description' => '',
		//'desc_tip' => bool,
		//'custom_attributes' => '',
	);
	$fields['purchase_order_number'] = array(
		'label' => __( 'Purchase Order Number', '_billing_purchase_order_number' ),
		'value'=> get_post_meta( $theorder->id, '_billing_purchase_order_number', true ),
		'show'  => true,
		'wrapper_class' => 'form-field-wide',
		'style' => '',
	);
	$fields['position'] = array(
		'label' => __( 'Position', '_billing_position' ),
		'value'=> get_post_meta( $theorder->id, '_billing_position', true ),
		'show'  => true,
		'wrapper_class' => 'form-field-wide',
		'style' => '',
	);
	$fields['department'] = array(
		'label' => __( 'Department', '_billing_department' ),
		'value'=> get_post_meta( $theorder->id, '_billing_department', true ),
		'show'  => true,
		'wrapper_class' => 'form-field-wide',
		'style' => '',
	);
	$fields['switchboard_phone_number'] = array(
		'label' => __( 'Switchboard Phone Number', '_billing_switchboard_phone_number' ),
		'value'=> get_post_meta( $theorder->id, '_billing_switchboard_phone_number', true ),
		'show'  => true,
		'wrapper_class' => 'form-field-wide',
		'style' => '',
	);

	return $fields;
}

//LOAD CUSTOMER USER FIELDS VIA AJAX ON ADMIN ORDER SCREEN FROM CUSTOMER RECORD
add_filter( 'woocommerce_found_customer_details', 'add_custom_fields_to_admin_order', 10, 1 );
function add_custom_fields_to_admin_order($customer_data){
	$user_id = $_POST['user_id'];
	$customer_data['billing_vat_number'] = get_user_meta( $user_id, 'billing_vat_number', true );
	$customer_data['billing_position'] = get_user_meta( $user_id, 'billing_position', true );
	$customer_data['billing_department'] = get_user_meta( $user_id, 'billing_department', true );
	$customer_data['billing_switchboard_phone_number'] = get_user_meta( $user_id, 'billing_switchboard_phone_number', true );
	return $customer_data;
}

//SAVE META DATA / CUSTOM FIELDS WHEN EDITING ORDER ON ADMIN SCREEN
add_action( 'woocommerce_process_shop_order_meta', 'woocommerce_process_shop_order', 10, 2 );
function woocommerce_process_shop_order ( $post_id, $post ) {

	if ( empty( $_POST['woocommerce_meta_nonce'] ) ) {
		return;
	}

	if(!wp_verify_nonce( $_POST['woocommerce_meta_nonce'], 'woocommerce_save_data' )){
		return;
	}

	if(!isset($_POST['cxccoo-save-billing-address-input'])){
		return;
	}

	if(isset($_POST['_billing_vat_number'])){
		update_user_meta( $_POST['user_ID'], 'billing_vat_number', sanitize_text_field( $_POST['_billing_vat_number'] ) );
	}
	if(isset($_POST['_billing_purchase_order_number'])){
		update_user_meta( $_POST['user_ID'], 'billing_purchase_order_number', sanitize_text_field( $_POST['_billing_purchase_order_number'] ) );
	}
	if(isset($_POST['_billing_position'])){
		update_user_meta( $_POST['user_ID'], 'billing_position', sanitize_text_field( $_POST['_billing_position'] ) );
	}
	if(isset($_POST['_billing_department'])){
		update_user_meta( $_POST['user_ID'], 'billing_department', sanitize_text_field( $_POST['_billing_department'] ) );
	}
	if(isset($_POST['_billing_switchboard_phone_number'])){
		update_user_meta( $_POST['user_ID'], 'billing_switchboard_phone_number', sanitize_text_field( $_POST['_billing_switchboard_phone_number'] ) );
	}
}

//OVERRIDE CHECKOUT FIELDS
//add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
function custom_override_checkout_fields( $fields ) {
     $fields['billing']['billing_postcode']['class'] = array('form-row-wide');
     return $fields;
}

// SHOW CUSTOM FIELDS ON CHECKOUT
add_filter( 'woocommerce_checkout_fields' , 'add_custom_fields_to_checkout' );
function add_custom_fields_to_checkout( $fields ) {
	$fields['billing']['billing_vat_number'] = array(
		'label'     => __('VAT Number', 'woocommerce'),
		'placeholder'   => _x('VAT Number', 'placeholder', 'woocommerce'),
		'required'  => false,
		'class'     => array('form-row-first'),
		'clear'     => false
	);
	$fields['billing']['billing_switchboard_phone_number'] = array(
		'label'     => __('Switchboard Phone Number', 'woocommerce'),
		'placeholder'   => _x('Switchboard Phone Number', 'placeholder', 'woocommerce'),
		'required'  => false,
		'class'     => array('form-row-last'),
		'clear'     => false
	);
	$fields['billing']['billing_position'] = array(
		'label'     => __('Position', 'woocommerce'),
		'placeholder'   => _x('Position', 'placeholder', 'woocommerce'),
		'required'  => false,
		'class'     => array('form-row-first'),
		'clear'     => false
	);
	$fields['billing']['billing_department'] = array(
		'label'     => __('Department', 'woocommerce'),
		'placeholder'   => _x('Department', 'placeholder', 'woocommerce'),
		'required'  => false,
		'class'     => array('form-row-last'),
		'clear'     => false
	);
	$fields['billing']['billing_purchase_order_number'] = array(
		'label'     => __('Purchase Order Number', 'woocommerce'),
		'placeholder'   => _x('Purchase Order Number', 'placeholder', 'woocommerce'),
		'required'  => false,
		'class'     => array('form-row-wide'),
		'clear'     => true
	);
	$user_id = get_current_user_id();
	if(isset($user_id)){
		$fields['billing']['save_address'] = array(
			'label'     => __('Save Address Details', 'woocommerce'),
			'placeholder'   => _x('Save Address Details', 'placeholder', 'woocommerce'),
			'required'  => false,
			'type'  => 'checkbox',
			'default' => 1
		);
	}

	return $fields;
}

add_filter("woocommerce_checkout_fields", "order_fields");

function order_fields($fields) {

    $order = array(
        "billing_first_name",
        "billing_last_name",
        "billing_email",
        "billing_phone",
        "billing_company",
        "billing_position",
        "billing_department",
        "billing_vat_number",
        "billing_switchboard_phone_number",
        "billing_address_1",
        "billing_address_2",
        "billing_postcode",
        "billing_state",
        "billing_country",
        "save_address",
        "billing_purchase_order_number",
    );
    foreach($order as $field)
    {
        $ordered_fields[$field] = $fields["billing"][$field];
    }

    $fields["billing"] = $ordered_fields;
    return $fields;

}

//SAVE CUSTOM USER FIELDS TO ORDER ON CHECKOUT
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
	$user_id = get_current_user_id();
	//save po and vat numbers
	if ( ! empty( $_POST['_billing_vat_number'] ) ) {
		update_post_meta( $order_id, '_billing_vat_number', sanitize_text_field( $_POST['_billing_vat_number'] ) );
	}
	if ( ! empty( $_POST['_billing_purchase_order_number'] ) ) {
		update_post_meta( $order_id, '_billing_purchase_order_number', sanitize_text_field( $_POST['_billing_purchase_order_number'] ) );
	}
	if ( ! empty( $_POST['position'] ) ) {
		update_post_meta( $order_id, '_billing_position', sanitize_text_field( $_POST['_billing_position'] ) );
	}
	if ( ! empty( $_POST['_billing_department'] ) ) {
		update_post_meta( $order_id, '_billing_department', sanitize_text_field( $_POST['_billing_department'] ) );
	}
	if ( ! empty( $_POST['_billing_switchboard_phone_number'] ) ) {
		update_post_meta( $order_id, '_billing_switchboard_phone_number', sanitize_text_field( $_POST['_billing_switchboard_phone_number'] ) );
	}
	//if customer logged in and save address checkbox checked, save customer data to customer profile
	if(!isset( $_POST['save_address'] )){
		return;
	}
	if ( ! empty( $_POST['_billing_vat_number'] && isset($user_id) ) ) {
		update_user_meta( $user_id, 'billing_vat_number', sanitize_text_field( $_POST['_billing_vat_number'] ) );
	}
	if ( ! empty( $_POST['_billing_position'] && isset($user_id) ) ) {
		update_user_meta( $user_id, 'billing_position', sanitize_text_field( $_POST['_billing_position'] ) );
	}
	if ( ! empty( $_POST['_billing_department'] && isset($user_id) ) ) {
		update_user_meta( $user_id, 'billing_department', sanitize_text_field( $_POST['_billing_department'] ) );
	}
	if ( ! empty( $_POST['_billing_switchboard_phone_number'] && isset($user_id) ) ) {
		update_user_meta( $user_id, 'billing_switchboard_phone_number', sanitize_text_field( $_POST['_billing_switchboard_phone_number'] ) );
	}

}

////// END CUSTOM FIELDS //////