Skip to main content Accessibility Feedback

Selling things with Easy Digital Downloads

I use Easy Digital Downloads to sell my books and other products.

I’ve made some customizations and added some extensions to the out-of-the-box setup. Today, I wanted to share with you what I’ve done.

Payment gateways #

EDD supports PayPal Standard by default. It’s kind of terrible.

I added the free PayPal for Easy Digital Downloads plugin, which adds PayPal Express Checkout and other options.

I also purchased the Stripe Payment Gateway extension, so that people can pay via credit card through Stripe.

Updates by email #

Since I planned on giving people free updates, I purchased the Product Updates extension. This lets you send email updates to people who have purchased a product with links to download the updated files.

I would strongly recommend using something like Postman SMTP with this, otherwise emails will get lost in the PHP void.

MailChimp Integration #

EDD sells a MailChimp extension that lets you add purchasers to a list in MailChimp.

I’m both too cheap to buy it, and wanted the ability to segment purchasers within a list, which the extension doesn’t not allow you to do. So, I wrote my own.

I already have a custom MailChimp plugin I use to embed MailChimp forms on my site. MailChimp for EDD extends it, giving you the ability to add people who buy a product or use a discount code to a list, and segment them into groups within that list.

A better empty cart #

The default empty cart message is a bit lame. The free Easy Digital Downloads – Empty Cart plugin lets you customize it.

Removing the name fields #

I don’t need someone’s name when they buy one of my books. I only need their email address, and wanted to keep the checkout process as frictionless as possible.

I used the following code in my functions.php file to remove the name fields:

 * Unset first and last name as required fields in checkout
 * @param  Array $required_fields Required fields
