Steps to swap Woocommerce ‘Billing’ with ‘Shipping’

There was once a client requested to swap the position of Woocommerce’s billing and shipping details, because by default WooCommerce displays the Billing info first. But, the client cares more about the shipping address because that is the most important information he needs for him to ship the products.

Update on 3/8/2019:

I realised the above method wasn’t the best method because there might be complications in your shipping methods and prices so the shipping options might not be accurate when the billing and shipping addresses are different. I am using Flatsome theme for this project so you might see some classes that are not in the original Woocommerce template.

So this is the new solution I’ve found:
1. Before you start modifying the code, make sure your shipping destination (Woocommerce -> Settings -> Shipping -> shipping options) is set to Default to customer shipping address

2. In your form-checkout.php, swap shipping and billing. You may notice that the email and phone fields will be at the bottom and the first field you see now will be the ‘Ship to a different address?’ checkbox.

<?php if ( $checkout->get_checkout_fields() ) : ?>

		<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>

		<div class="col2-set" id="customer_details">
			<div class="col-1">
				<?php do_action( 'woocommerce_checkout_shipping' ); ?>
			</div>

			<div class="col-2">
				<?php do_action( 'woocommerce_checkout_billing' ); ?>
			</div>
		</div>

		<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>

	<?php endif; ?>

3. In your form-shipping.php, copy the #ship-to-different-address section to form-billing.php. In your form-billing.php, add the ‘Bill to a different address’ checkbox under the else statement. Once done, remove the code from form-shipping.php. The rest remain unchanged.

<?php if ( wc_ship_to_billing_address_only() && WC()->cart->needs_shipping() ) : ?>

		<h3><?php esc_html_e( 'Billing &amp; Shipping', 'woocommerce' ); ?></h3>

	<?php else : ?>
		
		<h3 id="ship-to-different-address">
			<label class="woocommerce-form__label woocommerce-form__label-for-checkbox checkbox">
				<input id="ship-to-different-address-checkbox" class="woocommerce-form__input woocommerce-form__input-checkbox input-checkbox" <?php checked( apply_filters( 'woocommerce_ship_to_different_address_checked', 'shipping' === get_option( 'woocommerce_ship_to_destination' ) ? 1 : 0 ), 1 ); ?> type="checkbox" name="ship_to_different_address" value="1" /> <span><?php esc_html_e( 'Bill to a different address?', 'woocommerce' ); ?></span>
			</label>
		</h3>

	<?php endif; ?>

4. Lastly in your <script> add the below code. This is to make sure that when shipping address is change, the changes are reflected to the billing address, so the required fields are not left empty.

jQuery(window).on('load', function() {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') == 'checked') {
jQuery('.woocommerce-billing-fields__field-wrapper').show();
jQuery('.woocommerce-shipping-fields__field-wrapper').show();
jQuery('.woocommerce-shipping-fields').show();
jQuery('.shipping_address').show();
} else {
jQuery('.woocommerce-billing-fields__field-wrapper').hide();
jQuery('.woocommerce-shipping-fields__field-wrapper').show();
jQuery('.woocommerce-shipping-fields').show();
jQuery('.shipping_address').show();
}
}); jQuery('input#ship-to-different-address-checkbox').on('change', function (e) {
e.preventDefault();
if (jQuery(this).attr('checked') == 'checked') {
jQuery('.woocommerce-billing-fields__field-wrapper').show();
jQuery('.woocommerce-shipping-fields__field-wrapper').show();
jQuery('.woocommerce-shipping-fields').show();
jQuery('.shipping_address').show();
} else {
jQuery('.woocommerce-billing-fields__field-wrapper').hide();
jQuery('.woocommerce-shipping-fields__field-wrapper').show();
jQuery('.woocommerce-shipping-fields').show();
jQuery('.shipping_address').show();
// copy all existing fields
jQuery('input#billing_first_name').val(jQuery('.shipping_address input#shipping_first_name').val()).change();
jQuery('input#billing_last_name').val(jQuery('.shipping_address input#shipping_last_name').val()).change();
jQuery('input#billing_company').val(jQuery('input#shipping_company').val()).change();
jQuery('input#billing_address_1').val(jQuery('input#shipping_address_1').val()).change();
jQuery('input#billing_address_2').val(jQuery('input#shipping_address_2').val()).change();
jQuery('input#billing_city').val(jQuery('.shipping_address input#shipping_city').val()).change();
jQuery('select#billing_state').val(jQuery('.shipping_address select#shipping_state').val()).change();
jQuery('input#billing_postcode').val(jQuery('.shipping_address input#shipping_postcode').val()).change();
jQuery('select#billing_country').val(jQuery('.shipping_address select#shipping_country').val()).change();
}
}); jQuery('.shipping_address input#shipping_first_name').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_first_name').val();
jQuery('input#billing_first_name').val(shipping_val).change();
}
});

jQuery('.shipping_address input#shipping_last_name').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_last_name').val();
jQuery('input#billing_last_name').val(shipping_val).change();
}
});

jQuery('.shipping_address input#shipping_company').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_company').val();
jQuery('input#billing_company').val(shipping_val).change();
}
});

