Por qué desactivar Disable Comments no basta para reabrir los comentarios en WordPress

comentarios wordpress

Valencia, 22/08/2026, G.B.
Hace unos días me encontré con un problema aparentemente sencillo que terminó siendo bastante más terco de lo esperado: quería volver a permitir comentarios en las entradas de este blog, y por más que lo intentaba, el formulario para escribir un comentario nuevo seguía sin aparecer. Los comentarios antiguos se veían perfectamente, pero no había forma de dejar uno nuevo.

El sospechoso obvio: Disable Comments

En algún momento había usado el plugin Disable Comments para bloquear los comentarios en ciertos tipos de contenido. Cuando decidí revertir eso, hice lo que parecía razonable:

  1. Entré en los ajustes del plugin y cambié el tipo de contenido (la taxonomía de entradas) para el que se bloqueaban los comentarios, dejando «Entradas» fuera del bloqueo.
  2. Guardé los cambios.
  3. Desactivé el plugin.

Nada. Los comentarios seguían sin poder crearse.

Pensando que quizás el plugin no se había desactivado del todo bien, fui un paso más allá:

  1. Lo desinstalé por completo, borrándolo del sitio.
  2. Vacié toda la caché, tanto la del plugin de caché del sitio como cualquier caché a nivel de servidor.

Seguía sin funcionar. En este punto ya no tenía sentido seguir sospechando del plugin: ni siquiera estaba instalado.

Reduciendo el problema

Revisé el archivo single.php del tema por si el formulario de comentarios se estaba omitiendo por algún motivo relacionado con la plantilla, pero el código era el estándar, sin nada raro. También descarté que hubiera algún hook personalizado interfiriendo en functions.php del tema hijo: nada relacionado con comments_open, save_post ni wp_insert_post_data.

Lo que sí encontré, consultando directamente la base de datos, fue esto: entradas ya publicadas, incluso una programada, tenían el campo comment_status en closed en la tabla wp_posts, a pesar de que el ajuste general de WordPress (Ajustes > Comentarios > «Permitir que la gente envíe comentarios en las entradas nuevas») estaba correctamente en abierto.

La explicación tiene sentido una vez se entiende cómo funciona WordPress internamente: el ajuste default_comment_status solo se aplica en el momento en que se crea la fila del post por primera vez. Si esa entrada se creó (aunque fuera como borrador) mientras el ajuste global estaba en cerrado, o mientras Disable Comments seguía activo bloqueando ese tipo de contenido, el valor closed queda grabado de forma permanente en esa fila concreta. Cambiar el ajuste general después no reescribe retroactivamente las entradas que ya existían; solo afecta a las que se creen a partir de ese momento.

Es decir, el problema nunca estuvo en el plugin en sí, sino en un dato ya escrito en la base de datos que el plugin dejó como herencia antes de desactivarse.

La solución: una consulta SQL

Con muchas entradas afectadas, corregirlas una a una desde el panel de WordPress (edición en lote, cambiando «Comentarios» a «Permitir») era viable pero lento. La solución rápida fue una actualización directa en la base de datos desde phpMyAdmin:

USE nombre_de_tu_base_de_datos;
UPDATE wp_posts SET comment_status = 'open' WHERE post_type = 'post' AND comment_status = 'closed';

Esta consulta actualiza de golpe el estado de comentarios de todas las entradas (post_type = 'post') que estuvieran cerradas, dejando fuera páginas y otros tipos de contenido. Antes de ejecutarla conviene hacer una copia de seguridad de la tabla wp_posts (tienes que poner tu prefijo de las tablas. Por defecto, si no lo has cambiado en la instalación de WordPress es wp_), y si se quiere comprobar el alcance antes de aplicar el cambio, un simple SELECT COUNT(*) FROM wp_posts WHERE post_type = 'post' AND comment_status = 'closed'; da el número exacto de entradas que se van a ver afectadas.

Conclusión

Cuando un plugin como Disable Comments actúa escribiendo valores directamente en la base de datos en lugar de aplicar solo un filtro en tiempo real, desactivarlo (o incluso desinstalarlo) no revierte esos cambios. Los ajustes generales de WordPress tampoco se aplican de forma retroactiva a entradas ya existentes. En estos casos, revisar directamente la base de datos con una consulta SQL es la forma más fiable de confirmar la causa real del problema y, de paso, la manera más rápida de solucionarlo cuando hay muchas entradas implicadas.

Cómo montar un disco en Linux: guía sencilla para Ubuntu MATE

Valencia, 21/08/2026
Conectar un disco duro o una memoria USB en Linux no siempre es tan automático como en otros sistemas operativos. En este artículo repasamos las diferentes formas de montar un disco en Ubuntu MATE (que es mi distro favorita…), con el gestor de archivos Caja, y cómo dejarlo siempre disponible con un simple acceso directo en el escritorio.

