• Skip to main content
  • Skip to primary sidebar
  • About
  • Contact
  • Resources
  • Blog
    • Easy Digital Downloads
    • General
    • Genesis Framework
    • jQuery/JavaScript
    • Project Management
    • WordPress Functions
    • WordPress Plugin Development
  • Army Lessons

Scott DeLuzio

WordPress Development Tutorials

Easy Digital Downloads Limit One Per Customer

June 3, 2017 Scott DeLuzio 25 Comments

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.
		}
	}
}

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;
}

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.

Easy Digital Downloads

Reader Interactions

Comments

  1. Matt Whtieley says

    February 27, 2018 at 8:19 am

    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

    Reply
    • Scott DeLuzio says

      February 27, 2018 at 9:06 am

      Thanks Matt! I’m glad it helped.

      Reply
    • Adrianne says

      May 11, 2018 at 3:19 pm

      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.

      Reply
      • Adrianne says

        May 12, 2018 at 1:02 pm

        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

        Reply
      • Matt Whiteley says

        July 23, 2018 at 11:05 am

        Hey Adrianne – sorry for the delay here. This is what I use:

        https://gist.github.com/mwhiteley16/460d3978d8c60177bdbded943bbfcc26

        Reply
  2. Alberto says

    March 20, 2018 at 6:17 am

    Thankyou very much, but I have a question can we use multiple downloads id instead of the example 57?

    Reply
    • Scott DeLuzio says

      March 21, 2018 at 10:02 am

      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

      Reply
  3. morteza says

    July 18, 2018 at 10:22 am

    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

    Reply
    • Scott DeLuzio says

      October 1, 2018 at 1:56 pm

      Sorry, I haven’t tested this with FES or Email Tags.

      Reply
  4. Joel Acevedo says

    September 29, 2018 at 7:41 am

    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.

    Reply
    • Scott DeLuzio says

      October 1, 2018 at 11:23 am

      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.

      Reply
  5. Harvinder Singh says

    December 10, 2018 at 2:07 pm

    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

    Reply
    • Scott DeLuzio says

      December 10, 2018 at 2:48 pm

      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/

      Reply
  6. michael says

    May 21, 2019 at 11:05 am

    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,

    Reply
    • Scott DeLuzio says

      May 21, 2019 at 11:38 am

      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.

      Reply
  7. Jesús says

    October 17, 2019 at 4:47 am

    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!

    Reply
    • Scott DeLuzio says

      October 17, 2019 at 11:34 am

      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

      Reply
  8. Jesús says

    October 18, 2019 at 2:05 am

    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;

    Reply
    • Scott DeLuzio says

      October 18, 2019 at 2:52 pm

      Hey Jesus,
      I think this should get you closer. Note I haven’t tested it myself, but the logic seems right.

      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
       
      	$subscriber = new EDD_Subscription;
       
       
      	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.
      						$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.
      						if( $in_cart ){
      							// If the subscription isn't cancelled or expired the customer shouldn't be able to checkout
      							if( !$subscriber->get_subscriptions( 913, array( 'cancelled', 'expired' ) ) ){
      								$can_checkout = false;
      							}
      						}
      						break;
      					case '915': // If the customer has purchased the product we want to limit one per customer set an error message. Again change 915 to your product's ID.
      						$in_cart = edd_item_in_cart( '915' ); // Check to see if our download is in the customer's cart. Change 915 to your download's ID.
      						if( $in_cart ){
      							// If the subscription isn't cancelled or expired the customer shouldn't be able to checkout
      							if( !$subscriber->get_subscriptions( 915, array( 'cancelled', 'expired' ) ) ){
      								$can_checkout = false;
      							}
      						}
      						break;
      					case '917': // If the customer has purchased the product we want to limit one per customer set an error message. Again change 917 to your product's ID.
      						$in_cart = edd_item_in_cart( '917' ); // Check to see if our download is in the customer's cart. Change 917 to your download's ID.
      						if( $in_cart ){
      							// If the subscription isn't cancelled or expired the customer shouldn't be able to checkout
      							if( !$subscriber->get_subscriptions( 917, array( 'cancelled', 'expired' ) ) ){
      								$can_checkout = false;
      							}
      						}
      						break;
      					default:
      						$can_checkout = true;
      						break;
      				}
      			}
      		}
      	}
      	return $can_checkout;
      }

      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 $subscriber = new EDD_Subscription; 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. $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. if( $in_cart ){ // If the subscription isn't cancelled or expired the customer shouldn't be able to checkout if( !$subscriber->get_subscriptions( 913, array( 'cancelled', 'expired' ) ) ){ $can_checkout = false; } } break; case '915': // If the customer has purchased the product we want to limit one per customer set an error message. Again change 915 to your product's ID. $in_cart = edd_item_in_cart( '915' ); // Check to see if our download is in the customer's cart. Change 915 to your download's ID. if( $in_cart ){ // If the subscription isn't cancelled or expired the customer shouldn't be able to checkout if( !$subscriber->get_subscriptions( 915, array( 'cancelled', 'expired' ) ) ){ $can_checkout = false; } } break; case '917': // If the customer has purchased the product we want to limit one per customer set an error message. Again change 917 to your product's ID. $in_cart = edd_item_in_cart( '917' ); // Check to see if our download is in the customer's cart. Change 917 to your download's ID. if( $in_cart ){ // If the subscription isn't cancelled or expired the customer shouldn't be able to checkout if( !$subscriber->get_subscriptions( 917, array( 'cancelled', 'expired' ) ) ){ $can_checkout = false; } } break; default: $can_checkout = true; break; } } } } return $can_checkout; }

      Reply
  9. Jesús says

    October 21, 2019 at 12:48 am

    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

    Reply
    • Scott DeLuzio says

      October 21, 2019 at 8:05 am

      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.

      Reply
  10. Bilgi says

    April 11, 2021 at 8:54 am

    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…

    Reply
    • Scott DeLuzio says

      April 12, 2021 at 10:02 am

      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.

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Come say hi!

  • Facebook
  • GitHub
  • Instagram
  • LinkedIn
  • Twitter
  • YouTube

Tweets by scottdeluzio

My Products

Conditional Checkout FieldsFull Screen Background ImagesQuick CheckoutWP1099

I use affiliate links throughout this site and may earn a commission if you purchase through my links. I do not link to products or services that I do not trust, or use myself.
© 2025 · Scott DeLuzio · Built on the Genesis Framework