Favicones dinámicos para WordPress

Normalmente, se utiliza un único favicon en todo el dominio. Pero hay ocasiones en las que quieres intensificarlo con diferentes favicons según el contexto. Un sitio web puede cambiar el favicon para que coincida con el contenido que se está viendo. O un sitio podría permitir a los usuarios personalizar los colores de su tema y esas preferencias se reflejan en el favicon. Quizás hayas visto favicons que intentan alertar al usuario de algún evento.

Técnicamente, se pueden administrar varios favicons manualmente: Chris nos ha mostrado cómo usan dos favicons diferentes para el desarrollo y la producción. Pero cuando alcanzas la escala de docenas o cientos de variaciones, es hora de generarlas dinámicamente.

Esta fue la situación que encontré en un proyecto reciente de WordPress para un directorio de colegios y universidades. (Anteriormente escriba sobre la consulta de ubicaciones cercanas para el mismo proyecto). Al ver el perfil de una escuela, queríamos que el favicon usara los colores de una escuela en lugar nuestro de azul predeterminado, para darle ese toque extra.

Con más de 200 escuelas en el directorio y subiendo, necesitábamos ser dinámicos. Afortunadamente, ya teníamos metacampos personalizados que almacenaban datos sobre la identidad visual de cada escuela. Esto incluía los colores escolares, que se utilizaban en la hoja de estilo. Sólo necesitábamos una forma de aplicar estos metacolores personalizados a un favicon dinámico.

En este artículo, le explicaré nuestro enfoque y algunos aspectos a tener en cuenta. Puede ver los resultados en acción viendo diferentes escuelas.

SVG es clave

Gracias a la compatibilidad mejorada del navegador con favicons SVG, implementar favicons dinámicos es mucho más fácil que en el pasado. A diferencia de PNG (o el antiguo formato ICO), SVG se basa en el marcado para definir formas vectoriales. Esto los hace livianos, escalables y, lo mejor de todo, receptivos a todo tipo de diversión.

El primer paso es crear tu favicon en formato SVG. No hay más ejecutarlo también a través de un optimizador SVG para deshacerse del problema después. Esto es lo que usamos en el directorio de la escuela:

Conectarse a WordPress

A continuación, queremos agregar el marcado del enlace de favicon en el encabezado HTML. Cómo hacer esto depende totalmente de usted. En el caso de WordPress, se podría agregar a la plantilla de encabezado de un tema secundario o echomediante una wp_head()acción.

