Pre-fill WooCommerce billing fields with string url - php

I have a Wordpress site with WooCommerce webshop and a client (hotel) that wants customers to order products in my webshop. I want those customers not to have to fill in the hotel information during checkout (the products are delivered to their room).
I have build a custom page for the hotel where people can place certain products in the cart, and when they want to checkout they press a custom checkout button that prefills the checkout fields. I am using this technique to achieve this: https://newpulselabs.com/prefill-checkout-fields-cartflows/
// Autofill checkout fields from URL
add_filter( 'woocommerce_checkout_fields' , 'prefill_billing_fields' );
function prefill_billing_fields ( $address_fields ) {
// Get the data from the URL
if ( isset( $_GET['fname'] ) || isset( $_GET['lname'] ) || isset( $_GET['email'] ) || isset( $_GET['company'] ) )
{
// wp_die();
$fname = isset( $_GET['fname'] ) ? esc_attr( $_GET['fname'] ) : '';
$lname = isset( $_GET['lname'] ) ? esc_attr( $_GET['lname'] ) : '';
$em = isset( $_GET['email'] ) ? esc_attr( $_GET['email'] ) : '';
$company = isset( $_GET['company'] ) ? esc_attr( $_GET['company'] ) : '';
// First Name
if( isset($_GET['fname']) && ! empty($_GET['fname']) ){
if( isset( $address_fields['billing']['billing_first_name'] ) ){
$address_fields['billing']['billing_first_name']['default'] = $fname;
}
}
// Last Name
if( isset($_GET['lname']) && ! empty($_GET['lname']) ){
if( isset( $address_fields['billing']['billing_last_name'] ) ){
$address_fields['billing']['billing_last_name']['default'] = $lname;
}
}
// Email
if( isset($_GET['email']) && ! empty($_GET['email']) ){
if(isset( $address_fields['billing']['billing_email'] )){
$address_fields['billing']['billing_email']['default'] = $em;
}
}
// Company
if( isset($_GET['company']) && ! empty($_GET['company']) ){
if(isset( $address_fields['billing']['billing_company'] )){
$address_fields['billing']['billing_company']['default'] = $company;
}
}
}
return $address_fields;
}
The url looks like this:
https://www.yourweburl.com/checkout-page/?email=name#example.com&fname=John&lname=Smith&company=ABC Company
And it works perfectly… for new visitors. If a visitor happened to have ordered before in the webshop (and used a different billing address) then that is stored locally in the browser and auto filled.
This technique will not overwrite existing/previous autofill values. I think because it is checking if the cell is empty or not:
if( isset($_GET['fname']) && ! empty($_GET['fname']) ){
if( isset( $address_fields['billing']['billing_first_name'] ) ){
$address_fields['billing']['billing_first_name']['default'] = $fname;
}
}
I tried disabling autofill on the checkout page with this:
add_filter('woocommerce_checkout_get_value','__return_empty_string', 1, 1);
Again that works so well that it removes all prefilled text. So it also removes the information I want to prefill. It works too good ;)
I prefer to alter the first code so that it always overwrites existing values, regardless of what is stored in the browser.
Can anyone help point me in the right direction of how to change the code?
Thanks a lot!
Koen

Related

Get a list of categories with a relationship to other category

