WooCommerce: How to retain checkout info when client leaves then comes back? - php

Is there a simple way or a plugin to retain checkout information entered by the client after he/she leaves and comes back?
This plugin retains "fields information for customers when they navigate back and forth" however it has quite a lot of recent bad reviews so I don't think I'll use that for production. Any alternative suggestion?

---- Update ----
The code below is working, but only if data is submitted!
The only possible ways are javascript/jQuery form event detection on checkout fields and worpress Ajax:
Using ajax connected to some session transients function (as in code below).
Using (javascript) web Storage: localStorage, sessionStorage…
I have found some real interesting code in this thread that is using sessions transients to store checkout data.
// this function sets the checkout form data as session transients whenever the checkout page validates
function set_persitent_checkout ( $a ) {
$arr = array();
foreach ( $a as $key => $value )
if ( ! empty($value) )
$arr[$key] = $value;
WC()->session->set( 'form_data', $arr );
return $a;
}
add_action( 'woocommerce_after_checkout_validation', 'set_persitent_checkout' );
// this function hooks into woocommerce_checkout_get_value to substitute standard values with session values if present
function get_persistent_checkout ( $value, $index ) {
$data = WC()->session->get('form_data');
if ( ! $data || empty($data[$index]) )
return $value;
return is_bool($data[$index]) ? (int) $data[$index] : $data[$index];
}
add_filter( 'woocommerce_checkout_get_value', 'get_persistent_checkout', 10, 2 );
// This is a fix for the ship_to_different_address field which gets it value differently if there is no POST data on the checkout
function get_persitent_ship_to_different ( $value ) {
$data = WC()->session->get('form_data');
if ( ! $data || empty($data['ship_to_different_address']) )
return $value;
return is_bool($data['ship_to_different_address']) ? (int) $data['ship_to_different_address'] : $data['ship_to_different_address'];
}
add_action( 'woocommerce_ship_to_different_address_checked', 'get_persitent_ship_to_different' );
Add this code to the functions.php file located in your active child theme or theme.
Explanations from the author:
1. Save the form data:
The first function set_persitent_checkout hooks into woocommerce_after_checkout_validation.
Whenever that hook is fired, any current form data is saved as a WordPress transient via the WC_Session_Handler class (which was recently updated in version 2.5 to be a lot more efficient).
2. Check the saved data on reload:
Next we hook woocommerce_checkout_get_value with get_persitent_checkout. As the name suggests, here we check the session transients and return any matches for the current field if found.
3. Make ship_to_different_address work:
The only difficult was the ship_to_different_address field, which gets its value through a different method.
To get around this the final function was added. This works exactly the same as the previous function, but hooks into woocommerce_ship_to_different_address_checked.
There you have it. It would be nice if the data was saved after every field update on checkout, but the woocommerce_after_checkout_validation hook fires enough to capture the data at all the important points.

Functions.php snipped posted by LoicTheAztec didn't work for me.
I found this plugin which remembers everything I type or select in Woocommerce checkout, including shipping fields and my custom additions to the template:
Save Abandoned Carts – WooCommerce Live Checkout Field Capture
Account passwords, if creating during checkout, are naturally not remembered.

Related

Add custom fields to Stripe checkout information and send via webhook

I am using wordpress to build a website that uses Stripe as its payment gateway.
Through the Paid Membership Pro plugin I have configured my Stripe connection.
The issue I am faced with is that I need to append a custom field, in this case a unique identifier for the customer, to the payment information for it to be available to send via my webhook to my server for processing.
I have come across a load of answers but none seem to be doing exactly what I am looking for.
I noticed in the PMPro plugin it allows you to add User Fields which I presumed would be a way to add custom data to the information but after checking the JSON payloads in Stripe none of the user field information is available.
I then tried adding the code from this answer to my functions.php file in word press just using a test meta key but again this information was not available in the payloads.
I am not using woocommerce.
How can I achieve this?
So I was able to crack this using a php script that intercepts the Stripe checkout event.
I added this as a snippet to my Wordpress site and to read in a custom field from the post submit.
Stripe allows you to add custom filed data to the metadata block and once populated this was successfully sent to my webhook.
function my_pmpro_stripe_params_send_user_id( $params, $order = null ) {
global $my_pmpro_checkout_order;
if ( empty( $params['metadata'] ) ) {
$params['metadata'] = array();
}
if ( empty ( $order ) ) {
// Save order while creating payment intent.
$order = $my_pmpro_checkout_order;
} else {
// Use saved order while creating subscription.
$my_pmpro_checkout_order = $order;
}
$params['metadata']['my_custom_field'] = $_POST['my_custom_value'];
return $params;
}
add_filter( 'pmpro_stripe_payment_intent_params', 'my_pmpro_stripe_params_send_user_id', 10, 2 );
add_filter( 'pmpro_stripe_create_subscription_array', 'my_pmpro_stripe_params_send_user_id', 10, 1 );

