woocommerce set user meta value as default field value if exist - wordpress

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;
}
}

Related

Split a WooCommerce order, and create a new one with line items that has specific product tag

I have tried modifying the answer provided in //stackoverflow.com/a/59544491/19984414. I am not getting any errors when testing it, but also nothing really happens to my test order.
How can I test, why nothing happens when I make an order?
add_action( 'woocommerce_checkout_order_processed', 'action_woocommerce_checkout_order_processed', 10, 3 );
function action_woocommerce_checkout_order_processed( $order_id, $posted_data, $order ) {
// Initialize
$check_for_stock = false;
$taxonomy = 'product_tag';
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Get product
$product = $item->get_product();
// Product has tag 'stock'
if ( has_term( 'stock', $taxonomy, $product ) ) {
// Will only be executed once if the order contains line items with tag "stock"
if ( $check_for_stock == false ) {
$check_for_stock = true;
// Create new order with stock items
$stock_order = wc_create_order();
}
// Add product to 'backorder' order
$stock_order->add_product( $product, $item['quantity'] );
$stock_order->save();
// Delete item from original order
$order->remove_item( $item->get_id() );
}
}
// If current order contains line items with product tag "stock", retrieve the necessary data from the existing order and apply it in the new order
if ( $check_for_stock ) {
// Recalculate and save original order
$order->calculate_totals();
$order->save();
// Obtain necessary information
// Get address
$address = array(
'first_name' => $order->get_billing_first_name(),
'last_name' => $order->get_billing_last_name(),
'email' => $order->get_billing_email(),
'phone' => $order->get_billing_phone(),
'address_1' => $order->get_billing_address_1(),
'address_2' => $order->get_billing_address_2(),
'city' => $order->get_billing_city(),
'state' => $order->get_billing_state(),
'postcode' => $order->get_billing_postcode(),
'country' => $order->get_billing_country()
);
// Get shipping
$shipping = array(
'first_name' => $order->get_shipping_first_name(),
'last_name' => $order->get_shipping_last_name(),
'address_1' => $order->get_shipping_address_1(),
'address_2' => $order->get_shipping_address_2(),
'city' => $order->get_shipping_city(),
'state' => $order->get_shipping_state(),
'postcode' => $order->get_shipping_postcode(),
'country' => $order->get_shipping_country()
);
// Get order currency
$currency = $order->get_currency();
// Get order payment method
$payment_gateway = $order->get_payment_method();
// Required information has been obtained, assign it to the 'backorder' order
// Set address
$stock_order->set_address( $address, 'billing' );
$stock_order->set_address( $shipping, 'shipping' );
// Set the correct currency and payment gateway
$stock_order->set_currency( $currency );
$stock_order->set_payment_method( $payment_gateway );
// Calculate totals
$stock_order->calculate_totals();
// Set order note with original ID
$stock_order->add_order_note( 'Automated "stock" order. Created from the original order ID: ' . $order_id );
// Optional: give the new 'backorder' order the correct status
$stock_order->update_status( 'on-hold' );
$stock_order->save();
}
}
I am running the snippet from WPCodeBox with the following (default) settings:
How to run the snippet: Always (On Page Load)
Hook/Priority: Root (Default)
Snippet Order: 10
Where to run the snippet: Everywhere

Add total orders and customer status in new order email notification in WooCommerce

I would like to add a note to the new order email notifications that the admin gets. This note should indicate whether the order is from a new customer, or from a returning customer.
This so that the people in the warehouse know what they should add in the shippingbox. We give new customers a ticket and don't want customers who order again to receive the same ticket, they get a diffrent ticket.
This should apply to both logged in users and users who are not logged in. A check via email address perhaps?
This code is using the has_bought for all customer orders - source
function has_bought() {
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => 1, // one order is enough
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed', // Only orders with "completed" status
'fields' => 'ids', // Return Ids "completed"
) );
// return "true" when customer has already at least one order (false if not)
return count($customer_orders) > 0 ? true : false;
}
But I don't get it on the the new order email that admins receive, I would like to show it as:
Customer: new OR returning
Number of purchases: 4
How would i go about this and is this possible to create?
Some comments/suggestions:
To display text in email notifications, you can use different hooks, depending on where exactly you want to display the text. For example, the woocommerce_email_order_details hook is very suitable for this
To target a specific email notification you can use $email->id
Via wc_get_orders() you can get and count the existing orders for a customer based on the email address. If desired, pass a series of arguments that define the criteria for the search
So you get:
function action_woocommerce_email_order_details( $order, $sent_to_admin, $plain_text, $email ) {
// Target specific email notification
if ( $email->id == 'new_order' ) {
// Get email
$customer_email = $order->get_billing_email();
// NOT empty
if ( ! empty ( $customer_email ) ) {
// Get orders from customer by email and statuses
$orders_by_customer_email = wc_get_orders( array(
'customer' => $customer_email,
'status' => array( 'wc-on-hold','wc-processing','wc-completed' ),
'limit' => -1,
'return' => 'ids'
));
// When new customer
if ( count( $orders_by_customer_email ) == 1 ) {
$customer = __( 'new', 'woocommerce' );
} else {
$customer = __( 'returning', 'woocommerce' );
}
// Output
echo '<p style="color:red;font-size:14px;">' . sprintf( __( 'Customer: %s, number of purchases: %d', 'woocommerce' ), $customer, count( $orders_by_customer_email ) ) . '</p>';
}
}
}
add_action( 'woocommerce_email_order_details', 'action_woocommerce_email_order_details', 10, 4 );

