WooCommerce - One Purchase per Product per Customer

13 views
Skip to first unread message

Tim Dobson

unread,
Oct 6, 2021, 11:00:22 AM10/6/21
to manchester-word...@googlegroups.com
Hi MWUG!

I have a WooCommerce shop. I am selling access to events.

All purchases are done by customers with accounts.

I want each customer to only be able to buy access to each event once.
If they've bought it before, they shouldn't be allowed to get it again.
If they try to buy something they've bought before, again, they should
get a nice message and not be allowed to.

I want to do this because: customers keep doing this and causing all
sorts of drama and headaches for themselves and me.

I've tried a few different approaches to finding a solution here, and
feel a bit stuck. Can anyone recommend snippets, plugins, approaches to
write snippets, good pizza takeaways or a counsellor?

Ok, maybe just the first 3.

Thanks in advance,

-Tim


P.S.
List member since 2009, last posted here in 2013... did I miss much? ;)

Mike Little

unread,
Oct 7, 2021, 8:06:42 AM10/7/21
to Manchester WordPress WordPress User Group (MWUG)
On Wed, 6 Oct 2021 at 16:00, Tim Dobson <li...@tdobson.net> wrote:
Hi MWUG!

I have a WooCommerce shop. I am selling access to events.

All purchases are done by customers with accounts.

I want each customer to only be able to buy access to each event once.
If they've bought it before, they shouldn't be allowed to get it again.
If they try to buy something they've bought before, again, they should
get a nice message and not be allowed to.

I want to do this because: customers keep doing this and causing all
sorts of drama and headaches for themselves and me.

I've tried a few different approaches to finding a solution here, and
feel a bit stuck. Can anyone recommend snippets, plugins, approaches to
write snippets, good pizza takeaways or a counsellor?

Ok, maybe just the first 3.

Thanks in advance,


Hi Tim,
WooCommerce has the ability to restrict items to one per purchase (though that may not be appropriate if someone wants to buy two tickets), but not prevent a second sale.

However, there is a filter ‘woocommerce_is_purchasable‘ which allows you to disable a product (or variant) dynamically. And a function wc_customer_bought_product() that will let you check whether a customer has already purchased a product.
So as long as the user was logged in you could disable the products they have already purchased. Or if they don't login until the checkout, check again and stop the checkout process at that point.

I did find some example code (https://memberfix.rocks/woocommerce-buy-product-once/) but it definitely needs some cleanup. It may be a good starting point.


--
Stay safe and healthy, best regards,

Mike



-- 
Mike Little
WordPress Specialist

Twitter: @mikelittlezed1

Founder and Director
Zed1.com Limited
https://zed1.com
Registered in England & Wales, no. 6745562

Tim Dobson

unread,
Oct 8, 2021, 8:52:36 AM10/8/21
to manchester-word...@googlegroups.com
On 07/10/2021 13:05, 'Mike Little' via Manchester WordPress User Group
wrote:
> WooCommerce has the ability to restrict items to one per purchase
> (though that may not be appropriate if someone wants to buy two
> tickets), but not prevent a second sale.

Yeah - I'm possibly making poor design choices - but trying to make
people only be able to buy a ticket for themselves. Since they're
adventurous sports events where people have to do disclaimers and accept
risk and stuff, it feels like the right decision.

> However, there is a filter ‘woocommerce_is_purchasable‘ which allows you
> to disable a product (or variant) dynamically. And a
> function wc_customer_bought_product() that will let you check whether a
> customer has already purchased a product.

It's this sort of info that made me know asking this question would be
worth 8 hours of googling. Thanks Mike.

> So as long as the user was logged in you could disable the products they
> have already purchased. Or if they don't login until the checkout, check
> again and stop the checkout process at that point.

Yes exactly.

> I did find some example code
> (https://memberfix.rocks/woocommerce-buy-product-once/
> <https://memberfix.rocks/woocommerce-buy-product-once/>) but it
> definitely needs some cleanup. It may be a good starting point.

Indeed.

Thanks for the pointers Mike. I shall take a good look. :)

Lovely to hear from you, and I'm thinking you may hear and see more from
me over the next bits of time. I'm sure it won't be a month, let a alone
7 years, til my next post to this list. ;)

Speak soon,

-Tim

Tim Dobson

unread,
Jan 5, 2023, 3:46:08 PM1/5/23
to Manchester WordPress User Group
Again, a somewhat delayed response... but in faireness I only got round to actually attempting to fix this today.