How to change which choice in a Gravity Forms radio button field is selected using PHP as part of a gform_pre_submission

My PHP skills are not good but I learn by code example because I am not familiar with the syntax, but in this case I can not find a code example that works.
I want to set a Product Option Radio Button Field's selected value during a gform_pre_submission add_action based on another field's value. I've tried something like this (there are other functions and variables are defined elsewhere in advance, this is an abstract) but this approach isn't working for me and I am wondering what I am missing:
add_action( 'gform_pre_submission_FORMIDhere', 'select_radio_button' );
function select_radio_button( $form) {
foreach( $form['fields'] as &$field ) {
if( 53 === $field->id ) {
foreach( $field->choices as &$choice ) {
echo($aag_kg_nummorn.' / /'.$choice['value']);
if( $aag_kg_nummorn == $choice['value'] ) {
echo('Bingo!');
$choice['isSelected'] = true; // <- THIS line doesn't work for me
}
}
}
}
return $form;
}
Thank you for helping me in advance.
There are a couple of things I want to point out before answering
You should be modifying $_POST instead of the field, I can see you already figured this out.
gform_pre_submission is an action, not a filter, so returning the form here doesn't do anything.
The Answer
Say you have a product option field that has the ID of 2, and it has 3 options
First Option|1
Second Option|2
Third Option|3
Then the code will look like
add_action( 'gform_pre_submission_FORMIDhere', 'select_radio_button' );
function select_radio_button( $form ) {
$_POST['input_2'] = 'New Option|6';
}
I assume you are using this with a payment form that utilizes one of the gravityforms payment add-ons like stripe or Paypal, some of these add-ons (like PayPal Checkout) sends the total value to the payment gateway using JS before this action is fired, so the total value sent to the payment gateway will be the value of the option the user has already selected, but the total value on the entry will use the value you set in the code.
If you need help on how to override this from the JS side as well so you can send the overridden value to the payment gateway, I can write that in a separate answer.

How to make woocommerce shop page with a custom post type +and a checkout page

I am sharing 3 screens step by step will be through woocommerce.
I have a shop page. On selecting a product, I will go to a front end form for creating a post. After creating a post I will go to checkout page.
My question is that, can I get the middle one (front end form for creating a post) in woocommerce platform ?
Please look my shared screen for understanding it better.
Thank you
First Screen
Second Screen
Third Screen
My question is that, can I get the middle one (front end form for
creating a post) in woocommerce platform ?
Sure, but you have to save the data from step 2 in the current session (cart).
Only when an order is created, collect the session data and create the (custom_post_type) job post. You don't want to create the job post before the order is completed / paid for.
Your question is very general, so you can expect a similar answer. We do not build complete plugins here. You will need to use multiple hooks to complete this.
EDIT: some more info
# step 2, collect, sanitize and validate the form values.
I would save this data in the cart session. something like this:
// I don't know how and where you collect the step 2 data,
// so i can't provide a hook for this function.
function step_2_data_to_session() {
global $woocommerce;
$step_two_data = array();
// validate and sanitize data first
// save data to woocommerce session
$woocommerce->session->set('step_two_data', $step_two_data );
}
Then when the user pays and creates an order, use a hook to collect the session data and save it to your costom post type.
add_action('woocommerce_checkout_update_order_meta', 'new_order', 10, 2)
function new_order($order_id, $data) {
global $woocommerce;
// At this point the order is created and the session data is still alive.
if(! is_admin() ) {
$step_two_data = $woocommerce->session->get('step_two_data');
if($step_two_data) {
$args = array(
'post_author' => get_current_user_id(),
'post_title' => 'The Job title here',
'post_type' => 'job',
'post_status' => 'publish'
);
$new_job_post_id = wp_insert_post($args);
if($new_job_post_id) {
// Job post is saved now..
// Now you'll probably want to add step_two_data as meta data to the post.
}
}
}
}
NOTE: I haven't tested this code, error handling is not included, etc. This is just a pointer how to save the session data when the order is created.
You'll have to do much more, for example, i see that the job listing has a set expiration date. I would use a cron-job to daily check which jobs have to be removed, with the same cron i would also inform customers their job post 'will be removed in 2 days' etc etc ;-)
Regards, Bjorn