function keel_edd_purchase_form_required_fields( $required_fields ) {
    unset( $required_fields['edd_first'] );
    unset( $required_fields['edd_last'] );
    return $required_fields;
add_filter( 'edd_purchase_form_required_fields', 'keel_edd_purchase_form_required_fields' );

 * Remove default name fields from checkout
function keel_edd_remove_names() {
  remove_action( 'edd_purchase_form_after_user_info', 'edd_user_info_fields' );
add_action( 'init', 'keel_edd_remove_names' );

 * Override the checkout fields markup without the name fields
function keel_edd_user_info_fields() {
    if( is_user_logged_in() ) :
        $user_data = get_userdata( get_current_user_id() );
    <fieldset id="edd_checkout_user_info">
        <?php do_action( 'edd_purchase_form_before_email' ); ?>
        <p id="edd-email-wrap">
            <label class="edd-label" for="edd-email"><strong><?php _e('Email Address', 'edd'); ?></strong></label>
            <input class="edd-input required" type="email" name="edd_email" placeholder="<?php _e('Email address', 'edd'); ?>" id="edd-email" value="<?php echo is_user_logged_in() ? $user_data->user_email : ''; ?>"/>
        <?php do_action( 'edd_purchase_form_after_email' ); ?>
        <?php do_action( 'edd_purchase_form_user_info' ); ?>
add_action( 'edd_purchase_form_after_user_info', 'keel_edd_user_info_fields' );

Only allow a single item on checkout #

Because I’m not running a proper store, I don’t want to have a “View Cart” link in my navigation. I want someone to click on the “Buy Now” button and go right to the checkout. Choosing another item removes the first one.

(Admittedly, this made more sense when I sold just one book with three different packages.)

Here’s the PHP I added to my functions.php file to make that happen:

 * Only allow a single item at checkout
function keel_edd_force_single_item_cart() {
    return edd_get_cart_contents();
add_filter( 'edd_add_to_cart', 'keel_edd_force_single_item_cart', 1, 1 );

Display “JavaScript Required” message on checkout if JS is disabled #

Both PayPal and Stripe require JavaScript to work. To make this more obvious, I wanted to disable the checkout button and add an error message if it’s disabled.

First, I added this PHP to my functions.php file. It creates the deactivated button and error message:

 * Disable purchase button if no JS
function keel_edd_no_js_disable_purchase() {
    $label = edd_get_option( 'checkout_label', '' );

    if ( edd_get_cart_total() ) {
        $complete_purchase = ! empty( $label ) ? $label : __( 'Purchase', 'easy-digital-downloads' );
    } else {
        $complete_purchase = ! empty( $label ) ? $label : __( 'Free Download', 'easy-digital-downloads' );

        '<div id="keel-edd-no-js-purchase-message">' .
            '<em>' . __( 'Please enabled JavaScript to complete your purchase.', 'keel' ) . '</em><br>' .
            '<button class="btn btn-large disabled" disabled="disabled">' . $complete_purchase . '</button>' .
add_action( 'edd_purchase_form_after_submit', 'keel_edd_no_js_disable_purchase' );

Then, I added this JavaScript to my site, which adds a special class to the site if JavaScript is enabled:

;(function (window, document, undefined) {

    'use strict';

    // JavaScript enabled
    document.documentElement.className += ' js-edd';

})(window, document);

Finally, I included this CSS on my site, which hooks into that class to hide the error message when JavaScript is available:

/* Message above disabled "Complete Purchase" button when JS isn't enabled */
.js-edd #keel-edd-no-js-purchase-message {
    display: none;
    visibility: hidden;

Only load PayPal scripts and styles at checkout #

The free PayPal payment gateway plugin loads some extra CSS and JavaScript throughout the whole site. I only want those files to load on checkout for better performance.

This bit of PHP added to my functions.php file does the trick:

 * Only load PayPal JS and CSS on checkout page
function keel_edd_only_load_files_on_checkout() {
    if ( is_page( 'checkout' ) ) return;
    wp_dequeue_style( 'pal-for-edd' );
    wp_dequeue_script( 'pal-for-edd' );
    wp_dequeue_script( 'pal-for-eddpaypal_for_edd_blockUI' );
add_action( 'wp_enqueue_scripts', 'keel_edd_only_load_files_on_checkout' );

Hide unneeded Stripe fields #

When paying with credit card, the Stripe payment gateway adds address fields. I’m not shipping anything, so the only one I need is a zip code and country, which are used to verify the credit card.

I added this bit of PHP to my functions.php file to hide the others:

 * Removes the credit card billing address fields
function keel_edd_remove_default_fields() {
    remove_action( 'edd_after_cc_fields', 'edd_default_cc_address_fields' );
add_action( 'init', 'keel_edd_remove_default_fields' );

 * Adds in only the required credit card address fields
 * @link
function keel_edd_default_cc_address_fields() {
    ob_start(); ?>
    <fieldset id="edd_cc_address" class="cc-address">
        <span><legend><?php _e( 'Billing Details', 'edd' ); ?></legend></span>
        <?php do_action( 'edd_cc_billing_top' ); ?>
        <p id="edd-card-zip-wrap">
            <label for="card_zip" class="edd-label">
                <?php _e( 'Billing Zip / Postal Code', 'edd' ); ?>
                <?php if( edd_field_is_required( 'card_zip' ) ) { ?>
                    <span class="edd-required-indicator">*</span>
                <?php } ?>
            <span class="edd-description"><?php _e( 'The zip or postal code for your billing address.', 'edd' ); ?></span>
            <input type="text" size="4" name="card_zip" class="card-zip edd-input required" placeholder="<?php _e( 'Zip / Postal code', 'edd' ); ?>" value="<?php echo $zip; ?>"/>

        <p id="edd-card-country-wrap">
            <label for="billing_country" class="edd-label">
                <?php _e( 'Billing Country', 'edd' ); ?>
                <?php if( edd_field_is_required( 'billing_country' ) ) { ?>
                    <span class="edd-required-indicator">*</span>
                <?php } ?>
            <span class="edd-description"><?php _e( 'The country for your billing address.', 'edd' ); ?></span>
            <select name="billing_country" id="billing_country" class="billing_country edd-select<?php if( edd_field_is_required( 'billing_country' ) ) { echo ' required'; } ?>">
                $selected_country = edd_get_shop_country();
                if( $logged_in && ! empty( $user_address['country'] ) && '*' !== $user_address['country'] ) {
                    $selected_country = $user_address['country'];
                $countries = edd_get_country_list();
                foreach( $countries as $country_code => $country ) {
                  echo '<option value="' . esc_attr( $country_code ) . '"' . selected( $country_code, $selected_country, false ) . '>' . $country . '</option>';

        <?php do_action( 'edd_cc_billing_bottom' ); ?>
    echo ob_get_clean();
add_action( 'edd_after_cc_fields', 'keel_edd_default_cc_address_fields' );

Additional style updates #

I added a handful of other little style changes, mostly to bring the default EDD layout inline with the rest of my site.

Since they’re custom to my theme, I won’t share them here, but if EDD provides plenty of classes and IDs you can hook into for styling.

🔥 Level-up your JavaScript skills! All of the Vanilla JS Pocket Guides have been updated for ES6 with new methods, techniques, and browser APIs. Learn more →

Have any questions or comments about this post? Email me at or contact me on Twitter at @ChrisFerdinandi.

Get Daily Developer Tips