Nota: aunque los ejemplos están hechos en Ubuntu MATE, todo lo relacionado con fstab, lsblk, blkid y el uso de la terminal es igualmente válido en cualquier distribución basada en Debian (Ubuntu, Linux Mint, MX Linux, etc.), independientemente del escritorio que uses. Lo único específico de este artículo es el apartado del gestor de archivos Caja: si usas otro entorno con un explorador distinto (Nautilus en GNOME, Dolphin en KDE, Thunar en Xfce…), el montaje temporal y la creación de accesos directos se hacen de forma similar, pero con menús y nombres de opción diferentes.

¿Qué significa «montar» un disco?

En Linux, un disco no aparece disponible hasta que el sistema lo «monta» en una carpeta concreta. Montar significa asociar la unidad física a un punto del sistema de archivos, de forma que todo lo que hay en el disco se pueda ver y usar como si fuera una carpeta más.

Opción 1: montaje temporal desde Caja (modo fácil)

Si solo necesitas usar el disco de forma puntual, la manera más sencilla es conectarlo y abrir el gestor de archivos Caja. Normalmente aparecerá automáticamente en el panel lateral, bajo «Dispositivos». Basta con hacer clic para montarlo.

Este tipo de montaje se guarda en /media/tu_usuario/ y solo está disponible mientras tienes la sesión gráfica abierta. Es ideal para discos USB que conectas de vez en cuando.

Opción 2: montaje permanente con fstab (modo avanzado)

Si usas un disco de forma habitual, como un disco duro interno o externo que siempre quieres tener disponible, lo mejor es configurarlo en el archivo /etc/fstab para que se monte automáticamente en cada arranque, en la misma ubicación y con los permisos correctos.

Los pasos generales son:

  1. Identificar el disco y su identificador único (UUID) con el comando lsblk -f.
  2. Hacer una copia de seguridad del archivo original con sudo cp /etc/fstab /etc/fstab.bak.
  3. Crear una carpeta fija donde montar el disco, por ejemplo sudo mkdir -p /mnt/midisco.
  4. Añadir una línea en /etc/fstab indicando el UUID, la carpeta de destino, el tipo de sistema de archivos y las opciones de montaje.
  5. Probar el resultado con sudo mount -a, sin necesidad de reiniciar el equipo.

Un ejemplo de línea para un disco en formato exFAT sería:

UUID=XXXX-XXXX /mnt/midisco exfat defaults,uid=1000,gid=1000,umask=022,nofail 0 0

La opción uid=1000,gid=1000 es especialmente importante en discos exFAT o NTFS, ya que estos formatos no usan permisos de tipo Unix: sin esa opción, el disco quedaría accesible solo para el usuario root, y no podrías abrirlo con normalidad desde tu propio usuario ni desde el explorador gráfico.

La opción nofail también es recomendable en discos externos, porque evita que el sistema se quede bloqueado en el arranque si el disco no está conectado en ese momento.

Comprobar que todo funciona

Una vez editado el archivo, conviene verificar que el propietario de la carpeta es tu usuario y no root:

ls -ld /mnt/midisco

Si el resultado muestra tu nombre de usuario en vez de «root», el montaje está bien configurado y podrás acceder al disco sin necesidad de usar sudo.

Crear un acceso directo en el escritorio

Para acceder al disco con un simple doble clic, puedes crear un enlace en el escritorio. Hay dos formas de hacerlo:

Por terminal:

ln -s /mnt/midisco ~/Escritorio/midisco

(sustituye «Escritorio» por «Desktop» si tu carpeta de escritorio está en inglés).

Desde Caja, de forma gráfica:

  1. Abre Caja y navega hasta la carpeta del disco.
  2. Haz clic derecho sobre ella y selecciona «Crear enlace».
  3. Corta el enlace generado y pégalo en tu carpeta de Escritorio.

En ambos casos obtendrás un icono en el escritorio que apunta directamente al disco, sin duplicar ni mover ningún archivo.

Un consejo extra: añade también un marcador en Caja

Si el disco no está en /media sino en una ruta como /mnt, no aparecerá automáticamente en el panel lateral de Caja. Puedes añadirlo tú mismo navegando hasta la carpeta y pulsando Ctrl+D, o desde el menú «Marcadores > Añadir este marcador». Así lo tendrás siempre a un clic de distancia, junto a tus demás carpetas.

Resumen

Para un uso ocasional, el montaje automático desde Caja es suficiente. Para un disco que quieras tener siempre disponible, con permisos correctos y accesible desde el arranque, la configuración en fstab es la opción más robusta. Y con un acceso directo en el escritorio y un marcador en el explorador de archivos, tendrás tu disco a mano en todo momento.

Badman’s Song: a ver si consigo hacer y tocar una versión de esta canción…

badman song

Momentos musicales y ya de vacaciones!!…

Valencia, 21/08/2026, G.B.
«Badman’s Song» es un tema de Tears for Fears, incluido en su álbum Songs from the Big Chair (1985), aunque en algunas ediciones aparece como bonus track o en directo (hay versiones «Live» y «Townhouse Live Jam Sessions»). Es un tema largo, de más de 11 minutos de duración en la versión en directo que os muestro, con un marcado carácter de jam: estructura extensa, mucho espacio para instrumental, groove funk/soul y un aire muy distinto al pop más compacto de singles como «Shout» o «Everybody Wants to Rule the World» del mismo álbum, que en cambio son mucho más cortos y directos. Canta también y toca el piano en esta canción -maravillosamente, por cierto- Oleta Adams.

