Contact Form Shortcode Without a Plugin
Adds a [wpide_contact_form] shortcode with name, email and message fields that emails you each message, protected by a nonce, a hidden honeypot, a time trap and a per-visitor hourly limit.
Opens WPIDE on
Code
$wpide_contact = array(
'to' => '', // Recipient; empty = Settings > General admin email.
'subject' => 'New message from your website',
'max_per_hour' => 3, // Messages allowed per visitor per hour.
'min_seconds' => 3, // Faster submissions are treated as bots.
);
add_action( 'template_redirect', function () use ( $wpide_contact ) {
if ( empty( $_POST['wpide_contact_nonce'] ) || 'POST' !== strtoupper( isset( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : '' ) ) {
return;
}
$back = remove_query_arg( 'wpide_contact', wp_get_referer() ? wp_get_referer() : home_url( '/' ) );
$finish = function ( $status ) use ( $back ) {
wp_safe_redirect( add_query_arg( 'wpide_contact', $status, $back ) . '#wpide-contact' );
exit;
};
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['wpide_contact_nonce'] ) ), 'wpide_contact' ) ) {
$finish( 'expired' );
}
$stamp = isset( $_POST['wpide_ts'] ) ? sanitize_text_field( wp_unslash( $_POST['wpide_ts'] ) ) : '';
$parts = explode( '.', $stamp, 2 );
$human = 2 === count( $parts ) && hash_equals( wp_hash( 'contact' . $parts[0] ), $parts[1] ) && time() - (int) $parts[0] >= $wpide_contact['min_seconds'];
if ( ! empty( $_POST['wpide_website'] ) || ! $human ) {
$finish( 'sent' ); // Pretend success so bots learn nothing.
}
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
$key = 'wpide_contact_' . md5( wp_salt() . $ip );
if ( (int) get_transient( $key ) >= $wpide_contact['max_per_hour'] ) {
$finish( 'limit' );
}
$name = str_replace( array( '<', '>', '"' ), '', sanitize_text_field( wp_unslash( isset( $_POST['wpide_name'] ) ? $_POST['wpide_name'] : '' ) ) );
$email = sanitize_email( wp_unslash( isset( $_POST['wpide_email'] ) ? $_POST['wpide_email'] : '' ) );
$message = sanitize_textarea_field( wp_unslash( isset( $_POST['wpide_message'] ) ? $_POST['wpide_message'] : '' ) );
if ( '' === $name || ! is_email( $email ) || strlen( $message ) < 10 ) {
$finish( 'invalid' );
}
$to = is_email( $wpide_contact['to'] ) ? $wpide_contact['to'] : get_option( 'admin_email' );
$body = "Name: $name\nEmail: $email\nPage: $back\n\n$message";
$sent = wp_mail( $to, $wpide_contact['subject'], $body, array( 'Reply-To: ' . $name . ' <' . $email . '>' ) );
set_transient( $key, (int) get_transient( $key ) + 1, HOUR_IN_SECONDS );
$finish( $sent ? 'sent' : 'error' );
} );
add_shortcode( 'wpide_contact_form', function () {
$messages = array(
'sent' => array( 'success', 'Thank you! Your message has been sent.' ),
'invalid' => array( 'error', 'Please fill in your name, a valid email and a message of at least 10 characters.' ),
'limit' => array( 'error', 'You have sent several messages recently. Please try again later.' ),
'expired' => array( 'error', 'The form expired. Please try again.' ),
'error' => array( 'error', 'Sorry, the message could not be sent. Please email us directly.' ),
);
$status = isset( $_GET['wpide_contact'] ) ? sanitize_key( $_GET['wpide_contact'] ) : '';
$time = (string) time();
ob_start();
?>
<div id="wpide-contact" class="wpide-form wpide-contact-form">
<?php if ( isset( $messages[ $status ] ) ) : ?>
<p class="wpide-form-notice wpide-form-<?php echo esc_attr( $messages[ $status ][0] ); ?>" role="<?php echo 'success' === $messages[ $status ][0] ? 'status' : 'alert'; ?>"><?php echo esc_html( $messages[ $status ][1] ); ?></p>
<?php endif; ?>
<form method="post" action="">
<p><label for="wpide-contact-name">Name</label><br><input type="text" id="wpide-contact-name" name="wpide_name" required autocomplete="name" maxlength="100"></p>
<p><label for="wpide-contact-email">Email</label><br><input type="email" id="wpide-contact-email" name="wpide_email" required autocomplete="email" maxlength="200"></p>
<p><label for="wpide-contact-message">Message</label><br><textarea id="wpide-contact-message" name="wpide_message" rows="6" required minlength="10" maxlength="5000"></textarea></p>
<p style="position:absolute;left:-9999px;" aria-hidden="true"><label>Website <input type="text" name="wpide_website" tabindex="-1" autocomplete="off"></label></p>
<input type="hidden" name="wpide_ts" value="<?php echo esc_attr( $time . '.' . wp_hash( 'contact' . $time ) ); ?>">
<?php wp_nonce_field( 'wpide_contact', 'wpide_contact_nonce', false ); ?>
<p><button type="submit">Send message</button></p>
</form>
</div>
<?php
return ob_get_clean();
} );
Notes
Add [wpide_contact_form] to any page (messages go to the admin email unless you set a recipient), and exclude that page from full-page caching so its security token stays fresh.
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.