Archivo de la categoría: tips

WordPress: Creando flash-message

Para que una aplicación web sea más entendible lo que está haciendo, muchas veces recurrimos a los «flash message». Esto son unos avisos que aparecen una vez aterrizamos en una página y solo la primera vez que llegamos. Útiles para notificar que se hizo algo en la anterior página y el resultado de esa acción.

Como mi premisa siempre es intentar no reinventar la rueda, usar los patrones más cercanos a «core» para que la experiencia de usuario sea sencilla me puse a investigar como genera «core» sus flash-message para hacerlos igual.

En general, en el admin de WordPress estamos hablando de engancharnos al hook de acción ‘admin_notices’ y pintar un div con classs «notice».

Y digo en general, porque cuando llegamos a la pantalla de edición de post nos encontramos con el editor Guttenberg, que se renderiza principalmente en el navegador, no en el servidor. No se ejecuta el hook ‘admin_notices’ y aquí toca lanzar un ‘snackbar’ será ejecutar código javascript. En concreto contra el API de guttenber ‘core/notices’.

Voy a poner como ejemplo la solución a un plugin que tiene que mostrar un flash-message después de crear un post y aterrizar en la pantalla de edición, y que funcione tanto para los wordpress viejunos (o que tengan deshabilitado Guttenberg) como para los modernos:

<?php
// Al crear el post, guarda un transient
$post_id = wp_insert_post( array(
    'post_title'   => 'Mi Nuevo Post',
    'post_content' => 'Contenido',
    'post_status'  => 'draft',
    'post_type'    => 'post',
    'post_author'  => get_current_user_id(),
) );

if ( ! is_wp_error( $post_id ) ) {
    // Guardar un transient indicando que se acaba de crear
    set_transient( 'post_creado_' . $post_id, true, HOUR_IN_SECONDS );
    
    wp_redirect( admin_url( 'post.php?action=edit&post=' . $post_id ) );
    exit;
}

// En el admin_notices hook
add_action( 'admin_notices', 'mostrar_notice_post_creado' );

function mostrar_notice_post_creado() {
    global $post;
    
    if ( ! $post ) return;
    
    // Verificar si se acaba de crear
    if ( get_transient( 'post_creado_' . $post->ID ) ) {
        delete_transient( 'post_creado_' . $post->ID );
        
        // Mostrar para editor clásico
        ?>
        <div class="notice notice-success is-dismissible">
            <p><?php esc_html_e( 'Post creado exitosamente', 'tu-textdomain' ); ?></p>
        </div>
        
        <!-- Para Gutenberg -->
        <script>
            ( function( wp ) {
                if ( wp && wp.data ) {
                    wp.data.dispatch( 'core/notices' ).createNotice(
                        'success',
                        '<?php echo esc_js( 'Post creado exitosamente' ); ?>',
                        { isDismissible: true, type: 'snackbar' }
                    );
                }
            } )( window.wp );
        </script>
        <?php
    }
}
?>

Detectar código PHP malicioso oculto en presuntos PDFs (o TTF, JPG, PNG, ICO…) atacando WordPress

En el ataque a instalaciones WordPress comprometidas, es habitual que, además de usar una brecha de seguridad que les permite inyectar un fichero de entrada, luego el grueso del código del webshell (aplicación maliciosa que se instala oculta) vaya en ficheros que a priori no son ejecutables y son de extensiones conocidas: documentos PDFs, imágenes JPG o PNG, ficheros de fuente TTF, o incluso iconos ICO. Esta técnica evade filtros básicos en busca de código malicioso y persiste tras limpiezas superficiales. Para hacer una limpieza completa y detectar si el sistema ha sido infectado habrá que buscar estos ficheros. Vamos a ver que comandos Linux utilizo para ello.

¿Por qué pasa en WordPress?

Por una combinación de estas tres circunstancias (que suele ser bastante habitual):

  • Plugins o themes desactualizados que permiten subidas de ficheros y/o que permiten ejecución PHP en la carpeta uploads; un plugin o theme desactualizado puede tener un agujero de seguridad que ya se ha subsanado en versiones posteriores.
  • .htaccess ausente o débil no fuerza octet-stream, con lo que acceder a estos ficheros puede ejecutar el código php en su interior.
  • Malware que se inyecta en ficheros habituales de WordPress como functions.php o wp-head.php y luego carga el código de estos «PDFs» que no son tal.

¿Un fichero no de PHP con código PHP dentro?