Mi intención (solo intención por ahora…) es unir los dos grupos con los que toco incluyendo a una cantante invitada (ya sé quién sería, aunque ella aún no lo sepa…). El principal problema será los teclados (piano y órgano). Hablaré con Gaby para que llame a su hermano, ¿Me hará caso?…

Esta canción tiene ventajas claras: al ser tan extensa y de raíz jam, admite fácilmente repartir secciones entre dos voces principales (por ejemplo alternando estrofas o dejando que una voz lleve el groove y la otra entre en los pasajes más soul/gospel), y al tener tanto desarrollo instrumental da mucho margen para que ambos grupos nos turnemos (si conseguimos unirnos y hay espacio suficiente…)  en riffs de bajo, guitarra y teclado sin pisarnos.

Aquí dejo un vídeo en directo de 1985 de Badman’s Song. Disfrutadlo como yo!

Función para calcular el tiempo de lectura de una entrada (post)

Valencia, 19/08/2026, G.B.
Si alguna vez has visto en un blog un texto como «5 min de lectura» justo encima del contenido de una entrada, seguramente te hayas preguntado cómo se calcula. La buena noticia es que no hace falta instalar ningún plugin para conseguirlo: con una función sencilla en el functions.php del tema hijo es suficiente.

La idea detrás del cálculo

El tiempo de lectura estimado se basa en un cálculo muy simple: se cuenta el número de palabras del contenido y se divide entre una velocidad media de lectura, normalmente entre 200 y 250 palabras por minuto. No es una ciencia exacta, pero da una idea útil y realista al lector sobre cuánto tiempo le va a llevar la entrada.

La función paso a paso

Lo primero es una función que calcule ese tiempo a partir del contenido del post:

function indaga_calculate_reading_time( $post_id = null ) {
  if ( ! $post_id ) {
    $post_id = get_the_ID();
  }
  $content = get_post_field( 'post_content', $post_id );
  $content = strip_shortcodes( $content );
  $content = wp_strip_all_tags( $content );
  preg_match_all( '/[\p{L}\p{N}]+/u', $content, $matches );
  $word_count = count( $matches[0] );
  $reading_time = ceil( $word_count / 200 );
  if ( $reading_time < 1 ) {
    $reading_time = 1;
  }
  return $reading_time;
}

Merece la pena detenerse en un par de detalles. Antes de contar palabras, se eliminan los shortcodes y las etiquetas HTML con strip_shortcodes() y wp_strip_all_tags(), para no contar código como si fuera texto. Y el conteo de palabras se hace con una expresión regular UTF-8 (preg_match_all con el patrón /[\p{L}\p{N}]+/u) en lugar de la función nativa str_word_count(), porque esta última no reconoce bien acentos ni la letra «ñ», algo imprescindible al trabajar con contenido en castellano.

Mostrarlo automáticamente en cada entrada

Con el cálculo ya resuelto, el siguiente paso es mostrarlo sin tener que tocar ninguna plantilla del tema. Para eso se engancha a un filtro que WordPress ya tiene previsto: the_content.

function indaga_add_reading_time_to_content( $content ) {
  if ( is_single() && in_the_loop() && is_main_query() && 'post' === get_post_type() ) {
    $reading_time = indaga_calculate_reading_time();
    $notice = '<p class="indaga-reading-time">Tiempo de lectura: ' . $reading_time . ' min</p>';
    $content = $notice . $content;
  }
  return $content;
}
add_filter( 'the_content', 'indaga_add_reading_time_to_content' );

Las tres comprobaciones dentro del if son las que marcan la diferencia entre que esto funcione bien o dé problemas: is_single() asegura que solo se muestre en la página individual de una entrada, in_the_loop() y is_main_query() evitan que el aviso aparezca duplicado en widgets, feeds o bucles secundarios, y la comprobación del tipo de contenido lo limita a entradas de blog, dejando fuera páginas u otros tipos de contenido.

Personalizar el estilo

El aviso se genera con la clase CSS indaga-reading-time, así que basta con añadir unas líneas al style.css del tema hijo para darle el aspecto deseado, por ejemplo:

.indaga-reading-time {
  font-style: italic;
  color: #666;
  margin-bottom: 1em;
}

En resumen

Con menos de treinta líneas de código, sin dependencias externas y sin necesidad de un plugin adicional, es posible añadir una funcionalidad que mejora la experiencia de lectura y encaja perfectamente con la filosofía de mantener el sitio ligero y bajo control propio.

Nota: Descargar de mi cuenta pCloud el código completo (en formato .txt)

Plugin Autores revisado y actualizado (versión 3.9)

autores-plugin

