Save cart on the current session - wordpress

I'm building a wordpress ecommerce site with the woocommerce plugin, it turns that when an user gets logged in and add products to his cart, but the user don't want to proceed to the checkout process, the user prefers to logout and continue with the checkout process later... when the user comes back and gets logged in again the cart is empty.
What is going on here?.
Is this a normal behavior of woocommerce?.
Do I have to do something else? maybe a plugin?
Thanks.

I thought that the cart is emptied when a user logs out, and I finally tracked it down.
On wp_logout() WordPress runs wp_clear_auth_cookie() function. wp_clear_auth_cookie() triggers the do_action( 'clear_auth_cookie' ); action hook.
WooCommerce's Session handler class then runs it's destroy method on this hook.
add_action( 'clear_auth_cookie', array( $this, 'destroy_session' ) );
The destroy_session() method then calls the wc_empty_cart() function, which is a wrapper for the cart class's empty_cart() method.
WC()->cart->empty_cart( false );
But the key thing here is that the parameter is false. Because when we finally track down the empty_cart() method we see that the default is true.
/**
* Empties the cart and optionally the persistent cart too.
*
* #access public
* #param bool $clear_persistent_cart (default: true)
* #return void
*/
public function empty_cart( $clear_persistent_cart = true ) {
$this->cart_contents = array();
$this->reset();
unset( WC()->session->order_awaiting_payment, WC()->session->applied_coupons, WC()->session->coupon_discount_amounts, WC()->session->cart );
if ( $clear_persistent_cart && get_current_user_id() ) {
$this->persistent_cart_destroy();
}
do_action( 'woocommerce_cart_emptied' );
}
When passing true the persistant_cart_destroy() method is called and it is this method that deletes the meta data where the user's cart is kept.
/**
* Delete the persistent cart permanently.
*
* #access public
* #return void
*/
public function persistent_cart_destroy() {
delete_user_meta( get_current_user_id(), '_woocommerce_persistent_cart' );
}
SO, all of that is to say that I do not think the cart should be emptied when a user logs out and then back in. A little more evidence is that WooCommerce attempts to load the persistent cart as soon as a user logs back in.
/**
* Load the cart upon login
*
* #param mixed $user_login
* #param integer $user
* #return void
*/
function wc_load_persistent_cart( $user_login, $user = 0 ) {
if ( ! $user )
return;
$saved_cart = get_user_meta( $user->ID, '_woocommerce_persistent_cart', true );
if ( $saved_cart )
if ( empty( WC()->session->cart ) || ! is_array( WC()->session->cart ) || sizeof( WC()->session->cart ) == 0 )
WC()->session->cart = $saved_cart['cart'];
}
add_action( 'wp_login', 'wc_load_persistent_cart', 1, 2 );
I would try disabling all other plugins to see if the behavior reverts back to what I think is the normal behavior. From there, you can re-enable them one at a time to isolate the culprit.

I faced same problem and solved it by placing following function to my functions.php file:
/**
* Load the persistent cart if exists
*
* #return void
*/
function adian_load_persistent_cart(){
global $current_user;
if( ! $current_user )
return false;
$saved_cart = get_user_meta( $current_user->ID, '_woocommerce_persistent_cart', true );
if ( $saved_cart ){
if ( empty( WC()->session->cart ) || ! is_array( WC()->session->cart ) || sizeof( WC()->session->cart ) == 0 ){
WC()->session->set('cart', $saved_cart['cart'] );
}
}
}
add_action( 'init', 'adian_load_persistent_cart', 10, 1 );
Function checks if the user has persistent cart saved and replaces session cart with it.

Related

"woocommerce_can_reduce_order_stock" filter is not working on backend

I have a custom order status called 'quote', and I have added the following code to try and prevent stock levels being decremented for orders with this status.
function bw_do_not_reduce_quote_stock( $reduce_stock, $order ) {
if ( $order->has_status( 'quote' ) ) {
$reduce_stock = false;
}
return $reduce_stock;
}
add_filter( 'woocommerce_can_reduce_order_stock', 'bw_do_not_reduce_quote_stock', 10, 2 );
This works for orders placed on the front-end website. But if the admin adds or edits an order on the backend, the stock is decremented.
Is there an alternative hook for the backend? Or am I missing something else?
In addition to your current code, add the woocommerce_prevent_adjust_line_item_product_stock filter hook
/**
* Prevent adjust line item
*
* #param $prevent
* #param $item
* #param $quantity
*/
function filter_woocommerce_prevent_adjust_line_item_product_stock ( $prevent, $item, $quantity ) {
// Get order
$order = $item->get_order();
if ( $order->has_status( 'quote' ) ) {
$prevent = true;
}
return $prevent;
}
add_filter( 'woocommerce_prevent_adjust_line_item_product_stock', 'filter_woocommerce_prevent_adjust_line_item_product_stock', 10, 3 );