Dentro del fichero, en lugar de la información habitual de estos ficheros, esconden <?php eval(base64_decode(...)); ?>, o sea, código PHP ofuscado que se ejecuta si el servidor lo interpreta como PHP.

Así que, como el código PHP, al menos su etiqueta de apertura, va en claro podemos utilizar el siguiente comando linux:

grep -RIn --include="*.pdf" -e "<?php" /ruta/a/wp-content/uploads/
  • -R: Recursivo en subdirectorios (uploads suele tenerlos).
  • -I: Ignora binarios puros, pero procesa ficheros híbridos.
  • -n: Muestra línea exacta.
  • --include="*.pdf": Solo PDFs.

Ejemplo de salida sospechosa:

wp-content/uploads/2026/04/malicious.pdf:154:<?php eval(gzuncompress(base64_decode('3vilc0d3-3vilc0d33vilc0d3-3vilc0d3')));?>

Podemos hacer una búsqueda más amplia si no sabemos en que extensiones se pueden ocultar, aunque esto puede dar mucho falso positivo:

grep -RIn --exclude="*.php" -e "<?php" /ruta/a/wp-content/uploads/

--exclude="*.php": Todos los ficheros que no sean PHP.

Lo anterior podemos replantearlo con un pipe para borrar lo encontrado directamente. ATENCIÓN esto borra todo lo que encuentra, incluidos falsos positivos.

grep -RIlZ --include="*.pdf" -e "<?php" /ruta/a/uploads/ | xargs -0 rm -f
  • -l esta opción de grep nos devuelve solo nombres de archivo, listos para pasar por el pipe.

Principalmente el vector de ataque en WordPress suele ser el directorio /wp-content/uploads/ específicamente; otros directorios son menos comunes.

Prevención básica: .htaccess

Por otro lado, revisa que la carpeta uploads tiene prohibido ejecutar ficheros PHP que se encuentren allí, cualquier código PHP no se interpreta.

# En .htaccess de /uploads/
<Files "*.php">
Order Deny,Allow
Deny from all
</Files>
php_flag engine off

Pero no confiemos solo en .htaccess: mejor usar open_basedir en php.ini y validar cualquier subida a uploads.

Aún así, también es interesante hacer el mismo grep por toda la instalación desde la raíz y quizá ampliar a buscar cosas como <?=, <% o eval() ofuscado. Prueba con grep -P '(?i)(<\?php|eval\()'.

Fuente: wpsecurityninja

Primeros pasos para domar un código legacy

Me gusta el reto de llegar a un proyecto ajeno y domarlo. Entender como lo diseñaron y ver como mejorarlo. Pero antes de poder ampliar ese código hay que estabilizarlo para poder caminar seguros. El objetivo con el que atacamos ese código es poder tener una base de código entendible y con cobertura de tests que nos dé tranquilidad.

El enfoque es gradual y seguro, priorizando la comprensión del código, las pruebas y la refactorización incremental. Haremos primero los pasos 0, 1 y 2 y luego realizaremos los pasos 3 por bloques de funcionalidad.

Seguir leyendo Primeros pasos para domar un código legacy

La importancia del directorio .well-known en nuestro servidor para conectar servicios de terceros

El directorio .well-known es un estándar definido por el RFC 8615 que actúa como un directorio especial ubicado en la raíz de un sitio web, accesible como /.well-known/. Sirve para almacenar archivos de metadatos y configuraciones importantes para diversos protocolos web, como validaciones de certificados SSL, configuraciones de seguridad, autenticación (OpenID, OAuth 2.0) y otras integraciones automáticas entre servicios y aplicaciones.

Este mecanismo permite que aplicaciones, navegadores y servicios automaticen procesos de configuración, validación y descubrimiento de servicios de forma estandarizada, sin necesidad de configuración personalizada para cada caso.

Por ejemplo, aquí podemos dejar archivos como security.txt para indicar como reportar vulnerabilidades, o carpetas como /.well-known/pki-validation/ usadas para validar la propiedad de un dominio al emitir certificados SSL.

Y sin duda es un avance de limpieza frente a dejar estos ficheros en la carpeta raíz.

Usos más habituales

