How to make Customer Billing Phone Number Unique in Wordpress - wordpress

Actually I want customers to add unique-phone numbers in the billing address of woo-commerce. if any tries to add / update already existed phone numbers then it should throw an error.
I tried the below code but it is not working. Can anyone give me the correct solution for unique phone numbers in the Woocommerce billing address?
add_filter( 'update_user_meta', 'ts_unique_wc_phone_field');
function ts_unique_wc_phone_field( $errors ) {
if ( isset( $_POST['billing_phone'] ) ) {
$hasPhoneNumber= get_users('meta_value='.$_POST['billing_phone']);
if ( !empty($hasPhoneNumber)) {
$errors->add( 'billing_phone_error', __( '<strong>Error</strong>: Mobile number is already used!.', 'woocommerce' ) );
}
}
return $errors;
}

Your get_users call is wrong. Use
$hasPhoneNumber = get_users(array(
'meta_key' => 'billing_phone',
'meta_value' => $_POST['billing_phone'],
)
);
Careful: you did not mention your meta key in your post. This might be something else than 'billing_phone'. Adapt it as necessary.
This will however allow users to do shenanigans like adding a space/-/+ or something like that to the phone number, reusing it. This might need a function to filter out redundant characters upon meta value insertion, and apply the same function to $_POST['billing_phone'] before the meta query for get_users.

I have setup on one of my sites the same code within two (2) functions - one for woocommerce -> my account, and one at the checkout which checks for validity of the phone number provided specific to my country, and the other to check if the phone number already exists.
add_action( 'woocommerce_save_account_details_errors', 'wc_myaccount_validate_billing_phone', 20, 1); // My Account
function wc_myaccount_validate_billing_phone( $args ){
if ( isset ( $_POST['billing_phone'] ) && !empty ( $_POST['billing_phone'] ) ) {
if ( !preg_match( '/^04[0-9]{8}$/D', str_replace( ' ', '', $_POST['billing_phone'] ) ) ) {
wc_add_notice( __( '<strong>Billing Mobile Phone</strong> is invalid (Example: 0412 345 678).' ), 'error' );
}
$existing_billing_phone = get_users( 'meta_value=' . str_replace( ' ', '', $_POST['billing_phone'] ) );
$current_user = wp_get_current_user();
if ( !empty ( $existing_billing_phone ) ) {
if ( $current_user->billing_phone != str_replace( ' ', '', $_POST['billing_phone'] ) ) {
wc_add_notice( __( '<strong>Billing Mobile Phone</strong> already exists.' ), 'error' );
}
else {
return;
}
}
}
}
add_action('woocommerce_checkout_process', 'wc_checkout_validate_billing_phone'); // Checkout
function wc_checkout_validate_billing_phone() {
if ( isset( $_POST['billing_phone'] ) && !empty( $_POST['billing_phone'] ) ) {
if ( !preg_match('/^04[0-9]{8}$/D', str_replace(' ', '', $_POST['billing_phone'] ) ) ) {
wc_add_notice( __( '<strong>Billing Mobile Phone</strong> is invalid (Example: 0412 345 678).' ), 'error' );
}
$existing_billing_phone = get_users( 'meta_value=' . str_replace(' ', '', $_POST['billing_phone'] ) );
$current_user = wp_get_current_user();
if ( !empty( $existing_billing_phone ) ) {
if ( $current_user->billing_phone != str_replace(' ', '', $_POST['billing_phone'] ) ) {
wc_add_notice( __( '<strong>Billing Mobile Phone</strong> already exists.' ), 'error' );
}
else {
return;
}
}
}
}
As I want to save all phone numbers as 0412345678 (no spaces) and some people enter phone numbers as 0412 345 678, the str_replace() removes this prior to saving.
add_action( 'woocommerce_checkout_update_user_meta', 'wc_checkout_save_billing_phone' );
function wc_checkout_save_billing_phone( $user_id ) {
if ( $user_id && $_POST['billing_phone'] ) {
update_user_meta( $user_id, 'billing_phone', str_replace(' ', '', $_POST['billing_phone'] ) );
}
}
While I have not tested this next part yet, and this example is referenced from this link, if you are wanting to update the admin user area you may want to use something like this.
add_action( 'show_user_profile', 'wc_checkout_validate_billing_phone', 10 );
add_action( 'edit_user_profile', 'wc_checkout_validate_billing_phone', 10 );
Below is a screenshot of the results of trying to change my phone number to one that already exists while in the woocommerce->my account section.

Related

Add link or anchor tag in add_error() method in wordpress