Valencia, 18/08/2026, G.B.
El pequeño plugin que hice para insertar publicaciones, Autores, me fallaba en Puntocomunica.com y en este sitio Indaga.net. Tenía que crear la tabla «a mano» desde phpMyAdmin.

En la web para la que hice este plugin funcionaba perfectamente. La diferencia es que esa web tiene la última versión de mariaDB y las otras dos, las mías, una versión más antigua de MySQL. Además, la seguridad no estaba del todo «afinada«.  Ahora creo que sí. Para mostrarlo hay que insertar el shortcode (entre corchetes[ ], como todos los shortcodes): autores_form

Una muestra:

Añadir nueva publicación

No tiene permiso para agregar autores.

Publicaciones listadas

Este es el enlace de descarga de mi cuenta pCloud: descargar autores-plugin.zip

Eliminar hipervínculos de títulos en WordPress: Cómo crear un plugin sencillo

eliminar_enlaces_en_titulo

Valencia, 17/08/2026, G.B.
Los títulos con enlaces en WordPress pueden ser un problema cuando necesitas mantener la consistencia visual o evitar navegación innecesaria. Si administras un directorio o catálogo de productos y tus títulos contienen HTML con hipervínculos, te voy a mostrar cómo crear un plugin personalizado para eliminarlos automáticamente.

El problema

Durante un tiempo, estuve poniendo el enlace en el título a las entradas de la parte del directorio de Indaga.net. No sé, en ese momento me pareció una buena idea… Con el tiempo comprobé que era un error, por lo que he decidido quitar el código HTML en el título de las entradas afectadas., las cuales, además, deben tener una etiqueta (tag) específica: en mi caso «directorio».

Un ejemplo de título de una entrada con el enlace incluido, el que quiero borrar, para que veas a qué me refiero:

<a href="https://www.ejemplo.com" target="_blank" rel="nofollow">Título de la entrada</a>

Esto no solo afecta la apariencia, sino que también puede generar problemas de SEO y navegación indeseada. ¿La solución? Un plugin personalizado que elimine estos enlaces automáticamente.

La expresión regular

La clave está en esta expresión regular: /<a[^>]*>(.*?)<\/a>/i

Desglosándola:

  • <a[^>]*> – Captura la etiqueta de apertura con cualquier atributo
  • (.*?) – Extrae el texto dentro (no greedy)
  • <\/a> – Captura el cierre de la etiqueta
  • i – Ignora mayúsculas/minúsculas

Crear el plugin en 3 pasos

Paso 1: Crear el archivo del plugin

Accede a tu servidor mediante FTP,  SFTP o el administrador de archivos de tu hosting, y crea un nuevo archivo:

/wp-content/plugins/eliminar_enlaces_en_titulo.php

Más rápido:
También puedes crear una carpeta con el mismo nombre del archivo .php e incluirlo ahí. Luego la comprimes como .zip y navegas en tu escritorio de WordPress a  Plugins: Añadir plugin. Subes el archivo .zip, lo instalas y lo activas.

Paso 2: Agregar el código

Copia y pega el siguiente código:

<?php
/**
 * Plugin Name: Eliminar Enlaces en Título
 * Description: Elimina hipervínculos del título solo en entradas con tag "directorio"
 * Version: 1.0
 * Author: Guillermo Beltrán Pilato
 * Text Domain: eliminar-enlaces-directorio
 */

function eliminar_enlaces_de_titulos_directorio($titulo, $id = 0) {
    // Solo aplicar si el post tiene el tag "directorio"
    if ($id && has_tag('directorio', $id)) {
        return preg_replace('/<a[^>]*>(.*?)<\/a>/i', '$1', $titulo);
    }
    return $titulo;
}

add_filter('the_title', 'eliminar_enlaces_de_titulos_directorio', 10, 2);
?>

Paso 3: Activar el plugin

  1. Ve a Plugins → Plugins instalados en tu panel de WordPress
  2. Busca «Eliminar Enlaces en Tag Directorio»
  3. Haz clic en Activar

¿Cómo funciona?

El plugin actúa como un filtro invisible que:

  • Detecta todas las entradas con el tag «directorio»
  • Elimina el código HTML de los enlaces en los títulos
  • Conserva el texto original sin el hipervínculo
  • No modifica la base de datos (solo afecta la visualización)

Ejemplo:

AntesDespués
<a href=»…»>Traductor online Deepl</a>Traductor online Deepl

Personalización

Usar un tag diferente

Si tu tag no se llama «directorio», simplemente cambia el nombre en la función:

