One thing I don't understand is that WordPress does not yet include a simple but complete contact form by default.
As I regularly do WordPress optimisation work , both here and on third-party sites, I often replace unnecessarily bloated plugins with options, blocks, and decorations that are never used or not needed with code to lighten the load.
This contact form is a complete and customisable solution for WordPress, designed to be secure, easy to use and respectful of user privacy. In addition, you can add or remove options as you wish. This is the form I use here .
These are its main functions and features and the instructions to add it to any page or post of your blog with a shortcode.
Structure and options Name : Mandatory field for the user to enter his or her name.Email address : Required field for the user to enter their email address.Message : Mandatory field for the user to write their message. It must be at least 15 characters long.Sum captcha : A simple captcha that asks the user to solve a sum of two random numbers between 1 and 9.Acceptance of privacy policy : Mandatory checkbox to accept the privacy policy before submitting the form.Validations and security Validation of mandatory fields : All fields are mandatory. If any are missing, an error message is displayed.Link validation : No links (URLs) are allowed in the name or message fields.Addition Captcha : Prevents automated spam by requiring the user to solve a simple mathematical operation.Google reCAPTCHA (optional) : If Google reCAPTCHA keys are configured, a second level of security is added to prevent bots. If reCAPTCHA keys are not added to the code, the code will not be added to the form.Validation of forbidden words : Optionally, specific words can be blocked in the message, e.g.: pineapple, pizza, bitcoin (separated with comma and no spaces).Nonce security : Protects against CSRF (Cross-Site Request Forgery) attacks.3. Privacy No data storage : No user data is stored (no emails, no IPs, no referring URLs, nothing). This approach complies with privacy regulations such as the GDPR, as no personal information is collected or stored.Privacy policy : Includes a link to the privacy policy that the user must read and accept before submitting the form.4. Feedback messages Error messages : Displayed in a block at the top of the form if there are errors in the validation.Success message : After successfully submitting the form, a success message is displayed in green, 14px in size and in bold:"Thank you! Your message has been sent ". You can change this text and its formatting in the code. The rest of the styles such as the yellow background, the border and shadow of the box containing the form that you can see here , as well as other external elements are not included in the code as they are added with a GenerateBlocks container.5. Personalisation Captcha text : Customisable (default: "Are you human? Solve this sum:").Prohibited words : A comma-separated list of prohibited words can be added.Google reCAPTCHA : Optional, only added if you configure and add the site and secret keys of your captcha to the code.The code checks if the shortcode is present and if the shortcode is not present, it will not display anything, so it will only run on the page or post where the shortcode has been added.
Performance where it is shown is optimal.
Installation and configuration instructions 1. Copy and add the code Open the functions.php file of your WordPress theme (or create a custom plugin if you prefer not to modify the theme or use Code Snippets ). Copy and paste the complete form code into your functions.php file. 2. Set up Google reCAPTCHA (Optional) Go to Google reCAPTCHA . Select reCAPTCHA v2 and select the "I'm not a robot" Checkbox . Register your website and get the keys:Polylang placeholder do not modify In the form code, replace 'YOUR_SITE_KEY'
and 'YOUR_SECRET_KEY'
with the keys you obtained.Polylang placeholder do not modify 3. Set banned words (Optional) 1 - In the form code, find the line:
$palabras_prohibidas = ' ';
2 - Add the words you want to block, separated by commas. For example:
$palabras_prohibidas = 'caca,culo,pedo,pis';
If you do not want to block any words, leave the variable empty.
4. Customise the captcha text of the sum (Optional) In the form code, look for this line:
<label for="captcha">¿Eres humano? Resuelve esta suma: <strong><?php echo $num1; ?> + <?php echo $num2; ?> = </strong></label>
Change the text "Are you human? Solve this sum:" with the one you want to show.
5. Add the URL of your privacy policy Replace the example url with the URL of your site's privacy policy on this line:
$politica_privacidad_url = 'https://tuweb.com/declaracion-de-privacidad/';
6. Shortcode Add the shortcode to the page or post where you want the form to be displayed.
[formulario_contacto]
Finally, you will just have to test it to verify that the emails are sent and arrive and observe the usage to prevent relentless spammers from sneaking their shit in by complicating the mathematical captcha and/or activating both captchas at the same time. The code can always be improved and can be debugged and optimised. You can also translate it if you need to use it in another language.
If I make changes or improvements to the code depending on the result, I will add the notes here.
Code //Crea un shortcode que genera un formulario de contacto para añadir en cualquier página o post de tu blog. Código actualizado en https://jrmora.com/formulario-contacto-wordpress-sin-plugin/
// Shortcode para mostrar el formulario de contacto
function contacto_form_shortcode() {
// Verificar si el shortcode está presente en el contenido actual
if (!has_shortcode(get_the_content(), 'formulario_contacto')) {
return ''; // Si no está el shortcode, no mostrar nada
}
ob_start(); // Iniciar el buffer de salida
// Claves de Google reCAPTCHA (cambia estas por las tuyas)
$site_key = 'TU_CLAVE_DEL_SITIO'; // Clave del sitio de reCAPTCHA
$secret_key = 'TU_CLAVE_SECRETA'; // Clave secreta de reCAPTCHA
// Verificar si las claves son las predeterminadas
$recaptcha_enabled = ($site_key !== 'TU_CLAVE_DEL_SITIO' && $secret_key !== 'TU_CLAVE_SECRETA');
// Lista de palabras prohibidas (separadas por comas)
// Ejemplo: $palabras_prohibidas = 'spam,publicidad,oferta';
$palabras_prohibidas = ''; // No hay palabras prohibidas por defecto
// Convertir la lista de palabras prohibidas en un array
$palabras_prohibidas_array = !empty($palabras_prohibidas) ? explode(',', $palabras_prohibidas) : [];
// Variables para almacenar errores
$errors = [];
// Verificar si el formulario ha sido enviado
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['contacto_nonce'])) {
// Verificar el nonce para seguridad
if (!wp_verify_nonce($_POST['contacto_nonce'], 'contacto_form_nonce')) {
$errors[] = 'Error de seguridad. Inténtalo de nuevo.';
} else {
// Validar el captcha de suma
$captcha = sanitize_text_field($_POST['captcha']);
$captcha_correct = sanitize_text_field($_POST['captcha_correct']);
if ($captcha !== $captcha_correct) {
$errors[] = 'El resultado de la operación es incorrecto. Inténtalo de nuevo.';
} else {
// Validar la aceptación de la política de privacidad
if (!isset($_POST['aceptar_privacidad'])) {
$errors[] = 'Debes aceptar la política de privacidad para enviar el formulario.';
} else {
// Validar Google reCAPTCHA (solo si está habilitado)
if ($recaptcha_enabled) {
if (isset($_POST['g-recaptcha-response'])) {
$recaptcha_response = sanitize_text_field($_POST['g-recaptcha-response']);
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_data = [
'secret' => $secret_key,
'response' => $recaptcha_response,
];
$recaptcha_options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($recaptcha_data),
],
];
$recaptcha_context = stream_context_create($recaptcha_options);
$recaptcha_result = file_get_contents($recaptcha_url, false, $recaptcha_context);
$recaptcha_json = json_decode($recaptcha_result);
if (!$recaptcha_json->success) {
$errors[] = 'Por favor, verifica que no eres un robot.';
}
} else {
$errors[] = 'Por favor, completa el reCAPTCHA.';
}
}
// Si no hay errores, procesar el formulario
if (empty($errors)) {
$nombre = sanitize_text_field($_POST['nombre']);
$email = sanitize_email($_POST['email']);
$mensaje = sanitize_textarea_field($_POST['mensaje']);
// Validar campos obligatorios
if (empty($nombre)) {
$errors[] = 'El campo nombre es obligatorio.';
}
if (empty($email)) {
$errors[] = 'El campo email es obligatorio.';
}
if (empty($mensaje)) {
$errors[] = 'El campo mensaje es obligatorio.';
}
// Validar que no se hayan añadido enlaces en los campos
if (preg_match('/http|www|\[url|\[link|href=/i', $nombre . $mensaje)) {
$errors[] = 'No se permiten enlaces en los campos del formulario.';
}
// Validar que el mensaje tenga al menos 15 caracteres
if (strlen($mensaje) < 15) {
$errors[] = 'El mensaje debe tener al menos 15 caracteres.';
}
// Validar palabras prohibidas (solo si hay palabras en la lista)
if (!empty($palabras_prohibidas_array)) {
foreach ($palabras_prohibidas_array as $palabra) {
if (stripos($mensaje, $palabra) !== false) {
$errors[] = 'El mensaje contiene palabras no permitidas.';
break; // Detener la validación al encontrar una palabra prohibida
}
}
}
// Si no hay errores, enviar el correo
if (empty($errors)) {
$to = get_option('admin_email'); // Correo del administrador
$subject = 'Nuevo mensaje de contacto desde el sitio web';
$headers = array('Content-Type: text/html; charset=UTF-8', 'From: ' . $nombre . ' <' . $email . '>');
$body = "<p><strong>Nombre:</strong> $nombre</p>";
$body .= "<p><strong>Email:</strong> $email</p>";
$body .= "<p><strong>Mensaje:</strong> $mensaje</p>";
if (wp_mail($to, $subject, $body, $headers)) {
// Redirigir para evitar reenvío al refrescar la página
wp_redirect(add_query_arg('contacto', 'success', wp_get_referer()));
exit;
} else {
$errors[] = 'Hubo un error al enviar el mensaje. Inténtalo de nuevo.';
}
}
}
}
}
}
}
// Mostrar mensaje de éxito después de la redirección
if (isset($_GET['contacto']) && $_GET['contacto'] === 'success') {
echo '<p style="font-size: 14px; font-weight: bold; color: green;">¡Gracias! Tu mensaje ha sido enviado.</p>';
}
// Generar un captcha de suma de dos números aleatorios entre 1 y 9
$num1 = rand(1, 9); // Primer número aleatorio entre 1 y 9
$num2 = rand(1, 9); // Segundo número aleatorio entre 1 y 9
$captcha_result = $num1 + $num2; // Resultado de la suma
// URL de la política de privacidad
$politica_privacidad_url = 'https://tuweb.com/declaracion-de-privacidad/';
// Mostrar el formulario
?>
<?php if (!empty($errors)) : ?>
<div style="color: red; margin-bottom: 20px;">
<?php foreach ($errors as $error) : ?>
<p><?php echo esc_html($error); ?></p>
<?php endforeach; ?>
</div>
<?php endif; ?>
<form action="" method="post">
<p>
<label for="nombre">Nombre:</label><br>
<input type="text" name="nombre" id="nombre" value="<?php echo isset($nombre) ? esc_attr($nombre) : ''; ?>" required>
</p>
<p>
<label for="email">Email:</label><br>
<input type="email" name="email" id="email" value="<?php echo isset($email) ? esc_attr($email) : ''; ?>" required>
</p>
<p>
<label for="mensaje">Mensaje:</label><br>
<textarea name="mensaje" id="mensaje" rows="5" required><?php echo isset($mensaje) ? esc_textarea($mensaje) : ''; ?></textarea>
</p>
<p>
<label for="captcha">¿Eres humano? Resuelve esta suma: <strong><?php echo $num1; ?> + <?php echo $num2; ?> = </strong></label><br>
<input type="text" name="captcha" id="captcha" required>
<input type="hidden" name="captcha_correct" value="<?php echo $captcha_result; ?>">
</p>
<?php if ($recaptcha_enabled) : ?>
<p>
<div class="g-recaptcha" data-sitekey="<?php echo esc_attr($site_key); ?>"></div>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</p>
<?php endif; ?>
<p>
<input type="checkbox" name="aceptar_privacidad" id="aceptar_privacidad" required>
<label for="aceptar_privacidad">He leído y acepto la <a href="<?php echo esc_url($politica_privacidad_url); ?>" target="_blank">política de privacidad</a>.</label>
</p>
<p>
<?php wp_nonce_field('contacto_form_nonce', 'contacto_nonce'); ?>
<input type="submit" value="Enviar">
</p>
</form>
<?php
return ob_get_clean(); // Devolver el contenido del buffer
}
add_shortcode('formulario_contacto', 'contacto_form_shortcode');