4
votes

I am not a developer but somehow managed to add Woocommerce custom fields to checkout and order edit pages. There are similar questions, but I can't find the correct solution.

The custom fields are visible in the admin order edit page but they don't display the values and are not added to order emails.

What am I missing?

Please see screenshot at the end.

Here is all the code a put together:

// Woocommerce - Add user custom billing fields
// =============================================================================

function add_woocommerce_admin_billing_fields($billing_fields) {
    $billing_fields['billing_birthday'] = array(
        'label' => __('Datum rojstva', 'woocommerce')
    );
    $billing_fields['billing_socialno'] = array(
        'label' => __('Davčna številka', 'woocommerce')
    );

    return $billing_fields;
}
add_filter('woocommerce_admin_billing_fields', 'add_woocommerce_admin_billing_fields');

function add_woocommerce_found_customer_details($customer_data, $user_id, $type_to_load) {
    if ($type_to_load == 'billing') {
        $customer_data[$type_to_load . 'billing_birthday'] = get_user_meta($user_id, $type_to_load . 'billing_birthday', true);
        $customer_data[$type_to_load . 'billing_socialno'] = get_user_meta($user_id, $type_to_load . 'billing_socialno', true);

    }
    return $customer_data;
}
add_filter('woocommerce_found_customer_details', 'add_woocommerce_found_customer_details', 10, 3);

function add_woocommerce_billing_fields($billing_fields) {
    $billing_fields['billing_birthday'] = array(
        'type' => 'tel',
        'label' => __('Datum rojstva'),
        'value' => get_post_meta( $order->id, 'billing_birthday', true ),
        'placeholder' => __('dd/mm/yyyy', 'placeholder'),
        'pattern' => __('\d{1,2}/\d{1,2}/\d{4}', 'pattern' ),
        'class' => array('form-row-first'),
        'required' => true,
        'clear' => true

    );
    $billing_fields['billing_socialno'] = array(
        'type' => 'tel',
        'label' => __('Davčna številka'),
        'value' => get_post_meta( $order->id, 'billing_socialno', true ),
        'placeholder' => _x('8-mestna številka', 'placeholder'),
        'class' => array('form-row-last'),
        'required' => false,
        'clear' => true
    );

    return $billing_fields;
}
add_filter('woocommerce_billing_fields', 'add_woocommerce_billing_fields');

//Doda user meta v backend profil
function add_woocommerce_customer_meta_fields($billing_fields) {
    if (isset($billing_fields['billing']['fields'])) {
        $billing_fields['billing']['fields']['billing_birthday'] = array(
            'label' => __('Datum rojstva', 'woocommerce'),
            'description' => 'Pa kaj bo končno ratalo memo milo?'
        );
        $billing_fields['billing']['fields']['billing_socialno'] = array(
            'label' => __('Davčna številka', 'woocommerce'),
            'description' => ''
        );

    }
    return $billing_fields;
}
add_filter('woocommerce_customer_meta_fields', 'add_woocommerce_customer_meta_fields');

function add_woocommerce_order_fields($address, $order) {
    $address['billing_birthday'] = $order->billing_birthday . get_post_meta($order->id, '_billing_birthday', true) ;
    $address['billing_socialno'] = $order->billing_socialno;
    return $address;
}
add_filter('woocommerce_order_formatted_billing_address', 'add_woocommerce_order_fields', 10, 2);

function add_woocommerce_formatted_address_replacements($replace, $args) {
    $replace['{billing_birthday}'] = !empty($args['billing_birthday']) ? 'Datum rojstva' . $args['billing_birthday'] : '';
    $replace['{billing_socialno}'] = !empty($args['billing_socialno']) ? 'Davčna številka' . $args['billing_socialno'] : '';
    return $replace;
}
add_filter('woocommerce_formatted_address_replacements', 'add_woocommerce_formatted_address_replacements', 10, 2);

function add_woocommerce_localisation_address_formats($formats) {
    $formats['default'] = $formats['default'] . "\n{billing_birthday}\n{billing_socialno}";
    return $formats;
}
add_filter('woocommerce_localisation_address_formats', 'add_woocommerce_localisation_address_formats', 10, 1);

// Change field type to tel woocommerce checkout

function bbloomer_change_checkout_field_input_type() {
echo "<script>document.getElementById('billing_postcode').type = 'tel';</script>";
echo "<script>document.getElementById('billing_birthday').type = 'tel';</script>";

}

add_action( 'woocommerce_after_checkout_form', 'bbloomer_change_checkout_field_input_type'); 

screenshot of order edit page

enter image description here

2

2 Answers

4
votes

I have tested your code and there is just some little errors. You are very near to make it work as you expect. so you should need some changes in the following code:

1) Removed the 'values' as this hooked function works for checkout and dont need values (and still less when you are trying to get them from a non existing order).

This will avoid hidden errors and will display the correct values when customer has already filled the fields in a previous purshase…

// Add custom Checkout billing fields
add_filter('woocommerce_billing_fields', 'add_woocommerce_billing_fields', 20, 1);
function add_woocommerce_billing_fields( $billing_fields ) {

    $billing_fields['billing_birthday'] = array(
        'type' => 'tel',
        'label' => __('Datum rojstva'),
        'placeholder' => __('dd/mm/yyyy', 'placeholder'),
        'pattern' => __('\d{1,2}/\d{1,2}/\d{4}', 'pattern' ),
        'class' => array('form-row-first'),
        'required' => true,
        'clear' => true
    );

    $billing_fields['billing_socialno'] = array(
        'type' => 'tel',
        'label' => __('Davčna številka'),
        'placeholder' => _x('8-mestna številka', 'placeholder'),
        'class' => array('form-row-last'),
        'required' => false,
        'clear' => true
    );

    return $billing_fields;
}