function ca_favicon() {  if ( is_singular( 'school' ) ) {    $post_id = get_the_ID();    $color = get_post_meta( $post_id, 'color', true );    if ( isset( $color ) ) {      $color = ltrim( $color, '#' ); // remove the hash      echo 'link rel="icon" href="' . plugins_url( 'images/favicon.php?color=' . $color, __FILE__ ) . '" type="image/svg+xml"';    }  }}add_filter( 'wp_head' , 'ca_favicon' );

Aquí estamos verificando que el tipo de publicación sea schooly tomando los colormetadatos de la escuela que hemos almacenado previamente usando get_post_meta(). Si tenemos un color, lo pasamos favicon.phpa través de la cadena de consulta.

De PHP a SVG

En un favicon.phparchivo, comenzamos configurando el tipo de contenido en SVG. A continuación, guardamos el valor de color que se pasó o usamos el color predeterminado si no hay ninguno.

Luego, usamos la sintaxis heredoc de PHP (útil para crear plantillas) echocon el fragmento grande y de varias líneas de marcado SVG. Variables como se expanden cuando se utiliza esta sintaxis.$color

Finalmente, hacemos un par de modificaciones al marcado SVG. Primero, se asignan clases a los elementos que cambian de color. En segundo lugar, agregue un elemento de estilo justo dentro del elemento SVG, declarando las reglas CSS apropiadas y echoagregando -el archivo $color.

En lugar de un styleelemento, también podríamos reemplazar el color predeterminado $colordondequiera que aparezca si no se usa en demasiados lugares.

?phpheader( 'Content-Type: image/svg+xml' );$color = $_GET[ 'color' ] ?? '065281';$color = sanitize_hex_color_no_hash( $color );echo EOLsvg  xmlns_xlink="http://www.w3.org/1999/xlink"  style type="text/css"  ![CDATA[  .primary {    fill: #$color;  }  .shield {    stroke: #$color;  }  ]]  /style  defs    path d="M0 34L318 0l316 34v417.196a97 97 0 01-14.433 50.909C483.553 722.702 382.697 833 317 833S150.447 722.702 14.433 502.105A97 97 0 010 451.196V34z"/  /defs  g fill="none" fill-rule="evenodd"    g transform="translate(183 65)"      mask fill="#fff"        use xlink_href="#a"/      /mask      use fill="#FFF" xlink_href="#a"/      path mask="url(#b)" d="M317-37h317v871H317z"/      path mask="url(#b)" d="M0 480l317 30 317-30v157l-317-90L0 517z"/      path fill="#FFF" mask="url(#b)" d="M317 510l317-30v37l-317 30z"/    /g    g fill-rule="nonzero"      path d="M358.2 455.2c11.9 0 22.633-.992 32.2-2.975 9.567-1.983 18.375-4.9 26.425-8.75 8.05-3.85 15.458-8.458 22.225-13.825 6.767-5.367 13.3-11.433 19.6-18.2l-34.3-34.65c-9.567 8.867-19.192 15.867-28.875 21-9.683 5.133-21.525 7.7-35.525 7.7-10.5 0-20.125-2.042-28.875-6.125s-16.217-9.625-22.4-16.625-11.025-15.167-14.525-24.5-5.25-19.25-5.25-29.75v-.7c0-10.5 1.75-20.358 5.25-29.575 3.5-9.217 8.4-17.325 14.7-24.325 6.3-7 13.825-12.483 22.575-16.45 8.75-3.967 18.258-5.95 28.525-5.95 12.367 0 23.508 2.45 33.425 7.35 9.917 4.9 19.658 11.667 29.225 20.3l34.3-39.55a144.285 144.285 0 00-18.2-15.4c-6.533-4.667-13.65-8.633-21.35-11.9-7.7-3.267-16.275-5.833-25.725-7.7-9.45-1.867-19.892-2.8-31.325-2.8-18.9 0-36.167 3.325-51.8 9.975-15.633 6.65-29.05 15.75-40.25 27.3s-19.95 24.967-26.25 40.25c-6.3 15.283-9.45 31.675-9.45 49.175v.7c0 17.5 3.15 33.95 9.45 49.35 6.3 15.4 15.05 28.758 26.25 40.075 11.2 11.317 24.5 20.242 39.9 26.775 15.4 6.533 32.083 9.8 50.05 9.8z"/      path fill="#FFF" d="M582.35 451l22.4-54.95h103.6l22.4 54.95h56.35l-105-246.75h-49.7L527.4 451h54.95zM689.1 348.45H624L656.55 269l32.55 79.45z"/    /g    path stroke-width="30" d="M183 99l318-34 316 34v417.196a97 97 0 01-14.433 50.909C666.553 787.702 565.697 898 500 898S333.447 787.702 197.433 567.105A97 97 0 01183 516.196V99h0z"/  /g/svgEOL;?

Con eso, tienes un favicon dinámico funcionando en tu sitio.

Consideraciones de seguridad

Por supuesto, echocambiar a ciegas los parámetros de URL abre el camino a los hacks. Para mitigarlos, debemos desinfectar todos nuestros insumos.

En este caso, solo nos interesan los valores que coinciden con el formato de color hexadecimal de 3 o 6 dígitos. Podemos incluir una función como la de WordPress sanitize_hex_color_no_hash()para garantizar que solo se pasen colores.

function sanitize_hex_color( $color ) {  if ( '' === $color ) {    return '';  }  // 3 or 6 hex digits, or the empty string.  if ( preg_match( '|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) ) {    return $color;  }}function sanitize_hex_color_no_hash( $color ) {  $color = ltrim( $color, '#' );  if ( '' === $color ) {    return '';  }  return sanitize_hex_color( '#' . $color ) ? $color : null;}

Querrá agregar sus propios controles según los valores que desee pasar.

Almacenamiento en caché para un mejor rendimiento

Los navegadores almacenan en caché los SVG, pero este beneficio se pierde para los archivos PHP de formato predeterminado. Esto significa que cada vez que se carga el favicon, tu servidor será atacado.

Para reducir la carga del servidor y mejorar el rendimiento, es esencial que almacene específicamente este archivo en caché. Puede configurar su servidor, establecer una regla de página a través de su CDN o agregar un encabezado de control de caché en la parte superior, favicon.phpasí:

header( 'Cache-Control: public, max-age=604800' );  // 604,800 seconds or 1 week

En nuestras pruebas, sin almacenamiento en caché, nuestro archivo SVG de 1,5 KB tardó unos 300 milisegundos en procesarse en la primera carga y unos 100 milisegundos en las cargas posteriores. Eso es bastante asqueroso. Pero con el almacenamiento en caché, lo redujimos a 25 ms desde CDN en la primera carga ya 1 ms desde el caché del navegador en cargas posteriores, tan bueno como un SVG antiguo y simple.

Soporte del navegador

Si hubiéramos terminado allí, esto no sería desarrollo web. Todavía tenemos que hablar sobre la compatibilidad del navegador.

Como se mencionó anteriormente, la compatibilidad de los navegadores modernos con favicons SVG es sólida y totalmente compatible con las versiones actuales de Chrome, Firefox y Edge.

Una advertencia es que Firefox requiere el atributo type="image/svg+xml"en la declaración de favicon para funcionar. Los otros navegadores son más indulgentes, pero es simplemente una buena práctica. Deberías incluirlo sizes="any"mientras lo haces.

link rel="icon" href="path/to/favicon.svg" type="image/svg+xml"

Safari

Safari no admite favicons SVG hasta el momento, fuera de la función de icono de máscara destinada a pestañas fijadas. En mi experimentación, esto tenía errores y era inconsistente. No manejaba bien formas o colores complejos y almacenaba en caché el mismo ícono en todo el dominio. Al final decidimos no molestarnos y simplemente usar un respaldo con el relleno azul predeterminado hasta que Safari mejore el soporte.

Reservas

Por más sólida que sea la compatibilidad con favicon SVG, todavía no es del 100%. Así que asegúrese de agregar alternativas. Podemos configurar un favicon adicional para cuando los íconos SVG no sean compatibles con el rel="alternative icon"atributo:

link rel="icon" href="path/to/favicon.svg" type="image/svg+xml"link rel="alternate icon" href="path/to/favicon.png" type="image/png"

Para que el sitio sea aún más a prueba de balas, también puedes colocar lo eterno favicon.icoen tu raíz.

Ir más lejos

Tomamos un favicon relativamente simple y cambiamos un color por otro. Pero adoptar este enfoque dinámico abre la puerta a mucho más: modificar múltiples colores, otras propiedades como positionformas y animaciones completamente diferentes.

Por ejemplo, aquí hay una demostración que he denominado Favicoin. Traza los precios de las criptomonedas en el favicon como un minigráfico.

La implementación de favicons dinámicos como este no se limita a WordPress o PHP; Cualquiera que sea su pila, se aplican los mismos principios. Diablos, incluso podrías lograr este lado del cliente con URL de datos y JavaScript... no es que lo recomiende para producción.

Pero una cosa es segura: seguramente veremos aplicaciones creativas de favicons SVG en el futuro. ¿Has visto o creado tus propios favicons dinámicos? ¿Tiene algún consejo o truco para compartir?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir