14

I am trying to reorder the billing fields on the checkout page but everything I tried so far is not working.

Here is the snippet I am currently trying:

add_filter("woocommerce_checkout_fields", "order_fields");

function order_fields($fields) {
  $order = array(
    "billing_first_name", 
    "billing_last_name", 
    "billing_country", 
    "billing_state", 
    "billing_address_1", 
    "billing_address_2", 
    "billing_email", 
    "billing_phone"
  );

  foreach($order as $field) {
    $ordered_fields[$field] = $fields["billing"][$field];
  }

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

Could something be overriding this snippet, because it used to work for me.

Yahya Hussein
  • 8,767
  • 15
  • 58
  • 114

6 Answers6

39

The method you are using no longer works (since the WooCommerce 3.0.4 update - link to github issue here). It's not exactly a bug, but rather a change of spec.

To fix this, you simply need to adjust the priority of each of the fields to fit the order that you want.

add_filter("woocommerce_checkout_fields", "custom_override_checkout_fields", 1);
function custom_override_checkout_fields($fields) {
    $fields['billing']['billing_first_name']['priority'] = 1;
    $fields['billing']['billing_last_name']['priority'] = 2;
    $fields['billing']['billing_company']['priority'] = 3;
    $fields['billing']['billing_country']['priority'] = 4;
    $fields['billing']['billing_state']['priority'] = 5;
    $fields['billing']['billing_address_1']['priority'] = 6;
    $fields['billing']['billing_address_2']['priority'] = 7;
    $fields['billing']['billing_city']['priority'] = 8;
    $fields['billing']['billing_postcode']['priority'] = 9;
    $fields['billing']['billing_email']['priority'] = 10;
    $fields['billing']['billing_phone']['priority'] = 11;
    return $fields;
}

add_filter( 'woocommerce_default_address_fields', 'custom_override_default_locale_fields' );
function custom_override_default_locale_fields( $fields ) {
    $fields['state']['priority'] = 5;
    $fields['address_1']['priority'] = 6;
    $fields['address_2']['priority'] = 7;
    return $fields;
}

Please note that it's not the line in code that adjusts the placement in the order, but the priority assigned to the field. In this case, I changed the ['billing_state'] priority to 5 which is (in this example) after ['billing_country'] and before ['billing_address_1'].


EDIT:

As per the comments, this wasn't working for some reason (it worked on my first test WooCommerce installation, but I managed to get it to fail after changing the store location).

After some digging, I found that the default locale settings get applied on top of the override (not sure how else to explain this, but bear with me).

I managed to get an install running where the above code was not working, and managed to fix it by adding the following code as well:

add_filter( 'woocommerce_default_address_fields', 'custom_override_default_locale_fields' );
function custom_override_default_locale_fields( $fields ) {
    $fields['state']['priority'] = 5;
    $fields['address_1']['priority'] = 6;
    $fields['address_2']['priority'] = 7;
    return $fields;
}

I have added the extra snippet to the first code block to validate the entire block.

Frits
  • 7,341
  • 10
  • 42
  • 60
  • $fields['billing']['billing_first_name']['priority'] = 1; $fields['billing']['billing_last_name']['priority'] = 2; $fields['billing']['billing_country']['priority'] = 3; $fields['billing']['billing_state']['priority'] = 4; $fields['billing']['billing_address_1']['priority'] = 5; $fields['billing']['billing_address_2']['priority'] = 6; $fields['billing']['billing_phone']['priority'] = 7; $fields['billing']['billing_email']['priority'] = 8; --This is displaying fields in the following order, first name, last, country, phone, mail, address1, address2, state – Yahya Hussein Jul 26 '17 at 01:20
  • @YahyaHussein it's possible that there is another function doing the same thing (either in your theme file, or another plugin). My suggestion would be to adjust the priority of the filter to something like `add_filter("woocommerce_checkout_fields", "custom_override_checkout_fields", 999);` so that it runs __after__ any potential duplicate functions. – Frits Jul 26 '17 at 07:40
  • 1
    @YahyaHussein I've finally managed to replicate your problem, and have edited my answer to include an additional snippet to help. Have a look and let me know :) – Frits Jul 26 '17 at 12:36
  • it worked, thank you it would be great if you can add more explanation about the reason and how your answer solves it – Yahya Hussein Jul 26 '17 at 15:26
3

To change woocommerce checkout fields you need to also change field order and required class base on display. you can add below code in functions.php and it work.

add_filter("woocommerce_checkout_fields", "woocommerce_reorder_checkout_fields", 9999);

if ( ! function_exists( 'woocommerce_reorder_checkout_fields' ) ) {
    function woocommerce_reorder_checkout_fields( $fields ) {

        /* To reorder state field you need to add this array. */
        $order = array(
        "billing_first_name", 
        "billing_last_name", 
        "billing_country", 
        "billing_state", 
        "billing_address_1", 
        "billing_address_2", 
        "billing_email", 
        "billing_phone"
        );

        foreach($order as $field) {
        $ordered_fields[$field] = $fields["billing"][$field];
        }

        $fields["billing"] = $ordered_fields;

        /* To change email and phone number you have to add only class no need to add priority. */

        $fields['billing']['billing_email']['class'][0] = 'form-row-first';
        $fields['billing']['billing_phone']['class'][0] = 'form-row-last';

    return $fields;
    }
}

See attached image enter image description here For more info check this link

Mukesh Panchal
  • 1,956
  • 2
  • 18
  • 31
3

The ordering(sorting) works on address-i18n.min.js not in php code.

enter image description here

In my case, I did something wrong on my js code. So, the ordering didn't work well( javascript stop there ).

Please check dev console and js error.

And this is php code which change only priority.

function rpf_edit_default_address_fields($fields) {

  /* ------ reordering ------ */
  $fields['country']['priority'] = 10;
  $fields['first_name']['priority'] = 20;
  $fields['last_name']['priority'] = 30;
  $fields['address_1']['priority'] = 40;
  $fields['address_2']['priority'] = 50;
  $fields['city']['priority'] = 60;
  $fields['state']['priority'] = 70;
  $fields['postcode']['priority'] = 80;

  return $fields;
}
add_filter( 'woocommerce_default_address_fields', 'rpf_edit_default_address_fields', 100, 1 );

Good Luck!

Byeongin Yoon
  • 3,233
  • 6
  • 26
  • 44
3

As @Byeongin correctly mentions in his answer, apart from the backend ordering (that @Frits answer covers) there is also ordering that happens via JavaSrcipt in the front-end when the user selects specific countries from the dropdown menu.

If you also want to stop this front-end reordering from happening, the best solution I've encountered so far would be to hook into the woocommerce_get_country_locale filter and remove the priority overrides that are added there.

Something like the following will do the trick (tested with WooCommerce v3.5.4):

add_filter( 'woocommerce_get_country_locale', function( $locale ) {
    foreach ( $locale as $country_code => $locale_fields ) {
        foreach ( $locale_fields as $field_key => $field_options ) {
            if ( isset( $field_options['priority'] ) ) {
                unset( $field_options['priority'] );
            }

            $locale[ $country_code ][ $field_key ] = $field_options;
        }
    }

    return $locale;
} );

psymeons
  • 31
  • 6
  • You should only do this if your shop ships to a single country only. When the user selects a different country, WooCommerce changes the order of address fields to match the user's expectations in terms of the locale, as addresses are different in each country. The JavaScript (`address-i18n.js` / `country.js`) sorts the fields by their country-specific priority. – sun Jan 09 '20 at 08:51
  • @sun I agree with you — reordering the address fields could raise UX issues in the checkout when you are selling to multiple countries. The solution I posted above should be used only when you're aware of its UX-related fallbacks and you're sure about what you're doing. Thanks for bringing this up. – psymeons Jan 10 '20 at 16:51
  • I've been looking for this for ages, thanks! This is so annoying, why letting me overwrite the order, just to revert it on the frontend? So frustrating... – Xriuk Mar 14 '20 at 15:37
1

For WooCommerce > 4.0 you need to have a priority key, because it's using asort on the array just before printing it.

You can do this:

function order_fields( $fields ) {
    $i = 0;

    $order = array(
        "billing_email",
        "billing_customfield", <- this is your custom field
        "billing_company",
        "billing_cvr",
        "billing_ean",
        "billing_first_name",
        "billing_last_name",
        "billing_address_1",
        "billing_address_2",
        "billing_country",
        "billing_postcode",
        "billing_city",
        "billing_phone"
    );

    foreach ( $order as $field ) {
        $ordered_fields[ $field ] = $fields["billing"][ $field ];
        $ordered_fields[ $field ][ "priority" ] = ++$i;
    }

    $fields["billing"] = $ordered_fields;

    return $fields;

}

add_filter( "woocommerce_checkout_fields", "order_fields" );
Unicco
  • 2,466
  • 1
  • 26
  • 30
0

Change native woocommerce class This method works with me. In fact, woocommerce uses a class : form-row-first (css: float left) end form-row-last: float right. If you change the priority 2 to 1 but ccs class is form-row-last, the field will still be on the right.

add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields',1 );
function custom_override_checkout_fields( $fields ) {
    $fields['billing']['billing_email']['priority'] = 3;
    $fields['billing']['billing_email']['label'] = mb_strtoupper("adresse email");
    $fields['billing']['billing_email']['class'] = array('form-left');
    $fields['billing']['billing_company']['priority'] = 5;
    $fields['billing']['billing_company']['label'] = mb_strtoupper("entreprise");
    $fields['billing']['billing_company']['required'] = false;
    $fields['billing']['billing_company']['class'] = array('form-left');
    $fields['billing']['billing_phone']['priority'] = 6;
    $fields['billing']['billing_phone']['label'] = mb_strtoupper("téléphone");
    $fields['billing']['billing_phone']['required'] = false;
    $fields['billing']['billing_phone']['class'] = array('form-right');
    $fields['billing']['billing_phone']['validate'] = array('phone');
    $fields['shipping']['shipping_company']['priority'] = 3;
    $fields['shipping']['shipping_company']['label'] = mb_strtoupper("entreprise");
    $fields['shipping']['shipping_company']['required'] = false;
    $fields['shipping']['shipping_company']['class'] = array('form-left');

    return $fields;
}

Others fields like first_name, last_name, address_1, address-2, post_code, city, country, state must be placed in this filter

add_filter( 'woocommerce_default_address_fields','custom_override_default_locale_fields');
function custom_override_default_locale_fields( $fields ) {
    $fields['last_name']['priority'] = 1;
    $fields['last_name']['label'] = mb_strtoupper("nom");
    $fields['last_name']['class'] = array('form-left');
    $fields['first_name']['priority'] = 2;
    $fields['first_name']['label'] = mb_strtoupper("prénom");
    $fields['first_name']['class'] = array('form-right');
    $fields['address_1']['priority'] = 110;
    $fields['address_1']['label'] = mb_strtoupper("adresse 1");
    $fields['address_2']['priority'] = 120;
    $fields['address_2']['label'] = mb_strtoupper("adresse 2");
    $fields['postcode']['label'] = mb_strtoupper("code postal");
    $fields['postcode']['priority'] = 130;
    $fields['postcode']['class'] = array('form-left-small');
    $fields['city']['label'] = mb_strtoupper("ville");
    $fields['city']['priority'] = 140;
    $fields['city']['class'] = array('form-right-big');
    $fields['country']['priority'] = 4;
    $fields['country']['label'] = mb_strtoupper("pays");
    $fields['country']['required'] = true;
    $fields['country']['class'] = array('form-right','address-field','update_totals_on_change');
    $fields['state']['priority'] = 120;
    $fields['state']['label'] = mb_strtoupper("téléphone");
    $fields['state']['required'] = true;
    $fields['state']['class'] = array('form-right');
return $fields;
    return $fields;
}

AND CSS

.woocommerce form .form-right,
.woocommerce form .form-left,
.woocommerce form .form-left-small,
.woocommerce form .form-right-big {
    display: inline-block;
}
.woocommerce form .form-right,
.woocommerce form .form-left {
    width: 48%
}
.woocommerce form .form-right,
.woocommerce form .form-big-right {
    margin-left: 2% !important;
}
.woocommerce form .form-left,
.woocommerce form .form-left-small {
    margin-right: 2% !important;
}
.woocommerce form .form-big-right {
    width: 63%;
}
.woocommerce form .form-left-small {
    width: 33%;
}
.woocommerce form .woocommerce-input-wrapper strong {
    height: 38px;
    line-height: 38px;
}

RESULT :

enter image description here

Otis Feru
  • 111
  • 1
  • 4