Wordpress: save custom billing field in account Billing address

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

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!

Update user meta after woocommerce checkout form process

I am using woocommerce with Wordpress and have added some custom fields to the checkout:
add_action('woocommerce_after_order_notes', 'my_custom_checkout_field');
function my_custom_checkout_field( $checkout ) {
$extra_fields = array('job_title', 'company', 'telephone', 'occupation');
foreach($extra_fields as $key => $value) {
woocommerce_form_field($value, array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __($label),
'value' => '',
), $checkout->get_value( $value ));
}
}
Now currently, these appear in the checkout fine, not sure if using woocommerce_after_order_notes is right in this case. I have also added some custom fields to the user meta that correspond to the fields added to the checkout - which all display in the user profile page:
function add_contact_methods( $contactmethods ) {
$contactmethods['job_title'] = 'Job Title';
$contactmethods['company'] = 'Company Name';
$contactmethods['telephone'] = 'Telephone';
$contactmethods['occupation'] = 'Occupation';
$contactmethods['refer'] = 'How you heard about us?';
return $contactmethods;
}
add_filter('user_contactmethods','add_contact_methods',10,1);
As you can imagine, if I update any of these field in any profile page, it works fine but what I cant seem to do is update the user meta when a new user makes a purchase, it does not update the user meta for these fields in the database.
I understand alot of how this works, and understand that I must hook into a Woocommerce process to add the fields into the process. So I have added this code into my functions too:
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta');
function my_custom_checkout_field_update_user_meta( $user_id ) {
global $extra_fields;
foreach($extra_fields as $key => $value) {
if ($_POST[$value]) update_user_meta( $user_id, $value, esc_attr($_POST[$value]));
}
}
Now the twist is, this works if a user who is already signed in as a member, makes a repurchase and goes through the checkout - the reason this works is because $user_id already exists, but when a new user is checking out, they do not yet exist as a user, hence the function cannot update the user meta of NIL where $user_id does not exist.
My question is, how do I hook into the checkout process, presumably AFTER the user has been created, so I that I can get the $user_id returned, and execute this function to update the user meta.
class-wc-checkout.php line 639 creates the new user with $this->customer_id = wp_insert_user( apply_filters( 'woocommerce_new_customer_data', $new_customer_data ) ); The new customer data is an array listed just above that line.
Following that, you can access the user id with line 649's action do_action( 'woocommerce_created_customer', $this->customer_id );
It is unlikey, in your case, you will need to use the filter, but simply add the action 'woocommerce_created_customer', pull in the id, and add the meta.
When customer is not logged in checkout page should be acceptable field customer want to create a new account.Below sample code change in checkout page when customer order a new item and update user meta data.
function user_extra_meta_fields(){
return array(
'job_title' => __( 'Job Title', 'yourtext_domain'),
'company' => __( 'Company Name', 'yourtext_domain'),
'telephone' => __( 'Telephone', 'yourtext_domain'),
'occupation' => __( 'Occupation', 'yourtext_domain'),
'refer' => __( 'How you heard about us?', 'yourtext_domain'),
);
}
function add_contact_methods( $contactmethods ) {
$contactmethods = array_merge( $contactmethods, user_extra_meta_fields());
return $contactmethods;
}
add_filter('user_contactmethods','add_contact_methods',10,1);
add_action('woocommerce_after_order_notes', 'my_custom_checkout_field');
function my_custom_checkout_field( $checkout ) {
foreach( user_extra_meta_fields() as $name => $label) {
$value = '';
if( is_user_logged_in() )
$value = get_user_meta( get_current_user_id(), $name, true );
woocommerce_form_field( $name, array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => $label,
), $value );
}
}
add_action( 'woocommerce_checkout_process', 'user_fields_woocommerce_checkout_process' );
function user_fields_woocommerce_checkout_process(){
if( is_user_logged_in() )
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta' );
else
add_action( 'woocommerce_created_customer', 'my_custom_checkout_field_update_user_meta' );
}
function my_custom_checkout_field_update_user_meta( $user_id ) {
foreach( array_keys( user_extra_meta_fields() ) as $meta_name ){
if( isset( $_POST[$meta_name] ) ){
$meta_value = $_POST[$meta_name] ? esc_attr($_POST[$meta_name]) : '';
update_user_meta( $user_id, $meta_name, $meta_value );
}
}
}
// if want to validate field
add_action( 'woocommerce_after_checkout_validation', 'user_fields_woocommerce_after_checkout_validation' );
function user_fields_woocommerce_after_checkout_validation( $posted ){
$validate = true;
if( ! is_user_logged_in() && empty( $posted['createaccount'] ) )
$validate = false;
if( $validate == false )
return;
$meta_data = user_extra_meta_fields();
foreach( array_keys( $meta_data ) as $meta_name ){
if( empty($_POST[$meta_name]) )
wc_add_notice( sprintf( __(' <strong>%s</strong> is required.', 'yourtext_domain'), $meta_data[$meta_name] ), 'error' );
}
}

Resources