I'm using a WordPress theme which has 3 different taxonomies. Country, State, City. So there are no parent child categories.
**What I'm trying to achieve:
**
On each state archive, I'm trying to show a list of cities and areas (each terms) which have a relationship with that state.
On each city archive, I want to show other cities (each terms) which have the same state.
This is how the theme currently saves the post meta for state, city and area:
// State
if( isset( $_POST['administrative_area_level_1'] ) ) {
$listing_state = sanitize_text_field( $_POST['administrative_area_level_1'] );
$state_id = wp_set_object_terms( $listing_id, $listing_state, 'listing_state' );
$homey_meta = array();
$homey_meta['parent_country'] = isset( $_POST['country'] ) ? $_POST['country'] : '';
if( !empty( $state_id) ) {
update_option('_homey_listing_state_' . $state_id[0], $homey_meta);
}
}
// City
if( isset( $_POST['locality'] ) ) {
$listing_city = sanitize_text_field( $_POST['locality'] );
$city_id = wp_set_object_terms( $listing_id, $listing_city, 'listing_city' );
$homey_meta = array();
$homey_meta['parent_state'] = isset( $_POST['administrative_area_level_1'] ) ? $_POST['administrative_area_level_1'] : '';
if( !empty( $city_id) ) {
update_option('_homey_listing_city_' . $city_id[0], $homey_meta);
}
}
// Area
if( isset( $_POST['neighborhood'] ) ) {
$listing_area = sanitize_text_field( $_POST['neighborhood'] );
$area_id = wp_set_object_terms( $listing_id, $listing_area, 'listing_area' );
$homey_meta = array();
$homey_meta['parent_city'] = isset( $_POST['locality'] ) ? $_POST['locality'] : '';
if( !empty( $area_id) ) {
update_option('_homey_listing_area_' . $area_id[0], $homey_meta);
}
}
Any advice is appreciated.
Thanks.

WooCommerce Session Variables Initialization

I'm trying to create a session variable in shop page and then I want to show this variable values in checkout page.
I wrote this code in woocommerce function page:
// Creating session variables
add_action( 'template_redirect', 'oturum_degiskeni_olustur' );
function oturum_degiskeni_olustur () {
if ( isset( $_GET['konumu'] ) || isset( $_GET['masa_no'] ) ) {
$konum = isset( $_GET['konumu'] ) ? esc_attr( $_GET['konumu'] ) : '';
$masa = isset( $_GET['masa_no'] ) ? esc_attr( $_GET['masa_no'] ) : '';
// Set the session data
WC()->session->set( 'custom_data', array( 'konum' => $konum, 'masa' => $masa ) );
}
}
// Show session variables in checkout page
add_action('woocommerce_before_checkout_form', 'yeni_alanlar');
function yeni_alanlar($checkout){
$data = WC()->session->get('custom_data');
echo '<div id="custom_checkout_field">';
if( isset($data['konum']) && ! empty($data['konum']) && isset($data['masa']) && ! empty($data['masa']) ){
echo '<p><strong>Konumunuz : </strong>' . $data['konum'] .'<br/><strong>Masanız : </strong>' . $data['masa'] .'</p>';
}
echo '</div>';
}
URL for session variables: www.domain.com/shop/?konumu=newyork&masa_no=12
But this code working when user's second visit.
For example; user use this custom URL and visit the shop page and continue to cart and checkout page. But, my code is not working. Then, user going to this custom URL again and continue to cart & checkout page and code is working this time.
It is not working when first visit.
Why is that? How can I solve this issue?
You need to early init customer session, so we will change template_redirect to init hook using the WC_Session_Handler method set_customer_session_cookie() like:
// Creating session variables
add_action( 'init', 'oturum_degiskeni_olustur' );
function oturum_degiskeni_olustur () {
// Early initialize customer session
if ( isset(WC()->session) && ! WC()->session->has_session() ) {
WC()->session->set_customer_session_cookie( true );
}
if ( isset( $_GET['konumu'] ) && isset( $_GET['masa_no'] ) ) {
$konum = isset( $_GET['konumu'] ) ? esc_attr( $_GET['konumu'] ) : '';
$masa = isset( $_GET['masa_no'] ) ? esc_attr( $_GET['masa_no'] ) : '';
// Set the session data
WC()->session->set( 'custom_data', array( 'konum' => $konum, 'masa' => $masa ) );
}
}
// Show session variables in checkout page
add_action('woocommerce_before_checkout_form', 'yeni_alanlar');
function yeni_alanlar(){
if( ( $data = WC()->session->get('custom_data') )
&& isset($data['konum']) && isset($data['masa']) ) {
echo '<div id="custom_checkout_field">
<p><strong>Konumunuz : </strong>' . $data['konum'] .'<br/>
<strong>Masanız : </strong>' . $data['masa'] .'</p>
</div>';
}
}
Now it should better work.

