Página de contacto para WordPress sin plugins y notificación vía email con Google Apps

Compartir

En este artículo mostraré como realizar un formulario de contacto para WordPress (WP) sin necesidad de plugins utilizando una página con plantilla personalizada (custom page templates), campos personalizados (custom fields) para configuración como veremos más adelante, pre-validación con jQuery, simple validación y limpieza de datos, anti-spam con un honeypot captcha y un captcha normal para asegurarnos (Securimage CAPTCHA), y finalmente por si fuera poco integrarlo a tu cuenta de correo manejada con Google Apps para la notificación vía email y mostraré como hacer una plantilla con estilo para el email. ¿Interesado?



Trevor Davis en su blog nos cuenta la razón posible para no usar un plugin y parte de la inspiración y código salió de su artículo WordPress & jQuery Contact Form without a Plugin.

¡Hay una versión más reciente que puedes revisar en el siguiente link: “Video Tutorial #2 – Formulario de contacto WordPress sin plugins (simplificado)“! Aún así manten ambos artículos como referencia ;)

Si quieres ver un demo o bajar el código fuente lo tienes a continuación:

Procedimiento

  1. Crear una plantilla personalizada de página para WP.
  2. Crear una página en WP que use esa plantilla (nuestra página de contacto).
  3. Crear campos personalizados en la página de contacto.

1. La plantilla de página personalizada WP

En esta plantilla está toda la magia y está apoyada por las siguientes librerias y scripts:

  • Securimage CAPTCHA Librería para verificar que el usuario es humano.
  • PHPMailer Librería para enviar el email usando Gmail/Google Apps o cualquier servidor SMTP
  • contact-form.js Script para pre-validar con jQuery, para incluirse en el tema de WP
  • functions.php Archivo PHP de las funciones de nuestro tema WP, se agregan unas funciones.

Entendiendo la estructura de la plantilla de contacto

En el siguiente código definimos una plantilla de página para WordPress, en ella está la estructura básica que conformará nuestra página de contacto. No es necesario copiar este código, sólo lo purgue de tal modo que se entienda lo que se está haciendo sin tanto detalle.

<?php
/*
Template Name: Pagina de Contacto
*/

//Si ha sido enviado el formulario
if(isset($_POST['submitted']))
{
	//Validar y limpiar los datos (codigo aqui)

	//Si no hay ningún error, enviar el email. (codigo aqui)

}

//Obtener el Header
get_header();

//El Loop de WordPress para obtener el contenido y poder usar campos personalizados
if (have_posts()):
	while (have_posts()) : the_post();

		//Si se envió el email, mostrar mensaje de notificación
		if(isset($emailSent) && $emailSent == true):
			# <!-- Mensaje de notificación -->

		//No se envió el email, hubo errores
		elseif(isset($hasError) OR isset($honeypotError) OR isset($captchaError)):
			# <!-- Mensaje de error -->

		//Se carga normalmente el contenido de la página
		else:
			the_content();
		endif;

		//Si no se ha intentado enviar el mensaje o hubo errores, carga el formulario
		if(!isset($emailSent) OR $emailSent == false)
			// <!-- Codigo del Formulario -->
		endif;

	endwhile;
endif;

//Obtener Sidebar (opcional)
get_sidebar();
//Obtener el Footer
get_footer();
?>

Lo que se hace es verificar si se ha enviado el formulario, si no, carga normalmente la página. Si ha sido enviado entonces se realizan las validaciones y si todo va bien se envía el email de notificación y se avisa al usuario. Si hay errores se despliegan ya sea con Javascript habilitado o no.

Validación

Este código primero verifica el Captcha, después la trampa (honeypot captcha) que básicamente se trata de un campo que no debe tener datos y se oculta al usuario con código CSS (más adelante el código CSS necesario), después verifica que cada campo del formulario tenga contenido y lo limpia de caracteres especiales con las funciones stripslashes y htmlspecialchars nativas de PHP. Finalmente comprueba que el campo oculto contactId sea numérico pues este se utiliza para obtener los datos de los campos personalizados y es el ID de la página para WP. En caso de haber cualquier error, se activa una variable $hasError.

<?php
//Checa si el codigo captcha es correcto
if ($securimage->check($_POST['ccode']) == false)
{
 $captchaError = true;
 $hasError = true;
}