// Change field type to tel for woocommerce checkout
add_action( 'woocommerce_after_checkout_form', 'change_checkout_field_input_type');
function change_checkout_field_input_type() {
    echo "<script>document.getElementById('billing_postcode').type = 'tel';</script>";
    echo "<script>document.getElementById('billing_birthday').type = 'tel';</script>";
}

2) The keys where wrong here, so that's why the fields values doesn't get displayed in Admin order edit pages.

It was 'birthday' and 'socialno' instead of 'billing_birthday' and 'billing_socialno'.

// Setting custom fields Keys/Labels pairs in admin edit order pages and allow edit this fields correctly.
add_filter('woocommerce_admin_billing_fields', 'add_woocommerce_admin_billing_fields');
function add_woocommerce_admin_billing_fields($billing_fields) {
    $billing_fields['birthday'] = array( 'label' => __('Datum rojstva', 'woocommerce') );
    $billing_fields['socialno'] = array( 'label' => __('Davčna številka', 'woocommerce') );

    return $billing_fields;
}

3) Get correctly the missing field values to be displayed in Order edit pages.

// Get the field values to be displayed in admin Order edit pages
add_filter('woocommerce_order_formatted_billing_address', 'add_woocommerce_order_fields', 10, 2);
function add_woocommerce_order_fields($address, $order ) {
    $address['billing_birthday'] = get_post_meta( $order->get_id(), '_billing_birthday', true );
    $address['billing_socialno'] = get_post_meta( $order->get_id(), '_billing_socialno', true );
    return $address;
}

4) Other Unchanged hooked functions:

//Doda user meta v backend profil
add_filter('woocommerce_customer_meta_fields', 'add_woocommerce_customer_meta_fields');
function add_woocommerce_customer_meta_fields($fields) {
    if (isset($fields['billing']['fields'])) {
        $fields['billing']['billing_birthday'] = array(
            'label' => __('Datum rojstva', 'woocommerce'),
            'description' => 'Pa kaj bo končno ratalo memo milo?'
        );
        $fields['billing']['billing_socialno'] = array(
            'label' => __('Davčna številka', 'woocommerce'),
            'description' => ''
        );
    }
    return $fields;
}

add_filter( 'woocommerce_found_customer_details', 'add_woocommerce_found_customer_details', 10, 3);
function add_woocommerce_found_customer_details($customer_data, $user_id, $type_to_load) {
    if ($type_to_load == 'billing') {
        $customer_data[$type_to_load . 'billing_birthday'] = get_user_meta($user_id, $type_to_load . 'billing_birthday', true);
        $customer_data[$type_to_load . 'billing_socialno'] = get_user_meta($user_id, $type_to_load . 'billing_socialno', true);

    }
    return $customer_data;
}

//add_filter('woocommerce_formatted_address_replacements', 'add_woocommerce_formatted_address_replacements', 10, 2);
function add_woocommerce_formatted_address_replacements($replace, $args) {
    $replace['{billing_birthday}'] = !empty($args['billing_birthday']) ? 'Datum rojstva' . $args['billing_birthday'] : '';
    $replace['{billing_socialno}'] = !empty($args['billing_socialno']) ? 'Davčna številka' . $args['billing_socialno'] : '';
    return $replace;
}

add_filter('woocommerce_localisation_address_formats', 'add_woocommerce_localisation_address_formats', 10, 1);
function add_woocommerce_localisation_address_formats($formats) {
    $formats['default'] = $formats['default'] . "\n{billing_birthday}\n{billing_socialno}";
    return $formats;
}

Code goes in function.php file of the active child theme (or active theme).


Email notifications - Display the custom fields (with their labels).

Overriding Woocommerce template emails/email-addresses.php via your active child theme:

This template can be overridden by copying from:
plugin/woocommerce/templates/emails/email-addresses.php
To yourtheme/woocommerce/emails/email-addresses.php
Official documentation: Template structure & Overriding templates via a theme

You will insert after line 34 (just after the billing phone) the following:

<?php
    // Billing birthday
    $billing_birthday = get_post_meta($order->get_id(), '_billing_birthday', true );
    echo $billing_birthday ? '<br/>'.__('Datum rojstva', 'woocommerce').': '.$billing_birthday : '';

    // Billing socialno
    $billing_socialno = get_post_meta($order->get_id(), '_billing_socialno', true );
    echo $billing_socialno ? '<br/>'.__('Davčna številka', 'woocommerce').': '.$billing_socialno : '';
?>

Tested and works.

0
votes

If you want to add your custom field, it is not about just adding new billing details, but anyway it is simple enough.

I recommend you to use hook woocommerce_admin_order_data_after_billing_address, so it will be something like this:

add_action( 'woocommerce_admin_order_data_after_billing_address', 'mishafunction' );        
function mishafunction( $order ){        
    $x = get_post_meta( $order->get_order_number(), 'CUSTOM FIELD NAME', true );
    ?>
    <div class="address">
    <p<?php if( !$x ) echo ' class="none_set"' ?>>
        <strong>Datum rojstva:</strong>
        <?php echo ( $x ) ? $x : '' ?>
    </p>
    </div>
    <div class="edit_address"><?php
    woocommerce_wp_text_input( array(
        'id' => 'CUSTOM FIELD NAME',
        'label' => 'Datum rojstva:',
        'value' => $x,
        'wrapper_class' => 'form-field-wide'
    ) );
    ?></div><?php
}

add_action( 'woocommerce_process_shop_order_meta', 'misha_save_it' );

function misha_save_it( $order_id ){
    update_post_meta( $order_id, 'CUSTOM FIELD NAME', wc_clean( $_POST[ 'CUSTOM FIELD NAME' ] ) );
}

You can also check the complete tutorial here.