How to limit customers buy one product with woocommerce - php

I want that customer can purchase only one product from woo commerce whenever they came back to shop page they will be redirected to my account page.
<?php
/**
* Loop Add to Cart
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
global $product;
$current_user = wp_get_current_user();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product->id)) {
$redirect = $myaccount;
}
i am using the following code placed in loop folder but its not working.
i want that user can purchase product once in lifetime
note - its not about purchasing one product at one time
its like if someone purchased the product Then he/she will never able to purchase any other product.

The loop/add-to-cart.php template creates a link. Your template only lists some variables (where are $redirect and $myaccount defined?) and does not create a link so it doesn't do anything.
A better solution would be to filter the link that is created in the loop/add-to-cart.php template via the woocommerce_loop_add_to_cart_link filter. This way if the item hasn't been purchased you can leave the regular link in tact.
Add the following to your theme's functions.php file:
add_filter( 'woocommerce_loop_add_to_cart_link', 'so_add_to_cart_link', 10, 2 );
function so_add_to_cart_link( $link, $product ){
$current_user = wp_get_current_user();
if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product->id)) {
$link = sprintf( '%s',
esc_url( get_permalink( wc_get_page_id( 'myaccount' ) ) ),
esc_attr( $product->product_type ),
__( 'View my account', 'theme-text-domain' ),
),
}
return $link;
}
Note that the above hasn't been tested, so be wary of typos.

Open your theme functions.php, and put below code at the end.
add_filter( 'woocommerce_add_cart_item_data', 'woo_custom_add_to_cart' );
function woo_custom_add_to_cart( $cart_item_data ) {
global $woocommerce;
$woocommerce->cart->empty_cart();
return $cart_item_data;
}
Now you can test by adding new product to your existing cart with items, see whether it will added the latest product only and remove all previous products in the cart.

Here's how you can limit the purchase to 1 product in your entire life in the store. I'm not sure about the quantity allowed for that product for the first time so I'll keep it variable in the below code.
Task 1: Allow to purchase 1 product at a time.
This can be simply achieved by the standard Woocommerce settings:
Task 2: Allow users to buy a product only once in their entire lifetime.
This will ensure that any user can purchase any product from your store only once and then can't buy any other product
This code will go in your functions.php file of the child theme or you can use any snippets plugin to do so.
add_action( 'woocommerce_add_to_cart', 'remove_product_from_cart_redirect', 999);
function remove_product_from_cart_redirect() {
global $woocommerce;
//Only use this code if the user is logged in
if ( is_user_logged_in() ) {
$userId = get_current_user_id();
// Get the TOTAL number of orders for the User
$totalOrders = wc_get_customer_order_count( $userId );
// Get CANCELLED orders for customer
$args = array(
'customer_id' => $userId,
'post_status' => 'cancelled',
'post_type' => 'shop_order',
'return' => 'ids',
);
$cancelledOrders = count( wc_get_orders( $args ) );
//all orders except cancelled ones
$totalNotCancelled = $totalOrders - $cancelledOrders;
if ($totalNotCancelled > 1) { //if already purchased anything on the store.
//empty the cart
WC()->cart->empty_cart( true );
//Optionally displaying a notice for the removed item:
wc_add_notice( __( 'We have removed the product from your cart.', 'woocommerce' ), 'notice' );
//Redirect to a my-account page
wp_redirect( get_permalink(get_option('woocommerce_myaccount_page_id')));
}
}
}
Note: Above code will not work with Ajax add to cart so please turn that off from Woocommerce settings here:

Related

Add a prefix/suffix to Woocommerce product name everywhere, including cart and email

I am using Woocommerce and I have integrated some custom fields to allow the user to specify new values that I will later append to the product title.
I am using update_post_meta/get_post_meta to save the new information. This part works fine.
Then I used the filter woocommerce_product_title to update the title. This filter is working fine when there is the use of $product->get_title() but will do nothing when using $product->get_name()which isn't an issue because in some places I don't want to append the new information.
I also used the filter the_title for the product page.
Basically my code looks like below where return_custom() will be the function than will build the new information based on the product ID.
function update_title($title, $id = null ) {
$prod=get_post($id);
if (empty($prod->ID) || strcmp($prod->post_type,'product')!=0 ) {
return $title;
}
return $title.return_custom($id);
}
function update_product_title($title, $product) {
$id = $product->get_id();
return $title.return_custom($id);
}
add_filter( 'woocommerce_product_title', 'update_product_title', 9999, 2);
add_filter( 'the_title', 'update_title', 10, 2 );
The issue arise when adding the product to the cart. The name used is the default one so my below code isn't enough to update the product name used in the cart. Same thing for the notification mails. I suppose this is logical since the email will use the information of the cart.
I am pretty sure that everything is happening inside add_to_cart() but I am not able to find any filter/hook related to the product name.
How to make sure the name used in the cart is good? What filter/hook shoud I consider in addition to the ones I am already using in order to append my new information to the product title within the cart?
I want to make sure that the new title will be seen during all the shopping process. From the product page until the notification mail.
The following will allow you to customize the product name in cart, checkout, orders and email notifications, just with one hooked function:
// Just used for testing
function return_custom( $id ) {
return ' - (' . $id . ')';
}
// Customizing cart item name in cart, checkout, orders and email notifications
add_action( 'woocommerce_before_calculate_totals', 'set_custom_cart_item_name', 10, 1 );
function set_custom_cart_item_name( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Required since Woocommerce version 3.2 for cart items properties changes
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get the product name and the product ID
$product_name = $cart_item['data']->get_name();
$product_id = $cart_item['data']->get_id();
// Set the new product name
$cart_item['data']->set_name( $product_name . return_custom($product_id) );
}
}
Code goes on function.php file of your active child theme (or active theme). Tested and works.
Try using woocommerce_cart_item_name filter.
[woocommerce_cart] shortcode uses cart/cart.php template, and the code displaying the title is this:
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' ' );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
}

How to check if a product is created by a user in woocommerce

Good Day, i'm trying to check if a product is created by a user and if no, the add to cart button should be removed.
I'm working on a store whereby a registered user can create product from frontend. I added this argument to create the product from frontend;
$post = array(
'post_author' => $currentCOUser_ID // This Return the User's ID using wp_get_current_user()->ID
'post_status' => "publish",
'post_excerpt' => $pProduct_excerpt,
'post_title' => $ProductTitle,
'post_type' => "product",
);
//create product for product ID
$product_id = wp_insert_post( $post, __('Cannot create product', 'izzycart-function-code') );
When product is created i only want the author and admin to be able to see the add to cart button on the product single page. I used the below code but didn't work;
function remove_product_content() {
global $post;
$current_user = wp_get_current_user();
$product_author_id = $current_user->ID;
$admin_role = in_array( 'administrator', (array) $current_user->roles );
//check if is a product & user is logged in and is either admin or the author
//is a product and user is not logged in, remove add to cart
//is a product and user is logged in and not either admin or product author, remove add to cart button
if ( is_product() && is_user_logged_in() && (!$admin_role || $product_author_id != $post->post_author) ) {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
}
}
add_action( 'wp', 'remove_product_content' );
when i run the above code, it completely hide the add to cart button from everyone. Not sure what i'm doing wrong. Thanks for your help.
You are missing an ampersand. It should be &&. & is a bit wise AND. See this link for more details on the difference between the two: https://stackoverflow.com/a/2376353/10987825
Also, wrap the || portion of the statement in parentheses. Otherwise, as long as the current user is not the author, it will be hidden. Check these two links to see the difference.
Incorrect Version
Correct Version
So your code would become:
function remove_product_content() {
global $post;
$current_user = wp_get_current_user();
$product_author_id = $current_user->ID;
//check if is a product & user is logged in and is either admin or the author
//is a product and user is not logged in, remove add to cart
//is a product and user is logged in and not either admin or product author, remove add to cart button
if ( is_product() && (!is_user_logged_in() || (!is_admin() && $product_author_id != $post->post_author)) ) {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
}
}
add_action( 'wp', 'remove_product_content' );

Prevent post-authors from buying and bidding their own products in WooCommerce

With WooCommerce, I am using WC Vendors Pro plugin + Rehub theme + Auction plugin (by wp giene) + Simple Auctions plugin (by WC Vendors).
How can I prevent post-authors from buying and bidding their own products in WooCommerce?
I don't want the post authors to bid on the products they have posted, to prevent price increases (which is not correct).
Where to start, any Ideas?
Thanks
I suppose that your "post authors" (vendors) have a custom role (or some specific capabilities). So you can target the user role "post authors" (or one of his specifics capabilities) checking and removing cart items on checkout page for this user roles.
Here is that code:
add_action( 'woocommerce_before_checkout_form', 'checking_allowed_cart_items_on_checkout', 100, 1);
function checking_allowed_cart_items_on_checkout() {
// Allow only "administrator" and "customer" user roles to buy all products
if( ! current_user_can('administrator') || ! current_user_can('customer') ){
// Ititializing variables
$found = false;
$cart_object = WC()->cart;
$current_user_id = get_current_user_id();
// Checking cart items
foreach($cart_object->get_cart() as $cart_item_key => $cart_item){
// get the WC_Product object and the product ID
$product = $cart_item['data'];
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
// Get the product post object to get the post author
$post_obj = get_post( $product_id );
$post_author = $post_obj->post_author;
if( $post_author == $current_user_id ){
// removing the cart item
$cart_object->remove_cart_item( $cart_item_key );
$found = true; // set to true if a product of this author is found
}
}
// Display a custom message in checkout page when items are removed
if( $found ){
// Display an error message
wc_add_notice( __( 'Items removed - As a Vendor, you are not allowed to buy your own products.' ), 'error' );
}
}
}
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.

Adding "Sale" product category to products that are on sale in Woocommerce

As part of a WooCommerce site I want to have a sale page that lists sale items (with pagination and filtering). I think the best way to do this is to have a 'Sale' category that is added automatically to any posts that are part of the sale (as category pages allow for filtering and pagination automatically.
I have this code so far to programatically add the sale category to products when you save them:
function update_test( $product) {
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
add_action( 'save_post', 'update_test', 1, 2);`
However, I only want this to happen if a product is on sale (i.e has sale price set) so that saving posts that are not on sale does not add the sale category. I have tried several different things, but have had no luck. I tried this, but it didnt work:
function update_test( $product ) {
if($product->is_on_sale()){
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
}
add_action( 'save_post', 'update_test', 1, 2);`
but this just made my site freeze on save.
Any ideas?
Andy
Updated 2 (October 2018)
save_post is a WordPress hook that works with $post_id argument and target all kind of posts. You need to target product custom WooCommerce post_type first in a condition (and publish post_status).
Also as it's not a post object you can't use is_on_sale() method with it. But you can use get_post_meta() function to check if the sale price is set in the product.
Here is the fully functional and tested code (for simple products only):
add_action( 'save_post_product', 'update_product_set_sale_cat' );
function update_product_set_sale_cat( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
if ( ! current_user_can( 'edit_product', $post_id ) ) {
return $post_id;
}
if( get_post_status( $post_id ) == 'publish' && isset($_POST['_sale_price']) ) {
$sale_price = $_POST['_sale_price'];
if( $sale_price >= 0 && ! has_term( 'Sale', 'product_cat', $post_id ) ){
wp_set_object_terms($post_id, 'sale', 'product_cat', true );
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related: Auto remove Sale product category from not on sale products in Woocommerce
I think a more convenient way of doing this, that also works on variable products, would be adding the following in child theme's function.php (or via a plugin, etc):
add_action( 'woocommerce_update_product', 'update_product_set_sale_cat', 10, 2 );
function update_product_set_sale_cat( $product_id, $product ) {
if ( $product->is_on_sale() ) {
wp_add_object_terms($product_id, "sale", 'product_cat');
} else { // this will also remove the sale category when the product in no longer on sale
wp_remove_object_terms($product_id, "sale", 'product_cat');
}
}
It uses the woocommerce_update_product hook which runs whenever a product is updated/created in the database.

How do I automatically set WooCommerce Product to draft if sold out

I tried using the 'Hide if sold out' option in Woocommerce. But I am using a different plugin to display my products (GridFX Masonry Gallery) and it is still showing the sold out products. Is there a way to change the product to draft when the last item has been purchased and is sold out? Is there a snippet to do this?
The previous answer by Maha Dev cannot work.
In a theme functions file the get_stock_quantity() method doesn't exist unless you call the product data using wc_get_product.
Using set_post_type will change the actual type of the post, not it's status, you need to use wp_update_post and set the post status.
This is the code I ended up using:
/*
* Unpublish products after purchase
*/
function lbb_unpublish_prod($order_id) {
$order = new WC_Order( $order_id );
$all_products = $order->get_items();
foreach ($all_products as $product){
$product_object = wc_get_product($product['product_id']);
// This will only work if stock management has been enabled
if( ! $product_object->get_stock_quantity() ) {
wp_update_post(array(
'ID' => $product['product_id'],
'post_status' => 'draft'
));
}
}
}
add_action( 'woocommerce_thankyou', 'lbb_unpublish_prod', 10, 1 );
Better way is to set product stock (1 in your case). Select 'Hide out of stock products'. It will hide out of stock products. But if you actually want to hide ordered products then see my code below:
//functions.php
add_action( 'woocommerce_thankyou', 'your_func', 10, 1 );
function your_func($order_id) {
$order = new WC_Order( $order_id );
$all_products = $order->get_items();
foreach ($all_products as $product){
// This will only work if stock management has been enabled
if( ! $product->get_stock_quantity() )
set_post_type ($product['product_id'], 'draft');
}
}
This will hide all the products added in the cart for order. You can customize this function as you want.

Categories