Selling services online has become much easier over the years. All kinds of services can be sold online – anything from landscaping and pest control to SEO or website maintenance services. If you ever considered selling your services online, this tutorial will show an easy way to sell service credits with Easy Digital Downloads.
Why sell service credits?
Customers sometimes will want the ability to pre-pay for a service in order to receive a discounted rate. It’s sort of a win-win. The customer gets the discounted price they are looking for, and the service provider gets a bunch of money up front.
Let’s say, for example, you provide copywriting services and you charge $200 per page up to 800 words. I don’t even know if that’s in the ballpark for what that service goes for – it’s just an example.
Anyway, for purposes of this example, let’s say there’s a client who has 20 pages of work for you over the course of the year. They realize they’ll be spending around $4,000 at the end of the year, and you’ll be trickling in $200 every few weeks – after spending time creating and sending out invoices – blah!
But what if you offered an incentive to have them pre-pay for your service? Maybe a 10% pre-payment discount? That way you can charge $3,600 today and do the work as it’s needed. Another benefit is that if someone has paid for a service up front, they’re more likely to want to use their “balance” right away. This creates an opportunity for you to sell them another block of services sooner.
A little code goes a long way
Easy Digital Downloads is an awesome plugin. You can customize how it functions in so many different ways with just a few lines of code. This is one of those cases.
We’re going to extend Easy Digital Downloads with the edd_complete_purchase
action. This action runs when a payment is marked as complete. This typically happens after your payment processor (i.e. Stripe) processes the payment.
Before we dive into the code though, you’re going to want to look at a couple settings.
First, make sure your customers can adjust the quantities at checkout. To do this, go to Downloads > Settings > Misc tab then check the box next to Item Quantities. The quantity of the service product that the customer purchases will become the “credit” used later on.
Next, while still on the Misc tab, click Checkout Settings below the tabs. Check the box next to Require Login. If the customer doesn’t have an account on your site (or isn’t logged in) you won’t be able to attribute the purchase to any particular user.
OK, back to the code.
<?php add_action( 'edd_complete_purchase', 'sd_add_credits' ); function sd_add_credits( $payment_id ){ // Get the items in the customer's cart $cart_items = edd_get_payment_meta_cart_details( $payment_id ); // Get the user's ID associated with this payment $user_id = edd_get_payment_user_id( $payment_id ); // Get the customer ID associated with this user ID. Must use true as second parameter to indicate we're passing the WP user id $customer = new EDD_Customer( $user_id, true ); foreach( $cart_items as $cart_item ){ // Check each item in the customer's cart. Look for the ID of the service product. switch ( $cart_item[ 'id' ] ) { // This is the ID of the service product. Add the quantity purchased to the customer's account. case 'XX': $quantity = !empty( $customer->get_meta( 'service_quantity', true ) ) ? absint( $customer->get_meta( 'service_quantity', true ) ) : 0; $quantity = $quantity + absint( $cart_item[ 'quantity' ] ); $customer->update_meta( 'service_quantity', $quantity ); break; default: //do nothing if not the service product break; } } } |
What this function does is it gets the items in the customer’s cart in the $cart_items
variable. Next, we get the customer’s WordPress user ID in the $user_id
variable. Finally, we’ll use the EDD_Customer
class to manipulate the customer’s meta entry for their credits. Stick with me.
The foreach
loop loops through each item in the customer’s cart to see if they purchased the particular service we’re looking to add credits to their account for. In this example, the first case 'XX':
in the switch statement represents the product ID for the service. Just replace the XX with your service’s actual ID.
The service_quantity
key in the get_meta
and update_meta
functions is the meta key used to save the balance to the customer’s account. We’re adding the quantity purchased to the amount already in the customer’s account before updating, or to 0 if they don’t have a balance.
Great, so we have a way for our customer to purchase credits now let’s get a way for us to administer those credits.
Administering service credits
Another area we can manipulate in Easy Digital Downloads is the customer profile page under Downloads > Customers > View.
Here we will add a table just above the Customer Emails table that lists the service we’re offering, the customer’s balance, and an add/deduct credit section. Really, we can probably get away with just deduct credits where you will deduct them as the service is used. I’m including a way to add credits in case you accidentally deduct too many, or need to give a freebie for some reason.
To do this we’ll use the edd_customer_before_tables
action.
<?php add_action( 'edd_customer_before_tables', 'sd_customer_service_balance' ); function sd_customer_service_balance( $customer ){?> <h3>Service Balance</h3> <table class="wp-list-table widefat striped balances"> <thead> <tr> <th>Type</th> <th>Balance</th> <th>Add Credit</th> <th>Delete Credit</th> </tr> </thead> <tbody> <tr> <td><strong>Service</strong></td> <td> <?php echo absint( $customer->get_meta( 'service_quantity' ) ); ?> </td> <td> <form id="sd-add-service" method="post" action="<?php echo admin_url( 'edit.php?post_type=download&page=edd-customers&view=overview&id=' . $customer->id ); ?>"> <input type="number" id="add-service" name="add_service" /> <input type="hidden" id="customer-id" name="customer_id" value="<?php echo $customer->id; ?>" /> <input type="hidden" name="sd_action" value="add-customer-service" /> <?php wp_nonce_field( 'add-customer-service', 'add_customer_service_nonce', true, true ); ?> <input id="add-customer-service" class="right button-secondary" type="submit" value="Add" /> </form> </td> <td> <form id="sd-delete-service" method="post" action="<?php echo admin_url( 'edit.php?post_type=download&page=edd-customers&view=overview&id=' . $customer->id ); ?>"> <input type="number" id="delete-service" name="delete_service" /> <input type="hidden" id="customer-id" name="customer_id" value="<?php echo $customer->id; ?>" /> <input type="hidden" name="sd_action" value="delete-customer-service" /> <?php wp_nonce_field( 'delete-customer-service', 'delete_customer_service_nonce', true, true ); ?> <input id="delete-customer-service" class="right button-secondary" type="submit" value="Delete" /> </form> </td> </tr> </tbody> </table> <?php } |
This will give us something that looks like this:
Next, we’ll need to be able to adjust the customer’s balance when you click Add or Delete.
<?php add_action( 'admin_init', 'sd_adjust_customer_balance' ); function sd_adjust_customer_balance(){ if( !isset( $_POST ) || !isset( $_POST[ 'sd_action' ] ) || !isset( $_POST[ 'customer_id' ] ) ){ return false; } $customer = new EDD_Customer( $_POST[ 'customer_id' ] ); switch ( $_POST[ 'sd_action' ] ) { case 'add-customer-service': if ( !isset( $_POST[ 'add_customer_service_nonce' ] ) || ! wp_verify_nonce( $_POST[ 'add_customer_service_nonce' ], 'add-customer-service' ) ){ return false; } $balance = absint( $customer->get_meta( 'service_quantity' ) ); $qty = absint( $_POST[ 'add_service' ] ); $new_qty = $balance + $qty; $update = 'service_quantity'; break; case 'delete-customer-service': if ( !isset( $_POST[ 'delete_customer_service_nonce' ] ) || ! wp_verify_nonce( $_POST[ 'delete_customer_service_nonce' ], 'delete-customer-service' ) ){ return false; } $balance = absint( $customer->get_meta( 'service_quantity' ) ); $qty = absint( $_POST[ 'delete_service' ] ); $new_qty = $balance - $qty; $update = 'service_quantity'; break; default: exit; break; } $customer->update_meta( $update, $new_qty ); } |
Now, as your customer uses the service, you can deduct credits as needed.
Display balance to your customer
It would be nice for your customer to be able to log in and see what their balance is.
You probably can piece it together from the examples above, but just in case, here’s an example:
<?php function sd_display_customer_service_balance(){ if ( !is_user_logged_in() ){ return false; } $user_id = get_current_user_id(); // Get the customer ID associated with this user ID. Must use true as second parameter to indicate we're passing the WP user id $customer = new EDD_Customer( $user_id, true ); $service_balance = absint( $customer->get_meta( 'service_quantity', true ) ); ob_start(); ?> <div class="customer-service-balance"> <span class="balance-title">Service Remaining Balance: </span> <span class="balance-amount"><?php echo $service_balance; ?></span> </div> <h3>Need to order additional services?</h3> <div class="order"> <a href="#add-to-cart-link" class="button">Order more of my great service</a><br /> </div> <?php return ob_get_clean(); } |
You can make that function into a shortcode, or display it some other way in the customer’s account.
What about the discounts?
Right! If your customer is paying for this service in bulk they’re going to probably expect some sort of discount.
The Discounts Pro extension for Easy Digital Downloads is a great way to give those discounts.
With that plugin, you can give a discount based on the quantity of the product in the customer’s cart. So you could have it set up so if they buy 1-5 of a product they are charged the normal price. 6-10 gets them a 10% discount. 11-20 gets a 20% discount, etc. You can set up the discounts anyway you can imagine.
If you’re selling services, you may also want the free Downloads as Services plugin, which removes things like the “no downloadable files” notice on the purchase confirmation page.
Not just for services
I suppose this can be used for any number of things that aren’t totally considered services. Maybe you operate a sports facility like a golf driving range. You could let customers pre-purchase a dozen buckets of balls to hit. Then deduct the balance from their account when they pick up their balls at your service desk.
What services are you offering? Do you encourage pre-payment with a discounted rate?
John says
Hi there,
Thank you so much for this article. Really appreciated.
I just needed this!
Just a short question (and sorry for that): where should I put the codes exactly?
Many thank you once again
Scott DeLuzio says
You can put it in a custom plugin, or in your child theme’s functions.php file.
John says
Many thank you! Got it!
The back end customer’s credit view is fantastic!
On the other hand, my customer can’t buy credit.. Have I missed something?
Thank you once again and great article btw!
John says
Sorry, I mean a customer can buy credit, but he can’t see the balance of the credits.
How can I set this?
And how can I let the customer spend his credit buying my digital products?
Thnx
Scott DeLuzio says
Hi John,
Check out the section “Display Balance To Your Customer” for a guide on how to display that to the customer. It isn’t a complete example, but you can make it into a shortcode that can be placed in their account page.
As for spending the credit, the way I have it set up is that the customer would come to you through another means to request the service and then you would deduct a credit from their account.
For example, if the service is landscaping and the customer prepays (on your site) for 3 months worth of weekly service (so 12 credits), every time you went to their house to preform the landscaping service, you would deduct a credit from their account. They don’t need to necessarily “pay” for it again on your site since there is an agreement that you would provide the service weekly that they already prepaid for.
However, if you did want them to “pay” for the service on your site, you could create a separate product that they would use to cash in their credits. You could then use bits from the first and third code blocks above to adjust their balance when they purchased the product.
John says
Many thank you once again Scott.
What I would like to reach is a way to sell credits packages and then have the customers buying my downloads with the credits.
I created few credits packages as you suggested and it works.
Now, I need to create a way to let them buy my download through their credits.
I’m not sure how to do it in the best way…
Any advice about this?
Thank you!
My best regards
Scott DeLuzio says
I think you might want to try setting up a separate payment gateway that you can use for this purpose. You’ll want to take a look at this post from Pippin Williamson https://pippinsplugins.com/create-custom-payment-gateway-for-easy-digital-downloads/
You can then create a custom payment form for paying with credits. When you process the “payment” you will need to check to see that (1) the customer is logged in (although this might be a condition that is checked before showing “pay with credits” as an option), and (2) the customer has sufficient credit in their account to pay for the item(s). If they don’t have enough credits you can show a link to purchase more. I would suggest setting up your credits to have a value that is easily calculated against the currency of your store. For example, if 1 credit = $1, it’s pretty easy to check if they have sufficient credits. On the other hand, if 15 credits = $1 there is the added layer of complexity of running a calculation to determine whether or not the customer has enough credits. It isn’t impossible, but just makes the job a bit more complex.
You also want to pay attention to your pricing. For argument’s sake, if 1 credit = $1 and you are charging $9.99 for an item, the customer will need at least 10 credits to purchase it. After the purchase they will have .01 credits left over in their account, which might be confusing (can they even purchase anything for .01 credits?) You may want to round the credits up that are deducted to avoid this. So instead of deducting 9.99 credits, deduct 10 maybe. Just throwing out ideas here.
After the payment processes, you can use the code from the example to deduct the necessary credits from the customer’s account.