Wordpress: save custom billing field in account Billing address - wordpress

Using Wordpress/Woocommerce.
I have this code which adds a custom billing field in checkout page called: "NIF/CIF". It works fine but its value it not saved in the customer account "Billing Address" data.
Once the customer makes a first order all billing address values are saved in his account: Address, State, Country, etc. But my custom field is not saved.
I guess that in my function is missing a line of code to save its value in the database, but I don't know how to start with this.
/*******************************
CUSTOM BILLING FIELD
*********************************/
add_filter('woocommerce_billing_fields', 'custom_woocommerce_billing_fields');
function custom_woocommerce_billing_fields($fields)
{
$fields['nif_cif'] = array(
'label' => __('NIF/CIF', 'woocommerce'), // Add custom field label
'placeholder' => _x('NIF/CIF', 'placeholder', 'woocommerce'), // Add custom field placeholder
'required' => true, // if field is required or not
'clear' => false, // add clear or not
'type' => 'text', // add field type
'class' => array('my-css') // add class name
);
return $fields;
}

Here is an example of how to save your custom field:
add_action( 'woocommerce_checkout_order_processed', 'prefix_save_field_on_checkout', 11, 2 );
function checkout_order_processed_add_referral_answer( $order_id, $posted ) {
if ( ! isset( $_POST['nif_cif'] ) ) {
return;
}
$order = wc_get_order( $order_id );
// WC < 3.0
update_post_meta( $order->id, 'order_meta_field_name', wc_clean( $_POST['nif_cif'] ) );
// WC > 3.0
$order->add_meta_data( 'order_meta_field_name', wc_clean( $_POST['nif_cif'] ), true );
$order->save();
}

Adding an extra field through 'woocommerce_billing_fields' hook is not enough. you are missing out two things.
Proper validation of NIF/CIF field using
'woocommerce_after_checkout_validation' hook
Saving data in order
using 'woocommerce_checkout_order_processed' hook

Related

woocommerce set user meta value as default field value if exist

I am trying to set the default field value of a custom confirm email field in checkout.
If billing_email exists in user meta I would like to set the meta value as default value for the field.
If billing_email not exists in user meta I want to set the meta value of user_email as default value for the field.
I tried this:
$fields['billing_email_confirm'] = array(
'label' => 'confirm email *',
'class' => array( 'form-row-last' ),
'priority' => 9999,
);
$current_user = wp_get_current_user();
$havemeta = get_user_meta($customer_id, 'billing_email', false);
if ($havemeta)
{
$fields['billing_email_confirm']['default'] = $current_user->user_email;
} else {
$fields['billing_email_confirm']['default'] = $current_user->billing_email;
}
return $fields;
}
It works if the billing_email exists in user meta. But if not the field is empty.
There are few logical mistakes in your code, here is cleaned code with explanations:
$fields['billing_email_confirm'] = array(
'label' => 'confirm email *',
'class' => array( 'form-row-last' ),
'priority' => 9999,
);
// Check is customer ID is available or not?
if ( ! empty( $customer_id ) ) {
// Get customer data using customer id.
$customer = get_userdata( $customer_id );
// Get billing email from user meta.
// 3rd param should be true as we need single value not an array.
$billing_email = get_user_meta( $customer_id, 'billing_email', true );
// Check if billing email is empty or not?
if ( ! empty( $billing_email ) ) {
// when billing email is not empty.
$fields['billing_email_confirm']['default'] = $billing_email;
} else {
// When billing email is empty use, user account email.
$fields['billing_email_confirm']['default'] = $customer->user_email;
}
}

Choose role in register form (Woocommerce)