(Well, I tried various times in the intervening months)

In the unlikely event that someone on this silent list needs it, the snippet you need looks something like this. Maybe not exactly, but something. This does 99% I think.

Thanks for the pointers Mike!

-Tim

/**
 * Disables repeat purchase for products / variations
 *
 * @param bool $purchasable true if product can be purchased
 * @param \WC_Product $product the WooCommerce product
 * @return bool $purchasable the updated is_purchasable check
 * https://memberfix.rocks/woocommerce-buy-product-once/
 */
function sv_disable_repeat_purchase( $purchasable, $product ) {
     // Don’t run on parents of variations,
    // function will already check variations separately
        if ( $product->is_type( 'variable' ) ) {
    return $purchasable;
    }
   
    // Get the ID for the current product (passed in)
    $product_id = $product->get_id();
   
       // Return false if the customer has bought the product,
    // unless the product is ID 2118
    if ( $product_id != 2118 && wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $product_id ) ) {
        $purchasable = false;
    }

   
    // Double-check for variations: if parent is not purchasable, then variation is not
    if ( $purchasable && $product->is_type('variation') ) {
    $parent = wc_get_product( $product->get_parent_id() );
    $purchasable = $parent->is_purchasable();
    }
   
   
    return $purchasable;
}



add_filter( 'woocommerce_is_purchasable', 'sv_disable_repeat_purchase', 10, 2 );

/**
 * Shows a "purchase disabled" message to the customer
 */

function sv_purchase_disabled_message() {
    // Get the current product to see if it has been purchased
    global $product;
   
    // If the product has been purchased, display a message to the customer
    if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $product->get_id() ) ) {
        echo '<div class="woocommerce"><div class="woocommerce-info wc-nonpurchasable-message">You\'ve already signed up to this event! <br />If a family member, friend or colleague wants to sign up, get them to do it on their own device.</div></div>';
    }
}
add_action( 'woocommerce_single_product_summary', 'sv_purchase_disabled_message', 31 );



/**
 * Generates a "purchase disabled" message to the customer for specific variations
 *
 * @param \WC_Product $product the WooCommerce product
 * @param int $no_repeats_id the id of the non-purchasable product
 */
function sv_render_variation_non_purchasable_message( $product, $no_repeats_id ) {
    // Double-check we're looking at a variable product
    if ( $product->is_type( 'variable' ) && $product->has_child() ) {
        $variation_purchasable = true;
       
        foreach ( $product->get_available_variations() as $variation ) {
            // Only show this message for non-purchasable variations matching our ID
            if ( $no_repeats_id === $variation['variation_id'] ) {
                $variation_purchasable = false;
                echo '<div class="woocommerce"><div class="woocommerce-info wc-nonpurchasable-message js-variation-' . sanitize_html_class( $variation['variation_id'] ) . '">You\'ve already signed up to this event! <br />If a family member, friend or colleague wants to sign up, get them to do it on their own device.</div></div>';
            }
        }
    }
   
        if (!$variation_purchasable) {
        wc_enqueue_js("
    jQuery('.variations_form')
    .on( 'woocommerce_variation_select_change', function( event ) {
    jQuery('.wc-nonpurchasable-message').hide();
    })
    .on( 'found_variation', function( event, variation ) {
    jQuery('.wc-nonpurchasable-message').hide();
    if ( ! variation.is_purchasable ) {
    jQuery( '.wc-nonpurchasable-message.js-variation-' + variation.variation_id ).show();
    }
    })
    .find( '.variations select' ).change();
    ");
    }
}

Mike Little

unread,
Jan 5, 2023, 6:38:10 PM1/5/23
to Manchester WordPress WordPress User Group (MWUG)
Nice. I'm glad you got it fixed.

I'd probably dedupe the html message as you'll have to update it twice if it ever changes.
--
See the group blog at https://mwug.uk
 
You received this message because you are subscribed to the Google
Group "Manchester WordPress User Group".
 
To post to this group, send email to
 
For more options, visit this group at
---
You received this message because you are subscribed to the Google Groups "Manchester WordPress User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to manchester-wordpress-...@googlegroups.com.

Nicole Fearon

unread,
Jan 11, 2023, 1:06:27 PM1/11/23
to manchester-word...@googlegroups.com

Tim Dobson

unread,
Jan 11, 2023, 1:17:00 PM1/11/23
to manchester-word...@googlegroups.com
Yes, that's a good suggestion!

Thanks Mike 

Reply all
Reply to author
Forward
0 new messages