Crear un formulario de contacto en WordPress desde cero

Con este tutorial aprenderás a crear un formulario de contacto en WordPress sin instalar ningún plugin.

¿No es mejor usar un plugin de formularios?

Hay varias razones por las que a veces recomiendo no usar plugins.

Vamos a suponer el caso de que solamente necesitas un simple formulario de contacto para tu web. El minimalismo está a la orden del día y está comprobado que cuanto menos datos pidas en tu formulario mayor será la conversión así que con cuatro campos te basta.

Podrías instalar uno de los muchos plugins de formularios que hay en el repositorio de WordPress y configurarlo con unos cuantos clicks pero estarías sobrecargando el servidor con código que no utilizas constantemente.

Vamos a echar un vistazo a las razones por la que podrías plantearte crear un formulario desde cero en vez de usar un plugin:

  • Los plugins cargan mucho más código del que realmente necesitas
  • Si eres desarrollador tener que rellenar un mega formulario (en el admin) para poder crear un pequeño formulario de contacto a parte de irónico resulta tedioso.
  • Aprenderás más acerca de WordPress y de como funciona por dentro.
  • Ahorrarás cargar más hojas de estilo y JavaScript.

Creando un formulario de contacto desde cero

Vamos a hacerlo de forma fácil, siempre estamos a tiempo de complicarlo, así que vamos a ver cómo crear un formulario de contacto desde cero en el mismo theme.

Crear un archivo de plantilla

El primer paso es crear un archivo de plantilla (template file) en nuestro theme o child theme. Vamos a llamarlo page-contacto.php.

El nombre no es casualidad, lo llamaremos así para que se cargue cuando vayamos a la página con el slug «contacto». Evidentemente puedes llamarlo como quieras pero mi consejo es que incluya «page-» al principio para aprovechar la jerarquía de plantilla de WordPress.

Ahora cuando visites tuweb.com/contacto debería aparecer una página en blanco. ¡Vamos a llenarla!

<?php get_header(); ?>
    <div id="primary" class="content-area">
        <main id="main" class="site-main">
        <?php while ( have_posts() ) : the_post(); ?>
        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <header class="entry-header">
                <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
            </header><!-- .entry-header -->
            <div class="entry-content">
                <?php
                the_content();
                // AQUÍ VAMOS A PONER EL FORMULARIO
                ?>
            </div><!-- .entry-content -->
        </article><!-- #post-<?php the_ID(); ?> -->
        </main><!-- #main -->
    </div><!-- #primary -->
<?php
get_footer();

Lo siguiente es construir el formulario pero antes vamos a ver qué opciones tenemos para procesar los datos fuera del mismo archivo de plantilla.

Hooks admin_post vs wp_ajax

WordPress dispone de dos hooks especiales para recibir datos de un formulario:

admin_post se encarga de procesar datos de forma síncrona. Eso significa que nos tendremos que valer de redirecciones y tendremos que volver a cargar la página.

wp_ajax por su parte permite procesar los datos de forma asícrona de modo que no será necesario recargar la página pero deberemos hacer uso de JavaScript.

Para simplificar vamos utilizar admin_post.

Creando el formulario

Primero creamos un formulario con el atributo action apuntando a admin-post.php.

Añadimos un input type="hidden" con el atributo name="action" y le asignamos un valor único que usaremos para acceder al hook más adelante.

<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST">

    <!-- CAMPOS DEL FORMULARIO -->

    <input type="hidden" name="action" value="mytheme_contact_form">

</form>

También añadiremos un plus de seguridad con otro campo oculto que mandará un nonce mediante la función wp_nonce_field().

El formulario final quedaría así:

<div id="contact" class="contact-form">
    <form 
        action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" 
        method="post" 
        id="contact-form" 
        class="contact-form"
        >
        <p class="contact-form-name">
            <label for="name">Nombre</label>
            <input 
                id="name" 
                name="name" 
                type="text" 
                placeholder="Escribe aquí tu nombre" 
                required="required" 
                autocomplete="on"
            >
        </p>
        <p class="contact-form-email">
            <label for="email">Email</label>
            <input
                id="email" 
                name="email" 
                type="email" 
                placeholder="Escribe aquí tu Email" 
                required="required" 
                autocomplete="on"
            >
        </p>
        <p class="contact-form-message">
            <label for="message">Mensaje</label>
            <textarea 
                id="message" 
                name="message" 
                placeholder="Escribe aquí tu mensaje" 
                cols="45" 
                rows="5" 
                required="required" 
            >
            </textarea>
        </p>
        <p class="contact-form-privacy-consent">
            <input 
                id="contact-privacy-consent" 
                name="contact_privacy_consent[]" 
                type="checkbox" 
                required="required">
            <label for="contact-privacy-consent">Acepto la política de privacidad</label>
        </p>
        <p class="form-submit">
            <input name="submit" type="submit" id="submit" class="submit" value="Enviar">
            <?php wp_nonce_field( 'mytheme_send_contact_form_nonce' , 'mytheme_contact_form_nonce' ); ?>
            <input type="hidden" name="action" id="action" value="mytheme_contact_form">
        </p>
    </form>