//Checa si la trampa (honeypot captcha) está vacia
if($_POST['ageCheck'] !== '')
{
 $honeypotError = true;
 $hasError = true;
}

//Checa que no esté vacio el campo Nombre
if(trim($_POST['contactName']) === '')
{
 $nameError = 'Olvidaste escribir tu nombre.';
 $hasError = true;
}
else
 $name = trim($_POST['contactName']);

//Checa que sea una dirección email válida
if(trim($_POST['email']) === '')
{
 $emailError = 'Olvidaste tu direcci&oacute;n de email.';
 $hasError = true;
}
else if (!is_email(trim($_POST['email'])))
{
 $emailError = 'Direcci&oacute;n de email no v&aacute;lida.';
 $hasError = true;
}
else
 $email = trim($_POST['email']);

//Checa que hallan escrito un mensaje
if(trim($_POST['message']) === '')
{
 $messageError = 'Olvidaste escribir tu mensaje.';
 $hasError = true;
}
else
{
 if(function_exists('stripslashes') && function_exists('htmlspecialchars'))
 $message = htmlspecialchars(stripslashes(trim($_POST['message'])));
 else
 $message = trim($_POST['message']);
}
//Checa que la ID de la página "the_ID" sea numérica
if(is_numeric($_POST['contactId']))
 $contactId = $_POST['contactId'];
else
 $hasError = true;
?>

Envío de email

Esta parte del código es la que utiliza los campos personalizados de WP. ¿Bueno, y para qué? En principio es para poder alterar los parámetros del servidor de correo SMTP desde el panel de administración de WP en la edición de la entrada/página y de este modo no tener que estar tocando el código PHP. La segunda es para manipular los datos del remitente del email (Nombre, Email, Asunto, Cuerpo del mensaje). La tercera es para poder usar una plantilla en el email con diseño en caso de que el usuario se envíe una copia a sí mismo y de este modo manejar el branding de nuestra empresa.

<?php
//Si no hay ningún error, envía el email.
	if(!isset($hasError))
	{
		$sendCopy = $_POST['sendCopy'];

		$keywords = array('%name%','%email%','%message%','%bloginfo%');
		$replace = array($name, $email, $message, get_bloginfo());

		$mail = new PHPMailer();
		$mail->IsSMTP();
		$mail->SMTPAuth = true;
		$mail->SMTPSecure = "ssl";
		$mail->Host = get_post_meta($contactId, "mailHost", true); #"smtp.gmail.com";
		$mail->Port = get_post_meta($contactId, "mailPort", true); #465;
		$mail->Username = get_post_meta($contactId, "mailUsername", true); #"contacto@tudominio.com";
		$mail->Password = get_post_meta($contactId, "mailPassword", true); #"password";

		$mail->From = get_post_meta($contactId, "mailFrom", true); #'noreply@tudominio.com'; #get_option('admin_email');
		$mail->FromName = str_replace($keywords, $replace, get_post_meta($contactId, "mailFromName", true)); #get_bloginfo();
		$mail->Subject = str_replace($keywords, $replace, get_post_meta($contactId, "mailSubject", true)); #'Contacto: ' . $name;
		$mail->AltBody = str_replace($keywords, $replace, get_post_meta($contactId, "mailText", true)); #"Envia: $name <$email>\n\n$message";
		$mail->MsgHTML(str_replace($keywords, $replace, get_post_meta($contactId, "mailHTML", true))); #"<p><strong>$name</strong>&lt;$email&gt;</p><p>$message</p>";

		$mail->AddBCC(get_post_meta($contactId, "mailUsername", true), get_bloginfo());

		if($sendCopy == true)
			$mail->AddAddress($email, $name);

		$mail->AddReplyTo($email, $name);
		$mail->IsHTML(true);
		$mail->AddCustomHeader('Mime-Version: 1.0\r\n');

		$emailSent = $mail->Send();
	}
?>

El formulario de contacto

Esta sección define el código del formulario HTML que incluye código PHP para rellenar los campos válidos, las notificaciones de error y los CAPTCHAS, además recordar que aquí se pone la ID de la entrada en un campo oculto.

<form action="<?php the_permalink(); ?>" id="contactForm" method="post">
<p><label for="contactName">Nombre</label><br/>
	<input type="text" name="contactName" id="contactName" value="<?php if(isset($_POST['contactName'])) echo $_POST['contactName'];?>" class="requiredField" />
	<?php if($nameError != '') { ?>
		<span class="error"><?=$nameError;?></span>
	<?php } ?>
