If you are using Easy Digital Downloads, there may be times where you need to limit the purchase of a particular download on your site. There are plugins like the Purchase Limit extension, which allows you to globally limit the purchase of certain products. But what if you need to have Easy Digital Downloads limit one per customer?
As far as I know, there isn’t a plugin that lets you do this. But it isn’t that difficult to set up either.
Set up the checkout error message
We need to be able to let the customer know why they won’t be able to check out if they have a certain download in their cart.
add_action( 'edd_before_purchase_form', 'sd_set_purchase_limit_error' ); function sd_set_purchase_limit_error(){ $user_id = get_current_user_id(); // Get the current customer's ID $downloads = edd_get_users_purchased_products( $user_id ); // Get all of the products the customer has purchased in the past $can_checkout = true; // Allow checkout for now $in_cart = edd_item_in_cart( '57' ); // Check to see if our download is in the customer's cart. Change 57 to your download's ID. if ( $in_cart == true ){ // If the item isn't in the customer's cart we don't need to go any further. if ( ! empty( $downloads ) ){ // If the customer hasn't purchased anything before we don't need to go any further. foreach ( $downloads as $download ){ // Loop through each product the customer has purchased before. switch ( $download->ID ) { case '57': // If the customer has purchased the product we want to limit one per customer set an error message. Again change 57 to your product's ID. edd_set_error( 'already_purchased', apply_filters( 'edd_pc_error_message', __( 'You have already purchased the one-per-customer plugin. There is a limit of one per customer. You can log out and purchase with a different account, or remove it from your cart with the link above.' ) ) ); break; default: edd_unset_error( 'already_purchased' ); break; } } edd_print_errors(); // Display the errors on the checkout page. } } } |
Actually prevent checkout
So far all we have done is display an error message if the customer has purchased the download before. This won’t actually prevent them from going through the checkout process though.
Next, we need to use the edd_can_checkout
filter to let the checkout process know that the customer can’t checkout while this product is still in their cart.
add_filter( 'edd_can_checkout', 'sd_limit_purchase' ); function sd_limit_purchase(){ $user_id = get_current_user_id(); // Get the current customer's ID $downloads = edd_get_users_purchased_products( $user_id );// Get all of the products the customer has purchased in the past $can_checkout = true; // Allow checkout for now $in_cart = edd_item_in_cart( '57' ); // Check to see if our download is in the customer's cart. Change 57 to your download's ID. if ( $in_cart == true ){ // If the item isn't in the customer's cart we don't need to go any further. if ( ! empty( $downloads ) ){ // If the customer hasn't purchased anything before we don't need to go any further. foreach ( $downloads as $download ){ // Loop through each product the customer has purchased before. switch ( $download->ID ) { case '57': // If the customer has purchased the product we want to limit one per customer set an error message. Again change 57 to your product's ID. $can_checkout = false; break; default: $can_checkout = true; break; } } } } return $can_checkout; } |
And that’s it!
Now if your customer has purchased a certain product before that you want to have Easy Digital Downloads limit one per customer, they will see an error message and the checkout fields will be removed from the checkout page.
Great little tutorial. I was able to modify this to use it globally to limit all downloads to one per person for a specific client case. This is the only tutorial on the web addressing this which is crazy. Thanks again!
Matt
Thanks Matt! I’m glad it helped.
Matt – I’m intrigued to know how you did this as all of my files are single purchase as well and it would be so much easier to have it set globally.
Also Scott – I modified the code slightly to block checkout and leave the nag message simultaneously. I also added a variable for the name of the download so the customer knew exactly which download to remove before moving on.
Guess gist embedding doesn’t work in comments, but that’s okay because it turned out my first version was blocked everyone from checking out, not just duplicates (oops). I have corrected it and now it only blocks repeats (YAY)
https://gist.github.com/adriannees/900242b5f19d9e1123a1708232595184
Hey Adrianne – sorry for the delay here. This is what I use:
https://gist.github.com/mwhiteley16/460d3978d8c60177bdbded943bbfcc26
Thankyou very much, but I have a question can we use multiple downloads id instead of the example 57?
You would need to put together an array of the download IDs that you want to check and loop through that. The example below should work, although I haven’t tested it.
https://gist.github.com/ScottDeLuzio/941eb623d86d796bd09f0b77c37d65cb
Hi
Thank you for your awesome post.
It seems new updates of this plugin doesn’t support EDD frontend submissions & Email tags….
There are several images and words about that features in this page (http://wpweb.co.in/documents/edd-purchase-limit/), but only in this page! and this plugin not support FES and Email tags for me.
Do you have any idea?
Regard
Sorry, I haven’t tested this with FES or Email Tags.
Hi,
Thank you very much for this, I’m curious if it would be possible to check all the downloads under a specific category, so every time I add a new download to that category I don’t have to edit this code?
Thanks in advance.
This is a somewhat tricky one. Currently Easy Digital Downloads uses custom post types for their downloads. That makes it fairly simple to use WP_QUERY to list all posts from the custom post type “download” in the taxonomy (category) you want. You can then loop through each post (download) that is returned, and feed the download ID to the code provided above.
With that said, EDD version 3.0 is coming out (no official release date has been announced yet). From what I understand, that version will be moving away from using custom post types and will instead have downloads in their own database table. While this will improve performance, it will make the WP_QUERY I mentioned not work anymore. I don’t know exactly how it will work in v3.0 so I can’t say for sure what code you would need…yet.
nice article, I have one more question,
how can I set a limit so that customer can add only one product at a time in a cart?
For example, if someone clicks on product A and after that go back and then click on product B, then plugin must show product B and remove the product A from cart automatically.
thanks
Hey Harvinder,
Great question! I haven’t personally used this, but it looks like there is a filter that will do the trick for you. Check out this post https://amdrew.com/restrict-cart-one-download-easy-digital-downloads/
hi,
is it possible to limit 1 trial on 1st purchase, after that user payment will get deducted immediately.
currently if we add a trial based product, the edd give trial on each checkout, so a same user can get multiple trials,
I don’t know if there is a way to limit trial purchases. As far as I can tell, a “trial” status isn’t stored with the list of the customer’s previously purchased products. There might be a way to do it, but it would need some digging to figure out.
Hi Scott,
This snippet works fine, thanks! but i need change it for subscriptions.
I would like to can purchase again a “download id” (subscription) if the subscription is not active ( cancelled or expired)
Is it possible? How i can modify snippet? Thanks!
You would need to add your own logic to the function to check if the subscription is cancelled or expired. Then instead of blocking the purchase, allow it in that instance.
Take a look at the Recurring Payments documentation on getting subscriber information. You’ll also need to read up on the
EDD_Subscription
object.While I haven’t tested it, you probably would use something like this:
$subscriber->get_subscriptions( 123, array( 'cancelled', 'expired' ) ); //Valid statuses for the array are 'pending', 'active', 'cancelled', 'expired', 'failing', 'completed' so adjust to your needs
Hi Scott,
Thanks for your response, Im tried it adding this code but is not working for me, my knowledge from php is very poor, can you help me, please?, the code would be working for id= 913, 915 and 917:
add_filter( ‘edd_can_checkout’, ‘sd_limit_purchase’ );
function sd_limit_purchase(){
$user_id = get_current_user_id(); // Get the current customer’s ID
$downloads = edd_get_users_purchased_products( $user_id );// Get all of the products the customer has purchased in the past
$can_checkout = true; // Allow checkout for now
$in_cart = edd_item_in_cart( ‘913’ ); // Check to see if our download is in the customer’s cart. Change 913 to your download’s ID.
$subscriber->get_subscriptions( 123, array( ‘cancelled’, ‘expired’ ) );
if ( $in_cart == true ){ // If the item isn’t in the customer’s cart we don’t need to go any further.
if ( ! empty( $downloads ) ){ // If the customer hasn’t purchased anything before we don’t need to go any further.
foreach ( $downloads as $download ){ // Loop through each product the customer has purchased before.
switch ( $download->ID ) {
case ‘913’: // If the customer has purchased the product we want to limit one per customer set an error message. Again change 913 to your product’s ID.
if (! ($subscriber = ‘cancelled’))
$can_checkout = false;
break;
if (! ($subscriber = ‘expired’))
$can_checkout = false;
break;
default:
$can_checkout = true;
break;
}
}
}
}
return $can_checkout;
Hey Jesus,
I think this should get you closer. Note I haven’t tested it myself, but the logic seems right.
Thanks Scott, i’m tested your code snippet but is not working for me.
I have an user with 2 sucriptions:
1 active and 1 cancelled and i can purchase again all suscriptions.
I will try yo explain better my web:
I have 3 types of suscription:
1 Montly (id 913)
2º Quaterly (id 915)
3º Yearly (917)
If the user have a montly active suscription, the user will can purchase only quaterly or yearly, and it will be perfect if could be possible to display an advertisment message that he have an active montly suscription.
If the user have a quaterly active suscription, the user will can purchase only montly or yearly, and it will perfect if coul be possible to display an advertisment message that he have an active quaterly suscription.
If the user have a yearly active suscription, the user will can purchase only montly or quaterly, and it will perfect if coul be possible to display an advertisment message that he have an active yearle suscription.
If the user have a cancelled or expired montly suscription, he will can purchase montly suscription too again.
If the user have a cancelled or expired quaterly suscription, he will can purchase quaterly suscription too again.
If the user have a cancelled or expired yearly suscription, he will can purchase yearly suscription too again.
If the user have an active montly suscription, he can’t purchase montly suscription again and it display a message error.
If the user have an active quaterly suscription, he can’t purchase quaterly suscription again and it display a message error.
If the user have an active yearly suscription, he can’t purchase quaterly suscription again and it display a message error.
I would be very grateful if you could help me, I would pay you if necessary. Can we talk in private? Thanks again!
You can check my website: https://desa2.fundaciontransparenciayopinion.org/colabora
I can’t really dig into this much more than I have already. I’d suggest hiring a developer who can make these customizations for you. I wouldn’t think it would take much to get done. I suggest Codeable for custom development work. They should be able to help you out with this.
Hi,
For free downloads, I want it to download a maximum of 5 times in 24 hours.
I want to allow 5 or less downloads within 24 hours from your email and IP address.
How can I do that? How can I check the IP address, mail address and whether it has been in the last 24 hours? Any help would make me happy. I would love to know if there are any hooks.
Good work, thanks for all…
I think that would probably require quite a bit of custom coding to work. It is most likely possible, but I don’t know the best way to go about it, especially with the upcoming EDD 3.0 release, which introduces some major changes to the way that data will be stored in the back end. It might be best to reach out to EDD support to see if they have any suggestions. They may have answered this question for another customer already, so it may be an easy answer for them.