One of my client wants that when new users comes to website then they"ll get Rs. 500 discount. Here's the complication, the discount like that on first order he get Rs. 250 discount after entering the coupon code and on second order he also get coupon discount of Rs. xxxx.
NOTE : Only one coupon used at a time.
So can you please suggest me how to do that or if any plugin available like that for first and second order discount.
/**
* Frontend validate new customer only coupon code
* hook: woocommerce_after_checkout_validation
*/
add_action('woocommerce_after_checkout_validation','check_new_customer_coupon', 0);
function check_new_customer_coupon(){
global $woocommerce;
// you might change the firstlove to your coupon
$new_cust_coupon_code = 'firstlove';
$has_apply_coupon = false;
foreach ( WC()->cart->get_coupons() as $code => $coupon ) {
if($code == $new_cust_coupon_code) {
$has_apply_coupon = true;
}
}
if($has_apply_coupon) {
if(is_user_logged_in()) {
$user_id = get_current_user_id();
// retrieve all orders
$customer_orders = get_posts( array(
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
'numberposts'=> -1
) );
if(count($customer_orders) > 0) {
$has_ordered = false;
$statuses = array('wc-failed', 'wc-cancelled', 'wc-refunded');
// loop thru orders, if the order is not falled into failed, cancelled or refund then it consider valid
foreach($customer_orders as $tmp_order) {
$order = wc_get_order($tmp_order->ID);
if(!in_array($order->get_status(), $statuses)) {
$has_ordered = true;
}
}
// if this customer already ordered, we remove the coupon
if($has_ordered == true) {
WC()->cart->remove_coupon( $new_cust_coupon_code );
wc_add_notice( sprintf( "Coupon code: %s is only applicable for new customer." , $new_cust_coupon_code), 'error' );
return false;
}
} else {
// customer has no order, so valid to use this coupon
return true;
}
} else {
// new user is valid
return true;
}
}
}
May help you. Got from some blog.
Related
I'm using Dokan and the idea is to hide Cash on Pickup at checkout depending on the vendor.
My code is this but it doesn't work:
function change_payment_gateway( $gateways ){
$COP = array(
"vendor1"=>"yes",
"vendor2"=>"no",
"vendor3"=>"yes"
);
$orderId->get_id();
$vendorId = dokan_get_seller_id_by_order( $orderId );
$vendorName = get_user_by( 'id', $vendorId );
if(!$vendorId) {
return;
}
if(empty($vendorName)) {
return;
}
if( $COD[$vendorName] === "no"){
unset( $gateways['cop'] );
}
return $gateways;
}
Any help? Thanks!
In Woocommerce, i want to hide the credit card payment option if a specific product variation is in the cart. Please help.
Thanks.
This is what i have working now. I assigned a separate shipping class to each variation i want to disable a specific payment method at checkout. But it would be much easier if i coud target specific attribute values, so i don't have to assign a shipping class.
<?php
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
$shipping_class_target = 106; // the shipping class ID assigned to specific variations
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
unset($available_gateways['cod']); // unset 'cod'
}
else {
unset($available_gateways['bacs']); // unset 'bacs'
}
return $available_gateways;
}
If you are looking to check the variations for each item in the cart, you have to lookup the attributes $product->get_attributes() and then loop through those and get the array key and value for each.
In this example, I used
Size (pa_size) and Small
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
// See if there is an attribute called 'pa_size' in the cart
// Replace with whatever attribute you want
if (array_key_exists('pa_size', (array) $values['data']->get_attributes() ) ) {
foreach ($values['data']->get_attributes() as $attribute => $variation);
// Replace 'small' with your value.
if ($variation == 'small') $in_cart = true; //edited
}
}
if ( $in_cart ) {
unset($available_gateways['cod']); // unset 'cod'
}
else {
unset($available_gateways['bacs']); // unset 'bacs'
}
return $available_gateways;
}
I need to customize cash on delivery (COD) in WooCommerce based on user role and product category.
Requirements:
By default COD is hidden
COD is visible when a product in cart, belongs to a certain category (category 1)
Users who have the role "x" must always see COD, even if they don't have category 1 products in the cart.
This is my code attempt to meet the above requirements:
function disable_cod($available_gateways)
{
if (is_admin()) return $available_gateways;
$role = false;
//check whether the avaiable payment gateways have Cash on delivery and user is not logged in or he is a user with role customer
if (isset($available_gateways['cod']) && (current_user_can('customer') || !is_user_logged_in()))
{
$role = true;
}
foreach (WC()
->cart
->get_cart() as $cart_item_key => $cart_item)
{
$prod_simple = true;
// Get the WC_Product object
$product = wc_get_product($cart_item['product_id']);
// Get the product types in cart (example)
if ($product->is_product_category('X')) $prod_simple = false;
}
if ($prod_simple = $role = true) unset($available_gateways['cod']); // unset 'cod'
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'disable_cod', 99, 1);
I definitely got something wrong in the syntax, but I hope the logical concept is correct? Any advice?
Your code contains some minor mistakes:
is_product_category() is a conditional tag which returns true when viewing a product category archive. Use has_term() instead.
Loop through the cart is only necessary when the user role is not fulfilled.
So you get:
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// Initialize: flag - default true
$flag = true;
// Has certain user role
if ( current_user_can( 'certain-user-role' ) ) {
// False
$flag = false;
} else {
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$categories = array( 63, 15, 'categorie-1' );
// Isset
if ( WC()->cart ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Has term (product category)
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
// False, break loop
$flag = false;
break;
}
}
}
}
// True
if ( $flag ) {
// Cod
if ( isset( $payment_gateways['cod'] ) ) {
// Remove
unset( $payment_gateways['cod'] );
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
Only related reference for the same I found with accepted by few people is the below mentioned code but there is no session stored in options table with the following key '_wc_session_'.$user_id
function add_products_programmatically($user_id) {
// Get the current session data and saved cart
$wc_session_data = get_option('_wc_session_'.$user_id);
// Get the persistent cart
$full_user_meta = get_user_meta($user_id,'_woocommerce_persistent_cart', true);
// Create a new WC_Cart instance and add products programmatically
$cart = get_new_cart_with_products();
// If there is a current session cart, overwrite it with the new cart
if($wc_session_data) {
$wc_session_data['cart'] = serialize($cart->cart_contents);
update_option('_wc_session_'.$user_id, $wc_session_data);
}
// Overwrite the persistent cart with the new cart data
$full_user_meta['cart'] = $cart->cart_contents;
update_user_meta($user_id, '_woocommerce_persistent_cart', $full_user_meta);
}
After a lot of research to the way woo-commerce uses persistent cart I have created a working solution.
function woocomm_add_to_cart($param) {
global $wpdb;
$user_id = $param['user_id'];
$objProduct = new WC_Session_Handler();
$wc_session_data = $objProduct->get_session($user_id);
// Get the persistent cart may be _woocommerce_persistent_cart can be in your case check in user_meta table
$full_user_meta = get_user_meta($user_id,'_woocommerce_persistent_cart_1',true);
// create new Cart Object
$cartObj = new WC_Cart();
// Add old cart data to newly created cart object
if($full_user_meta['cart']) {
foreach($full_user_meta['cart'] as $sinle_user_meta) {
$cartObj->add_to_cart( $sinle_user_meta['product_id'], $sinle_user_meta['quantity'] );
}
}
// Add product and quantities coming in request to the new cart object
if($param['products']){
foreach($param['products'] as $prod) {
$cartObj->add_to_cart( $prod['product_id'], $prod['quantity'] );
}
}
$updatedCart = [];
foreach($cartObj->cart_contents as $key => $val) {
unset($val['data']);
$updatedCart[$key] = $val;
}
// If there is a current session cart, overwrite it with the new cart
if($wc_session_data) {
$wc_session_data['cart'] = serialize($updatedCart);
$serializedObj = maybe_serialize($wc_session_data);
$table_name = 'wp_woocommerce_sessions';
// Update the wp_session table with updated cart data
$sql ="UPDATE $table_name SET 'session_value'= '".$serializedObj."', WHERE 'session_key' = '".$user_id."'";
// Execute the query
$rez = $wpdb->query($sql);
}
// Overwrite the persistent cart with the new cart data
$full_user_meta['cart'] = $updatedCart;
update_user_meta($user_id, '_woocommerce_persistent_cart_1', $full_user_meta);
$response = [
'status' => true,
'message' => 'Products successfully added to cart'
];
return rest_ensure_response($response);
}
Here is the Request json data for the Rest API:
{"user_id": 15, "products" : [{"product_id":"81","quantity":"0.5"},{"product_id":"1817","quantity":"0.5"}]}
I have done some changes in previous code as this code is not working with me independently.
I have created Rest API for my Vue.js application.
Create route and make function and paste this code use as add to
cart
This can also update the session of user on web side when you add
from mobile end
if (checkloggedinuser()) {
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';
global $wpdb;
$user_id = get_current_user_id();
WC()->session = new WC_Session_Handler();
WC()->session->init();
$wc_session_data = WC()->session->get_session($user_id);
// Get the persistent cart may be _woocommerce_persistent_cart can be in your case check in user_meta table
$full_user_meta = get_user_meta($user_id,'_woocommerce_persistent_cart_1',true);
WC()->customer = new WC_Customer( get_current_user_id(), true );
// create new Cart Object
WC()->cart = new WC_Cart();
// return $full_user_meta;
// Add old cart data to newly created cart object
if($full_user_meta['cart']) {
foreach($full_user_meta['cart'] as $sinle_user_meta) {
WC()->cart->add_to_cart( $sinle_user_meta['product_id'], $sinle_user_meta['quantity'] );
}
}
WC()->cart->add_to_cart( $request['product_id'], $request['quantity'] );
$updatedCart = [];
foreach(WC()->cart->cart_contents as $key => $val) {
unset($val['data']);
$updatedCart[$key] = $val;
$updatedCart[$key]['file'] = "hello file herer";
}
// If there is a current session cart, overwrite it with the new cart
if($wc_session_data) {
$wc_session_data['cart'] = serialize($updatedCart);
$serializedObj = maybe_serialize($wc_session_data);
$table_name = 'wp_woocommerce_sessions';
// Update the wp_session table with updated cart data
$sql ="UPDATE $table_name SET 'session_value'= '".$serializedObj."', WHERE 'session_key' = '".$user_id."'";
// Execute the query
$rez = $wpdb->query($sql);
}
// Overwrite the persistent cart with the new cart data
$full_user_meta['cart'] = $updatedCart;
update_user_meta($user_id, '_woocommerce_persistent_cart_1', $full_user_meta);
return array(
'success' => false,
'responsecode' => 403,
"message" => "Products successfully added to cart",
"data" => [],
);
}else{
return array(
'success' => false,
'responsecode' => 403,
"message" => "Please Logged In to get Data",
"data" => [],
);
}
this is the simplest solution:
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).
WC()->cart->get_cart();
}
WC()->cart->add_to_cart($prod['product_id'], $prod['quantity']);
reference from the link:
https://barn2.com/managing-cart-rest-api-woocommerce-3-6/
I'm trying to create a custom function for a WooCommerce shipping plugin by wooforce. There are two plugins, ups and usps.
What I'm trying to achieve is if a customer adds a product from category X or any of its sub categories, all rates except for ups ground get unset.
If those products are not present in the cart, all options remain available.
The developers pointed me to this code, but I'm still pretty new to PHP and WordPress/WooCommerce structured PHP so I'm a bit stuck as how to proceed.
Here's the code they gave me.
add_filter('woocommerce_package_rates', 'hide_shipping_method_when_shipping_class_product_is_not_in_cart', 10, 2);
function hide_shipping_method_when_shipping_class_product_is_not_in_cart($available_shipping_methods, $package)
{
// Shipping class IDs that need the method removed
$shipping_class_ids = array(
27,
);
$shipping_services_to_hide = array(
'wf_fedex_woocommerce_shipping:FEDEX_GROUND',
'wf_fedex_woocommerce_shipping:FEDEX_2_DAY_AM'
);
$shipping_class_exists = false;
foreach(WC()->cart->cart_contents as $key => $values) {
if (in_array($values['data']->get_shipping_class_id() , $shipping_class_ids)) {
$shipping_class_exists = true;
break;
}
}
if (!$shipping_class_exists) {
foreach($shipping_services_to_hide as & $value) {
unset($available_shipping_methods[$value]);
}
}
return $available_shipping_methods;
}
I was able to figure this out on my own. Here's the code for anyone who may need this function in the future.
This function works specifically with the WooForce Shipping plugins.
add_filter('woocommerce_package_rates', 'hide_shipping_method_when_shipping_class_product_is_not_in_cart', 10, 2);
function hide_shipping_method_when_shipping_class_product_is_not_in_cart($available_shipping_methods, $package){
// set our flag to be false until we find a product in that category
$cat_check = false;
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
// replace 'membership' with your category's slug
if ( has_term( 'ammo', 'product_cat', $product->id ) ) {
$cat_check = true;
// break because we only need one "true" to matter here
break;
}
}
// if a product in the cart is in our category, do something
if ( $cat_check ) {
// we have the category, do what we want
// Shipping class IDs that need the method removed
$shipping_class_ids = array(
1,
2,
3,
18,
23,
33,
47,
49
);
$shipping_services_to_hide = array(
'wf_shipping_usps:D_PRIORITY_MAIL',
'wf_shipping_usps:D_EXPRESS_MAIL'
);
$shipping_class_exists = false;
foreach(WC()->cart->cart_contents as $key => $values) {
if (in_array($values['data']->get_shipping_class_id() , $shipping_class_ids)) {
$shipping_class_exists = true;
break;
}
}
if (!$shipping_class_exists) {
foreach($shipping_services_to_hide as & $value) {
unset($available_shipping_methods[$value]);
}
}
return $available_shipping_methods;
}
else{
return $available_shipping_methods;
}
}