How to Fix Checkout Fields in WooCommerce

Prevent checkout errors for repeat customers in WooCommerce by making their previous order details read-only. Implement this code snippet to enhance the user experience.

🕒 7 mins read

For online store owners using WooCommerce, managing the checkout process efficiently is paramount. A smooth and intuitive checkout experience directly impacts conversion rates and customer satisfaction. One scenario that can sometimes introduce friction is when returning customers place additional orders. They might have moved, updated their contact information, or simply want to use different details this time. However, if their previous information auto-populates and they don’t carefully review, it can lead to errors and confusion.

This blog post explores a practical technique to address this by providing you with a way to fix or disable checkout fields for subsequent orders, ensuring the information used for their previous successful order is presented as a read-only reference. This can be particularly useful if you want to minimize potential discrepancies and ensure the accuracy of shipping and billing details for repeat purchases.

The Challenge of Repeat Orders and Checkout Information

Imagine a loyal customer who placed an order a month ago using a specific shipping address. Now, they’re back to buy more items. WooCommerce, by default, might pre-fill the checkout form with their previously entered details. While convenient in many cases, this can become problematic if:

  • Their shipping address has changed.
  • They want to use a different billing method or address for this specific order.
  • They simply overlook the pre-filled information and don’t realize it’s outdated.

These scenarios can lead to incorrect shipments, billing issues, and ultimately, a less-than-ideal customer experience.

The Solution: Making Checkout Fields Read-Only for Subsequent Orders

The following code snippet provides a clever way to address this. It leverages a WooCommerce filter to dynamically add the readonly attribute to checkout fields for logged-in customers who have successfully placed previous orders. This presents their past information as a reference without allowing them to directly modify it on the current checkout.

/**
 * Disable all the Fields to make them fixed as the customer used for the previous order
 *
 * @param  array $fields
 * @return array
*/
function yasglobal_customer_details( $fields ) {
  global $wpdb;

  // Get current user ID
  $user_id = get_current_user_id();

  $post_types      = wc_get_order_types();
  $comma_separated = implode( "','", $post_types );
  $comma_separated = "'" . $comma_separated . "'";
  $sql_query = "
    SELECT post_id FROM $wpdb->posts
    INNER JOIN $wpdb->postmeta ON post_id = ID
    WHERE post_type IN (" . $comma_separated . ")
      AND post_status = 'wc-processing'
      AND meta_key = '_customer_user'
      AND meta_value = " . $user_id . "
    ORDER BY post_id";
  $items = $wpdb->get_results( $sql_query );
  if ( ! empty( $items ) ) { // only for additional orders
    if ( isset( $fields['billing'] ) ) {
      foreach ( $fields['billing'] as $key => $value ) {
        if ( ! isset( $fields['billing'][$key]['type'] ) ) {
          $fields['billing'][$key]['custom_attributes'] = array( 'readonly' => true );
        }
      }
    }
    if ( isset( $fields['shipping'] ) ) {
      foreach ( $fields['shipping'] as $key => $value ) {
        if ( ! isset( $fields['shipping'][$key]['type'] ) ) {
          $fields['shipping'][$key]['custom_attributes'] = array( 'readonly' => true );
        }
      }
    }
  }

  return $fields;
}

add_filter( 'woocommerce_checkout_fields', 'yasglobal_customer_details', 10, 1 );

How the Code Works: A Step-by-Step Explanation

  1. yasglobal_customer_details( $fields ) Function: This function is hooked into the woocommerce_checkout_fields filter, which allows you to modify the checkout form fields before they are displayed. It receives an array $fields containing all the billing and shipping fields.
  2. global $wpdb;: This line brings the WordPress database object into the scope of the function, allowing us to perform database queries.
  3. get_current_user_id();: This retrieves the ID of the currently logged-in user. This functionality is only relevant for returning, logged-in customers.
  4. Fetching Previous Order IDs:
    • wc_get_order_types();: This gets an array of all WooCommerce order post types (e.g., shop_order).
    • The subsequent lines construct an SQL query to find the post_id of previous orders placed by the current user that have a status of wc-processing. This ensures we’re looking at completed orders. The _customer_user meta key stores the user ID associated with each order.
    • $wpdb->get_results( $sql_query );: This executes the SQL query and returns an array of objects, where each object represents a previous order.
  5. Conditional Application (Additional Orders):
    • if ( ! empty( $items ) ) { … }: This crucial check ensures that the code only runs if the current logged-in user has placed at least one previous order. This prevents the fields from being read-only for the very first order.
  6. Iterating Through Billing and Shipping Fields:
    • if ( isset( $fields['billing'] ) ) { … }: This checks if the billing fields exist in the $fields array.
    • foreach ( $fields['billing'] as $key => $value ) { … }: This loop iterates through each billing field.
    • if ( ! isset( $fields['billing'][$key]['type'] ) ) { … }: This condition specifically targets standard input fields (text, email, phone, etc.) and excludes special field types like select boxes or radio buttons, as making those read-only might hinder the user’s ability to choose options.
    • $fields['billing'][$key]['custom_attributes'] = array( 'readonly' => true );: This is the core of the modification. It adds the readonly attribute to the custom_attributes array of the current billing field, effectively making it non-editable.
    • The same logic is then applied to the shipping fields.
  7. Returning the Modified Fields:
    • return $fields;: The function returns the (potentially modified) $fields array, which WooCommerce then uses to render the checkout form.

Important Note on Using the readonly Attribute:

The code explicitly uses the readonly attribute to disable the fields visually and prevent modification. It’s crucial to understand the difference between readonly and disabled in HTML forms. Disabled input elements are not submitted with the form data, which would break the checkout process. readonly, on the other hand, prevents user input but still submits the field’s value.

Implementing the Code on Your WooCommerce Store:

To implement this functionality, you’ll need to add the code snippet to your WordPress site. The recommended way to do this is by using your child theme’s functions.php file. If you don’t have a child theme, it’s highly advisable to create one to avoid losing your customizations when your main theme is updated. Alternatively, you can use a code snippets plugin.

Beyond Making All Fields Read-Only: Selective Field Control

The provided code makes all standard billing and shipping fields read-only for subsequent orders. However, you might have a more specific requirement to only fix or disable certain fields. You can easily adapt the code to target specific fields by adding conditional checks within the loops.

For example, to only make the billing address fields read-only, you could modify the billing loop like this:

if ( isset( $fields['billing'] ) ) {
  $fields_to_fix = array( 'billing_first_name', 'billing_last_name', 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode', 'billing_country' );
  foreach ( $fields['billing'] as $key => $value ) {
    if ( in_array( $key, $fields_to_fix ) && ! isset( $fields['billing'][$key]['type'] ) ) {
      $fields['billing'][$key]['custom_attributes'] = array( 'readonly' => true );
    }
  }
}

This modified snippet only applies the readonly attribute to the fields listed in the $fields_to_fix array within the billing section. You can apply similar logic to the shipping section to selectively control which fields are fixed.

Conclusion

By implementing the techniques outlined in this blog post, you can gain more control over the checkout process for returning customers in your WooCommerce store. Making previous order details read-only can help minimize errors, ensure data accuracy, and ultimately contribute to a smoother and more reliable experience for your valued customers. Remember to choose the approach that best aligns with your store’s specific needs and always test thoroughly after implementing any code changes.