Los usos más comunes del directorio .well-known están ligados a la seguridad, la validación de dominio y la interoperabilidad entre aplicaciones y servicios web modernos.​

  • Validación de certificados SSL/TLS: Autoridades certificadoras (como Let’s Encrypt) solicitan archivos específicos en subcarpetas como /.well-known/acme-challenge/ o /.well-known/pki-validation/ para verificar la propiedad de un dominio antes de emitir un certificado.
  • Validación de email: SMTP Strict Transport Security puede configurar que los servodres solo acepten correos cifrados. /.well-known/mta-sts.txt
  • Archivos de políticas de seguridad: Como security.txt, donde se publica información de contacto para reportar incidentes de seguridad en el sitio, según recomendación RFC 9116.
  • Descubrimiento de servicios de identidad: Protocolos como OpenID Connect y OAuth 2.0 usan rutas como /.well-known/openid-configuration o /.well-known/oauth-authorization-server para que las aplicaciones detecten automáticamente endpoints y configuraciones relacionadas con autenticación y autorización.​
  • Integración de aplicaciones móviles: Android y Apple utilizan archivos en /.well-known/ para validar que un dominio es legítimo y permitir enlaces universales o “deep links”.​
  • Cumplimiento legal y privacidad: Algunas normativas como GDPR han motivado la publicación de información de contacto y políticas de privacidad accesibles públicamente en este directorio.​

Todos estos casos facilitan la automatización, estandarización, y seguridad de procesos web, permitiendo que diferentes servicios interactúen sin intervención manual y de manera segura.

En general, lo ideal es crear esta carpeta y ficheros reales directamente en nuestro servidor y revisar que no hay reglas (en .htaccess o similar) que redirijan el tráfico a esta ruta, impidiendo servir los ficheros.

La mejor manera de esperar a que el DOM esté listo y poder manipularlo

Aún recuerdo mis tiempos de jQuery (si, esa librería ha sido una gran herramienta durante mucho tiempo) en que había que esperar a $(document).ready() para garantizar que el DOM y las librerías habían cargado para poder ejecutar código y que todo funcionara.

Pero cuando empezamos a poner el javascript al final del HTML (si, fuera del Header) para aliviar los tiempos de carga provocamos que en realidad no hiciera falta esperar, porque si se había cargado ese código es porque ya se había parseado todo el DOM.

Pero ¿eso quiere decir que el DOM está listo? ¿que se han cargado todos los elementos? Pues se han cargado todos los elementos renderizados en servidor, PERO actualmente hay mucho renderizado que se hace en cliente (React, Angular… )

Así que si queremos manipular el DOM, necesitamos garantizar que existe ese elemento que queremos manipular. Puede que se lance un script cuando el DOM está listo pero necesite esperar a que ese elemento esté disponible.

La solución habitual es hacer un bucle con setTimeout que hace una comprobación cada cierto tiempo y se lanza a si mismo si no encuentra el elemento para intentarlo de nuevo.

function check() {
  if (!$('#elementId').size()){
    setTimeout(check, 200);
  } else {
    // el código a ejecutar
  }
}

Y esto puede que funcione, pero no es la manera más eficiente… y con los navegadores modernos puede que falle porque, cuando la pestaña / ventana no esté en primer plano puede que ahorren recursos y no corran ese código suficientemente «rápido».

Así que toca hacer una solución moderna para navegadores modernos, que no dependa de que la pestaña esté funcionando, o de que el timeout se ejecuta a tiempo. Y la respuesta es requestAnimationFrame

Se suele usar para animaciones, garantizando 60 refrescos por segundo. Pero también se puede usar para notificar al código que está esperando.

Así que usaremos algo como:

function check() {
  if (!$('#elementId').size()){
    window.requestAnimationFrame(check);
  } else {
    // el código a ejecutar
  }
}

Y aunque en teoría podría parecer que este código se comprobaría el DOM cada 1/60 de segundo para comprobar el elemento buscado, solo se hará una vez, cuando el elemento sea renderizado.

Y así es la manera adecuada de esperar a un elemento de DOM en los navegadores modernos.

Mas info: Swizec

Chrome dev tools: Como explorar un JSON

Si te dedicas al mundo del frontend, seguramente tienes que estar consultando un API REST que te devuelve documentos en formato JSON y en ocasiones querrás comprobar que lo que recibes es lo que esperar y poder explorarlo. Vamos a a ver un par de trucos para atacar rápidamente un JSON gigante usando las Developer Tools del navegador Google Chrome (o Chromium) y facilitarte la vida.

Truco 1: Cargar en el terminal

La consola de las Developer Tools no es solo l lugar donde probar el código, también podemos hacernos.