if ($id && has_tag('mi-tag', $id)) {

Aplicar a múltiples tags

if ($id && (has_tag('directorio', $id) || has_tag('catalogo', $id))) {

Filtrar por tipo de entrada

Si solo quieres que funcione en páginas en lugar de entradas:

if ($id && has_tag('directorio', $id) && get_post_type($id) === 'page') {

Ventajas de este enfoque

  • Automático: No necesitas hacer nada manualmente
  • Seguro: No modifica la base de datos
  • Flexible: Solo afecta las entradas que especifiques
  • Reversible: Desactiva el plugin y vuelve al estado anterior
  • Lightweight: Código mínimo, sin impacto en rendimiento

Actualizar títulos existentes en la base de datos

Si prefieres que los cambios se guarden permanentemente en la base de datos, puedes usar esta consulta SQL (con copia de seguridad previa):

UPDATE wp_posts 
SET post_title = REGEXP_REPLACE(post_title, '<a[^>]*>(.*?)</a>', '$1')
WHERE post_type = 'post' AND post_title LIKE '%<a%';

Conclusión

Con este plugin personalizado, tienes control total sobre cómo se muestran los títulos en tu sitio. Es especialmente útil para directorios, catálogos y sitios donde importas contenido regularmente. Fácil de instalar, sin configuración necesaria, y totalmente gratuito.

Bonus Track

Enlaces a páginas para aprender sobre expresiones regulares:

RegexOne: Tutorial interactivo donde practicas directamente en el navegador con ejercicios progresivos. Muy práctico para aprender haciendo

Regular Expressions Info: Aunque el sitio principal está en inglés, tiene una sección traducida en español y es muy exhaustivo. Excelente como referencia

MDN Web Docs de Mozilla – Expresiones regulares es probablemente tu mejor opción. Es completo, autorizado, tiene ejemplos claros y está bien traducido al español. Cubre desde lo básico hasta conceptos avanzados.

Comandos su y sudo en Linux: qué son, en qué se diferencian y cómo usarlos bien

sudo su

Valencia, 16/08/2026, G.B.
Si administras un sistema Linux, tarde o temprano necesitas ejecutar algo con privilegios de administrador. Para eso existen dos comandos clásicos: su y sudo. Se confunden a menudo porque hacen «cosas parecidas», pero funcionan de forma bastante distinta y esa diferencia importa, sobre todo en seguridad.

Qué hace su

su (substitute user) cambia de usuario dentro de la misma sesión de terminal, sin cerrar la sesión actual. Si lo ejecutas sin argumentos, intenta convertirte en root:

su

Te pedirá la contraseña de root. El problema en distribuciones como Ubuntu es que, por defecto, la cuenta root no tiene contraseña establecida (está bloqueada), así que su a secas no funciona salvo que la actives manualmente con sudo passwd root.

Un matiz importante que mucha gente pasa por alto: su sin el guión no carga el entorno completo del usuario destino (variables de entorno, PATH, etc.), lo que puede provocar errores de «orden no encontrada». La forma correcta es:

su -

Esto sí simula un login completo como root, con su propio entorno.

También puedes cambiar a otro usuario que no sea root:

su - nombreusuario

Y ejecutar un único comando como ese usuario sin abrir una sesión interactiva completa:

su nombreusuario -c 'whoami'

Qué hace sudo

sudo (superuser do) no cambia de usuario: ejecuta un comando puntual con privilegios elevados, pidiendo tu propia contraseña, no la de root.

sudo apt update
sudo systemctl restart nginx

Esto es justo lo que hace que Ubuntu y macOS desactiven la contraseña de root por defecto: en vez de compartir una contraseña maestra entre varios administradores, cada uno usa la suya y sudo decide, según el fichero /etc/sudoers, qué puede hacer cada cual.

Si necesitas una sesión completa como root en lugar de un comando suelto, existe el equivalente moderno:

sudo -i

Es prácticamente lo mismo que su -, pero pasando por el mecanismo de autenticación de sudo.

Diferencias clave (resumen práctico)

susudo
Contraseña que pideLa del usuario destino (root)La tuya propia
Uso típicoAbrir una sesión completaEjecutar un comando puntual
Registro de auditoríaLimitadoRegistra en /var/log/auth.log quién ejecutó qué y cuándo
Granularidad de permisosTodo o nadaSe puede limitar por comando, usuario o grupo
Estado en UbuntuRoot bloqueado por defectoHabilitado y recomendado

Este último punto es la razón real por la que sudo se ha impuesto: permite dar acceso administrativo limitado (por ejemplo, solo a systemctl restart nginx, no a todo el sistema), mientras que su es binario: o tienes la contraseña de root, o no tienes nada.

Configurar quién puede usar sudo

Los permisos se definen en /etc/sudoers, pero nunca se edita directamente con un editor de texto normal: un error de sintaxis ahí puede dejarte sin forma de recuperar privilegios de administrador. Se usa siempre:

sudo visudo

visudo bloquea el archivo, valida la sintaxis antes de guardar y evita dejar el sistema en un estado roto.

Hoy en día se recomienda no tocar /etc/sudoers en sí, sino añadir ficheros propios en /etc/sudoers.d/, por ejemplo:

sudo visudo -f /etc/sudoers.d/miusuario

Con una línea como esta le das a un usuario acceso completo:

miusuario ALL=(ALL:ALL) ALL

O, de forma mucho más segura, acceso solo a un comando concreto sin pedir contraseña (útil para scripts automatizados o tareas programadas):

deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx

Añadir a un usuario al grupo sudo (en Ubuntu/Debian) tiene el mismo efecto que la primera línea, y suele ser más práctico que editar ficheros a mano:

sudo usermod -aG sudo nombreusuario

Comandos de sudo que conviene conocer

  • sudo -l — lista qué comandos puede ejecutar tu usuario con sudo.
  • sudo -k — invalida la caché de autenticación, así el próximo sudo te vuelve a pedir contraseña.
  • sudo -v — refresca el «ticket» de sudo sin ejecutar ningún comando.
  • sudo !! — repite el último comando pero con sudo delante (muy útil cuando olvidas anteponerlo).

Sobre este último: por defecto, tras autenticarte con sudo, el sistema no vuelve a pedir contraseña durante 15 minutos. Es cómodo, pero también un riesgo si dejas la terminal desatendida. Se puede ajustar (o eliminar) ese margen con Defaults timestamp_timeout=0 en /etc/sudoers.d/.

sudo su: el atajo que todo el mundo usa

Es habitual ver esta combinación:

sudo su

Aquí pides tu propia contraseña (vía sudo) para lanzar una sesión de root (vía su), sin necesidad de activar nunca la contraseña de root. Es el método recomendado si de verdad necesitas una shell interactiva como root en un sistema Ubuntu moderno, en lugar de activar la cuenta root manualmente.

Alternativa más moderna: doas

En distribuciones más minimalistas (OpenBSD, y disponible también en Debian/Ubuntu vía paquete) existe doas, pensado como una alternativa ligera a sudo, con una configuración mucho más simple en /etc/doas.conf. No ha desplazado a sudo en el mundo Ubuntu/Debian, pero es una opción a tener en cuenta en entornos donde se prioriza minimizar la superficie de ataque.

Buenas prácticas

  1. Evita trabajar como root de forma continua; usa sudo comando a comando.
  2. Nunca edites /etc/sudoers sin visudo.
  3. Da permisos específicos por comando (NOPASSWD con ruta exacta) en vez de acceso total cuando sea posible, especialmente para cuentas de automatización.
  4. Revisa /var/log/auth.log periódicamente si gestionas un servidor con varios administradores; ahí queda constancia de cada uso de sudo.
  5. Ten en cuenta que sudo -s abre un shell que no registra los comandos que escribas dentro de él, a diferencia de invocaciones individuales de sudo comando. Si te importa la auditoría, evita ese patrón.

En resumen

su cambia de identidad; sudo presta privilegios para una acción concreta sin dejar de ser tú mismo. En cualquier sistema Ubuntu o Debian actual, la recomendación sigue siendo la misma que hace más de una década: usa sudo para el día a día, reserva sudo -i o sudo su para cuando de verdad necesites una shell completa como root, y controla los permisos finos vía visudo y /etc/sudoers.d/.

Cómo añadir un honeypot a un formulario de contacto de Contact Form 7

Valencia, 14/08/2024, G.B.
Para ampliar la información del artículo Cómo evitar el spam en los formularios de Contact Form 7 en WordPress, vamos ahora a ver cómo añadir un «honeypot» o «tarro de miel» a un formulario de Contact Form 7 para engañar a los bots y evitar así el maldito spam, en la medida de lo posible…

Son tres sencillos pasos:

1) Añadir el campo oculto al formulario

En el editor de Contact Form 7, dentro de la pestaña Formulario, añade este campo en cualquier parte del formulario (por ejemplo, justo después del campo de nombre):

[text website-url]

Esto genera un campo de texto normal llamado website-url. El nombre es arbitrario, pero conviene que suene «atractivo» para un bot (website, url, phone-number… campos que suelen rellenar automáticamente).

2) Ocultarlo con CSS

Añade esta regla a la hoja de estilos del tema (o al Personalizador → CSS adicional):

.wpcf7-form p:has(input[name="website-url"]) {
position: absolute;
left: -9999px;
top: -9999px;
}

Si prefieres no depender de :has() (por compatibilidad con navegadores muy antiguos), puedes envolver el campo en un <span> con una clase propia desde el editor de CF7 en modo HTML:

<span class="cf7-honeypot">[text website-url]</span>

y luego:

.cf7-honeypot {
position: absolute;
left: -9999px;
top: -9999px;
}

Ambas opciones son válidas; la primera es más simple si no necesitas soportar navegadores muy antiguos.

3) Validar el envío en functions.php