I am using the Ultimate Member plugin and I want to print the error message with the link(anchor tag) using add_error method. Can someone guide me, on how can I allow an anchor tag in my error message that you can see in the screenshot?
add_action( 'um_custom_field_validation_user_email_details', 'um_custom_validate_user_email_details', 999, 3 );
function um_custom_validate_user_email_details( $key, $array, $args ) {
if ( $key == 'user_email' && isset( $args['user_email'] ) ) {
if ( $args['user_email'] == '' ) {
UM()->form()->add_error( 'user_email', __( 'E-mail Address is required', 'ultimate-member' ) );
} elseif ( ! is_email( $args['user_email'] ) ) {
UM()->form()->add_error( 'user_email', __( 'The email you entered is invalid', 'ultimate-member' ) );
} elseif ( email_exists( $args['user_email'] ) ) {
UM()->form()->add_error( 'user_email', __( 'Your email is already registered, please login or reset your password', 'ultimate-member' ) );
}
}
}

Wordpress Gravity form custom Validation

I created a form with gravity forms in Wordpress, But I'm trying to create a custom validation with an auto text field I create, So unless the user pick one of the option I put in the form, it should give an error.
I found this example on the gravity forms website, so this form give you an error if you enter a lower case "One and Two".
add_filter( 'gform_field_validation_6_3', function ( $result, $value, $form, $field ) {
GFCommon::log_debug( __METHOD__ . '(): Running...' );
// Only for Single Line Text and Paragraph fields.
if ( $field->type == 'text' || $field->type == 'textarea' ) {
if ( $result['is_valid'] ) {
$stop_words = array( // List of words to not allow in lowercase.
'one',
'two',
);
if ( in_array( strtolower( $value ), $stop_words ) ) {
GFCommon::log_debug( __METHOD__ . '(): Stop word detected: ' . $value );
$result['is_valid'] = false;
$result['message'] = 'Sorry, you used a not allowed word.';
}
}
}
return $result;
}, 10, 4 );
I want to reverse it so that unless you put these specific words " one, two " you get an error
You can add an exclamation point before the in_array() function which will make it stop any value not found in the array:
add_filter( 'gform_field_validation_6_3', function ( $result, $value, $form, $field ) {
GFCommon::log_debug( __METHOD__ . '(): Running...' );
// Only for Single Line Text and Paragraph fields.
if ( $field->type == 'text' || $field->type == 'textarea' ) {
if ( $result['is_valid'] ) {
$stop_words = array( // List of words to not allow in lowercase.
'one',
'two',
);
if ( !in_array( strtolower( $value ), $stop_words ) ) {
GFCommon::log_debug( __METHOD__ . '(): Stop word detected: ' . $value );
$result['is_valid'] = false;
$result['message'] = 'Sorry, you used a not allowed word.';
}
}
}
return $result;
}, 10, 4 );

WooCommerce Looping on My Account Form Submission

I am trying to override the account_display_name field within the my-account (logged in user) section which I am undertaking through two hooks. The first removes the required attribute, and the second updates the display_name field based on the input of first and last name.
This filter allows me to remove the required="required" attribute from the display_name field and works as intended:
add_filter('woocommerce_save_account_details_required_fields', 'audp_myaccount_required_fields');
function audp_myaccount_required_fields( $required_fields ) {
unset( $required_fields['account_display_name'] );
return $required_fields;
}
This next action is intended to allow me to save the submitted account_first_name and account_last_name as the display_name:
add_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 );
function audp_myaccount_display_name( $display_name ) {
global $current_user;
if ( isset( $_POST['account_first_name'] ) && isset( $_POST['account_last_name'] ) ) {
if ( ! empty( $_POST['account_first_name'] ) && ! empty( $_POST['account_last_name'] ) ) {
wp_update_user(
array (
'ID' => $current_user->ID,
'display_name' => sanitize_text_field( $_POST['account_first_name'] ) . ' ' . sanitize_text_field( $_POST['account_last_name'] ),
)
);
}
}
}
The problem I'm having with this code is the looping after submitting the data. The page 'eventually' returns an Internal 500 Error. If I stop the process (escape) and reload the page, the data has updated. I just don't know how to get out of this loop?
I have researched some options including remove_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 ) before the wp_update_user() and then add_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 ) after wp_update_user() but that has not seemed to work either.
Any assistance would be appreciated!
You should be able to stop endless loops by adding an additional filter, with a default false value, that you check at the top of your function. Stopping your code from being executed when this filter returns true.
Then call that filter before you update the user meta and make it return true. And remove it after updating the user meta. This way the check at the top will return true the second time the functions gets called and stops the endless loop, resulting in your function only running once.
add_action( 'profile_update', 'audp_myaccount_display_name', 20, 2 );
function audp_myaccount_display_name( $display_name ) {
if ( apply_filters( 'prevent_endless_loop_updating_user_meta', false ) ) return; // prevent endless loops
global $current_user;
if ( isset( $_POST['account_first_name'] ) && isset( $_POST['account_last_name'] ) ) {
if ( ! empty( $_POST['account_first_name'] ) && ! empty( $_POST['account_last_name'] ) ) {
add_filter( 'prevent_endless_loop_updating_user_meta', '__return_true' );
wp_update_user(
array (
'ID' => $current_user->ID,
'display_name' => sanitize_text_field( $_POST['account_first_name'] ) . ' ' . sanitize_text_field( $_POST['account_last_name'] ),
)
);
remove_filter( 'prevent_endless_loop_updating_user_meta', '__return_true' );
}
}
}

