1

I'm using a custom WooCommerce checkout.js file for a plugin I'm creating but I'm having an issue whereby the billing address is getting saved as the shipping address when the order is placed.

Here is the custom 'checkout.js' code:

/* global wc_checkout_params */

jQuery( function( $ ) {

  // wc_checkout_params is required to continue, ensure the object exists

  if ( typeof wc_checkout_params === 'undefined' ) {

    return false;

  }

  console.log('Start');


  $.blockUI.defaults.overlayCSS.cursor = 'default';



  var wc_checkout_form = {

    updateTimer: false,

    dirtyInput: false,

    xhr: false,

    $order_review: $( '#order_review' ),

    $checkout_form: $( 'form.checkout' ),

    init: function() {

      console.log('Init');

      $( document.body ).bind( 'updated_checkout', this.updated_checkout );

      $( document.body ).bind( 'update_checkout', this.update_checkout );

      $( document.body ).bind( 'init_checkout', this.init_checkout );

      $( document.body ).bind( 'country_to_state_changed', this.upgrade_state_fields );

      $( document.body ).on( 'change', 'select.country_to_state, input.country_to_state', this.upgrade_state_fields );

      $( '.back-to-checkout' ).bind( 'click', this.close_drawer );



      // Payment methods

      this.$checkout_form.on( 'click', 'input[name="payment_method"]', this.payment_method_selected );



      if ( $( document.body ).hasClass( 'woocommerce-order-pay' ) ) {

        this.$order_review.on( 'click', 'input[name="payment_method"]', this.payment_method_selected );

      }

      $( 'button.details-next-button' ).bind( 'click', this.prevent_checkout );

      // Form submission

      $( document.body ).on( 'click', '#place_order', this.submit );

      this.$checkout_form.on( 'submit', this.submit );

      // Inline validation

      this.$checkout_form.on( 'blur change', '.input-text, select, input:checkbox', this.validate_field );



      // Manual trigger

      this.$checkout_form.on( 'update', this.trigger_update_checkout );



      // Inputs/selects which update totals

      this.$checkout_form.on( 'change', 'select.shipping_method, input[name^="shipping_method"], #ship-to-different-address input, .update_totals_on_change select, .update_totals_on_change input[type="radio"]', this.trigger_update_checkout );

      this.$checkout_form.on( 'change', '.address-field select', this.input_changed );

      this.$checkout_form.on( 'change', '.address-field input.input-text, .update_totals_on_change input.input-text', this.maybe_input_changed );

      this.$checkout_form.on( 'change keydown', '.address-field input.input-text, .update_totals_on_change input.input-text', this.queue_update_checkout );



      // Address fields

      this.$checkout_form.on( 'change', '#ship-to-different-address input.mdl-switch__input', this.ship_to_different_address );

      this.$checkout_form.on( 'change', '#order_notes input.mdl-switch__input', this.order_notes );



      // Trigger events

      this.$checkout_form.find( '#ship-to-different-address input' ).change();

      this.init_payment_methods();



      // Update on page load

      if ( wc_checkout_params.is_checkout === '1' ) {

        $( document.body ).trigger( 'init_checkout' );

      }

      if ( wc_checkout_params.option_guest_checkout === 'yes' ) {



        $( 'input#createaccount' ).change( this.toggle_create_account ).change();

      } else {

        $( 'div.create-account' ).show();

      }





jQuery('.woocommerce-message').remove();





    },

    init_payment_methods: function( selectedPaymentMethod ) {

      console.log('Init payment_methods');

      var $payment_methods = $( '.woocommerce-checkout' ).find( 'input[name="payment_method"]' );



      // If there is one method, we can hide the radio input

      if ( 1 === $payment_methods.length ) {

        $payment_methods.eq(0).hide();

      }



      // If there was a previously selected method, check that one.

      if ( selectedPaymentMethod ) {

        $( '#' + selectedPaymentMethod ).prop( 'checked', true );

      }



      // If there are none selected, select the first.

      if ( 0 === $payment_methods.filter( ':checked' ).length ) {

        $payment_methods.eq(0).prop( 'checked', true );

      }



      // Trigger click event for selected method

      $payment_methods.filter( ':checked' ).eq(0).trigger( 'click' );

      wc_checkout_form.convert_payment_textinputs();

    },

    close_drawer: function() {

      console.log('close_drawer');

      jQuery('.mdl-layout__obfuscator.is-visible').click();

    },

    updated_checkout: function() {

      console.log('updated_checkout');

        jQuery('.mdl-layout__drawer .shipping input[type=radio]').each(function() {

          var name = $(this).attr('name');

          var id = $(this).attr('id');

          $(this).attr('name','review_' + name);

          $(this).attr('id','review_' + id);

        });



        componentHandler.upgradeDom();

        window.setTimeout(function() {

          jQuery('.mdl-textfield').each(function() {

            if (!jQuery(this).is('.validate-required')) {



              jQuery(this).removeClass('is-invalid');

            }

            if (jQuery(this).find('.mdl-textfield__input').val() != '') {

              jQuery(this).addClass('is-dirty');

            }

          });

        },10);

      if (jQuery('.woocommerce-error').length > 0) {

        var message ='';

        jQuery('.woocommerce-error').find('li').each(function() {

          message+= jQuery(this).text();

        });

        jQuery('.woocommerce-error').remove();

        var snackbarContainer = document.querySelector('#error-snackbar');

        var data = {

          message: message,

          timeout: 5000

        };

        snackbarContainer.MaterialSnackbar.showSnackbar(data);



      }





      jQuery('.woocommerce-message').remove();



    },



    convert_payment_textinputs: function() {

      console.log('convert_payment_textinputs');

      jQuery('.payment_box').find('input[type=text],input[type=tel],input[type=email],input[type=date],input[type=password]').each(function() {

        if (jQuery(this).parent().is('[data-upgraded]') || jQuery(this).parent().find('input[type=text],input[type=tel],input[type=email],input[type=date],input[type=password]').length > 1) {

          return;

        }



        jQuery(this).parent().addClass('mdl-textfield mdl-js-textfield mdl-textfield--floating-label');



        jQuery(this).addClass('mdl-textfield__input');



        jQuery(this).parent().find('label').addClass('mdl-textfield__label');



        componentHandler.upgradeElement(jQuery(this).parent()[0]);

      });

    },











    upgrade_state_fields: function() {

      console.log('upgrade_state_fields');

        $('#billing_state,#shipping_state').addClass('mdl-textfield__input');

      $('#billing_state,#shipping_state,#billing_country, #shipping_country').each(function() {

        jQuery(this).parent().removeAttr('data-upgraded');

        jQuery(this).find('option[value=""]').text('');

        componentHandler.upgradeElement(jQuery(this).parent()[0]);

      });

      window.setTimeout(function() {

      jQuery('.mdl-textfield').each(function() { jQuery(this).find('.mdl-textfield__input').each(function() {

        if (jQuery(this).val() && jQuery(this).val() != '') {

          jQuery(this).parent().addClass('is-dirty');

        } else {

          jQuery(this).parent().removeClass('is-dirty');

        }

        if (jQuery(this).attr('placeholder') && jQuery(this).attr('placeholder') != '') {

          jQuery(this).parent().addClass('has-placeholder');

        } else {

          jQuery(this).parent().removeClass('has-placeholder');

        }

      }); });

      },100);





    },

    get_payment_method: function() {

      console.log('get_payment_method');

      return wc_checkout_form.$checkout_form.find( 'input[name="payment_method"]:checked' ).val();

    },

    payment_method_selected: function() {

      console.log('payment_method_selected');

      if ( $( '.payment_methods input.input-radio' ).length > 1 ) {

        var target_payment_box = $( 'div.payment_box.' + $( this ).attr( 'ID' ) );



        if ( $( this ).is( ':checked' ) && ! target_payment_box.is( ':visible' ) ) {

          $( 'div.payment_box' ).filter( ':visible' ).slideUp( 250 );



          if ( $( this ).is( ':checked' ) ) {

            $( 'div.payment_box.' + $( this ).attr( 'ID' ) ).slideDown( 250 );

          }

        }

      } else {

        $( 'div.payment_box' ).show();

      }



      if ( $( this ).data( 'order_button_text' ) ) {

        $( '#place_order' ).val( $( this ).data( 'order_button_text' ) );

      } else {

        $( '#place_order' ).val( $( '#place_order' ).data( 'value' ) );

      }

    },

    toggle_create_account: function() {

      console.log('toggle_create_account');

      $( 'div.create-account' ).hide();



      if ( $( this ).is( ':checked' ) ) {

        $( 'div.create-account' ).slideDown();

      }

    },

    init_checkout: function() {

      console.log('init_checkout');

      $( '#billing_country, #shipping_country, .country_to_state' ).change();

      $( document.body ).trigger( 'update_checkout' );

    },

    maybe_input_changed: function( e ) {

      console.log('maybe_input_changed');

      if ( wc_checkout_form.dirtyInput ) {

        wc_checkout_form.input_changed( e );

      }

    },

    input_changed: function( e ) {


      console.log('input_changed');
      wc_checkout_form.dirtyInput = e.target;

      wc_checkout_form.maybe_update_checkout();

    },

    queue_update_checkout: function( e ) {

    console.log('queue_update_checkout');

      var code = e.keyCode || e.which || 0;



      if ( code === 9 ) {

        return true;

      }



      wc_checkout_form.dirtyInput = this;

      wc_checkout_form.reset_update_checkout_timer();

      wc_checkout_form.updateTimer = setTimeout( wc_checkout_form.maybe_update_checkout, '1000' );

    },

    trigger_update_checkout: function() {

      console.log('trigger_update_checkout');

      wc_checkout_form.reset_update_checkout_timer();

      wc_checkout_form.dirtyInput = false;

      $( document.body ).trigger( 'update_checkout' );

    },

    maybe_update_checkout: function() {

      console.log('maybe_update_checkout');

      var update_totals = true;



      if ( $( wc_checkout_form.dirtyInput ).length ) {

        var $required_inputs = $( wc_checkout_form.dirtyInput ).closest( 'div' ).find( '.address-field.validate-required' );



        if ( $required_inputs.length ) {

          $required_inputs.each( function() {

            if ( $( this ).find( 'input.input-text' ).val() === '' ) {

              update_totals = false;

            }

          });

        }

      }

      if ( update_totals ) {

        wc_checkout_form.trigger_update_checkout();

      }

    },

    ship_to_different_address: function() {

      console.log('ship_to_different_address');

      if ( $( this ).is( ':checked' ) ) {

        $( '#shipping_address_section' ).slideDown();

      } else {

        $( '#shipping_address_section' ).slideUp();

      }

    },

    order_notes: function() {


      console.log('order_notes');


      if ( $( this ).is( ':checked' ) ) {

        $( '#order_notes_section' ).slideDown();

      } else {

        $( '#order_notes_section' ).slideUp();

      }

    },

    reset_update_checkout_timer: function() {

      console.log('reset_update_checkout_timer');

      clearTimeout( wc_checkout_form.updateTimer );

    },

    validate_field: function() {

      console.log('validate_field');

      var $this     = $( this ),

        $parent   = $this.closest( '.form-row' ),

        validated = true;



      if ( $parent.is( '.validate-required' ) ) {

        if ( 'checklox' === $this.attr( 'type' ) && ! $this.is( ':checked' ) ) {

          $parent.removeClass( 'woocommerce-validated' ).addClass( 'woocommerce-invalid woocommerce-invalid-required-field' );

          validated = false;

        } else if ( $this.val() === '' ) {

          $parent.removeClass( 'woocommerce-validated' ).addClass( 'woocommerce-invalid woocommerce-invalid-required-field' );

          validated = false;

        }

      }



      if ( $parent.is( '.validate-email' ) ) {

        if ( $this.val() ) {



          /* https://stackoverflow.com/questions/2855865/jquery-validate-e-mail-address-regex */

          var pattern = new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);



          if ( ! pattern.test( $this.val()  ) ) {

            $parent.removeClass( 'woocommerce-validated' ).addClass( 'woocommerce-invalid woocommerce-invalid-email' );

            validated = false;

          }

        }

      }



      if ( validated ) {

        $parent.removeClass( 'woocommerce-invalid woocommerce-invalid-required-field' ).addClass( 'woocommerce-validated' );

      }

    },

    update_checkout: function( event, args ) {

      console.log('update_checkout');

      // Small timeout to prevent multiple requests when several fields update at the same time

      wc_checkout_form.reset_update_checkout_timer();

      wc_checkout_form.updateTimer = setTimeout( wc_checkout_form.update_checkout_action, '5', args );

    },

    update_checkout_action: function( args ) {

      console.log('update_checkout_action');

      if ( wc_checkout_form.xhr ) {

        wc_checkout_form.xhr.abort();

      }



      if ( $( 'form.checkout' ).length === 0 ) {

        return;

      }



      args = typeof args !== 'undefined' ? args : {

        update_shipping_method: true

      };



      var country            = $( '#billing_country' ).val(),

        state            = $( '#billing_state' ).val(),

        postcode         = $( 'input#billing_postcode' ).val(),

        city             = $( '#billing_city' ).val(),

        address          = $( 'input#billing_address_1' ).val(),

        address_2        = $( 'input#billing_address_2' ).val(),

        s_country        = country,

        s_state          = state,

        s_postcode       = postcode,

        s_city           = city,

        s_address        = address,

        s_address_2      = address_2;

        has_full_address = true;


      if ( $( '#ship-to-different-address' ).find( 'input' ).is( ':checked' ) ) {

        s_country        = $( '#shipping_country' ).val();

        s_state          = $( '#shipping_state' ).val();

        s_postcode       = $( 'input#shipping_postcode' ).val();

        s_city           = $( '#shipping_city' ).val();

        s_address        = $( 'input#shipping_address_1' ).val();

        s_address_2      = $( 'input#shipping_address_2' ).val();

      }



      var data = {

        security:                   wc_checkout_params.update_order_review_nonce,

        payment_method:             wc_checkout_form.get_payment_method(),

        country:                    country,

        state:                      state,

        postcode:                   postcode,

        city:                       city,

        address:                    address,

        address_2:                  address_2,

        s_country:                  s_country,

        s_state:                    s_state,

        s_postcode:                 s_postcode,

        s_city:                     s_city,

        s_address:                  s_address,

        s_address_2:                s_address_2,

        has_full_address: has_full_address,

        post_data:                  $( 'form.checkout' ).serialize()

      };

      console.log(data);



      if ( false !== args.update_shipping_method ) {

        var shipping_methods = {};



        $( 'select.shipping_method, input[name^="shipping_method"][type="radio"]:checked, input[name^="shipping_method"][type="hidden"]' ).each( function() {

          shipping_methods[ $( this ).data( 'index' ) ] = $( this ).val();

        } );



        data.shipping_method = shipping_methods;

      }



      $( '.woocommerce-checkout-payment, .woocommerce-checkout-review-order-table' ).block({

        message: null,

        overlayCSS: {

          background: '#fff',

          opacity: 0.6

        }

      });



      wc_checkout_form.xhr = $.ajax({

        type:       'POST',

        url:        wc_checkout_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'update_order_review' ),

        data:       data,

        success:    function( data ) {



          var selectedPaymentMethod = $( '.woocommerce-checkout input[name="payment_method"]:checked' ).attr( 'id' );



          // Reload the page if requested

          if ( 'true' === data.reload ) {

            window.location.reload();

            return;

          }



          // Remove any notices added previously

          $( '.woocommerce-NoticeGroup-updateOrderReview' ).remove();



          var termsCheckBoxChecked = $( '#terms' ).prop( 'checked' );

          window.fragmentss = data.fragments;

          // Always update the fragments

          if ( data && data.fragments ) {

            $.each( data.fragments, function ( key, value ) {

              $( key ).replaceWith( value );

              $( key ).unblock();

            } );

          }



          // Recheck the terms and conditions box, if needed

          if ( termsCheckBoxChecked ) {

            $( '#terms' ).prop( 'checked', true );

          }



          // Check for error

          if ( 'failure' === data.result ) {



            var $form = $( 'form.checkout' );



            // Remove notices from all sources

            $( '.woocommerce-error, .woocommerce-message' ).remove();



            // Add new errors returned by this event

            if ( data.messages ) {

              $form.prepend( '<div class="woocommerce-NoticeGroup-updateOrderReview">' + data.messages + '</div>' );

            } else {

              $form.prepend( data );

            }



            // Lose focus for all fields

            $form.find( '.input-text, select, input:checkbox' ).blur();



            // Scroll to top

            $( 'html, body' ).animate( {

              scrollTop: ( $( 'form.checkout' ).offset().top - 100 )

            }, 1000 );



          }



          // Re-init methods

          wc_checkout_form.init_payment_methods( selectedPaymentMethod );



          // Fire updated_checkout e

          $( document.body ).trigger( 'updated_checkout', [ data ] );

        }



      });

    },

    prevent_checkout: function(e) {

      console.log('prevent_checkout');

      console.log('clickprevent');

      e.preventDefault();

    },

    submit: function(e) {

      console.log('submit');

      e.preventDefault();

      wc_checkout_form.reset_update_checkout_timer();

      var $form = $( wc_checkout_form.$checkout_form );

      console.log('Form:' + $form);

      if ( $form.is( '.processing' ) ) {

        return false;

      }

      $( document )

        .on(

          'stripeError',

          wc_checkout_form.updated_checkout

        )

        .on(

          'checkout_error',

          wc_checkout_form.updated_checkout

        );

      // Trigger a handler to let gateways manipulate the checkout if needed

      if ( $form.triggerHandler( 'checkout_place_order' ) !== false && $form.triggerHandler( 'checkout_place_order_' + wc_checkout_form.get_payment_method() ) !== false ) {



        $form.addClass( 'processing' );



        var form_data = $form.data();

        console.log ('Form Data:' + form_data );

        if ( 1 !== form_data['blockUI.isBlocked'] ) {

          $form.block({

            message: null,

            overlayCSS: {

              background: '#fff',

              opacity: 0.6

            }

          });

        }



        // ajaxSetup is global, but we use it to ensure JSON is valid once returned.

        $.ajaxSetup( {

          dataFilter: function( raw_response, dataType ) {

            // We only want to work with JSON

            if ( 'json' !== dataType ) {

              return raw_response;

            }



            try {

              // Check for valid JSON

              var data = $.parseJSON( raw_response );



              if ( data && 'object' === typeof data ) {



                // Valid - return it so it can be parsed by Ajax handler

                return raw_response;

              }



            } catch ( e ) {



              // Attempt to fix the malformed JSON

              var valid_json = raw_response.match( /{"result.*"}/ );



              if ( null === valid_json ) {

                console.log( 'Unable to fix malformed JSON' );

              } else {

                console.log( 'Fixed malformed JSON. Original:' );

                console.log( raw_response );

                raw_response = valid_json[0];

              }

            }



            return raw_response;

          }

        } );


        console.log($form.serialize());
        alert($form.serialize());

        $.ajax({

          type:     'POST',

          url:      wc_checkout_params.checkout_url,

          data:     $form.serialize(),

          dataType:   'json',

This is the '$form.serialize()' data that is getting sent by the AJAX request:

billing_first_name=Testname&billing_last_name=Testlastname&billing_phone=0800000000&billing_email=test%40wpmad.com&billing_country=GB&billing_address_1=4+Test+Street&billing_address_2=&billing_city=Test+City&billing_state=Worcestershire&billing_postcode=DY11+1JR&shipping_first_name=Testname&shipping_last_name=Testlastname&shipping_company=&shipping_country=GB&shipping_address_1=99+Test+Street&shipping_address_2=&shipping_city=Worcester&shipping_state=Worcestershire&shipping_postcode=WR1+2DS&order_comments=&shipping_method%5B0%5D=free_shipping%3A1&terms=on&terms-field=1&_wpnonce=34d56c864b&_wp_http_referer=%2F%3Fwc-ajax%3Dupdate_order_review

As above, the order is placed, but the shipping address is replaced with the billing address on the order confirmation page and within the WooCommerce orders in the admin.

Any ideas why? Any help would be greatly appreciated!

Mat
  • 958
  • 8
  • 18

1 Answers1

1

Problem solved.

The issue was being caused as the checkbox in the WooCommerce checkout had been changed to a Google Material design checkbox/switch and was not setting the value of the checkbox to '1'.

Effectively, the $form.serialize() data didn't contain the ship_to_different_address=1 that is required in the WooCommerce AJAX request.

Mat
  • 958
  • 8
  • 18