Contact Form 7 incluye desde la versión 5.1 el filtro wpcf7_spam, pensado justo para esto:

add_filter( 'wpcf7_spam', function ( $spam, $submission ) {
if ( $spam ) {
return $spam; // ya marcado como spam por otra regla, no seguimos
}

$data = $submission->get_posted_data();

if ( ! empty( $data['website-url'] ) ) {
return true; // el honeypot llegó relleno: es un bot
}

return $spam;
}, 10, 2 );

Con esto, si el campo website-url llega con cualquier contenido, Contact Form 7 marca el envío como spam internamente y lo bloquea antes de que se envíe el correo, sin mostrar ningún error confuso al bot (simplemente no pasa nada, como sería el comportamiento esperado desde su perspectiva).

Nota importante sobre el name del campo

Evita nombres como honeypot o trap: los bots más elaborados ya los reconocen y los saltan. Cuanto más «normal» parezca el nombre del campo (address, company, fax-number), más probable es que un bot lo rellene sin sospechar nada.

Cómo evitar el spam en los formularios de Contact Form 7 en WordPress

Valencia, 13/08/2026, G.B.
Cualquiera que administre un sitio en WordPress con un formulario de contacto conoce el problema: tarde o temprano, la bandeja de entrada empieza a llenarse de mensajes automáticos, ofertas de SEO milagroso o enlaces sospechosos. Contact Form 7, uno de los plugins de formularios más usados del ecosistema WordPress, no incorpora protección antispam por defecto, así que esa tarea recae en quien lo instala. La buena noticia es que evitarlo no requiere grandes conocimientos técnicos, sino combinar bien un puñado de técnicas.

