6

For a special group of customers that aren't yet WP user in my system, I am directing them to a special page, where they'll choose from a limited set of products. I already have all of their information and I it's going to pre-populate on this landing page. When they've verified their information, it will add their product to the cart and skip straight to the checkout. I've got all that down so far.

What I want to do is pre-populate the checkout data with the customer name and billing information that I have and I'm not entirely certain how to do that. But here's what I've got so far:

    function onboarding_update_fields( $fields = array() ) {

      $token = ( ! empty( $_GET['token'] ) ) ? $_GET['token'] : '';   
      if( 'testtoken' == $token ) {          
        $fields['billing']['billing_first_name']['value'] = 'Joe';
        var_dump( $fields ); 
      }  
      return $fields;
     }

    add_filter( 'woocommerce_checkout_fields', 'onboarding_update_fields' );

How do I change the value of the checkout fields? The code above doesn't do it. Point me in the right direction on one, and I can do the rest.

I looked here but didn't quite find what I was looking for either.

Thanks!

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Difster
  • 3,264
  • 2
  • 22
  • 32

3 Answers3

9

You should use this dedicated WooCommerce hook, made for prefilling checkout fields and defined in the WC_Checkout method get_value():

add_filter( 'woocommerce_checkout_get_value', 'populating_checkout_fields', 10, 2 );
function populating_checkout_fields ( $value, $input ) {
    
    $token = ( ! empty( $_GET['token'] ) ) ? $_GET['token'] : '';
    
    if( 'testtoken' == $token ) {
        // Define your checkout fields  values below in this array (keep the ones you need)
        $checkout_fields = array(
            'billing_first_name'    => 'John',
            'billing_last_name'     => 'Wick',
            'billing_company'       => 'Murders & co',
            'billing_country'       => 'US',
            'billing_address_1'     => '7 Random street',
            'billing_address_2'     => 'Royal suite',
            'billing_city'          => 'Los Angeles',
            'billing_state'         => 'CA',
            'billing_postcode'      => '90102',
            'billing_phone'         => '555 702 666',
            'billing_email'         => 'jhon.wick@murders.com',
            'shipping_first_name'   => 'John',
            'shipping_last_name'    => 'Wick',
            'shipping_company'      => 'Murders & co',
            'shipping_country'      => 'USA',
            'shipping_address_1'    => '7 Random street',
            'shipping_address_2'    => 'Royal suite',
            'shipping_city'         => 'Los Angeles',
            'shipping_state'        => 'California',
            'shipping_postcode'     => '90102',
            // 'account_password'       => '',
            'order_comments'        => 'This is not for me',
        );
        foreach( $checkout_fields as $key_field => $field_value ){
            if( $input == $key_field && ! empty( $field_value ) ){
                $value = $field_value;
            }
        }
    }
    return $value;
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

If user is not logged in, you could add additionally in your condition:

 if( 'testtoken' == $token &&  ! is_user_logged_in() ) {

This code is tested and works (but not tested with your specific code condition). For my testing I have used ! is_user_logged_in() as condition.

The you will get this (for the array defined in the function):

enter image description here

Community
  • 1
  • 1
LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • That would seem to be the cleaner way to do it. I'll test that out later. Thanks! – Difster Aug 10 '17 at 15:14
  • Yes, thanks. The code of "cale_b" is really a good PHP turn around, but `woocommerce_checkout_get_value` is the WooCommerce dedicated hook to make it... – LoicTheAztec Aug 10 '17 at 15:22
  • I looked at the documentation here and it didn't say anything about changing values. The documentation seemed a little lacking in that regard. https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/ – Difster Aug 10 '17 at 15:25
  • @Difster but the hook in WC_Checkout `get_value` method is maid for that, as it's very explicit... Now you need to test it and to see what is the more convenient for you. This answer is just another way, with a woocommerce dedicated hook and specific arguments. – LoicTheAztec Aug 10 '17 at 15:33
8

Filters allow you to modify information, but you must return that information from your function.

So, in this case, you're simply missing a return $fields; in your function:

function onboarding_update_fields( $fields = array() ) {
   // check if it's set to prevent notices being thrown
   $token = ( ! empty( $_GET['token'] ) ) ? $_GET['token'] : '';

   // yoda-style to prevent accidental assignment
   if( 'testtoken' == $token ) {
       // if you are having issues, it's useful to do this below:
       var_dump( $fields );
       // remove the var_dump once you've got things working

       // if all you want to change is the value, then assign ONLY the value
       $fields['billing']['billing_first_name']['value'] = 'Joe';
       // the way you were doing it before was removing core / required parts of the array - do not do it this way.
       // $fields['billing']['billing_first_name']['value'] = array( 'value' => 'Joe');

   }
   // you must return the fields array 
   return $fields;
}

add_filter( 'woocommerce_checkout_fields', 'onboarding_update_fields' );

Update:
After seeing for some reason the above doesn't work, I sniffed some code on another plugin, and they way they do it (and it clearly works) is like so:

function onboarding_update_fields( $fields = array() ) {
   $token = ( ! empty( $_GET['token'] ) ) ? $_GET['token'] : '';

   if( 'testtoken' == $token ) {
       // Assign the value to the $_POST superglobal
       $_POST['billing_first_name'] = 'Joe';
   }

   return $fields;
}

So - to be positive that this didn't overwrite / stomp user-entered information, I might suggest considering doing it something like this (of course test to be sure it works):

function onboarding_update_fields( $fields = array() ) {
   $token = ( ! empty( $_GET['token'] ) ) ? $_GET['token'] : '';

   if( 'testtoken' == $token ) {
       // Assign the value to the $_POST superglobal ONLY if not already set
       if ( empty( $POST['billing_first_name'] ) ) {
           $_POST['billing_first_name'] = 'Joe';
       }
   }

   return $fields;
}
random_user_name
  • 25,694
  • 7
  • 76
  • 115
  • Nope, the billing_first_name field is not being changed. – Difster Aug 10 '17 at 01:22
  • Sorry, I mean by "not working" the field value is not changed. But adding the `return` solved the disappearing field problem. – Difster Aug 10 '17 at 01:25
  • Put a `var_dump` outside your `if`. I'm guessing that your `if` isn't firing. – random_user_name Aug 10 '17 at 01:27
  • Yup, the var_dump showed up. In my haste, I retyped "testtoken" wrong. This is the relevant part of the var_dump: ` { ["billing_first_name"]=> array(4) { ["label"]=> string(10) "First Name" ["required"]=> bool(true) ` As you can see the value of billing_first_name is still blank. – Difster Aug 10 '17 at 01:29
  • Also just to make sure I didn't miss anything, I searched for "Joe" in the var dump and didn't find it. – Difster Aug 10 '17 at 01:30
  • I have the 'var_dump' inside the `if` and it is triggering. However, there the value of the field is not changing. I even hit ctrl-F5 to make sure it was clean reload. – Difster Aug 10 '17 at 01:33
6

Please use 'default', like:

$fields['billing']['billing_first_name']['default'] = "Thomas";

Refer to WooCommerce | Set billing field value

Skatox
  • 4,237
  • 12
  • 42
  • 47
Frank Liu
  • 151
  • 1
  • 5