Skip to main content Skip to secondary navigation 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.

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