How to use upgrader_process_complete hook in WordPress to check for spcific plugin update

Is it possible to use upgrader_process_complete hook to check if only a specific plugin is updated?
I want to run a function every time a certain plugin is updated, for example warn the user about the changes or updating the database.
Yes, for it you can use this code:
/**
* This function runs when WordPress completes its upgrade process
* It iterates through each plugin updated to see if ours is included
* #param $upgrader_object Array
* #param $options Array
*/
function wp_upe_upgrade_completed( $upgrader_object, $options ) {
// The path to our plugin's main file
$our_plugin = plugin_basename( __FILE__ );
// If an update has taken place and the updated type is plugins and the plugins element exists
if( $options['action'] == 'update' && $options['type'] == 'plugin' && isset( $options['plugins'] ) ) {
// Iterate through the plugins being updated and check if ours is there
foreach( $options['plugins'] as $plugin ) {
if( $plugin == $our_plugin ) {
// Your action if it is your plugin
}
}
}
}
add_action( 'upgrader_process_complete', 'wp_upe_upgrade_completed', 10, 2 );

How do I properly test a wordpress Cron job?

Simple Abandoned Cart
https://github.com/gregbast1994/msp-abandoned-cart
This plugin simply skims emails at checkout and saves the cart session data. Then we set a cron job to check if the session became an order, if not set another for tomorrow to email the user. Simple abandoned cart functionality.
I've checked the list of cron jobs and can see the 'await_order_for_cart_..' job. I've also dumped the $wp_filter to check if I can find my function connected to a hook anywhere. I've tried making the functions attached to the job static.
The job dumped looks like
[1566572607] => Array
(
[await_order_for_cart_04ff0471d799d19b53034ef078a600d8] => Array
(
[e0f32ed5d8b7b8d89f1d8f832df788f2] => Array
(
[schedule] =>
[args] => Array
(
[hash] => 04ff0471d799d19b53034ef078a600d8
[item_count] => 1
[customer_id] => aeac13344550563f2be4186690b44ef5
)
)
)
)
First setup the first job to check if the session becomes an order.
public function get_data( $email = '' )
{
...
$this->set_wait_for_order_cron();
}
public function set_wait_for_order_cron()
/**
* Creates a unique hook using cart hash, schedules a check on cart
*/
{
if( empty( $this->cart['hash'] ) ) return;
$hook = 'await_order_for_cart_' . $this->cart['hash'];
$this->hooks['before'] = $hook;
$one_hour = time() + 30;
if( ! wp_next_scheduled( $hook ) ){
wp_schedule_single_event( $one_hour, $hook, $this->cart );
add_action( $hook, array( $this, 'check_order_for_cart' ) );
}
}
I do not think the check_order_for_cart ever runs because I never see the 'email_customer_abandoned_cart_...' job.
public static function get_session( $customer_id )
{
$handler = new WC_Session_Handler();
return $handler->get_session( $customer_id );
}
public static function check_order_for_cart( $cart )
{
/**
* Splits up the session cookie, uses the first part to grab the cart session
* If session is false, that means the cart expired or was order.
*/
$session = $this->get_session( $cart['customer_id'] );
if( false !== $session ){
$hook = 'email_customer_abandoned_cart_' . $cart['hash'];
$this->hooks['after'] = $hook;
wp_schedule_single_event( time() + DAY_IN_SECONDS, $hook, $cart );
add_action( $hook, array( $this, 'email_customer_abandoned_cart' ) );
}
// kill action
remove_action( $this->hooks['before'], array( $this, 'check_order_for_cart' ) );
}
Well, I expect that after the first job runs, the second job is created and in the cron queue. I expect when that second job runs that my email is sent and my customer comes back and buys lots of dildo's from me.

Wordpress if current users is