Por qué llega el spam a un formulario de contacto

El spam en formularios no suele venir de personas, sino de bots que rastrean la web en busca de campos <form> y <input> para rellenarlos automáticamente. Cuantos más elementos «adivinables» tenga el formulario (nombre, email, mensaje), más fácil es para un bot completarlo sin intervención humana. Por eso las soluciones eficaces no se basan en dificultar la vida al usuario real, sino en tender trampas o barreras que solo detectan a las máquinas.

El método más eficaz y menos invasivo: el honeypot

La técnica del honeypot consiste en añadir al formulario un campo invisible para las personas pero visible para los bots, que recorren el HTML sin ejecutar el CSS que lo oculta. Si ese campo llega relleno al servidor, se descarta el envío sin más. Contact Form 7 permite implementarlo fácilmente combinando un campo de texto oculto con CSS y una validación en functions.php que rechace el envío si ese campo no está vacío. Es la opción que menos fricción añade, porque no exige nada al usuario legítimo.

Un honeypot («tarro de miel» en castellano) existe en el HTML, así que cualquier bot que analice el código lo detecta como un campo más a rellenar.
Está oculto para las personas, normalmente con CSS (display: none o posicionándolo fuera de la pantalla), así que un usuario real jamás lo ve ni lo rellena, por lo que debería llegar siempre vacío cuando el envío lo hace una persona.

Un bot que rastrea formularios no «ve» el CSS, solo el HTML crudo, así que interpreta ese campo como uno legítimo y lo completa automáticamente (a menudo con texto basura, o incluso su propia URL). En el servidor, la lógica es simple: si ese campo llega con algo escrito, el envío se descarta sin más, porque solo una máquina pudo haberlo rellenado.

Es una trampa en el sentido literal: no impide que el bot rellene el formulario, sino que aprovecha su propio comportamiento automático para delatarlo. Por eso es tan eficaz y tan poco invasivo a la vez —no le pide nada extra al usuario real, solo tiende una trampa que solo un bot puede pisar.

reCAPTCHA: la barrera más conocida

Google reCAPTCHA (en su versión v3, invisible) es la integración nativa de Contact Form 7 y sigue siendo una de las defensas más sólidas frente a bots más sofisticados. Se configura desde el propio panel de Contact Form 7, introduciendo la clave del sitio y la clave secreta que genera Google. Su ventaja es que analiza el comportamiento del visitante en segundo plano, sin mostrar los típicos rompecabezas de «selecciona las imágenes con semáforos», lo que evita perjudicar la conversión.

Validación estricta de campos

Otra capa de protección, complementaria a las anteriores, es endurecer la validación de los campos del formulario: exigir que el campo de email tenga un formato válido, limitar la longitud del mensaje, o bloquear la presencia de etiquetas HTML o enlaces en campos que no deberían contenerlos (el nombre, por ejemplo). Contact Form 7 admite expresiones regulares personalizadas en sus campos, lo que permite filtrar patrones típicos del spam antes de que el mensaje llegue siquiera a enviarse.

Filtrado adicional con Akismet

Si el sitio ya usa Akismet para proteger los comentarios de WordPress, se puede aprovechar el mismo servicio para los formularios: existen extensiones de Contact Form 7 que envían cada envío a Akismet para su análisis antes de reenviarlo por correo. Es un paso extra útil cuando el volumen de spam sigue siendo alto pese al honeypot y el reCAPTCHA.

Qué evitar

Conviene ser prudente con los bloqueos por IP y las limitaciones agresivas de frecuencia de envío: son medidas que, mal calibradas, terminan bloqueando a usuarios legítimos con más facilidad que a los propios bots, que suelen rotar de IP constantemente. Tampoco es necesario desactivar el formulario ni añadir capas de fricción visibles si con un honeypot y reCAPTCHA v3 ya se resuelve la mayor parte del problema.

En resumen

La combinación más razonable para un formulario de Contact Form 7 en WordPress es: honeypot como primera barrera invisible, reCAPTCHA v3 como segunda capa de análisis de comportamiento, y validación de campos para cerrar el paso a los patrones más evidentes de spam. Con estos tres elementos bien configurados, la gran mayoría de los envíos automáticos quedan filtrados sin que el visitante real note ninguna diferencia al escribir su mensaje.

