In Woocommerce checkout, I am adding a custom checkout field and here is my code:
add_action( 'woocommerce_before_order_notes', 'shipping_add_select_checkout_field' );
function shipping_add_select_checkout_field( WC_Checkout $checkout ) {
$options = array_merge( [ '' => __( 'Nothing to select' ), ], city_zone() );
woocommerce_form_field( 'billing_country_zone', array(
'type' => 'select',
'class' => array( 'form-row-wide', 'address-field', 'update_totals_on_change' ),
'label' => __( 'City zone' ),
'required' => true,
'options' => $options
), WC()->customer->billing_country_zone );
}
Now I am totally lost as I need to know what is WC()->customer->billing_country_zone for and how can I check it's value…
Any help is really appreciated.
For theWC()->customer->billing_country_zone:
First since Woocommerce 3, properties can be accessed on most all Woocommerce instances objects.
And "billing_country_zone" is no a default property of WC_Customer instance object.
As it's about checkout fields, instead you should use $checkout argument which is the instance of the WC_Checkout Object. Then there is the appropriated method get_value() to be used on it...
What is that for?
Once the customer has submitted at least one order, the selected value for "billing_country_zone" will be displayed on checkout page.
So you will have to replace the line:
), WC()->customer->billing_country_zone );
by this one:
), $checkout->get_value('billing_country_zone') );
If $checkout variable argument is not defined, you will use WC()->checkout like:
), WC()->checkout->get_value('billing_country_zone') );
Now when you will save this custom checkout field value, you will need to save it:
As order meta data
And also as User meta data
So Here is the complete code (commented):
// Display custom checkout field
add_action( 'woocommerce_before_order_notes', 'display_custom_checkout_field' );
function display_custom_checkout_field( $checkout ) {
$options = array_merge( [ '' => __( 'Nothing to select' ), ], city_zone() );
woocommerce_form_field( 'billing_country_zone', array(
'type' => 'select',
'class' => array( 'form-row-wide', 'address-field', 'update_totals_on_change' ),
'label' => __( 'City zone' ),
'required' => true,
'options' => $options
), $checkout->get_value('billing_country_zone') );
}
// custom checkout field validation
add_action( 'woocommerce_checkout_process', 'custom_checkout_field_validation' );
function custom_checkout_field_validation() {
if ( isset( $_POST['billing_country_zone'] ) && empty( $_POST['billing_country_zone'] ) )
wc_add_notice( __( 'Please select a <strong>"City zone"</strong>.', 'woocommerce' ), 'error' );
}
// Save custom checkout field value as custom order meta data and user meta data too
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_order_meta', 20, 2 );
function custom_checkout_field_update_order_meta( $order, $data ) {
if ( isset( $_POST['billing_country_zone'] ) ) {
// Save custom checkout field value
$order->update_meta_data( '_billing_country_zone', esc_attr( $_POST['billing_country_zone'] ) );
// Save the custom checkout field value as user meta data
if( $order->get_customer_id() )
update_user_meta( $order->get_customer_id(), 'billing_country_zone', esc_attr( $_POST['billing_country_zone'] ) );
}
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
Related
In Woocommerce checkout, I am adding a custom checkout field and here is my code:
add_action( 'woocommerce_before_order_notes', 'shipping_add_select_checkout_field' );
function shipping_add_select_checkout_field( WC_Checkout $checkout ) {
$options = array_merge( [ '' => __( 'Nothing to select' ), ], city_zone() );
woocommerce_form_field( 'billing_country_zone', array(
'type' => 'select',
'class' => array( 'form-row-wide', 'address-field', 'update_totals_on_change' ),
'label' => __( 'City zone' ),
'required' => true,
'options' => $options
), WC()->customer->billing_country_zone );
}
Now I am totally lost as I need to know what is WC()->customer->billing_country_zone for and how can I check it's value…
Any help is really appreciated.
For theWC()->customer->billing_country_zone:
First since Woocommerce 3, properties can be accessed on most all Woocommerce instances objects.
And "billing_country_zone" is no a default property of WC_Customer instance object.
As it's about checkout fields, instead you should use $checkout argument which is the instance of the WC_Checkout Object. Then there is the appropriated method get_value() to be used on it...
What is that for?
Once the customer has submitted at least one order, the selected value for "billing_country_zone" will be displayed on checkout page.
So you will have to replace the line:
), WC()->customer->billing_country_zone );
by this one:
), $checkout->get_value('billing_country_zone') );
If $checkout variable argument is not defined, you will use WC()->checkout like:
), WC()->checkout->get_value('billing_country_zone') );
Now when you will save this custom checkout field value, you will need to save it:
As order meta data
And also as User meta data
So Here is the complete code (commented):
// Display custom checkout field
add_action( 'woocommerce_before_order_notes', 'display_custom_checkout_field' );
function display_custom_checkout_field( $checkout ) {
$options = array_merge( [ '' => __( 'Nothing to select' ), ], city_zone() );
woocommerce_form_field( 'billing_country_zone', array(
'type' => 'select',
'class' => array( 'form-row-wide', 'address-field', 'update_totals_on_change' ),
'label' => __( 'City zone' ),
'required' => true,
'options' => $options
), $checkout->get_value('billing_country_zone') );
}
// custom checkout field validation
add_action( 'woocommerce_checkout_process', 'custom_checkout_field_validation' );
function custom_checkout_field_validation() {
if ( isset( $_POST['billing_country_zone'] ) && empty( $_POST['billing_country_zone'] ) )
wc_add_notice( __( 'Please select a <strong>"City zone"</strong>.', 'woocommerce' ), 'error' );
}
// Save custom checkout field value as custom order meta data and user meta data too
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_order_meta', 20, 2 );
function custom_checkout_field_update_order_meta( $order, $data ) {
if ( isset( $_POST['billing_country_zone'] ) ) {
// Save custom checkout field value
$order->update_meta_data( '_billing_country_zone', esc_attr( $_POST['billing_country_zone'] ) );
// Save the custom checkout field value as user meta data
if( $order->get_customer_id() )
update_user_meta( $order->get_customer_id(), 'billing_country_zone', esc_attr( $_POST['billing_country_zone'] ) );
}
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
I am having a problem trying to add a custom field called Discount_info to a simple product.
I have created a new tab called discount_info which shows up in the simple product view just fine. Problem is trying to add a custom number field to this tab. I'm using the code below which is causing a 500 error. Any ideas where i am going wrong?
// Display Fields using WooCommerce Action Hook
add_action( 'woocommerce_product_options_discount_info',
'woocom_general_product_data_custom_field' );
function woocom_general_product_data_custom_field() {
// Create a custom text field
// Number Field
woocommerce_wp_text_input(
array(
'id' => '_discount_info',
'label' => __( 'Discount %', 'woocommerce' ),
'placeholder' => '',
'description' => __( 'Enter the % discount here.', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'step' => 'any',
'min' => '1'
)
)
);
}
// Hook to save the data value from the custom fields
add_action( 'woocommerce_process_product_meta',
'woocom_save_general_proddata_custom_field' );
/** Hook callback function to save custom fields information */
function woocom_save_general_proddata_custom_field( $post_id ) {
// Save Number Field
$number_field = $_POST['_discount_info'];
if( ! empty( $number_field ) ) {
update_post_meta( $post_id, '_discount_info', esc_attr( $number_field ) );
}
}
First remove all related code, and try this instead:
// Add a custom product setting tab to edit product pages options FOR SIMPLE PRODUCTS only
add_filter( 'woocommerce_product_data_tabs', 'discount_new_product_data_tab', 50, 1 );
function discount_new_product_data_tab( $tabs ) {
$tabs['discount'] = array(
'label' => __( 'Discount', 'woocommerce' ),
'target' => 'discount_product_data', // <== to be used in the <div> class of the content
'class' => array('show_if_simple'), // or 'hide_if_simple' or 'show_if_variable'…
);
return $tabs;
}
// Add/display custom Fields in the custom product settings tab
add_action( 'woocommerce_product_data_panels', 'add_custom_fields_product_options_discount', 10 );
function add_custom_fields_product_options_discount() {
global $post;
echo '<div id="discount_product_data" class="panel woocommerce_options_panel">'; // <== Here we use the target attribute
woocommerce_wp_text_input( array(
'type' => 'number', // Add an input number Field
'id' => '_discount_info',
'label' => __( 'Percentage Discount', 'woocommerce' ),
'placeholder' => __( 'Enter the % discount.', 'woocommerce' ),
'description' => __( 'Explanations about the field info discount.', 'woocommerce' ),
'desc_tip' => 'true',
'custom_attributes' => array(
'step' => 'any',
'min' => '1'
),
) );
echo '</div>';
}
// Save the data value from the custom fields for simple products
add_action( 'woocommerce_process_product_meta_simple', 'save_custom_fields_product_options_discount', 50, 1 );
function save_custom_fields_product_options_discount( $post_id ) {
// Save Number Field value
$number_field = $_POST['_discount_info'];
if( ! empty( $number_field ) ) {
update_post_meta( $post_id, '_discount_info', esc_attr( $number_field ) );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.
There aren't enough information to help know the exact problem, but it worth testing with a cleaner version of your code:
// Display Fields using WooCommerce Action Hook
add_action( 'woocommerce_product_options_discount_info', 'wc_general_product_data_custom_field' );
function wc_general_product_data_custom_field() {
// Number Field
woocommerce_wp_text_input( array(
'id' => '_discount_info',
'label' => __( 'Discount %', 'woocommerce' ),
'desc_tip' => 'true',
'description' => __( 'Enter the % discount here.', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'min' => '1',
'step' => '1',
),
) );
}
// Hook to save the data value from the custom fields
add_action( 'woocommerce_process_product_meta', 'wc_save_general_proddata_custom_field' );
/** Hook callback function to save custom fields information */
function wc_save_general_proddata_custom_field( $post_id ) {
// Save Number Field
$number_field = isset( $_POST['_discount_info'] ) ? $_POST['_discount_info'] : '';
if( ! empty( $number_field ) ) {
update_post_meta( $post_id, '_discount_info', $number_field );
}
}
I am creating a custom field in billing section in woocommerce cart via this code:
add_filter( 'woocommerce_default_address_fields', 'fts_cdek_fields_address' );
function fts_cdek_fields_address($fields){
$fields['cdek_city_id'] = array(
'type' => 'text',
'label' => __('Shipping city id. Technically needed.', $WCFCT),
'placeholder' => '',
'class' => array( 'wc_fts_cdek_hide','update_totals_on_change','form-row-wide','address-field' ),
'required' => false,
'clear' => false,
'label_class' => array( 'wc_fts_cdek_hide' )
);
return $fields;
}
function fts_cdek_fields_error(){
// Check if thechnical field is clear => user didn't enter the city or entered it wrong! (Without cdek api and autocomplete)
if(!isset($_POST['billing_cdek_city_id'])){
wc_add_notice( __( 'Please reenter city in shipping area using autocomplete.' ), 'error' );
}
}
add_action('woocommerce_checkout_update_order_meta', 'fts_cdek_fields_save');
function fts_cdek_fields_save( $order_id ){
if( !empty( $_POST['billing_cdek_city_id'] ) ){
update_post_meta( $order_id, 'CDEK city ID', $_POST['billing_cdek_city_id'] );
}
}
And I want to add my fields value to $package variable in woocommerce custom shipping ( calculate_shipping). How can I add my data there ?
Is it possible to do add some extra fields in WooCommerce products pages shipping tab settings in backend, as I need to add something like 12 custom fields.
I have tried to find some related hooks without success. The only way that I have found was over attributes, but it was not a convenient solution…
How can I add custom fields to WooComerce product setting pages in the shipping tab?
This is possible and you will get this (here I have set to custom text fields):
Here is the code:
// Add custom fields to product shipping tab
add_action( 'woocommerce_product_options_shipping', 'add_custom_shipping_option_to_products');
function add_custom_shipping_option_to_products(){
global $post, $product;
echo '</div><div class="options_group">'; // New option group
woocommerce_wp_text_input( array(
'id' => '_custom_text_field1',
'label' => __( 'My Text Field one', 'woocommerce' ),
'placeholder' => 'something',
'desc_tip' => 'true',
'description' => __( 'Enter the custom value here.', 'woocommerce' ),
'value' => get_post_meta( $post->ID, '_custom_meta_field1', true ),
) );
woocommerce_wp_text_input( array(
'id' => '_custom_text_field2',
'label' => __( 'My Text Field two', 'woocommerce' ),
'placeholder' => 'something',
'desc_tip' => 'true',
'description' => __( 'Enter the custom value here.', 'woocommerce' ),
'value' => get_post_meta( $post->ID, '_custom_meta_field2', true ),
) );
}
// Save the custom fields values as meta data
add_action( 'woocommerce_process_product_meta', 'save_custom_shipping_option_to_products' );
function save_custom_shipping_option_to_products( $post_id ){
$custom_text_field1 = $_POST['_custom_text_field1'];
if( isset( $custom_text_field1 ) )
update_post_meta( $post_id, '_custom_meta_field1', esc_attr( $custom_text_field1 ) );
$custom_text_field2 = $_POST['_custom_text_field2'];
if( isset( $custom_text_field2 ) )
update_post_meta( $post_id, '_custom_meta_field2', esc_attr( $custom_text_field2 ) );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on WooCommerce 3+ and works
I've been trying to hook this function in one of the "Order Hooks" of the Woocommerce Checkout page:
add_action( 'woocommerce_checkout_before_order_review', 'add_box_conditional' );
function add_box_conditional ( $checkout ) {
woocommerce_form_field( 'test', array(
'type' => 'checkbox',
'class' => array('test form-row-wide'),
'label' => __('conditional test'),
'placeholder' => __(''),
), $checkout->get_value( 'test' ));
}
If i try to get the value of the custom box in any order hooks, the order info just hangs and stops loading. I've tried with another type of custom fields and the same happens.
Example
If I hook the function outside the order contents works perfectly. The custom check box will be used to add a fee (post validation), as it is a very important option for our shop I want it inside the order details, so it can have a strong focus. Is there a way to make the function work on these hooks, or should I put it anywhere and move it with a simple but not so clean CSS overwritte?
You can't just get the value like that $checkout->get_value( 'test' ));.
Hook woocommerce_checkout_create_order and get the value from $_POST there. Then add a custom fee to the order if the checkbox was checked.
Like this:
function add_box_conditional() {
woocommerce_form_field( 'test', array(
'type' => 'checkbox',
'class' => array( 'test form-row-wide' ),
'label' => __( 'conditional test' ),
'placeholder' => __( '' ),
) );
}
add_action( 'woocommerce_checkout_before_order_review', 'add_box_conditional' );
function edit_order( $order, $data ) {
if( ! isset( $_POST[ 'test' ] ) ) {
return;
}
$checkbox_value = filter_var( $_POST[ 'test' ], FILTER_SANITIZE_NUMBER_INT );
if( $checkbox_value ){
$fee = 20;
$item = new \WC_Order_Item_Fee();
$item->set_props( array(
'name' => __( 'Custom fee', 'textdomain' ),
'tax_class' => 0,
'total' => $fee,
'total_tax' => 0,
'order_id' => $order->get_id(),
) );
$item->save();
$order->add_item( $item );
$order->calculate_totals();
}
}
add_action( 'woocommerce_checkout_create_order', 'edit_order', 10, 2 );