</p>
<p><label for="email">Email</label><br/>
	<input type="text" name="email" id="email" value="<?php if(isset($_POST['email']))  echo $_POST['email'];?>" class="requiredField email" />
	<?php if($emailError != '') { ?>
		<span class="alert"><?=$emailError;?></span>
	<?php } ?>
</p>
<p><label for="messageText">Mensaje</label><br/>
	<textarea name="message" id="messageText" class="requiredField" rows="2" cols="24"><?php if(isset($_POST['message'])) { if(function_exists('stripslashes')) { echo stripslashes($_POST['message']); } else { echo $_POST['message']; } } ?></textarea>
	<?php if($messageError != '') { ?>
		<span class="error"><?=$messageError;?></span>
	<?php } ?>
</p>
<p><input type="checkbox" name="sendCopy" id="sendCopy" value="true"<?php if(isset($_POST['sendCopy']) && $_POST['sendCopy'] == true) echo ' checked="checked"'; ?> /><label for="sendCopy">Enviar una copia a tu email.</label>
</p>
<p class="screenReader"><label for="checking" class="screenReader">Para enviar tu mensaje no llenes este campo</label><br /><input type="text" name="ageCheck" id="checking" class="screenReader" value="<?php if(isset($_POST['checking'])) echo $_POST['checking'];?>" />
</p>
<p><label for="ccode">Escribe el c&oacute;digo siguiente</label><br />
	<img id="captcha" src="<?php bloginfo('template_url'); ?>/includes/securimage/securimage_show.php" alt="CAPTCHA Image" style="margin: 3px;" /><br />
	<a href="#" onclick="document.getElementById('captcha').src = '<?php bloginfo('template_url'); ?>/includes/securimage/securimage_show.php?' + Math.random(); return false">Recargar c&oacute;digo</a><br />
	<input type="text" name="ccode" id="ccode" size="8" maxlength="4" /><br />
	<span>No se distingue entre may&uacute;sculas y min&uacute;sculas.</span>
</p>
<p class="buttons">
	<input type="hidden" name="contactId" id="contactId" value="<?php the_ID(); ?>" />
	<input type="hidden" name="submitted" id="submitted" value="true" />
	<input type="submit" name="submit" value="Enviar &raquo;" />
</p>
</form>

La pre-validación con jQuery

La pre-validación lo que hace es iterar sobre los campos del formulario que tengan la clase requiredField y sólo verifica que tengan contenido, también realiza una simple comprobación sobre el campo que tenga la clase email para checar si está bien formada (no es posible verificar que la dirección exista). Si todo va bien, permite que el formulario sea enviado, si no, se muestran los mensajes de error (los puedes modificar en las líneas resaltadas).

$(document).ready(function() {
	$('form#contactForm').submit(function()
	{
		$('#contactForm .alert, #contactForm .error').remove();

		var hasError = false;

		$('.requiredField').each(function()
		{
			if(jQuery.trim($(this).val()) == '')
			{
				var labelText = $(this).prev().prev('label').text();
				$(this).parent().append('<span class="error">Olvidaste '+labelText+'.</span>');
				hasError = true;
			}
			else if($(this).hasClass('email'))
			{
				var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
				if(!emailReg.test(jQuery.trim($(this).val())))
				{
					var labelText = $(this).prev().prev('label').text();
					$(this).parent().append('<span class="error">El '+labelText+'no es v&aacute;lido.</span>');
					hasError = true;
				}
			}
		});

		return !hasError;

	});
});

Insertando el script de pre-validación en la página de contacto

Para insertar el código Javascript de jQuery para pre-validar se añade código al archivo de funciones del tema WP (functions.php). Se trata de dos funciones, una para llamar directamente desde nuestra plantilla y otra que se llama automáticamente cuando WP obtiene el pie de página (footer) e inserta la línea de código que vincula con nuestro script.