Pre-fill Woocommerce checkout fields with Url variables saved in session

When people enter the my woocommerce shop following a link in an sales email with email and name as parameters I would like to prefill the name and email in the checkout page.
Therefore I created an action and filter. This works as expected but only if I do a hard refresh on the sales page (ctrl + f5)
I've excluded the sales page and the checkout page from the cache and varnish cache but this didn't fix the issue.
Am I missing something here? Do you have any idea why this only works with a hard refresh?
Any help is greatly appreciated.
Code:
function save()
{
if ( is_page( 'sales-page' ) )
{
if ( isset( $_GET['tu_em'] ) ) {
global $woocommerce;
$woocommerce->session->set( 'tu_em', $_GET['tu_em'] );
}
if ( isset( $_GET['tu_name'] ) ) {
global $woocommerce;
$woocommerce->session->set( 'tu_name', $_GET['tu_name'] );
}
}
}
add_action( 'wp_enqueue_scripts', 'save_email' , 1100);
function override_checkout_email_field( $fields ) {
global $woocommerce;
$email = $woocommerce->session->get('tu_em');
if(!is_null($email)) {
$fields['billing']['billing_email']['default'] = $email;
}
$name = $woocommerce->session->get('tu_name');
if(!is_null($name)) {
$fields['billing']['billing_first_name']['default'] = $name;
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'override_checkout_email_field' );
Here below, you will find the correct working code, to save user data from an URL (GET) into WooCommerce sessions and to autofill with that data the related checkout fields.
URL will be like: http://example.com/sales-page/?tu_em=name#example.com&tu_name=theFirstName
This can be done from any URL as the code will detect the URL variable, when they are set.
The code;
// Save user data from URL to Woocommerce session
add_action( 'template_redirect', 'set_custom_data_wc_session' );
function set_custom_data_wc_session () {
if ( isset( $_GET['tu_em'] ) || isset( $_GET['tu_name'] ) ) {
$em = isset( $_GET['tu_em'] ) ? esc_attr( $_GET['tu_em'] ) : '';
$name = isset( $_GET['tu_name'] ) ? esc_attr( $_GET['tu_name'] ) : '';
// Set the session data
WC()->session->set( 'custom_data', array( 'email' => $em, 'name' => $name ) );
}
}
// Autofill checkout fields from user data saved in Woocommerce session
add_filter( 'woocommerce_billing_fields' , 'prefill_billing_fields' );
function prefill_billing_fields ( $address_fields ) {
// Get the session data
$data = WC()->session->get('custom_data');
// Email
if( isset($data['email']) && ! empty($data['email']) )
$address_fields['billing_email']['default'] = $data['email'];
// Name
if( isset($data['name']) && ! empty($data['name']) )
$address_fields['billing_first_name']['default'] = $data['name'];
return $address_fields;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Shipping information(send to another address) by default is auto we use that for autofill billing fildes
add_filter( 'woocommerce_checkout_fields' , 'ahmadyani_checkout_field_defaults', 20 );
function ahmadyani_checkout_field_defaults( $fields ) {
$user = get_user_meta(get_current_user_id());
$first_name = $user ? $user['shipping_first_name'][0] : '';
$last_name = $user ? $user['shipping_last_name'][0] : '';
$company = $user ? $user['shipping_company'][0] : '';
$shipping_address_1 = $user ? $user['shipping_address_1'][0] : '';
$shipping_address_2 = $user ? $user['shipping_address_2'][0] : '';
$shipping_city = $user ? $user['shipping_city'][0] : '';
$shipping_state = $user ? $user['shipping_state'][0] : '';
$shipping_postcode = $user ? $user['shipping_postcode'][0] : '';
$fields['billing']['billing_first_name']['default'] = $first_name;
$fields['billing']['billing_last_name']['default'] = $last_name;
$fields['billing']['billing_company']['default'] = $company;
$fields['billing']['billing_address_1']['default'] = $shipping_address_1;
$fields['billing']['billing_address_2']['default'] = $shipping_address_2;
$fields['billing']['billing_city']['default'] = $shipping_city;
$fields['billing']['billing_state']['default'] = $shipping_state;
$fields['billing']['billing_postcode']['default'] = $shipping_postcode;
return $fields;
}

Save custom user field in Woocommerce

I'm creating a simple plugin that lets me to save some input text fields while the user is registering on the site. This part works well.
But I want to let the users edit this fields on the user account page. I can load the saved info on the database but I can't update this info on the the user metadata.
This code puts the input on the register page, the others 4 possible inputs are dynamically added with jquery if the user clicks on the + button.
add_action ('register_form', 'save_dynamic_inputs', 10);
function save_dynamic_inputs() {
$user_cnpj = ( isset( $_POST['user_cnpj_1'] ) ) ? $_POST['user_cnpj_1'] : '';
$user_cnpj = ( isset( $_POST['user_cnpj_2'] ) ) ? $_POST['user_cnpj_2'] : '';
$user_cnpj = ( isset( $_POST['user_cnpj_3'] ) ) ? $_POST['user_cnpj_3'] : '';
$user_cnpj = ( isset( $_POST['user_cnpj_4'] ) ) ? $_POST['user_cnpj_4'] : '';
?>
<div class="cnpjs"><p><label for="user_cnpj_1"><?php _e( 'CNPJ', 'save_dynamic_inputs' ) ?><br /><input type="text" name="user_cnpj_1" id="user_cnpj_1" class="input" style="width: 445px; value="<?php echo esc_attr( stripslashes( $user_cnpj ) ); ?>" size="19" /><i class="button addmore fa fa-plus" aria-hidden="true"></i></label></p></div>
<?php
}
This another code saves every input if they exist in the user metadata, and this code works, but it's for the register form:
add_action( 'user_register', 'saving_my_dynamic_inputs', 10, 1 );
function saving_my_dynamic_inputs( $user_id ) {
for ($i = 1; $i < 5; $i++) {
if ( isset( $_POST['user_cnpj_'.$i] ) )
update_user_meta($user_id, 'user_cnpj_'.$i, $_POST['user_cnpj_'.$i]);
}
}
And this is the code that I'm using to update the user metadata on the user edit account page, this code does not work.
add_action('woocommerce_created_customer', 'update_fields_profile_user_woo', 10, 1);
function update_fields_profile_user_woo($customer_id) {
if ( isset( $_POST['user_cnpj_1'] ) ) {
update_user_meta($customer_id, 'user_cnpj_1', $_POST['user_cnpj_1']);
} else {
echo "<pre>",print_r($_POST),"</pre>";
exit();
}
}
Where you can read woocommerce_created_customer, I have tried woocommerce_save_account_details and others.
I don't understand why the inputs does not update the user metadata. I have tried to point the form to a php file that gets the $_POST var and prints this, and the array have all the inputs like the sample above:
Like I said, the user account profile loads all the inputs needed, but this last code does not update the info on user metadata.
Woocommerce handles all forms through Form Form Handler Class. You need to create an instance of that class and call its save_account_details method.
Another way to hook it with wp. It will be always invoked at the time of initialization.
function save_wc_additional_details() {
$user_id = get_current_user_id();
if( isset( $_POST['user_cnpj_1'] ) )
update_user_meta( $user_id, 'user_cnpj_1', sanitize_text_field( $_POST['user_cnpj_1'] ) );
if( isset( $_POST['user_cnpj_2'] ) )
update_user_meta( $user_id, 'user_cnpj_2', sanitize_text_field( $_POST['user_cnpj_1'] ) );
if( isset( $_POST['user_cnpj_3'] ) )
update_user_meta( $user_id, 'user_cnpj_3', sanitize_text_field( $_POST['user_cnpj_1'] ) );
if( isset( $_POST['user_cnpj_4'] ) )
update_user_meta( $user_id, 'user_cnpj_4', sanitize_text_field( $_POST['user_cnpj_1'] ) );
}
add_action( 'wp', 'save_wc_additional_details' );

Redirect to billing address setup page if the user metadata is not set

I want to make sure that all customers who register on my WordPress (with WooCommerce) site fill up their billing information before doing anything else.
Whenever customers login for the first time, filling up the billing information should be the first thing they do.
To do this, I added the following code in my themes's function.php:
add_action( 'wp', 'is_billing_address_set' );
function is_billing_address_set()
{
$curr_url = $_SERVER['PHP_SELF'];
if(is_user_logged_in ()){
if(strstr($curr_url, 'my-account/edit-address/billing') == false){
$current_user_id = get_current_user_id ();
$billing_country = get_user_meta ($current_user_id, 'billing_country', true);
if($billing_country == null || $billing_country == false || $billing_country == ""){
wp_redirect( 'https://localhost/my-account/edit-address/billing/' );
}
}
}
}
I know this is a wrong approach since it will create an infinite redirect loop.
In my wp_redirect function I am hard coding the absolute URL so I will have to change this code everytime my server location changes.
How can I solve this problem correctly?
---- (update) : This is tested and work perferctly
Finally you don't need any hook to do what you want, you just need to paste this snippet in your function.php file. With this approach, you will prevent:
Infinite redirect loop
Hardcoding the absolute URL
Simplified condition with empty()
Url errors on multi language website
I have test it, and it works just perfectly:
if(is_user_logged_in ()){
// Queried URL
$curr_url = home_url(add_query_arg(array(),$wp->request));
// localisable "Edit billing information" path
$edit_billing_path = __('/my-account/edit-address/billing', 'woocommerce');
// Target URL
$targ_url = home_url($edit_billing_path);
if ( !strstr($curr_url, $targ_url) ) {
$user_id = get_current_user_id ();
$billing_country = get_user_meta ($user_id, 'billing_country', true);
if ( empty( $billing_country ) ) {
wp_redirect( $targ_url );
}
}
}
With this little piece of code you can avoid, as you want, logged user to do anything until they have filled and completed their billing information.
You can also use multiple conditions based on different billing fields to redirect user. This way each field has to be filled and completed. This is just an example, and you can add, replace or remove any field to feet your needs:
if(is_user_logged_in ()){
// Queried URL
$curr_url = home_url(add_query_arg(array(),$wp->request));
// localisable "Edit billing information" path
$edit_billing_path = __('/my-account/edit-address/billing', 'woocommerce');
// Target URL
$targ_url = home_url($edit_billing_path);
if ( !strstr($curr_url, $targ_url) ) {
$user_id = get_current_user_id ();
// Using multiple condition based on user multiple billing fields
$first_name = get_user_meta ($user_id, 'billing_first_name', true);
$last_name = get_user_meta ($user_id, 'billing_last_name', true);
$address = get_user_meta ($user_id, 'billing_address_1', true);
$city = get_user_meta ($user_id, 'billing_city', true);
$country = get_user_meta ($user_id, 'billing_country', true);
if ( empty( $first_name ) && empty( $last_name ) && empty( $address ) && empty( $city ) && empty( $country ) ) {
wp_redirect( $targ_url );
}
}
}
All code is tested and working.
References:
How to get the current URL using wordpress… (Getting current queried Url)
Codex: home_url() (An alternative to hard coded Url)
Using empty(), is_null(), isset() or array_key_exists() as conditions
Gettex - I18n for WordPress Developers (Localisable strings)
This is the solution for plain url permalink and for preserving admins to be redirected in backend...
maybe useful for those who don't get this working
if( is_user_logged_in () && !is_admin() ){
// interroghiamo l'url corrente
global $wp;
$curr_url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
//$curr_url = home_url(add_query_arg(array(),$wp->request));
// path per la localizzazione
$edit_billing_path = __('/myaccount/edit-address/fatturazione', 'woocommerce');
// Target URL
$targ_url = home_url($edit_billing_path);
if ( !strstr($curr_url, $targ_url) ) {
$user_id = get_current_user_id ();
$billing_city = get_user_meta ($user_id, 'billing_city', true);
if ( empty( $billing_city ) ) {
wp_redirect($targ_url);
//echo $targ_url;
//echo $curr_url;
}
}
}

Categories