jQuery('.shipping_address input#shipping_address_1').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_address_1').val();
jQuery('input#billing_address_1').val(shipping_val).change();
}
}); jQuery('.shipping_address input#shipping_address_2').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_address_2').val();
jQuery('input#billing_address_2').val(shipping_val).change();
}
}); jQuery('.shipping_address input#shipping_city').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_city').val();
jQuery('input#billing_city').val(shipping_val).change();
}
});

jQuery('.shipping_address select#shipping_state').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address select#shipping_state').val();
jQuery('select#billing_state').val(shipping_val).change();
}
});

jQuery('.shipping_address input#shipping_postcode').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address input#shipping_postcode').val();
jQuery('input#billing_postcode').val(shipping_val).change();
}
}); jQuery('.shipping_address select#shipping_country').on('change', function (e) {
if (jQuery('input#ship-to-different-address-checkbox').attr('checked') != 'checked') {
// same billing address
var shipping_val = jQuery('.shipping_address select#shipping_country').val();
jQuery('select#billing_country').val(shipping_val).change();
}
});

5. Now, you have everything swapped but the only thing is the user will not know that they have to fill up the Email and Phone fields if they dont click ‘Bill to a different address’. To make things easier, I have downloaded the Checkout Field Editor (Checkout Manager) for WooCommerce plugin by ThemeHiGH. By using this plugin, I can easily add/remove my checkout fields. I have removed billing_email and billing_phone and add them back at shipping_email and shipping_phone.

If you are not comfortable with using plugins, you can explore the “woocommerce_checkout_fields” filter.

6. Remember to check your Checkout function and see if you missed anything. If possible, you can also do a test transaction to check the backend.

* This method is tested with Woocommerce 3.6.5. Might not be compatible with future versions

