I have a Woocommerce site that I want to detect if a user changes any of their billing details. I've had a look around and found this snippet:
add_filter( 'insert_user_meta', function( $meta, $user, $update ) {
if( true !== $update ) return $meta;
$old_meta = get_user_meta( $user->ID );
if( $old_meta[ 'first_name' ] !== $meta[ 'first_name' ] ) {
//* Do something
}
return $meta;
}, 10, 3 );
Will this fire everytime an update is made to the user meta? How can I add in all the following fields to see if any change:
Company
Billing address line 1
Billing address line 2
City
Postcode
Country
County
Or alternatively, is there a woocommerce hook for this?
Would something like this work?
function my_profile_update( $user_id ) {
if ( ! isset( $_POST['pass1'] ) || '' == $_POST['pass1'] ) {
return;
}
// password changed...
}
add_action( 'profile_update', 'my_profile_update' );
If a user edit address from woocommerce my account page in frontend, there is a hook available for edit address through which you can check and achieve your work. The hook as follow -
do_action( 'woocommerce_customer_save_address', $user_id, $load_address );
where $load_address return 'billing' whenever a user edit billing fields.
I would say that if the hook works, it is triggered for all Wordpress users, not only customers.
But I would recommend not to compare on data that a user can enter. In your case if he made a typo in his first name (like uppercase first letter), comparision fails and one can never correct that.
What you are looking for is one of the account page hooks. But unfortunately I can only point out a direction.
Related
I want a code that the password generated by woocommerce will be taken from the phone field on the checkout page when the user fills in the details for the billing
I tried the following code and it did not work
I would love a code that works. thanks.
<?php
//Use user phone number as auto-generated password
function wcs_filter_password_phone_number( $args ) {
$args['user_pass'] = $args['dbem_phone'];
return $args;
}
add_filter( 'woocommerce_new_customer_data', 'wcs_filter_password_phone_number' );
It's not really secure setting the password based on the customer's phone number. Anyone could find a way in to be honest.
Having said that, the task is interesting, and based on WooCommerce: Update Order Field Value After a Successful Order it is possible indeed to alter an order/user field after a successful checkout.
You could hook into "woocommerce_thankyou" as per the article, or even into "woocommerce_payment_complete" if you wanted to do that in the background and only for paid/completed orders.
Also, you should look into https://developer.wordpress.org/reference/functions/wp_set_password/ which is the WP function to set a new password programmatically.
Here's my attempt:
add_action( 'woocommerce_thankyou', 'bbloomer_alter_password_after_order' );
function bbloomer_alter_password_after_order( $order_id ) {
$order = wc_get_order( $order_id );
$phone = $order->get_billing_phone();
$user_id = $order->get_user_id();
if ( $phone && $user_id ) {
wp_set_password( $phone, $user_id );
}
}
How do I clear a specfic checkout fields in WooCommerce after placing an order?
For example Billing email and Billing Phone. So that when the registered customer makes his/her next order, he/she has to fill that fields again?
I see this code, but this clean all the fields, i need only a specific field. Any advice?
add_filter('woocommerce_checkout_get_value','__return_empty_string',10);
The woocommerce_checkout_get_value hook has 2 arguments:
$value argument that is returned
$input argument to target checkout field(s)
So in your case, you get:
function filter_woocommerce_checkout_get_value( $value, $input ) {
// Target checkout fields. Multiple fields can be added, separated by a comma
if ( in_array( $input, array( 'billing_phone', 'billing_email' ) ) ) {
$value = '';
}
return $value;
}
add_filter( 'woocommerce_checkout_get_value' , 'filter_woocommerce_checkout_get_value' , 10, 2 );
You could probably achieve this with some custom javascript:
document.getElementById('fieldID').value = ''
Or jQuery:
$('#fieldID').val('');
Everything I have read over the last couple of days has indicated that if I want to save fields in the user-edit.php (User Admin Backend), I should be using the edit_user_profile_update & personal_options_update hooks (and I'm not including the validation hook in this question...)
In the codex, they state that:
Consider an example:
update_user_meta($user_id, 'custom_meta_key', $_POST['custom_meta_key']);
Make doubly sure that you give a different key name for the $_POST data key and the actual user meta key. If you use the same key for both, Wordpress for some reason, empties the value posted under that key.
So you'll always get an empty value in $_POST['custom_meta_key'] so change it in the html input element's name attribute and append a suffix. Changing it to $_POST['custom_meta_key_data'] and it'll pass the data properly.
However, given the fact that I want to add validations to the existing billing_phone field, I do not know how to create said "custom_meta_key_data" (eg: '_billing_phone', or 'prefix_billing_phone') to then enter the value into said prefix_billing_phone to then convert to 'billing_phone' via update_user_meta().
I have provided my base code below, and I have searched the internet for two days as to a solution, but I cannot find a workaround.
In addition, the str_replace() doesn't action, which made me look inside the user-edit.php and the comments support the quoted notes above, where between hitting update, and the profile reloading, it saves each variable as _billing_ (prefixed '_') and records the original value (pre if statements / my code below) and saves that - not what I have conditioned/attempted to validate. I don't know how to copy that so that I can simply validate my fields...
add_action( 'personal_options_update', 'audp_save_user_account_fields' );
add_action( 'edit_user_profile_update', 'audp_save_user_account_fields' );
function audp_save_user_account_fields( $user_id ) {
/* Input Value: "0412 345 678"
* SHOULD Become: "0412345678"
*/
$billing_phone = str_replace( array( ' ', '(', ')' ), '', $_POST['billing_phone'] );
if ( !empty( $_POST['billing_phone'] ) && preg_match( '/^04[0-9]{8}$/D', $billing_phone ) ) {
$billing_phone_query = get_users( array(
'meta_key' => 'billing_phone',
'meta_value' => $billing_phone,
) );
foreach ( $billing_phone_query as $query ) {
if ( $user_id == $query->ID ) {
/* This value ($billing_phone) should be eg: "0412345678"
* but remains "0412 345 678"
*/
update_user_meta( $user_id, 'billing_phone', $billing_phone );
}
}
}
}
Addition / Edit
Under personal_options_update and edit_user_profile_update the fields still do not update as per the conditionals. For example, if I enter '0411 111 111' (spaces), the spaces are not removed. I have attempted to do var_dump( $_POST ); die(); at every stage of the conditional below and the value ('billing_phone') passes the changes (eg: 0411111111), but at the update_user_meta() and when the page reloads it reverts back to the '0411 111 111'? The code I have is:
function audp_save_user_account_fields( $user_id ) {
$billing_phone_key = 'billing_phone';
if ( isset( $_POST[$billing_phone_key] ) ) {
// var_dump( $_POST['billing_phone_key] ) = '0411 111 111'
$billing_phone = preg_replace( '/[^0-9]/i', '', sanitize_text_field($_POST[$billing_phone_key] ) );
// var_dump on $billing_phone = '0411111111'
if ( !empty( $_POST[$billing_phone_key] ) ) {
// var_dump( $billing_phone ) = '0411111111'
update_user_meta( $user_id, 'billing_phone', $billing_phone );
// page reloads with value '0411 111 111'.
}
}
}
add_action( 'edit_user_profile_update', 'audp_save_user_account_fields' );
I read somewhere that you might have to pass the old variable and the new variable somehow and/or delete the user_meta_data and then add the new one but I have not tried that yet...?? Any further suggestions would be appreciated.
Updated
Now to filter a phone number string keeping only numbers, you can better use preg_replace() than str_replace().
In the following, The billing phone number will be filtered before saving in:
Wordpress admin user dashboard
My Account Addresses Edit billing Address
Once order is placed (before data is saved)
The code:
// In Wordpress user profile (increased hook priority)
add_action( 'personal_options_update', 'save_user_billing_phone_fields', 999999 );
add_action( 'edit_user_profile_update', 'save_user_billing_phone_fields', 999999 );
function save_user_billing_phone_fields( $user_id ) {
$field_key = 'billing_phone';
if( isset($_POST[$field_key]) && ! empty($_POST[$field_key]) ) {
// Filtering billing phone (removing everything else than numbers)
$billing_phone = preg_replace( '/[^0-9]/', '', sanitize_text_field($_POST[$field_key]) );
// Update the billing phone
update_user_meta( $user_id, 'billing_phone', $billing_phone );
}
}
// On My account > edit addresses > Billing
add_action( 'woocommerce_process_myaccount_field_billing_phone', 'filter_my_account_billing_phone_fields' );
function filter_my_account_billing_phone_fields( $value ) {
return preg_replace( '/[^0-9]/', '', $value );
}
// On order submission
add_action( 'woocommerce_checkout_posted_data', 'wc_checkout_posted_data_filter_callback' );
function wc_checkout_posted_data_filter_callback( $data ) {
$field_key = 'billing_phone';
if( isset($data[$field_key]) ) {
// Filtering billing phone (removing everything else than numbers)
$data[$field_key] = preg_replace( '/[^0-9]/', '', $data[$field_key] );
}
return $data;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related: Extract numbers from a string
In the WooCommerce cart, you can set the default to ship to the billing address. The user can then check a box to enable a different shipping address. For returning customers it is a nuisance that you have to check the box again. I would like to remember the state of the checkbox for logged in users, so that not only the address information is shown, but also the state of the checkbox is the same as for the last order.
There are snippets published where you can add extra fields to shipping or billing, and let WooCommerce handle the storage. Other examples show custom fields where the data is stort in post. This is maintained on the order, but not available on the next order.
So I answered my own question above with the following. First have an action in functions.php of your child theme that saves the state of the checkbox in the user meta:
/**
* Update the user meta with checkbox setting
*/
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
$order = new WC_Order( $order_id );
update_user_meta( $order->user_id , 'shipping_different',$_POST['ship_to_different_address']) ;
}
Then add an action to retrieve the stored checkbox value and update the checkbox:
/*
* Get the user meta to set the checkbox if needed
*/
add_action( 'woocommerce_after_checkout_billing_form', 'my_checkout_fields', 10,1 );
function my_checkout_fields( $checkout ) {
$user_id = get_current_user_id();
if ($user_id !=0 ) {
if (get_user_meta($user_id, 'shipping_different', true ) == 1)
add_filter( 'woocommerce_ship_to_different_address_checked', '__return_true' );
}
}
Comments? Improvements?
I am trying to change the PayPal address that Woocommerce uses, depending on what page they are on. I only have 5 products at the moment, and all 5 need to use a different PayPal address.
I found this hook that can change the Paypal address, although not too sure how to add it in exactly (code is 3 years old apparently).
$paypal_args = apply_filters( 'woocommerce_paypal_args', $paypal_args );
add_filter( 'woocommerce_paypal_args' , 'custom_override_paypal_email' );
function custom_override_paypal_email( $paypal_args ) {
$paypal_args['business'] = 'paypalemail#domain.com';
print_r( $paypal_args['business'] );
return $paypal_args;
}
How can I use this hook to change the Paypal address depending on which page/product the user is on?
I've checked and found out that woocommerce_paypal_args has two arguments, the settings and the order. So based on the order, we can check what product it has and use the appropriate email.
add_filter( 'woocommerce_paypal_args' , 'custom_override_paypal_email', 10, 2 );
function custom_override_paypal_email( $paypal_args, $order ) {
foreach ( $order->get_items() as $item ) {
switch( $item['product_id'] ) {
case 561:
$paypal_args['business'] = 'paypalemail1#domain.com';
break;
case 562:
$paypal_args['business'] = 'paypalemail2#domain.com';
break;
}
}
return $paypal_args;
}
please take note that you have to make sure that there can only be one item on the cart. If there are more than 1 product in the cart, this will use the last found product in the foreach loop. The code above is just for guidance, please change accordingly.