Formulario de contacto para WordPress sin plugin

1 comentario

22.02.2026|

1 comentario

Tiempo de lectura Lectura: 14 min, 9 s
Número de palabras Palabras: 2620
Número de visitas Visitas: 161
Icono de traducción
⚡ Resumen rápido
Páginas de este post →
12

Código para formulario de contacto para WordPress sin plugin

//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 = 'copywriter'; // No hay palabras prohibidas por defecto si está vacío

    // 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 no se hayan añadido direcciones de correo en el mensaje
                        if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', $mensaje)) {
                            $errors[] = 'No se permiten direcciones de correo en el mensaje.';
                        }

                        // Validar que el mensaje tenga al menos 15 caracteres
                        if (strlen($mensaje) < 15) {
                            $errors[] = 'El mensaje debe tener al menos 15 caracteres.';
                        }

                        // Validar que el mensaje no supere los 1000 caracteres
                        if (strlen($mensaje) > 1000) {
                            $errors[] = 'El mensaje no puede superar los 1000 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://jrmora.com/declaracion-de-privacidad-ue/';

    // 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" maxlength="1000" 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');

Preguntas frecuentes

¿Por qué es mejor usar un formulario sin plugin en WordPress?

La principal ventaja es el rendimiento. Los plugins de formularios suelen cargar archivos CSS y JS en todas las páginas de tu web, incluso donde no hay formularios. Al usar una función personalizada, solo ejecutas el código necesario, reduces las peticiones HTTP y mejoras la velocidad de carga (WPO).

¿Es seguro un formulario de contacto creado con código manual?

Sí, siempre que se utilicen las funciones de seguridad nativas de WordPress. En el código propuesto se incluyen "nonces" para evitar ataques de falsificación de peticiones (CSRF) y funciones de saneamiento (sanitize_text_field) y validación para asegurar que los datos recibidos son limpios y seguros.

¿Cómo se evitan los envíos de SPAM sin usar ReCaptcha?

Una técnica muy efectiva y ligera es el uso de un "honeypot" (campo trampa). Consiste en un campo oculto que los humanos no ven, pero los bots rellenan automáticamente. Si el formulario llega con ese campo relleno, el sistema lo descarta silenciosamente sin necesidad de cargar scripts externos de Google.

¿Dónde debo pegar el código para que el formulario funcione?

El código PHP principal debe ir en el archivo functions.php de tu tema hijo (child theme) o en un plugin de funciones personalizadas como Code Snippets o similar. Para mostrar el formulario en una página, se utiliza un "shortcode" que puedes insertar en cualquier bloque de texto o página de contacto.

¿Qué pasa si mi servidor no envía los correos del formulario?

Este sistema utiliza la función wp_mail() de WordPress. Si los correos no llegan, suele ser un problema de configuración del servidor o de entregabilidad (caen en spam). La solución recomendada es configurar un servicio de SMTP profesional para asegurar que los correos lleguen correctamente a la bandeja de entrada.

Páginas de este post →
12

Donar

Documentales sobre dibujantesTontolares, los titulares más tontos

1 comentario en «Formulario de contacto para WordPress sin plugin»

  1. ¡Buenas!
    Muy buen aporte para quienes buscan un formulario de contacto sin depender de plugins en WordPress. Me ha gustado que incluya validaciones de seguridad como el nonce y la opción de Google reCAPTCHA. Además, el captcha de suma es un buen filtro anti-spam ligero. Es importante medir bien el uso de plugins, porque si los usas para todo, puedes acabar con un sitio pesado e impracticable. Este tipo de soluciones en código ayudan a mantener WordPress optimizado. Un código bien estructurado, funcional y con margen para personalizarlo según las necesidades de cada sitio. ¡Gracias, compañero!

Los comentarios están cerrados.

Este blog se aloja en LucusHost

LucusHost, el mejor hosting

Tu WordPress puede volar

Servicio de optimización de WordPress
Quiero velocidad

Servicio de optimización

Suscripción por e-mail

Recibe gratis los artículos completos en tu correo sin publicidad en el momento que se publiquen. Se envía el contenido íntegro del feed sin herramientas externas y sin anuncios.