8 thoughts on “Steps to swap Woocommerce ‘Billing’ with ‘Shipping’

  1. Donte says:

    What happens with the billing address doesnt match the card they are trying to pay with becuause it’s reading the shipping address?

    • kbxian says:

      Hey Donte, that’s a good question! I have not had any problems before but I don’t believe your address needs to match? I have been using Paypal and Stripe and haven’t had any problems.

    • kbxian says:

      Hi Alijafar, this code was probably using version 3.2 (I can’t recall the exact version number). There is a major update in 3.3. They are using a different method now and I haven’t had the time to manage the blog. Also sorry this was supposed to be in woocommerce/emails/email-addresses.php instead of function.php. The correct code is below (Please temporarily disable your Javascript to copy the code):

      <table id="addresses" cellspacing="0" cellpadding="0" style="width: 100%; vertical-align: top;" border="0">
      <tr>
      <?php if ( ! wc_ship_to_billing_address_only() && $order->needs_shipping_address() && ( $shipping = $order->get_formatted_shipping_address() ) ) : ?>
      <td class="td" style="text-align:<?php echo $text_align; ?>; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;" valign="top" width="50%">
      <h3><?php _e( 'Billing address', 'woocommerce' ); ?></h3>

      <p class="text">
      <!-- --><?php //echo $shipping; ?>
      <?php echo get_post_meta($order->ID,'_shipping_first_name', true).' '.get_post_meta($order->ID,'_shipping_last_name', true); ?><br/>
      <?php echo get_post_meta($order->ID,'_shipping_address_1', true); ?><br/>
      <?php echo get_post_meta($order->ID,'_shipping_address_2', true); ?><br/>
      <?php echo get_post_meta($order->ID,'_shipping_city', true).'<br/>';
      $state = get_post_meta($order->ID,'_shipping_state', true);
      if (get_post_meta($order->ID,'_shipping_country', true) == 'AU') {
      $state = str_replace('Victoria', 'VIC', $state);
      $state = str_replace('Australian Capital Territory', 'ACT', $state);
      $state = str_replace('Western Australia', 'WA', $state);
      $state = str_replace('Tasmania', 'TAS', $state);
      $state = str_replace('New South Wales', 'NSQ', $state);
      $state = str_replace('South Australia', 'SA', $state);
      $state = str_replace('Queensland', 'QLD', $state);
      $state = str_replace('Northern Territory', 'NT', $state);
      }
      echo $state.' '.get_post_meta($order->ID,'_shipping_postcode', true); ?><br/>
      <?php
      // if (get_post_meta($order->ID,'_shipping_country', true) != 'AU') {
      echo get_post_meta($order->ID,'_shipping_country', true);
      // }
      ?>
      </p>
      </td>
      <?php endif; ?>
      <td class="td" style="text-align:<?php echo $text_align; ?>; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;" valign="top" width="50%">
      <h3><?php _e( 'Shipping address', 'woocommerce' ); ?></h3>

      <!-- <p class="text" style="color: #000000;">--><?php //echo $order->get_formatted_billing_address(); ?><!--</p>-->
      <p class="text" style="color: #000000;">
      <?php echo get_post_meta($order->ID,'_billing_first_name', true).' '.get_post_meta($order->ID,'_billing_last_name', true); ?><br/>
      <?php echo get_post_meta($order->ID,'_billing_address_1', true); ?><br/>
      <?php echo get_post_meta($order->ID,'_billing_address_2', true); ?><br/>
      <?php echo get_post_meta($order->ID,'_billing_city', true).'<br/>';
      $state = get_post_meta($order->ID,'_billing_state', true);
      if (get_post_meta($order->ID,'_billing_country', true) == 'AU') {
      $state = str_replace('Victoria', 'VIC', $state);
      $state = str_replace('Australian Capital Territory', 'ACT', $state);
      $state = str_replace('Western Australia', 'WA', $state);
      $state = str_replace('Tasmania', 'TAS', $state);
      $state = str_replace('New South Wales', 'NSQ', $state);
      $state = str_replace('South Australia', 'SA', $state);
      $state = str_replace('Queensland', 'QLD', $state);
      $state = str_replace('Northern Territory', 'NT', $state);
      }
      echo $state.' '.get_post_meta($order->ID,'_billing_postcode', true); ?><br/>
      <?php
      // if (get_post_meta($order->ID,'_billing_country', true) != 'AU') {
      echo get_post_meta($order->ID,'_billing_country', true);
      // }
      ?>



      </p>
      </td>
      </tr>
      </table>
  2. John Boncalos says:

    Thank you for this solution! To skip editing core files for the email i just used the “woocommerce_checkout_update_order_meta” hook to swap the billing and shipping.

    add_action(‘woocommerce_checkout_update_order_meta’, ‘swap_billing_shipping’, 1, 2 );
    function swap_billing_shipping( $order_id, $data ) {

    if ( ! $order_id )
    return;
    $id = $order_id;
    $t_billing_first_name = get_post_meta($id, ‘_shipping_first_name’, true);
    $t_billing_last_name = get_post_meta($id, ‘_shipping_last_name’, true);
    $t_billing_company = get_post_meta($id, ‘_shipping_company’, true);
    $t_billing_address_1 = get_post_meta($id, ‘_shipping_address_1’, true);
    $t_billing_address_2 = get_post_meta($id, ‘_shipping_address_2’, true);
    $t_billing_city = get_post_meta($id, ‘_shipping_city’, true);
    $t_billing_state = get_post_meta($id, ‘_shipping_state’, true);
    $t_billing_postcode = get_post_meta($id, ‘_shipping_postcode’, true);
    $t_billing_country = get_post_meta($id, ‘_shipping_country’, true);

    $t_shipping_first_name = get_post_meta($id, ‘_billing_first_name’, true);
    $t_shipping_last_name = get_post_meta($id, ‘_billing_last_name’, true);
    $t_shipping_company = get_post_meta($id, ‘_billing_company’, true);
    $t_shipping_address_1 = get_post_meta($id, ‘_billing_address_1’, true);
    $t_shipping_address_2 = get_post_meta($id, ‘_billing_address_2’, true);
    $t_shipping_city = get_post_meta($id, ‘_billing_city’, true);
    $t_shipping_state = get_post_meta($id, ‘_billing_state’, true);
    $t_shipping_postcode = get_post_meta($id, ‘_billing_postcode’, true);
    $t_shipping_country = get_post_meta($id, ‘_billing_country’, true);

    update_post_meta($id, ‘_billing_first_name’, $t_billing_first_name);
    update_post_meta($id, ‘_billing_last_name’, $t_billing_last_name);
    update_post_meta($id, ‘_billing_company’, $t_billing_company);
    update_post_meta($id, ‘_billing_address_1’, $t_billing_address_1);
    update_post_meta($id, ‘_billing_address_2’, $t_billing_address_2);
    update_post_meta($id, ‘_billing_city’, $t_billing_city);
    update_post_meta($id, ‘_billing_state’, $t_billing_state);
    update_post_meta($id, ‘_billing_postcode’, $t_billing_postcode);
    update_post_meta($id, ‘_billing_country’, $t_billing_country);

    update_post_meta($id, ‘_shipping_first_name’, $t_shipping_first_name);
    update_post_meta($id, ‘_shipping_last_name’, $t_shipping_last_name);
    update_post_meta($id, ‘_shipping_company’, $t_shipping_company);
    update_post_meta($id, ‘_shipping_address_1’, $t_shipping_address_1);
    update_post_meta($id, ‘_shipping_address_2’, $t_shipping_address_2);
    update_post_meta($id, ‘_shipping_city’, $t_shipping_city);
    update_post_meta($id, ‘_shipping_state’, $t_shipping_state);
    update_post_meta($id, ‘_shipping_postcode’, $t_shipping_postcode);
    update_post_meta($id, ‘_shipping_country’, $t_shipping_country);

    }

    • kbxian says:

      Hi John, thanks for the solution! Will try it out next time 🙂 How does your solution react to online shops with different shipping options though?

  3. Vijay lathiya says:

    By this way way got issue in following case.
    In case of different Shipping methods & Rate based on Shipping address than on Entering Billing detail Shipping method with rate also getting change.
    any solutions for this ?

Leave a Reply

Your email address will not be published. Required fields are marked *