</div>

Los elementos clave aquí son los input type="hidden".

Gracias a la función wp_nonce_field() nuestro formulario tendrá un campo oculto con id y nombre mytheme_contact_form_nonce y el valor del campo será un nonce generado por WordPress que podremos validar antes de tratar los valores del formulario. También generará un campo oculto llamado _wp_http_referer cuyo valor será la url relativa desde la que se manda el formulario.

El otro campo clave es este:

<input type="hidden" name="action" id="action" value="mytheme_contact_form">

El valor mytheme_contact_form lo usaremos para recuperar los valores que nos manden a través del formulario.

Procesando los datos

A continuación creamos una función en functions.php que recogerá los valores del formulario mediante dos hooks.

function my_handle_form_submit() {

    // Aquí es donde podremos procesar los datos ya que tendremos acceso a la variable global $_POST.

}

// Usaremos el valor único del campo oculto "action" al llamar a los hooks:
add_action( 'admin_post_nopriv_mytheme_contact_form', 'my_handle_form_submit' );
add_action( 'admin_post_mytheme_contact_form', 'my_handle_form_submit' );

La razón de utilizar dos hooks es que WordPress diferencia entre usuarios logueados y no logueados. Al usar los dos hooks podremos recoger los datos tanto de unos como de otros.

Los pasos al recibir los datos serán los siguientes:

  1. Validar nonce
  2. Validar datos
  3. Sanitizar
  4. Mandar correo
  5. Redirigir al usuario

Validar nonce

Para validar el nonce usaremos los mismos valores que usamos para crearlo.

if ( isset( $_POST['mytheme_contact_form_nonce'] ) && wp_verify_nonce( $_POST['mytheme_contact_form_nonce'], 'mytheme_send_contact_form_nonce' ) ) {

	// Aquí es donde podemos actuar de forma segura

}
else {

	// Aquí redirigimos al usuario de vuelta al formulario 

}

wp_die(); // Siempre debemos terminar la validación con wp_die(); 

Validar datos

Aquí podemos complicarlo tanto como queramos pero para nuestro ejemplo vamos a validar que los campos no estén vacíos y que el email tenga el formato adecuado.

if ( empty( $_POST['name'] ) || ! is_email( $_POST['email'] ) || empty( $_POST['message'] ) || empty( $_POST['contact_privacy_consent'][0] ) ) {

	// Redirigimos al usuario de vuelta al formulario

}
else {

	// Seguimos con los pasos necesarios

}

Sanitizar

Es muy importante sanitizar los datos antes de mandarlos por email o mostrarlos en nuestra web ya que podrían contener código malicioso. Para ello usaremos las funciones propias de WordPress.

// Sanitizar datos
$name = sanitize_text_field( $_POST['name'] );
$email = sanitize_text_field( $_POST['email'] );
$message = sanitize_textarea_field( $_POST['message'] );

Mandar correo

Para mandar el correo también usaremos una función propia de WordPress. Se basa en PHP Mailer así que si ya lo has usado antes te resultará muy familiar.

$to = get_option( 'admin_email' );
$subject = 'Contacto de :' . $name;
$message = $name . ' con email ' . $email . ' dice: ' . $message;

$is_mail_sent = wp_mail( $to, $subject, $message );

if ( $is_mail_sent ) {

	// si el correo se manda sin errores redirigimos al usuario a una página de gracias

}
else {

	// si hay algún error al mandar el correo redirigimos al usuario de nuevo al formulario

}

Redirigir al usuario

Debemos tener en cuenta que todo el proceso de datos del formulario lo realizamos desde admin-post.php que se encuentra en la parte privada (wp-admin) de nuestro WordPress así que siempre que terminemos una validación debemos redirigir al usuario a la página correspondiente y detener la ejecución de PHP con exit;.

// redirigir al usuario
wp_safe_redirect( get_home_url() . '/pagina-donde-queremos-redirigir/' );
exit;

Y con esto tendríamos un formulario básico y operativo en nuestra web.

Conclusión

Ya ves que no son muchas líneas de código y tu web irá mucho más relajada que con cualquier plugin de formularios.

Eso sí, ten en cuenta que apenas hemos implementado lo mínimo para que funcione. Te propongo que lo termines mejorando la validación de los datos y gestionando mensajes de error para mejorar la experiencia del usuario.