<?php
/*
	Este bloque de código reemplaza al jQuery incluido en WP por el que está alojado en los
	CDN de Google
	Referencia: http://digwp.com/2009/06/use-google-hosted-javascript-libraries-still-the-right-way/
*/
if( !is_admin())
{
   wp_deregister_script('jquery');
   wp_register_script('jquery', ("http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"), false, '1.3.2');
   wp_enqueue_script('jquery');
}
/*
	Esta función agrega una acción para que se inserte el script de pre-validación
	en el "footer" de nuestro tema WP
	Referencias: http://codex.wordpress.org/Function_Reference/add_action
*/
function prepara_pre_validacion()
{
	add_action('wp_footer', 'inserta_pre_validacion');
}
/*
	Esta función se ejecuta automaticamente cuando se manda llamar la función "wp_footer()"
	en nuestro tema WP e inserta el script para pre-validar con jQuery
*/
function inserta_pre_validacion()
{
?>
		<script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/js/pre-valida-contacto.js"></script>
<?php
}
?>

Para instalar la plantilla en WP

Primero baja la librería Securimage CAPTCHA (yo uso la Version 2.0.1 BETA) mejorada respecto a la primer versión y viene con ejemplos y documentación.

La librería PHPMailer ya viene incluida en WP (al menos en versiones recientes), en el código de la plantilla se incluyen las clases necesarias.

Baja la plantilla con el código completo (pagina-contacto.php), el archivo de pre-validación en Javascript (pre-valida-contacto.js), copia el código PHP de functions.php en tu archivo functions.php del tema instalado, si no existe lo creas.

Los archivos deben quedar de la siguiente forma:

Extrae todos los archivos de Securimage dentro del directorio de tu tema WP y dentro de /includes/securimage/. El archivo Javascript (pre-valida-contacto.js) dentro de /js/. Como se muestra en seguida.

wordpress/wp-content/themes/directorio-tema/includes/securimage/
wordpress/wp-content/themes/directorio-tema/js/pre-valida-contacto.js
wordpress/wp-content/themes/directorio-tema/pagina-contacto.php
wordpress/wp-content/themes/directorio-tema/functions.php

Para configurar Securimage edita el archivo securimage_show.php ubicado en:

wordpress/wp-content/themes/directorio-tema/includes/securimage/securimage_show.php

Para más referencia te recomiendo la documentación oficial de Securimage, si no editas nada usa la configuración predeterminada, pero quizá te gustaría cambiar los colores, la tipografía, etc. pero esto ya es para otro artículo.

El código CSS necesario

El único código css que es necesario sirve para ocultar el campo del honeypot captcha, lo demás puede ser a gusto personal: colores, bordes, margenes, espacios, etc.

El siguiente código insertalo en la hoja de estilo del tema de WordPress que estés usando.

#contactForm .screenReader		{ display:none; visibility:hidden; }

2. Crear una página en WP con nuestra plantilla.

Ya que subiste los archivos necesarios como se explicó anteriormente, hay que crear una página en WordPress con el editor de páginas y seleccionar “Pagina de Contacto” como nuestra plantilla para que la use, ponerle título, dirección y el contenido que queramos vea el usuario antes del formulario.

Captura de pantalla, creación de página de contacto

3. Crear los campos personalizados en la página de contacto

Posteriormente viene algo de magia, se crearán los siguientes campos personalizados (custom fields) para la página, respetando minúsculas/mayúsculas:

  • mailHost: Dirección del servidor SMTP
  • mailPort: Puerto del servidor SMTP
  • mailUsername: Nombre de usuario de la cuenta de correo
  • mailPassword: Contraseña de la cuenta de correo
  • mailFrom: Dirección email que envía el correo electrónico
  • mailFromName: Nombre del remitente del email
  • mailSubject: Asunto del email
  • mailText: Contenido del email en texto plano
  • mailHTML: Contenido del email en HTML
  • successMessage: Mensaje de notificación de que el email fue enviado

Captura de pantalla, creación de campos personalizados

Aquí es necesario explicar algunos asuntos, primero los valores que hay que indicar para que esto funcione con cuentas de correo electrónico de Google Apps o Gmail y los valores de los demás campos para que contengan los datos que envía el usuario.

Configuración de Google Apps

La razón de usar PHPMailer y Google Apps (o cualquier servidor de correo SMTP) es que al enviar el email éste NO llega a la bandeja de SPAM tanto de nuestra propia cuenta así como en la del usuario que se envía a sí mismo una copia del mensaje. Es la razón principal, ya que la función mail() en algunos casos es imposible hacer que el correo no caiga en el spam.