Add custom checkout field as Order custom-meta data in Woocommerce 3

before WooCommerce 3.0 came out my code had worked like a charm to save custom values from the cart into the order on checkout. But since then I'm not able to create custom meta for orders.
Environment: Wordpress 4.9.4 & WooCommerce 3.3.3
Hooks
add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
add_action('woocommerce_checkout_create_order', 'custom_meta_to_order', 20, 1);
The Hook number 1 is the one I tried the most, the 2 one was just an experiment with some literal changes mentioned in this topic.
Function
The following functions-code is related to hook number 1:
if (!function_exists('custom_meta_to_order')) {
function custom_meta_to_order($order_id, $values) {
$order = wc_get_order( $order_id );
$order->update_meta_data('_TESTKEYstart', 'Hello');
if (isset($values['myValue'])) {
$myValue = $values['myValue'];
if (!empty($myValue)) $order->update_meta_data('_myKey', $myValue);
}
$order->update_meta_data('_TESTKEYend', 'Bye');
$order->save();
}
}
I've checked also in the mySQL table table wp_woocommerce_order_itemmeta if at least the two _TESTKEY*-meta-entrys will be created (because they don't have a condition).
But it seems that the meta-keys and values don't getting created via this hook and function.
The function itself getting called, so at least the hooks itselfs are working.
So my question is: "What am I doing wrong?"
UPDATED: There is some errors in your code…
Both hooks have only 1 argument (not 2, so $values doesn't exist)
To get your custom field you should use $_POST['myValue'] instead.
and other things like each hook has a different argument:
$order_id for woocommerce_checkout_update_order_meta
$order for woocommerce_checkout_create_order
Below I have replaced $_POST['myValue'] by $_POST['billing_country'] as you don't give the code for this custom checkout field…
So here are both ways:
1) The best way for me, as explained here:
if ( ! function_exists('custom_meta_to_order') ) {
add_action( 'woocommerce_checkout_create_order', 'custom_meta_to_order', 20, 1 );
function custom_meta_to_order( $order ) {
$order->update_meta_data('_TESTKEYstart', 'Hello');
if (isset($_POST['billing_country'])) {
$myValue = $_POST['billing_country'];
if (!empty($myValue)) $order->update_meta_data('_my_key', $myValue);
}
$order->update_meta_data('_TESTKEYend', 'Bye');
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
2) The other way:
if ( ! function_exists('custom_meta_to_order') ) {
add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
function custom_meta_to_order( $order_id ) {
// get an instance of the WC_Order object
$order = wc_get_order( $order_id );
$order->update_meta_data('_TESTKEYstart', 'Hello');
if (isset($_POST['billing_country'])) {
$myValue = $_POST['billing_country'];
if (!empty($myValue)) $order->update_meta_data('_my_key', $myValue);
}
$order->update_meta_data('_TESTKEYend', 'Bye');
// Save the order data and meta data
$order->save();
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
The proof:
And (in database wp_postmeta table for this order ID):
Tested in WooCommerce version 3.3+
You can use the old way too (which works):
if ( ! function_exists('custom_meta_to_order') ) {
add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
function custom_meta_to_order( $order_id ) {
update_post_meta( $order_id, '_TESTKEYstart', 'Hello' );
if ( isset( $_POST['billing_country'] ) ) {
$myValue = $_POST['billing_country'];
if (!empty($myValue))
update_post_meta( $order_id, '_my_key', $myValue);
}
update_post_meta( $order_id, '_TESTKEYend', 'Bye');
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
Related: Add extra meta for orders in Woocommerce
Because comments are really hard to read (because of to much restricted formatation), this answer is just a response to the answer from LoicTheAztec.
I wrote a longer answer but it seems gone, so I sorry now for the much shorter one!
First our misunderstanding
You understood that I would like to use custom values from products but in my case it was a little bit other. I wrote an external application which included the wp-load.php and posted then data back to the product-page into the cart.
So the problem showed up here was the attempt to write the data from the cart into the order on checkout.
Recommend ways doesn't worked at first
The recommend ways you suggested all doesn't worked. I also stripped them so much down that they have should work and just write something into the meta. I've no clue which plugin/theme-function pranked me this time here.
But I was able to solve the problem
And many more! Just because I found the blog-post where I found out in the past, how to do this and as addition to my personal luck the author wrote already the changes for WP3.0, related to this process.
Still your post helped me
The errors you showed me bugged me since then and because it was hard to follow and inspect everything with Sublime and CodeIntel (and my start with Symfony itself) I decided to buy PHPStorm which showed and allowed me to fix all of my deprecated (legacy-using) functions by updating them properly.
( Finally no more global-variables: Yay. )
I mean, showing up parameters inline and deprecation-strokes already did a great job. But a bug-free working code-intel/reference which doesn't dies on big projects is just awesome.
That's why I marked your answer now as solution, thanks. Otherwise I would have just fixed the problem maybe (thanks to the authors blog-post) but still would sit on a ticking time bomb.

Subscription Frequency and Price Change hook in Woocommerce Subscriptions

Maybe I overlooked it, but as much as I searched, I could not find which action to hook when a subscription changes price or frequency in Woocommerce Subscriptions.
The documentation says that to support price changes in your payment gateway you have to list subscription_amount_changes, but nowhere it says which function will be called when the amount actually changes..
Also in the Action reference I was unable to find an action hook which is called when the subscription amount or frequency changes. If anyone has a clue which hook to use or how to implement this particular feature, please tell me.
Edit
Ok thanks for the comments and answer by #Reigel, so if I understand correctly the change of a subscription in the admin menu (which I indeed refer to), has to be handled by the save_post action. Could you provide a small example how to hook this action and check if it is a subscription and get the $order_id (I guess this is the same as post_id?) to use in the subscription management calls?
Thank you very much already!
This should be considered an addon to the answer by #Reigel. If you upvote this, upvote his answer too.
Here's an example of hooking the pre_post_update action. It occurs a little before the save_post action. Both actions are triggered in the wp_insert_post() function in post.php.
function post_save_subscription_check( $post_ID, $data )
{
if( $data['post_type'] == 'product' ) {
if (!empty($_POST['_subscription_price']) && get_post_meta($post_ID, '_subscription_price', true) != $_POST['_subscription_price']) {
/* do stuff here */
}
if (!empty($_POST['_subscription_period']) && get_post_meta($post_ID, '_subscription_period', true) != $_POST['_subscription_period']) {
/* do stuff here */
}
}
}
add_action('pre_post_update', 'post_save_subscription_check', 10, 2 );
In the logic we are checking for the old value, obtained with get_post_meta() and the new value, held in the $_POST variable and comparing them.
This code only executes when a post updates, not for a new post
The code gets placed in your theme functions.php or custom plugin code.
In live code I would recommend cleaning any $_POST data before using it. I haven't bothered here.
I will try to explain about supports.
subscription_amount_changes is just a support and will not fire anything. You can use it for conditional statements, like:
if ( !$chosen_gateway->supports( 'subscription_amount_changes' )) {
echo 'Please be considerate and do not change the price for the chosen gateway does not support it.';
}
now, other plugins can then check if the chosen gateway supports subscription_amount_changes and do their appropriate actions.
action hook which is called when the subscription amount or frequency
changes
subscription is just a product type. Which means this is just a post with a post_type of product. The amount and frequency are just post meta. all are handled on save_post action. add_action( 'save_post', __CLASS__ . '::save_subscription_meta', 11 );. This is on the post_type=product. You have to check also for save_post on post_type=shop_order as it's more appropriate for checking support. Because there's already a gateway chosen.

Categories