Email-Gated Download Form
Adds a [wpide_gated_download] shortcode that asks for an email address before a guide or PDF can be downloaded, then emails a private download link valid for 48 hours.
Opens WPIDE on
Code
add_action( 'template_redirect', function () {
// Download link from the email.
if ( isset( $_GET['wpide_dl'], $_GET['f'], $_GET['e'] ) ) {
$file = absint( $_GET['f'] );
$expires = absint( $_GET['e'] );
$sig = sanitize_text_field( wp_unslash( $_GET['wpide_dl'] ) );
if ( $expires >= time() && hash_equals( wp_hash( 'dl|' . $file . '|' . $expires ), $sig ) && 'attachment' === get_post_type( $file ) ) {
wp_safe_redirect( wp_get_attachment_url( $file ) );
exit;
}
wp_die( 'This download link has expired. Please request a new one.', 'Link expired', array( 'response' => 410 ) );
}
if ( empty( $_POST['wpide_gate_nonce'] ) || empty( $_POST['wpide_gate_file'] ) ) {
return;
}
$file = absint( $_POST['wpide_gate_file'] );
$back = remove_query_arg( 'wpide_gate', wp_get_referer() ? wp_get_referer() : home_url( '/' ) );
$email = sanitize_email( wp_unslash( isset( $_POST['wpide_gate_email'] ) ? $_POST['wpide_gate_email'] : '' ) );
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['wpide_gate_nonce'] ) ), 'wpide_gate_' . $file ) || 'attachment' !== get_post_type( $file ) || ! is_email( $email ) || ! empty( $_POST['wpide_gate_hp'] ) ) {
wp_safe_redirect( add_query_arg( 'wpide_gate', 'invalid', $back ) );
exit;
}
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
$key = 'wpide_gate_' . md5( wp_salt() . $ip );
if ( (int) get_transient( $key ) < 5 ) {
$expires = time() + 2 * DAY_IN_SECONDS;
$link = add_query_arg( array( 'wpide_dl' => wp_hash( 'dl|' . $file . '|' . $expires ), 'f' => $file, 'e' => $expires ), home_url( '/' ) );
$title = wp_strip_all_tags( get_the_title( $file ) );
wp_mail( $email, 'Your download: ' . $title, "Here is your download link (valid for 48 hours):\n\n$link\n\nEnjoy!" );
wp_mail( get_option( 'admin_email' ), 'New download request', "$email requested \"$title\"." );
set_transient( $key, (int) get_transient( $key ) + 1, HOUR_IN_SECONDS );
}
wp_safe_redirect( add_query_arg( 'wpide_gate', 'sent', $back ) );
exit;
} );
add_shortcode( 'wpide_gated_download', function ( $atts ) {
$atts = shortcode_atts( array( 'file' => 0, 'title' => 'Download the guide', 'button' => 'Email me the link' ), $atts, 'wpide_gated_download' );
$file = absint( $atts['file'] );
if ( ! $file ) {
return current_user_can( 'edit_posts' ) ? '<p><em>Gated download: add file="ATTACHMENT_ID" to the shortcode.</em></p>' : '';
}
$status = isset( $_GET['wpide_gate'] ) ? sanitize_key( $_GET['wpide_gate'] ) : '';
$html = '<div class="wpide-form wpide-gated-download"><p><strong>' . esc_html( $atts['title'] ) . '</strong></p>';
if ( 'sent' === $status ) {
return $html . '<p role="status">Check your inbox, the download link is on its way.</p></div>';
}
$html .= 'invalid' === $status ? '<p role="alert">Please enter a valid email address.</p>' : '';
$html .= '<form method="post" action=""><label class="screen-reader-text" for="wpide-gate-' . $file . '">Email address</label>';
$html .= '<input type="email" id="wpide-gate-' . $file . '" name="wpide_gate_email" required autocomplete="email" placeholder="[email protected]"> ';
$html .= '<span style="position:absolute;left:-9999px;" aria-hidden="true"><input name="wpide_gate_hp" tabindex="-1" autocomplete="off"></span>';
$html .= '<input type="hidden" name="wpide_gate_file" value="' . esc_attr( $file ) . '">' . wp_nonce_field( 'wpide_gate_' . $file, 'wpide_gate_nonce', false, false );
$html .= '<button type="submit">' . esc_html( $atts['button'] ) . '</button></form></div>';
return $html;
} );
Notes
Use [wpide_gated_download file="123" title="Free pricing guide"] with the media attachment ID; the file URL is never shown on the page and collected emails are sent to the admin.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.