Con las DevTools abiertas, en la pestaña Network, realizamos la petición al API REST. Entonces abriremos el documento que hemos recibido y nos iremos a la pestaña preview y veremos el JSON en todo su esplendor. Entonces, seleccionando el elemento raíz, abrimos el menú contextual (botón derecho) y elegimos «Store to global variable».

Desde ese momento tendremos una variable (en mi caso fue temp1) con la que podremos trabajar en el terminal. Podremos hacer operaciones de array o de objeto sobre sus elementos y usar el autocompletado para hacer todo el path. Si escribimos el path y damos intro recibiremos el valor de ese elemento en el árbol JSON.

Truco 2: Extraer el path a un elemento

Un caso bastante habitual es tener un elemento bastante profundo en el árbol JSON y no querer tener problemas de erratas al transcribirlo. Puedes sacar el menú contextual del elemento y

Y puedes comprobar que está correctamente escibiendo en la consola:

temp1.PATH_COPIADO

Bola Extra: Una extensión para ver JSON.

Si no quieres tener que hacer el recorrido hasta las dev tools, y quieres ver directamente el JSON al llamar a su url en el navegador de una manera manejable, te recomiendo instalar JSON Formatter.

Truco: puedes expandir y contraer ramas pulsando ctrl para que lo haga con todas las del mismo nivel.

[WebDevTip] Forzar el refresco de CSS (y javascripts) cacheados

[Vía: Force CSS changes to “go live” immediately | Mark on WordPress]

TL;DR Un sencillo truco, cada vez que se actualiza el fichero, se le añade su fecha detrás de la interrogación. Este parametro GET no se utiliza para nada, pero al cambiar la URL el navegador no la tiene cacheada y deber refrescar ese contenido. Mientras no se cambie el fichero la URL no cambiará.

Cuando actualizas el archivo style.css de tu tema de WordPress, es posible que hayas notado que tienes que «forzar la recarga» de tu sitio en el navegador para ver los cambios. Esto se debe a que el navegador guarda una copia del CSS en caché en tu disco duro. Dependiendo de cómo esté configurado tu servidor, es posible que no verifique una nueva versión de la hoja de estilos durante un par de horas o incluso más tiempo. Incluso si fuerzas la recarga para ver los cambios, los visitantes que hayan accedido previamente a tu sitio aún podrían obtener la versión anterior del CSS. Una forma de solucionar esto es «versionar» tu archivo CSS, agregando ?v=123 al URL en el elemento de tu hoja de estilos. Sin embargo, hacer esto manualmente cada vez puede resultar tedioso, por lo que aquí te presento una manera mucho mejor de hacerlo:

<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); echo '?' . filemtime( get_stylesheet_directory() . '/style.css'); ?>" type="text/css" media="screen, projection" />

Con este código, se actualizará automáticamente la parte final ?12345678 cada vez que modifiques el archivo. ¡Boom! Ahora todos verán instantáneamente tus cambios.

Explicación del código

El código utiliza la función filemtime() para obtener la fecha de modificación del archivo style.css. Luego, se agrega esta información al URL del enlace a la hoja de estilos mediante echo '?' . filemtime( get_stylesheet_directory() . '/style.css'). Al hacerlo, se crea un nuevo valor después del signo de interrogación que cambia cada vez que se realiza una modificación en el archivo CSS.

De esta manera, cuando actualices el archivo style.css, el URL de la hoja de estilos cambiará automáticamente y el navegador del usuario solicitará la nueva versión en lugar de usar la versión en caché.

Beneficios de forzar el refresco del CSS

Al versionar el archivo CSS de esta manera, garantizas que los cambios realizados se muestren instantáneamente a los visitantes de tu sitio web. Ya no tendrás que preocuparte por los usuarios que siguen viendo la versión anterior del CSS debido a la caché del navegador. Además, si trabajas en colaboración con otros desarrolladores o si tienes un equipo de mantenimiento de tu sitio web, todos podrán ver rápidamente las actualizaciones realizadas sin tener que realizar acciones adicionales.

Forzar el refresco del CSS es una técnica muy útil para asegurarte de que los cambios que realizas en tu hoja de estilos se reflejen inmediatamente en tu sitio web. Mediante el versionado automático del archivo CSS, te aseguras de que los visitantes vean siempre la última versión y evitas problemas causados por la caché del navegador. ¡Utiliza este método y olvídate de las dificultades para ver tus cambios en tiempo real!