Wordpress Validate Billing_Phone in User Admin Area

I currently have wordpress/woocommerce and a billing_phone valiation function (provided below) which works within the My Account -> Account Details, Checkout, etc. This function firstly checks if the value is a valid phone number, and then checks if that phone number already exists. This is a very important function in my plugin as I cannot afford to have duplicates.
I require the same checks/balances as the front end in the backend... Where I am having problems is in locating the most appropriate hook or group of hooks to allow me to validate the billing_phone field within the admin area and 1) Display the error using error message you would normally see in the admin backend, and 2) Not update the field and show the error.
I have tried user_profile_update_errors - alas it only provides the error AFTER it has updated the meta and I cannot find any information on how to include checks within the $error variable. I also tried edit_user_profile_update and show_user_profile but I don't know how to add errors to the below function.
function user_admin_validate_billing_phone() {
if ( isset( $_POST['billing_phone'] ) && !empty( $_POST['billing_phone'] ) ) {
if ( !preg_match('/^04[0-9]{8}$/D', str_replace(' ', '', $_POST['billing_phone'] ) ) ) {
// Error: Billing Phone Number is Invalid.
}
$existing_billing_phone = get_users( 'meta_value=' . str_replace(' ', '', $_POST['billing_phone'] ) );
$current_user = wp_get_current_user();
if ( !empty( $existing_billing_phone ) ) {
if ( $current_user->billing_phone != str_replace(' ', '', $_POST['billing_phone'] ) ) {
// Error: Billing Phone Number Already Exists.
}
else {
return;
}
}
}
}
As stated, I have attempted the following hooks:
add_action( 'show_user_profile', 'user_admin_validate_billing_phone', 90 );
add_action( 'edit_user_profile', 'user_admin_validate_billing_phone', 90 );
add_action( 'personal_options_update', 'user_admin_validate_billing_phone' );
add_action( 'edit_user_profile_update', 'user_admin_validate_billing_phone' );
add_action( 'user_profile_update_errors, 'user_admin_validate_billing_phone', 10, 3 );
...however either the error comes up and the fields still change, or I don't know how to carry over the appropriate error handling, eg:
$error = new WP_Error();
$error->add( 'error', __( 'Billing Mobile Phone Number already exists.' ) );
Any assistance, or guidance to the right process would be most appreciated.
A example
function validate_phone_field(&$errors, $update = null, &$user = null) {
if ( empty($_POST['billing_phone']) ) {
$errors->add('empty_phone', '<strong>ERROR</strong>: Please Enter a phone number');
}
}
add_action( 'user_profile_update_errors', 'validate_phone_field' );
Use This code.
function user_admin_validate_billing_phone() {
if ( isset( $_POST['billing_phone'] ) && !empty( $_POST['billing_phone'] ) ) {
if ( !preg_match('/^04[0-9]{8}$/D', str_replace(' ', '', $_POST['billing_phone'] ) ) ) {
// Error: Billing Phone Number is Invalid.
wc_add_notice(__('Billing Phone Number is Invalid.', 'woocommerce'));
}
$existing_billing_phone = get_users( 'meta_value=' . str_replace(' ', '', $_POST['billing_phone'] ) );
$current_user = wp_get_current_user();
if ( !empty( $existing_billing_phone ) ) {
if ( $current_user->billing_phone != str_replace(' ', '', $_POST['billing_phone'] ) ) {
// Error: Billing Phone Number Already Exists.
wc_add_notice(__('Billing Phone Number Already Exists.', 'woocommerce'));
}
else {
return;
}
}
}
}
Hope this help.
add_action('woocommerce_checkout_process', 'wh_phoneValidateCheckoutFields');
function wh_phoneValidateCheckoutFields() {
$billing_phone = filter_input(INPUT_POST, 'billing_phone');
if (strlen(trim(preg_replace('/^[6789]\d{9}$/', '', $billing_phone))) > 0) {
wc_add_notice(__('Invalid <strong>Phone Number</strong>, please check your input.'), 'error');
}
}
Code goes in functions.php file of your active child theme (or theme). Or also in any plugin PHP files.
Please Note: By default WooCommerce use billing_phone field to take phone number, but if you have customized it then you can replace billing_phone with your field name.
Hope this helps!

Woocommerce recently viewed Products

I have created a recently viewed script which generated a shortcode which I then inserted into my home page.
The script is designed so that people who may have visited my website and left, once they come back can see instantly what products they had been viewing on their last visit.
I have placed the shortcode [woocommerce_recently_viewed_products]
and have generated the shortcode using the following script:
function rc_woocommerce_recently_viewed_products( $atts, $content = null ) {
// Get shortcode parameters
extract(shortcode_atts(array(
"per_page" => '5'
), $atts));
// Get WooCommerce Global
global $woocommerce;
// Get recently viewed product cookies data
$viewed_products = ! empty( $_COOKIE['woocommerce_recently_viewed'] ) ? (array) explode( '|', $_COOKIE['woocommerce_recently_viewed'] ) : array();
$viewed_products = array_filter( array_map( 'absint', $viewed_products ) );
// If no data, quit
if ( empty( $viewed_products ) )
return __( 'You have not viewed any product yet!', 'rc_wc_rvp' );
// Create the object
ob_start();
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
// Get products per page
if( !isset( $per_page ) ? $number = 4 : $number = $per_page )
// Create query arguments array
$query_args = array(
'posts_per_page' => $number,
'no_found_rows' => 1,
'post_status' => 'publish',
'post_type' => 'product',
'post__in' => $viewed_products,
'orderby' => 'rand'
);
// Add meta_query to query args
$query_args['meta_query'] = array();
// Check products stock status
$query_args['meta_query'][] = $woocommerce->query->stock_status_meta_query();
// Create a new query
$r = new WP_Query($query_args);
// If query return results
if ( $r->have_posts() ) {
$content = '<ul class="rc_wc_rvp_product_list_widget">';
// Start the loop
while ( $r->have_posts()) {
$r->the_post();
global $product;
$content .= '<li>
<a href="' . get_permalink() . '">
' . ( has_post_thumbnail() ? get_the_post_thumbnail( $r->post->ID, 'shop_thumbnail' ) : woocommerce_placeholder_img( 'shop_thumbnail' ) ) . ' ' . get_the_title() . '
</a> ' . $product->get_price_html() . '
</li>';
}
$content .= '</ul>';
}
// Get clean object
$content .= ob_get_clean();
// Return whole content
return $content;
}
// Register the shortcode
add_shortcode("woocommerce_recently_viewed_products",
"rc_woocommerce_recently_viewed_products");
Everything seems to have registered. However,when I test this myself. I view a few products, go back to the homepage where the shortcode is registered and I see the text
You have not viewed any product yet!
I can not figure out what might be missing in order to register and show the products which I or a potential customer may have viewed.
Woocommerce only save the recently viewed cookie IF woocommerce_recently_viewed_products WIDGET is ACTIVE! See code in wc-product-functions.php wc_track_product_view() function.
Code to save the cookie always in functions.php:
/**
* Track product views. Always.
*/
function wc_track_product_view_always() {
if ( ! is_singular( 'product' ) /* xnagyg: remove this condition to run: || ! is_active_widget( false, false, 'woocommerce_recently_viewed_products', true )*/ ) {
return;
}
global $post;
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) { // #codingStandardsIgnoreLine.
$viewed_products = array();
} else {
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) ); // #codingStandardsIgnoreLine.
}
// Unset if already in viewed products list.
$keys = array_flip( $viewed_products );
if ( isset( $keys[ $post->ID ] ) ) {
unset( $viewed_products[ $keys[ $post->ID ] ] );
}
$viewed_products[] = $post->ID;
if ( count( $viewed_products ) > 15 ) {
array_shift( $viewed_products );
}
// Store for session only.
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
remove_action('template_redirect', 'wc_track_product_view', 20);
add_action( 'template_redirect', 'wc_track_product_view_always', 20 );
You need to set the cookie when you are viewing a single product page so use something like this where I set the cookie to equal the product ID I just viewed. In your case you'll need to get the cookie value if it exists then append the new product to the list of products.
function set_user_visited_product_cookie() {
global $post;
if ( is_product() ){
// manipulate your cookie string here, explode, implode functions
wc_setcookie( 'woocommerce_recently_viewed', $post->ID );
}
}
add_action( 'wp', 'set_user_visited_product_cookie' );
Below code to set cookie 'woocommerce_recently_viewed' worked for me. Hope it helps other
$Existing_product_id = $_COOKIE['woocommerce_recently_viewed'];
if ( is_product() )
{
$updated_product_id = $Existing_product_id.'|'.$post->ID;
wc_setcookie( 'woocommerce_recently_viewed', $updated_product_id );
}

Resources