I'm building a site using Wordpress and WooCommerce. This site need to have 2 types of clients:
Normal customer (default customer of woocommerce)
B2B customer (this user have different prices and aditional products)
I need a checkbox to appear on the registration form.
When the user marks that checkbox, the b2b role would be assigned and additional fields would appear to complete the registration.
EDIT
I'm triying whit this code:
/*checkbox*/
add_action('woocommerce_after_checkout_billing_form', 'mostrar_campo_nif_profesionales');
function mostrar_campo_nif_profesionales( $checkout ) {
echo '<div id="mostrar_campo_nif_profesionales"><h3>'.__('¿Eres un profesional?').'</h3>';
woocommerce_form_field( 'check_profesional', array(
'type' => 'checkbox',
'class' => array('checkbox-profesionales form-row-wide'),
'label' => __('Profesional?'),
'required' => false,
), $checkout->get_value( 'profesional' ));
echo '</div>';
}
/*the field must appears when the checkbox are checked*/
if ("DON'T KNOW WHAT CONDITION MUST BE WRITE HERE") {
/*** Añadir campo personalizado a página de checkout ***/
add_action('woocommerce_after_checkout_billing_form', 'campo_nif_profesionales');
function campo_nif_profesionales( $checkout ) {
echo '<div id="campo_nif_profesionales"><h3>'.__('NIF/CIF').'</h3>';
woocommerce_form_field( 'NIF', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __('NIF/CIF'),
'placeholder' => __('Introduzca su NIF/CIF'),
'required' => true,
), $checkout->get_value( 'NIF' ));
echo '</div>';
}
/*** Validación del campo personalizado ***/
add_action('woocommerce_checkout_process', 'campo_nif_profesionales_process');
function campo_nif_profesionales_process() {
global $woocommerce;
// Comprobar si el campo ha sido completado, en caso contrario agregar un error.
if (!$_POST['NIF'])
$woocommerce->add_error( __('Por favor introduce tu NIF o CIF.') );
}
/*** Incluir campo personalizado a formato de orden ***/
add_action('woocommerce_checkout_update_order_meta', 'campo_nif_profesionales_update_order_meta');
function campo_nif_profesionales_update_order_meta( $order_id ) {
if ($_POST['NIF']) update_post_meta( $order_id, 'NIF/CIF', esc_attr($_POST['NIF']));
}
/*** Incluir campo personalizado a correos electrónicos de órdenes ***/
add_filter('woocommerce_email_order_meta_keys', 'campo_nif_profesionales_order_meta_keys');
function campo_nif_profesionales_order_meta_keys( $keys ) {
$keys[] = 'NIF/CIF';
return $keys;
}
}
But now the problem is only show the text field when the users chek the checkbox
Part 1.
At the start there are two options,
Add fields you need at the Start of the page
Add fields that you need at the End of the Page.
This can be done by woocommerce_register_form_start hook or woocommerce_register_form.
Here , the only way I can think of is to by default include the fields for all but only reveal them by JS / JQ when used click on the check box.
This would fix the part of adding the fields.
Part 2.
Validation of the Submitted form
Use the Hook woocommerce_register_post and then get hold of the registration data that is sent back to the server. And Validate it from server side as well. Say if the box is checked and all the related fields have the necessary data as well and sanitize the fields as well.
Part 3.
Now add the additional Data as well as the additional role to the user.
Now use the user_register hook and get hold of the newly registered user's ID. And then add the new data in there.
A bit of caution is suggested, as this hook is fired on every user register so first add a validation to check that this user is a customer , and then check that this user is registered via the front end form, this is can normally be done by checking the $_POST variable.
Use the wp_update_user and add_role function to achieve this.
Sample Code for part 3
function add_user_additional_details_frontend_reg( $user_id )
{
$registered_user = get_user_by('ID',$user_id);
if($registered_user) {
$user_role = $registered_user->roles;
if((in_array('customer', (array) $user_role))){
/* The field below "front_end_cust_form" is just a hidden field I added to check and make sure that this is coming from the Front end Reg form where I added the additional fields */
if($_POST['front_end_cust_form'] == 'front_end_cust_form')
{
$first_name = $_POST['billing_first_name'];
$last_name = $_POST['billing_last_name'];
update_user_meta($user_id, 'billing_first_name', $first_name);
update_user_meta($user_id, 'billing_last_name', $last_name);
$update_data = array(
'ID' => $user_id,
'first_name' => $first_name,
'last_name' => $last_name
);
$user_id = wp_update_user($update_data);
$registered_user->add_role('custom_role');
}
}
}
}
add_action( 'user_register', 'add_user_additional_details_frontend_reg', 10, 1 );
Hope this helps.

Wordpress Bulk Edit deletes custom taxonomy value

