I have been trying to build a custom api endpoint to add to cart. My local is working fine and adding the product to the cart easily. I made the code live and getting an error like:
Call to a member function generate_cart_id() on null
Here is the code I have written.
add_action('rest_api_init', function () {
register_rest_route( 'product/v1', 'add_to_cart',array(
'methods' => 'POST',
'callback' => 'wplms_add_to_cart'
));
});
function wplms_add_to_cart($request) {
$product_id = $request['product_id'];
$product_cart_id = WC()->cart->generate_cart_id($product_id);
if( ! WC()->cart->find_product_in_cart( $product_cart_id ) ){
// The product ID is NOT in the cart, let's add it then!
$added = $cart->add_to_cart( $product_id);
}
$response = new WP_REST_Response(var_dump($added));
$response->set_status(200);
return $response;
}
The way I resolved it.
if ( defined( 'WC_ABSPATH' ) ) {
// WC 3.6+ - Cart and other frontend functions are not included for REST requests.
include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
include_once WC_ABSPATH . 'includes/wc-template-hooks.php';
}
if ( null === WC()->session ) {
$session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
WC()->session = new $session_class();
WC()->session->init();
}
if ( null === WC()->customer ) {
WC()->customer = new WC_Customer( get_current_user_id(), true );
}
if ( null === WC()->cart ) {
WC()->cart = new WC_Cart();
// We need to force a refresh of the cart contents from session here (cart contents are normally refreshed on wp_loaded, which has already happened by this point).
$cart = WC()->cart->get_cart();
$product_cart_id = WC()->cart->generate_cart_id($request['product_id']);
$cart_item_key = WC()->cart->find_product_in_cart($product_cart_id);
if (!$cart_item_key) {
$add = WC()->cart->add_to_cart( $product_id = $request['product_id'], $quantity = 1, $variation_id = 0, $variation = array(), $cart_item_data = array() );
} else {
$add = false;
}
}
Related
I am trying to implement a function that will check if a customer has ever bought ANY product from my shop before, and if not - provide them with a free "sign-up gift" on first purchase.
I am able to automatically add the product to the cart fine enough, but the issue occurs afterwards - the product keeps getting added to the cart even after a customer has made a purchase.
Code below - can't figure what the issue might be.
function has_bought( $user_id = 0 ) {
global $wpdb;
$customer_id = $user_id == 0 ? get_current_user_id() : $user_id;
$paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$results = $wpdb->get_col( "
SELECT p.ID FROM {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $paid_order_statuses ) . "' )
AND p.post_type LIKE 'shop_order'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = $customer_id
" );
// Count number of orders and return a boolean value depending if higher than 0
return count( $results ) > 0 ? true : false;
}
function aaptc_add_product_to_cart() {
if( ! has_bought() && ! is_admin() && is_user_logged_in() ) {
$product_id = 2449; // Product Id of the free product which will get added to cart
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
add_action( 'init', 'aaptc_add_product_to_cart' );
**** EDIT ****
Based on the support provided I have some new code that auto-adds the product to the cart, checks for orders and removes the product if orders exist.
Can someone please confirm whether the code below is correct?
/*
* Automatically add product to cart
*/
function insta_add_product_to_cart() {
if ( ! is_admin() ) {
$product_id = 2449; // Product Id of the free product which will get added to cart
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
add_action( 'init', 'insta_add_product_to_cart' );
function remove_shirt_returning_customer() {
$product_id = 2449; // Product Id of the free product which will get added to cart
$user_id = get_current_user_id();
// Get orders by customer.
$args = array(
'customer_id' => $user_id,
);
$orders = wc_get_orders( $args );
if ( !empty($orders) ) {
WC()->cart->remove_cart_item( $product_id );
}
}
add_action( 'init', 'remove_shirt_returning_customer' );
**** EDIT ***
THE SOLUTION
So the previous code still gave me errors. What seems to work effectively (in my localhost environment) is the code below.
/*
* Automatically add product to cart
*/
function insta_add_product_to_cart() {
if ( ! is_admin() ) {
$product_id = 51; // Product Id of the free product which will get added to cart
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
add_action( 'init', 'insta_add_product_to_cart' );
/*
* Remove item from cart if previous order exists
*/
function remove_shirt_returning_customer() {
if ( ! is_admin() ) {
$cart_items = WC()->cart->get_cart();
$product_id = 51; // Product Id of the free product which will get added to cart
$user_id = get_current_user_id();
// Get orders by customer.
$args = array(
'customer_id' => $user_id,
);
$orders = wc_get_orders( $args );
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( $cart_item['product_id'] == $product_id && !empty( $orders ) ) {
WC()->cart->remove_cart_item( $cart_item_key );
}
}
}
}
add_action( 'init', 'remove_shirt_returning_customer' );
Instead of using that custom query try using the wc_get_orders function you can retrieve all the orders from a customer using the email address or the user id
// Get orders by customer with ID 12.
$args = array(
'customer_id' => 12,
);
$orders = wc_get_orders( $args );
More info about the wp_get_orders can be found here
You're only going to be able to tell whether the user has ordered from you before or not if they are logged into an account. So if the user is on your site and is logged into the account, you will have to find out which user that is:
$user_id = get_current_user_id();
From there use Enrique's answer to obtain whether that customer has placed an order with you or not.
$user_id = get_current_user_id();
$args = array(
'customer_id' => 12,
);
$orders = wc_get_orders( $args );
From there, test whether $orders is empty or not, if empty leave the item as a default in the cart, if not remove it.
A better approach would be to just automatically have the item in all carts, then conditionally check whether this user is logged in, and has placed an order with you before. If so, remove the item.
I'm creating a WooCommerce add-on to customize the product, based on selected options by the visitor and custom price is calculated and stored into session table also.
I am able to get that value in cart page also.
My problem: I would like to change the default price of the product and replace it with new calculated value in the WooCommerce process as cart, checkout, payment, mail notifications, order...
Any advice please?
Thanks
Ce right hook to get it working is woocommerce_before_calculate_totals. But you will have to complete (replace) the code to get the new price in the hooked function below:
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_items_prices', 10, 1 );
function custom_cart_items_prices( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop Through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get the product id (or the variation id)
$product_id = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = 500; // <== Add your code HERE
// Updated cart item price
$cart_item['data']->set_price( $new_price );
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce versions 3+. But as you don't give any code I can't test it for real getting the new price from session…
function save_subscription_wrap_data( $cart_item_data, $product_id ) {
$include_as_a_addon_subscription = get_field('include_as_a_addon_subscription',$product_id);
$subscricption_product_data = get_field('subscricption_product',$product_id);
$current_user = is_user_logged_in() ? wp_get_current_user() : null;
$subscriptions = wcs_get_users_subscriptions( $current_user->ID );
if($include_as_a_addon_subscription == "yes")
{
foreach ( $subscriptions as $subscription_id => $subscription ) {
$subscription_status = $subscription->get_status();
}
if($subscription_status == 'active')
{
$cart_item_data[ "subscribe_product" ] = "YES";
}
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'save_subscription_wrap_data', 99, 2 );
function render_meta_on_cart_and_checkout1( $cart_data, $cart_item = null ) {
$meta_items = array();
if( !empty( $cart_data ) ) {
$meta_items = $cart_data;
}
if( isset( $cart_item["subscribe_product"] ) ) {
$meta_items[] = array( "name" => "Product Type", "value" => "Package Addon" );
}
return $meta_items;
}
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout1', 100, 2 );
function calculate_gift_wrap_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
$additionalPrice = 100;
foreach ( WC()->cart->get_cart() as $key => $value ) {
if( isset( $value["subscribe_product"] ) ) {
if( method_exists( $value['data'], "set_price" ) ) {
$orgPrice = floatval( $value['data']->get_price() );
//$value['data']->set_price( $orgPrice + $additionalPrice );
$value['data']->set_price(0);
} else {
$orgPrice = floatval( $value['data']->price );
//$value['data']->price = ( $orgPrice + $additionalPrice );
$value['data']->price = (0);
}
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 99 );
I need to automatically add a product to the cart after user registration (which worked) but to decide which product to add by the user meta (which doesn't work).
The first action was just to add a product after registration and it worked perfectly:
add_action( 'user_register', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
$product_id = 115;
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
Now I need to add a specific product according to lists I have of users promoID I got, but it doesn't add anything to the cart.
example of the code:
add_action( 'user_register', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
$group1iid1 = array("1", "2", "3", "4");
$group1iid2 = array("5", "6", "7", "8");
if (in_array("2", $group1iid1)) {
$product_id = 115;
WC()->cart->add_to_cart( $product_id );
} elseif (in_array("0", $group1iid2)) {
$product_id = 219;
WC()->cart->add_to_cart( $product_id );
} else {
$product_id = 231;
WC()->cart->add_to_cart( $product_id );
}
}
}
If I take the code to a template file and just echo something instead of adding a product - it works ok, but when it's like this in the function.php > nothing happens.
What am I missing?
There are missing things in your code:
In your first condition you need also to add is_user_logged_in() condition, as I suppose that this code is for new registrated users only.
You need to get for the current user, HIS Promo ID value. I suppose that this value is set in user metadata, so to get this Promo ID value with get_user_meta() function, you have to define the correct meta_key.
In your code you have to replace in your conditions '2' and '0' values by the current user Promo ID… (Also elseif (in_array("0", $group1iid2)) { condition is going to be always false as "0" value doesn't exist in $group1iid2)
As I can't test for real all this, Here is some kind of work around, based on your code (without any guaranty):
add_action( 'user_register', 'add_product_to_cart' );
function add_product_to_cart( $user_id ) {
if ( ! is_admin() && $user_id > 0 ) {
// DEFINE BELOW THE META KEY TO GET THE VALUE FOR YOUR GROUP OF CURRENT USER
$meta_key = 'your_group_meta_key';
// Getting the current user group ID
$user_promo_id = get_user_meta( $user_id, $meta_key, true );
$group1_id1 = array('1', '2', '3', '4');
$group1_id2 = array('5', '6', '7', '8');
if (in_array( $user_promo_id, $group1_id1 ) ) {
$product_id = 115;
} elseif (in_array( $user_promo_id, $group1_id2 ) ) {
$product_id = 219;
} else {
$product_id = 231;
}
WC()->cart->add_to_cart( $product_id );
}
}
I'm using the code below to modify the WooCommerce Is_Purchasable option so that, item Y is purchasable if item X is added to the cart.
But it gives ajax error when trying to add item Y to the cart.
Here's the code:
function aelia_get_cart_contents() {
$cart_contents = array();
/**
* Load the cart object. This defaults to the persistant cart if null.
*/
$cart = WC()->session->get( 'cart', null );
if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart', true ) ) ) {
$cart = $saved_cart['cart'];
} elseif ( is_null( $cart ) ) {
$cart = array();
}
if ( is_array( $cart ) ) {
foreach ( $cart as $key => $values ) {
$_product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] );
if ( ! empty( $_product ) && $_product->exists() && $values['quantity'] > 0 ) {
if ( $_product->is_purchasable() ) {
// Put session data into array. Run through filter so other plugins can load their own session data
$session_data = array_merge( $values, array( 'data' => $_product ) );
$cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
}
}
}
}
return $cart_contents;
}
// Step 1 - Keep track of cart contents
add_action('wp_loaded', function() {
// If there is no session, then we don't have a cart and we should not take
// any action
if(!is_object(WC()->session)) {
return;
}
// Product Y
global $y_cart_items;
$y_cart_items = 2986;
//Product X
global $x_cart_items;
$x_cart_items = array(
'297'
);
// Step 2
add_filter('woocommerce_is_purchasable', function($is_purchasable, $product) {
global $y_cart_items;
global $x_cart_items;
if( $product->id == $y_cart_items ) {
// make it false
$is_purchasable = false;
// get the cart items object
foreach ( aelia_get_cart_contents() as $key => $item ) {
// do your condition
if( in_array( $item['product_id'], $x_cart_items ) ) {
// Eligible product found on the cart
$is_purchasable = true;
break;
}
}
}
return $is_purchasable;
}, 10, 2);
}, 10);
// Step 3 - Explain customers why they can't add some products to the cart
add_filter('woocommerce_get_price_html', function($price_html, $product) {
if(!$product->is_purchasable() && is_product()) {
$price_html .= '<p>' . __('Add Product X to be able to purchase Product Y.', 'woocommerce') . '</p>';
}
return $price_html;
}, 10, 2);
How do I fix this? Thank you.
I have searched far and wide for a solution to add a free item (that I have hidden with woocommerce) to the cart when someone enters the hiddenproduct coupon I made. This is the code that I am using, it is a modified version of this:http://docs.woothemes.com/document/automatically-add-product-to-cart-on-visit/. The difference is instead of using the cart total to add it, I am trying to use the applied coupon.
Here is my current code and it is not adding the product to the cart:
add_action( 'init', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
global $woocommerce;
$product_id = 1211;
$found = false;
$coupon_id = 1212;
if( $woocommerce->cart->applied_coupons == $coupon_id ) {
//check if product already in cart
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
$woocommerce->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
$woocommerce->cart->add_to_cart( $product_id );
}
}
}
}
I am pretty sure that the error is happening here '( $woocommerce->cart->applied_coupons == $coupon_id )' but I do not know the correct identifiers.
This is in my functions.php
Can anyone help me out? Thank you
I was in a similar situation and used some of your code and made some tweaks.. This worked for me: if(in_array($coupon_id, $woocommerce->cart->applied_coupons)){
Cheers!
I know this is ancient, but I had basically the same need. So I thought I'd go ahead and post my solution. I'm hardly an expert on any of this, so I'm sure there's plenty of room for improvement. I put this in my functions.php (obviously borrowing a lot from the original post here):
function mysite_add_to_cart_shortcode($params) {
// default parameters
extract(shortcode_atts(array(
'prod_id' => '',
'sku' => '',
), $params));
if( $sku && !$prod_id ) $prod_id = wc_get_product_id_by_sku($sku);
if($prod_id) {
$cart_contents = WC()->cart->get_cart_contents();
if ( sizeof( $cart_contents ) > 0 ) {
foreach ( $cart_contents as $values ) {
$cart_prod = $values['product_id'];
if ( $cart_prod == $prod_id ) $found = true;
}
// if product not found, add it
if ( ! $found ) WC()->cart->add_to_cart( $prod_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $prod_id );
}
}
return '';
}
add_shortcode('mysite_add_to_cart','mysite_add_to_cart_shortcode');
add_action( 'woocommerce_applied_coupon', 'mysite_add_product' );
function mysite_add_product($coupon_code) {
$current_coupon = new WC_Coupon( $coupon_code );
$coupon_description = $current_coupon->get_description();
do_shortcode($coupon_description);
return $coupon_code;
}
This lets me add a shortcode in the coupon description that specifies what product should get added when the coupon is applied. It can be either [mysite_add_to_cart prod_id=1234] or [mysite_add_to_cart sku=3456]. So far it seems to be working fine.