Bien, los valores de los campos personalizados para Google Apps son:

  • mailHost: smtp.gmail.com
  • mailPort: 465
  • mailUsername: tu_email@tu_dominio.com
  • mailPassword: La contraseña de la cuenta

¡Eso es todo para Google Apps!

Configuración del cuerpo del mensaje

Después, para el mensaje en sí, tenemos los siguientes comodines (wildcards) que serán sustituidos por los datos que introdujo el usuario.

  • %name%: Es sustituido por el nombre que introdujo el usuario.
  • %email%: Es sustituido por el email que introdujo el usuario.
  • %message%: Es sustituido por el mensaje que introdujo el usuario.
  • %bloginfo%: Es sustituido por el nombre de tu blog.

De esta forma, en los campos personalizados restantes usamos esos comodines para que contengan la información correspondiente. El modo de usarlos lo muestro a continuación:

  • mailFrom: noreply@tudominio.com
  • mailFromName: %bloginfo%
  • mailSubject: Contacto: %name%
  • mailText: De: %name% <%email%>\n\n%message%
  • mailHTML: (ver mas abajo)
  • successMessage: (ver mas abajo)

Ejemplo de mailHTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>%bloginfo%</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
	<div style="width:94%;padding:3%;margin:0 auto;font-family:Georgia; font-size:12px;">
	<h2 style="font-family:Arial,sans-serif;color:#AB7C00;">Gracias <span style="color:#CA412C;">%name%</span></h2>
	<p>Estar&eacute; en contacto muy pronto.</p>
	<h4>Tu mensaje</h4>
	<p>%message%</p>
	<p>&nbsp;</p>
	<p>&mdash;<br/>Atentamente,<br/>Julio Flores</p>
	<p>&nbsp;</p>
	<p><a href="http://jfastudios.com"><img src="http://jfastudios.com/blog/wp-content/themes/ArrowAttitude2/style/images/logo.png" alt="JFA Studios" style="border:none;outline:none;"/></a></p>
	<p>&nbsp;</p><hr/>
	<p style="font-family:Arial,Helvetica,sans-serif;"><small>La funci&oacute;n de este mensaje es &uacute;nicamente informativa. Las respuestas no se supervisar&aacute;n ni se contestar&aacute;n.<br />Para contactar puedes escribir al e-mail de <a href="mailto:contacto@jfastudios.com">contacto</a> o ingresar <a href="http://jfastudios.com/contacto">aqu&iacute;</a>.</small></p>
	</div>
</body>
</html>

Recuerden usar url’s completas para imágenes y estilos css de línea. También noten que aquí se usan los comodines.

Ejemplo de successMessage

<h3 class="archive">Gracias <span>%name%</span></h3>
	<p><strong>Tu mensaje ha sido enviado.</strong> Responder&eacute; a la brevedad posible.</p>
	<p>Si te enviaste una copia, por favor revisa en tu bandeja de <em>spam</em> ya que en ocasiones se filtra el email. Para evitar esto, agrega la direcci&oacute;n <tt>contacto@jfastudios.com</tt> a tu lista blanca o de contactos.</p>

En mailText noten los saltos de línea (\n) pues lo trata como cadena y PHP lo sustituye por el salto visible, en mailHTML nos valemos de párrafos y lo que les de la imaginación así que no es necesario. En successMessage se puede usar HTML ya que se inserta a mitad del Loop de WordPress sin el contenido de la página.

Notas finales

¡Eso es todo!, sólo publicamos la página y realizamos las pruebas. Quizá sea necesario ajustar algunas partes del código según el caso, para mayor facilidad en la instalación baja el código completo, descomprime y súbelo directamente al directorio de tu tema WP teniendo cuidado con el archivo functions.php (haz un respaldo previamente), si ya existe y tiene funciones, entonces sólo edítalo y agrega el código que viene en mi archivo functions.php.

En resumen

  1. Sube los archivos de la plantilla de contacto.
  2. Baja la librería Securimage, descomprime y coloca todos los archivos dentro del directorio del tema y en <directorio-tema>/includes/securimage/
  3. Inserta el código CSS necesario.
  4. Crea la página en el editor y especifícale la plantilla “Pagina de Contacto”.
  5. Crea todos los campos personalizados y asígnales los valores correspondientes.
  6. Publica la página.

Disfrútalo, haz un comentario, sugiere algo o si encontraste errores hazlo saber.

Enlaces de referencia