I have the following a function in my functions.php:
function admin_style()
{ global $user_ID;
if ( current_user_can( 'shop_manager') )
{ wp_enqueue_style('admin-styles', '/wp-content/themes/electa-child/admin.css');
}}
add_action('admin_enqueue_scripts', 'admin_style');
I would like to add another user role but when I do if ( current_user_can( 'shop_manager', 'shop_assistant') ) I am getting an error.
How should I add another user role to be checked upon?
Thanks in advance,
Please try
if( current_user_can('shop_manager') || current_user_can('shop_assistant') )
You can get you current user role (translated) like this.
then you can play around with it.
/**
* Returns the translated role of the current user.
* No role, get false.
*
* #return string The translated name of the current role.
**/
function get_current_user_role() {
global $wp_roles;
$current_user = wp_get_current_user();
$roles = $current_user->roles;
$role = array_shift( $roles );
return isset( $wp_roles->role_names[ $role ] ) ? translate_user_role( $wp_roles->role_names[ $role ] ) : FALSE;
}

Any change in post update inlcuding metadata?

Having code below (given in a class)
class X
{
public function __construct()
{
add_action( 'post_updated', array( $this, 'datachangecheck' ), 10, 3 );
}
function datachangecheck( $post_id, $post_after, $post_before )
{
if ( $post_before->post_title != $post_after->post_title )
{
//do whatever
}
return;
}
}
Above works fine when checking if a title has been changed, but is there any away way of managing the same thing when having metadata related to it?
I only want to know if any data has changed (I don't need any returned values). I can't manage to find any hook where I can see like meta_post_before and meta_post_after or similar. Can someone point me into right direction? Thank you!
This was kind of tricky, so I guess someone else might have the same issue so I share some code here and hopefully someone has any help from it :-) I have the most important part in the code below:
public function __construct()
{
add_action( 'post_updated', array( $this, 'datachangecheck' ), 10, 3 );
}
/*
* datachangecheck
*
* This function is called upon hook post_updated.
* The function checks if data for updated post has been changed,
* and saves a file when data has been changed
*
* #param string $post_id id of post affected
* #param WP_Post $post_after WP_Post after post has been updated
* #param WP_Post $post_before WP_Post before post has been updated
* #return N/A
*
*/
function datachangecheck( $post_id, $post_after, $post_before )
{
//Cast postobjects into arrays, so comparision is possible with builtin-php functions
$spf = (array)$post_before;
$spa = (array)$post_after;
//These would differ every update. so remove them for possible comparision
unset ( $spf['post_modified']);
unset ( $spf['post_modified_gmt']);
unset ( $spa['post_modified']);
unset ( $spa['post_modified_gmt']);
//Check if any difference between arrays (if empty no difference)
//If not empty, save file that tells plugin that data has been changed
$ard = array_diff ( $spf, $spa);
if ( !empty ( $ard ) )
{
$this->datahaschanged_save();
}
else
{
//No change of post native data, check if any metapost data has been changed
//Remove edit_last and edit_lock because they could differ without data being changed
$this->metadata_before = get_post_meta( $post_id );
unset ( $this->metadata_before['_edit_last']);
unset ( $this->metadata_before['_edit_lock']);
add_action('updated_post_meta', array( $this, 'checkmetadata_after'), 10, 2);
}
return;
}
/*
* checkmetadata_after
*
* This function is called upon hook updated_post_meta when data has been update, but no change in native post data
* has been made and saves a file when data has been changed
*
* #param string $post_id id of post affected
* #param WP_Post $post_after WP_Post after post has been updated
* #param WP_Post $post_before WP_Post before post has been updated
* #return N/A
*
*/
function checkmetadata_after( $meta_id, $post_id )
{
//Because updated_post_meta is used, now we can grab the actual updated values
//Remove edit_last and edit_lock because they could differ without data being changed
$this->metadata_after = get_post_meta( $post_id );
unset ( $this->metadata_after['_edit_last']);
unset ( $this->metadata_after['_edit_lock']);
//Make one-level index arrays of metadata
//so array_diff works correctly down below
$arr_mdb = $this->onelevel_array( $this->metadata_before );
$arr_mda = $this->onelevel_array( $this->metadata_after );
//Compare array with metapost values before and after
//If not empty, save file that tells plugin that data has been changed
$ard_metadata = array_diff ( $arr_mdb, $arr_mda );
if (!empty ( $ard_metadata))
{
$this->datahaschanged_save();
}
return;
}

Resources