Page 1 of 1

Getting an array of checkout fields

Posted: Sun Apr 14, 2019 4:26 pm
by renzocj
Hello guys, I have like a week trying to solve/understand this issue. I'm developing a website where the shipping delivery cost must be calculated based on a city area. As you may know, WooCommerce does this only for countries, provinces, states and cities. To solve this, I simply created a new custom field (with the usual filter woocommerce_checkout_fields):

Code: Select all

add_filter('woocommerce_checkout_fields', 'custome_district_checkout_field');

function custom_district_checkout_field($fields) {
   $option_cities = array(
      ' '   =>__('Select your district'),
      'port_area' =>'Port Area',
      'freeway_area'=>'Freeway Area'
      /** the list continue... **/
      );
      
      $fields['shipping']['shipping_district']['type'] = 'select';
      $fields['shipping']['shipping_district']['options'] = $option_cities;
      $fields['shipping']['shipping_district']['label'] = 'Distrito';
      $fields['shipping']['shipping_district']['required'] =  true;
      $fields['shipping']['shipping_district']['class'] = array('update_totals_on_change');
      $fields['shipping']['shipping_district']['input_class'] = array('wc-enhanced-select');
      
      $fields['billing']['billing_district']['type'] = 'select';
      $fields['billing']['billing_district']['options'] = $option_cities;
      $fields['billing']['billing_district']['label'] = 'Distrito';
      $fields['billing']['billing_district']['required'] =  true;
      $fields['billing']['billing_district']['input_class'] = array('wc-enhanced-select');
      
      wc_enqueue_js("jQuery( ':input.wc-enhanced-select' ).filter( ':not(.enhanced)' ).each( function() {var select2_args = { minimumResultsForSearch:5};jQuery( this ).select2( select2_args ).addClass( 'enhanced' );})");
      
      return $fields;
}

Then to process the checkout:

Code: Select all

add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');

function wps_select_checkout_field_process() {
    global $woocommerce;
    //Check if set, it not set an error
    if ($_POST['shipping_district'] == "blank") {
       wc_add_notice('<strong>Please, select an option</strong>', 'error' );
    }
}
Then to update the meta with field value:

Code: Select all

add_filter('woocommerce_checkout_update_order_meta', 'my_custom_checkout_district_field');

function my_custom_checkout_district_field($order_id) {
   if (!empty($_POST['shipping_district'])) {
      update_post_meta($order_id, 'Distrito', sanitize_text_field($_POST['shipping_district']));
   }
}
Then to display the field value on the order edit page:

Code: Select all

add_action('woocommerce_admin_order_data_after_shipping_address', 'custom_shipping_field', 10, 1);

function custom_shipping_field() {
   echo '<p><strong>'.__('My Field').':</strong> ' . get_post_meta( $order->id, 'shipping_district', true ) . '</p>';
}
On the other hand, the woocommerce-advanced-shipping plugin allows me to create lists with different prices and relate them with different options (like zipcode, city, state or country). As the additionally created field (district) already exists, I need to modify the plugin so that option can appear and be used.

Following in the footsteps of Jeremy Sormany https://gist.github.com/JeroenSormani/e ... 3485e6a8c9 He explains better the process to modify his plugin and be able to achieve the desired objective using different hooks. However in his code, there are some mistakes due to changes in the way of how WooCommerce now achieve some things, for example calling his methods.

Original Sormani Code:

Code: Select all

/**
 * WAS all checkout fields
 */
function was_conditions_add_shipping_fields( $conditions ) {
	$shipping_fields = WC()->checkout()->checkout_fields['shipping'];
	foreach ( $shipping_fields as $key => $values ) :
		if ( isset( $values['label'] ) ) :
			$conditions['Shipping Fields'][ $key ] = $values['label'];
		endif;
	endforeach;
	return $conditions;
}
add_filter( 'was_conditions', 'was_conditions_add_shipping_fields', 10, 1 );
Where

Code: Select all

$shipping_fields = WC()->checkout()->checkout_fields['shipping'];
$shipping_fields returned NULL

The correct method should be get_checkout_fields() based on the checkout class. Reading the WooCommerce documentation for the checkout class https://docs.woocommerce.com/wc-apidocs ... ml#186-232 the get_checkout_fields is:

Code: Select all

public function get_checkout_fields( $fieldset = '' ) {
        if ( is_null( $this->fields ) ) {
            $this->fields = array(
                'billing'  => WC()->countries->get_address_fields( $this->get_value( 'billing_country' ), 'billing_' ),
                'shipping' => WC()->countries->get_address_fields( $this->get_value( 'shipping_country' ), 'shipping_' ),
                'account'  => array(),
                'order'    => array(
                    'order_comments' => array(
                        'type'        => 'textarea',
                        'class'       => array( 'notes' ),
                        'label'       => __( 'Order notes', 'woocommerce' ),
                        'placeholder' => esc_attr__( 'Notes about your order, e.g. special notes for delivery.', 'woocommerce' ),
                    ),
                ),
            );
            if ( 'no' === get_option( 'woocommerce_registration_generate_username' ) ) {
                $this->fields['account']['account_username'] = array(
                    'type'         => 'text',
                    'label'        => __( 'Account username', 'woocommerce' ),
                    'required'     => true,
                    'placeholder'  => esc_attr__( 'Username', 'woocommerce' ),
                );
            }

            if ( 'no' === get_option( 'woocommerce_registration_generate_password' ) ) {
                $this->fields['account']['account_password'] = array(
                    'type'         => 'password',
                    'label'        => __( 'Create account password', 'woocommerce' ),
                    'required'     => true,
                    'placeholder'  => esc_attr__( 'Password', 'woocommerce' ),
                );
            }

            $this->fields = apply_filters( 'woocommerce_checkout_fields', $this->fields );
        }
        if ( $fieldset ) {
            return $this->fields[ $fieldset ];
        } else {
            return $this->fields;
        }
    }
I'm very lost here, I only get NULL trying everything and not the checkout fields array with the new custom field. I don't understand the parameter in the get_checkout_fields method, this $fieldset = ' ' anyone who can teachme this, I will greatly appreciate.

Code: Select all

get_checkout_fields( $fieldset = '' )
I also tried this:

Code: Select all

$shipping_fields = WC()->checkout->get_checkout_fields('fields');
Any help will be greatly appreciate!
Thank you 8)