I have a custom taxonomy that I am "auto" assigning a value whenever a post is saved. It is saving the first letter of the post_title so I can use in a custom A to Z list (similar to this: http://geekgirllife.com/alphabetical-index-of-posts-in-wordpress/)
I have registered the taxonomy in my theme's functions.php as well as the auto assign function. Everything is working, when create/edit/save a post it adds the first letter of the post title into this custom tax.
However when I bulk edited some posts from the default WP bulk actions functionality, it overwrites the custom taxonomy value for the posts being edited.
My question is, is there a way to exclude a custom taxonomy from the bulk edit action in WP? Or a way bulk edit action will treat a custom tax as "no change" rather than update it w/ empty value?
Register Taxonomy code:
function atoz_tax() {
register_taxonomy( 'atoz',array (
0 => 'page',
),
array( 'hierarchical' => false,
'label' => 'atoz',
'show_ui' => false,
'query_var' => true,
'show_admin_column' => false,
) );
}
add_action('init', 'atoz_tax');
Code that auto saves to taxonomy on save:
function atoz_save_first_letter( $post_id ) {
// verify if this is an auto save routine.
// If it is our form has not been submitted, so we dont want to do anything
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
//Check permissions
if ( !current_user_can( 'edit_post', $post_id ) )
return $post_id;
// find and save the data
$taxonomy = 'atoz';
//set term as first letter of post title, lower case
wp_set_object_terms($post_id,strtolower(substr($_POST['post_title'], 0, 1)), $taxonomy);
}
add_action( 'save_post', 'atoz_save_first_letter' );

Woocommerce order formatted billing address reorder and custom billing field

Thanks to the filter "WooCommerce admin billing fields" I have ordered the billing fields in the notificiación footer by email but when I try to insert my custom billing field does not appear.
add_filter( 'woocommerce_order_formatted_billing_address' , 'woo_reorder_billing_fields', 10, 2 );
function woo_reorder_billing_fields( $address, $wc_order ) {
$address = array(
'first_name' => $wc_order->billing_first_name,
'last_name' => $wc_order->billing_last_name,
'company' => $wc_order->billing_company,
'my_field' => $wc_order->billing_my_field,
'country' => $wc_order->billing_country
);
return $address;
}
In order admin edit I can show my custom billing field thanks to the filter "woocommerce_admin_billing_fields", first adding the field and then reordering the Array.
I note that I added before and I have reordered this field in my checkout with the filter "woocommerce_checkout_fields".
Why not show my custom field if "$ wc_order" object stores the field in the checkout?
Any ideas?
Thanks in advance!
Yes, here the explanation:
We will register the new cusotm field, in this example the field "VAT" to store the fiscal document for companies in the European Union. There is a lot of documentation on how to register the custom fields and display them in the admin / user panel.
add_filter( 'woocommerce_default_address_fields', 'woo_new_default_address_fields' );
function woo_new_default_address_fields( $fields ) {
$fields['vat'] = array(
'label' => __( 'VAT number', 'woocommerce' ),
'class' => array( 'form-row-wide', 'update_totals_on_change' ),
);
return $fields;
}
Then add the new field "VAT" only to the registration of billing fields for mails, we do not want it to appear in the address fileds section.
add_filter( 'woocommerce_order_formatted_billing_address' , 'woo_custom_order_formatted_billing_address', 10, 2 );
function woo_custom_order_formatted_billing_address( $address, $WC_Order ) {
$address = array(
'first_name' => $WC_Order->billing_first_name,
'last_name' => $WC_Order->billing_last_name,
'vat' => $WC_Order->billing_vat,
'company' => $WC_Order->billing_company,
'address_1' => $WC_Order->billing_address_1,
'address_2' => $WC_Order->billing_address_2,
'city' => $WC_Order->billing_city,
'state' => $WC_Order->billing_state,
'postcode' => $WC_Order->billing_postcode,
'country' => $WC_Order->billing_country
);
return $address;
}
The following code customizes the appearance of the addresses, this is where we must add the call to the new VAT field. This allows us to customize the address view for each country independently.
add_filter( 'woocommerce_formatted_address_replacements', function( $replacements, $args ){
$replacements['{vat}'] = $args['vat'];
return $replacements;
}, 10, 2 );
add_filter( 'woocommerce_localisation_address_formats' , 'woo_includes_address_formats', 10, 1);
function woo_includes_address_formats($address_formats) {
$address_formats['ES'] = "{name}\n{company}\n{vat}\n{address_1}\n{address_2}\n{postcode} {city}\n{state}\n{country}";
$address_formats['default'] = "{name}\n{company}\n{vat}\n{nif}\n{address_1}\n{address_2}\n{city}\n{state}\n{postcode}\n{country}";
return $address_formats;
}
Any questions ask!

Add Tax Exempt form on checkout in woocommerce

I am trying to add a form to my checkout page so when a user clicks the 'Tax Exempt' checkbox, a textbox will popup and ask the user what the Tax Exempt Id number is.
I got all of that working great, and I even added the update_totals_on_change class to my form field so it will update the totals.
My next step was to add an action/filter on a method so when the update_totals_on_change executes, I can set the tax to 0 and then it will finish calculating the total.
Does anyone know which functions I can hook on to?
Looking at the checkout.js file in WooCommerce, they set the action to woocommerce_update_order_review for the ajax operation.
I tried following that but soon got lost.
I was thinking I could add some post data by hooking in to woocommerce_checkout_update_order_review
and then hooking in to woocommerce_before_calculate_totals to modify the tax stuff, but I have no idea what I need to modify.
Am I even on the right path?
Alright, I finally figured it out in case anyone is interested.
In my plugin, I made a form after the order notes by hooking in to this function: 'woocommerce_before_order_notes'
add_action('woocommerce_before_order_notes', array(&$this, 'taxexempt_before_order_notes') );
my 'taxexempt_before_order_notes' function contained:
function taxexempt_before_order_notes( $checkout ) {
echo '<div style="clear: both"></div>
<h3>Tax Exempt Details</h3>';
woocommerce_form_field( 'tax_exempt_checkbox', array(
'type' => 'checkbox',
'class' => array('tiri taxexempt'),array( 'form-row-wide', 'address-field' ),
'label' => __('Tax Exempt'),
), $checkout->get_value( 'tax_exempt_checkbox' ));
woocommerce_form_field( 'tax_exempt_name', array(
'type' => 'text',
'class' => array('form-row-first', 'tiri', 'taxexempt', 'textbox', 'hidden'),
'label' => __('Tax Exempt Name'),
), $checkout->get_value( 'tax_exempt_name' ));
woocommerce_form_field( 'tax_exempt_id', array(
'type' => 'text',
'class' => array('form-row-last', 'tiri', 'taxexempt', 'textbox', 'hidden', 'update_totals_on_change'),
'label' => __('Tax Exempt Id'),
), $checkout->get_value( 'tax_exempt_id' ));
}
Then the most important woocommerce function to hook was: 'woocommerce_checkout_update_order_review'
add_action( 'woocommerce_checkout_update_order_review', array(&$this, 'taxexempt_checkout_update_order_review' ));
function taxexempt_checkout_update_order_review( $post_data ) {
global $woocommerce;
$woocommerce->customer->set_is_vat_exempt(FALSE);
parse_str($post_data);
if ( isset($tax_exempt_checkbox) && isset($tax_exempt_id) && $tax_exempt_checkbox == '1' && !empty($tax_exempt_id))
$woocommerce->customer->set_is_vat_exempt(true);
}
I simply parsed out the $post_data that is the serialized form data from the checkout.js file in woocommerce and checked if my part of the form was filled out correctly.
If it was, then I would set the tax exempt for the user.
The accepted solution didn't work for me, but I modified it to use the following:
//=============================================================================
// ADD TAX EXEMPT CHECKMARK
// =============================================================================
add_action( 'woocommerce_after_order_notes', 'qd_tax_exempt');
function qd_tax_exempt( $checkout ) {
echo '<div id="qd-tax-exempt"><h3>'.__('Tax Exempt').'</h3>';
woocommerce_form_field( 'shipping_method_tax_exempt', array(
'type' => 'checkbox',
'class' => array(),
'label' => __('My organization is tax exempt.'),
'required' => false,
), $checkout->get_value( 'shipping_method_tax_exempt' ));
echo '</div>';
}
add_action( 'woocommerce_checkout_update_order_review', 'taxexempt_checkout_update_order_review');
function taxexempt_checkout_update_order_review( $post_data ) {
global $woocommerce;
$woocommerce->customer->set_is_vat_exempt(FALSE);
parse_str($post_data);
if ( isset($shipping_method_tax_exempt) && $shipping_method_tax_exempt == '1')
$woocommerce->customer->set_is_vat_exempt(true);
}
The key here is understanding that any field with a name that starts with shipping_method is going to inherit this updating order functionality (which was the part that didn't work for me). I found this answer at http://www.affectivia.com/blog/have-a-checkbox-on-the-checkout-page-which-updates-the-order-totals/
After a long search I found that there is a method for the cart object called remove_taxes() .
So, after setting a user meta for the tax exempt users, this cancels the tax totals.
function remove_tax_for_exempt( $cart ) {
global $current_user;
$ok_taxexp = get_the_author_meta( 'granted_taxexempt', $current_user->ID );
if ($ok_taxexp){ // now 0 the tax if user is tax exempt
$cart->remove_taxes();
}
return $cart;
}
add_action( 'woocommerce_calculate_totals', 'remove_tax_for_exempt' );
Because $cart->remove_taxes(); is deprecated. This is what I used instead.
I didn't have a form on the frontend, but have a user roll that is tax exempt. This was my solution.
Also worth noting that set_is_vat_exempt(true) also works in the US to set as tax exempt.
/**
* Set customer as tax exempt if user is a wholesale customer
*/
function remove_tax_for_exempt( $cart ) {
global $woocommerce;
if ( is_user_logged_in() && current_user_can( 'wholesale_customer' ) ) {
$woocommerce->customer->set_is_vat_exempt(true);
}
return $cart;
}
add_action( 'woocommerce_calculate_totals', 'remove_tax_for_exempt' );
Since this answer still pops up on google, I thought I'd share that setting the customer as tax exempt only works during checkout, if you need to edit the order on the back-end after it is placed and use the "recalculate" button, the taxes will still appear. Fortunately there is a hook for this as well:
function remove_tax_for_exempt($exempt, $order){
return $exempt || user_can($order->get_user_id(), 'wholesale_customer');
}
add_filter('woocommerce_order_is_vat_exempt', 'remove_tax_for_exempt', 10, 2);

Resources