Comandos para configurar Debian desde terminal

Valencia, 13/08/2026, G.B.
Dejo un repaso práctico con comandos que suelen funcionar en Debian actuales para tareas comunes: identificar la versión, actualizar el sistema, configurar red (IP/DNS), revisar historial, gestionar discos, procesos, directorios/ficheros, usuarios y operaciones básicas.

Estructura y puntos principales (índice)

El contenido se divide en 10 bloques, cada uno con comandos concretos y listos para copiar:

  • Identificación del sistema — cat /etc/os-release y cat /etc/debian_version para saber la versión exacta de Debian.
  • Actualización de paquetes — diferencia claramente entre apt update, apt upgrade y apt full-upgrade, explicando que este último puede implicar remociones de paquetes incompatibles; añade autoremove y clean para limpieza de caché.
  • Configuración de red — cubre visualización de interfaces (ip link, ip addr, ip route), asignación temporal de IP y gateway, y edición de /etc/resolv.conf para DNS. Incluye una nota práctica útil: en sistemas donde NetworkManager o systemd-resolved gestionan la red, los cambios manuales al resolv.conf pueden revertirse si no se ajusta también el gestor de red.
  • Historial de comandos — history, borrado selectivo (history -d) y limpieza de pantalla.
  • Discos y particiones — lsblk, fdisk -l, df -h.
  • Procesos — listado con ps aux y terminación de procesos, distinguiendo kill de kill -9.
  • Directorios — operaciones básicas de creación, borrado y navegación.
    Ficheros — creación con touch y concatenación con cat.
  • Usuarios — cambio de contraseña, creación de usuarios, bloqueo de cuentas (passwd -l).
  • Operaciones del sistema — reinicio y apagado.

1) Comprobar sistema y versión de Debian

cat /etc/os-release

Versión específica:

cat /etc/debian_version

2) Actualizar paquetes y sistema

Actualizar listas de paquetes:

sudo apt update

Actualizar paquetes instalados (sin cambios agresivos):

sudo apt upgrade

Actualizar incluyendo dependencias que puedan requerir cambios/remociones (remociones se refiere a desinstalar algunos paquetes que ya no encajan con las nuevas dependencias, o que no se pueden mantener mientras el sistema queda consistente) si es necesario:

sudo apt full-upgrade

Si necesitas limpiar caché:

sudo apt autoremove
sudo apt clean

3) Configurar la red

Ver interfaces y direcciones

ip link
ip addr

Ver la ruta (por dónde sale el tráfico):

ip route

Configuración temporal de IP (para probar)

Asignar IP a una interfaz (temporal, hasta reiniciar o cambiar la configuración persistente):

sudo ip addr add 192.168.1.49/24 dev eth0

Eliminar esa IP:

sudo ip addr del 192.168.1.49/24 dev eth0

Añadir gateway por defecto (si aplica):

sudo ip route add default via 192.168.1.1

Quitar gateway por defecto:

sudo ip route del default via 192.168.1.1

DNS (nameservers)

Editar el fichero de resolución:

sudo nano /etc/resolv.conf

Añadir líneas como:

nameserver 192.168.0.1
nameserver 87.216.1.65

Nota práctica: en algunas instalaciones, /etc/resolv.conf lo gestiona NetworkManager o systemd-resolved. Si al editar “se revierte”, hay que ajustar la configuración en el gestor de red.

4) Historial de comandos

history

Mostrar los últimos 10:

history 10

Borrar historial:

history -c

Borrar una línea concreta (índice del historial):

history -d 342

Borrar la pantalla:

clear

5) Discos y particiones

Listar dispositivos/particiones:

lsblk

Ver particiones con detalle:

sudo fdisk -l

Ver espacio libre y puntos de montaje:

df -h

6) Procesos

Ver procesos en ejecución:

ps aux

Matar un proceso (por PID):

sudo kill -9 <PID>

(Para matar sin -9 cuando sea posible):

sudo kill <PID>

7) Directorios

Crear directorios:

mkdir directorio1 directorio2

Borrar directorio vacío:

rmdir directorio

Borrar directorio no vacío (con cuidado):

rm -r directorio

Mostrar directorio actual:

pwd

Listar contenido:

ls

Listar con permisos y propietarios:

ls -l

Volver al home:

cd ~

8) Ficheros

Crear un archivo vacío:

touch nombrearchivo

Crear un archivo concatenando dos archivos:

cat archivo1 archivo2 > suma

9) Usuarios

Cambiar contraseña del usuario actual:

passwd

Crear un usuario:

sudo useradd pruebas

Establecer contraseña del usuario:

sudo passwd pruebas

Bloquear el acceso por contraseña (bloquear cuenta):

sudo passwd -l pruebas

Mostrar usuarios (lista de /etc/passwd):

cat /etc/passwd

10) Operaciones básicas del sistema

Reiniciar:

sudo reboot

Apagar:

sudo shutdown -h now