Tutorial WordPress: Usar CSS para destacar enlaces externos con icono automático

·

·

Introducción

En este tutorial detallado aprenderás a destacar automáticamente los enlaces externos en WordPress añadiéndoles un icono mediante CSS. Verás varias opciones: una solución puramente CSS (con limitaciones), una solución con JavaScript en el frontend y una solución recomendada para WordPress con PHP que marca los enlaces en el contenido antes de mostrarlos. También cubriremos accesibilidad, seguridad (rel, noopener) y ajustes visuales avanzados.

Qué queremos conseguir

Limitaciones

Con CSS puro es posible detectar enlaces que comienzan por http(s) y excluir rutas relativas, pero no es posible (de forma fiable y dinámica) comparar con el dominio actual en todas las situaciones sólo con CSS en todos los navegadores. Por eso mostraremos también JavaScript (que funciona en el cliente) y PHP (que modifica el HTML en el servidor, recomendado para WordPress para un resultado consistente).

1) Solución CSS básica (flecha Unicode)

Esta es la opción más simple: añadir una pseudo-clase que agregue un carácter al final del enlace. Es rápido y no requiere modificar HTML. Funciona bien si estás dispuesto a aceptar un icono sencillo (↗ o ↗︎).

/ Aplica sólo a enlaces que empiezan por http(s) y no sean relativos ni anclas /
a[href^=http]:not([href=tudominio.com]):not([href^=#]):not([href^=/]) {
  position: relative
  padding-right: 0.9em / espacio para el icono /
  text-decoration: none
}

/ Pseudo-elemento con una flecha Unicode /
a[href^=http]:not([href=tudominio.com]):after {
  content: ↗              / flecha indicando salto a otro sitio /
  margin-left: 0.2em
  font-size: 0.85em
  vertical-align: middle
  opacity: 0.8
  display: inline-block
}

/ Evita imprimir el icono en impresión /
@media print {
  a[href^=http]:after { content: none }
}

Reemplaza tudominio.com por el dominio de tu sitio. Si el sitio tiene varios subdominios o idiomas, la comprobación desde CSS puede ser insuficiente en ese caso usa PHP o JS.

2) Icono SVG como background (más control visual)

Usar un pequeño SVG embebido en data URI proporciona un icono nítido y estilizable. Aquí un ejemplo con pseudo-elemento :after usando background-image.

/ Enlaces marcados con la clase .external-link (ver PHP/JS más abajo) /
a.external-link {
  position: relative
  padding-right: 1.4em
}

/ Pseudo-elemento con SVG embebido (data URI). Ajusta tamaño y posición /
a.external-link:after {
  content: 
  position: absolute
  right: 0
  top: 50%
  transform: translateY(-50%)
  width: 1em
  height: 1em
  background-repeat: no-repeat
  background-size: contain
  background-image: url(data:image/svg xmlutf8,)
  pointer-events: none / el icono no interfiere con el clic /
  opacity: 0.9
}

/ Ocultar en impresión /
@media print {
  a.external-link:after { display: none }
}

3) Marcar enlaces externos en WordPress con PHP (recomendado)

La mejor forma, consistente y sin depender del navegador, es procesar el HTML del contenido en el servidor y añadir una clase (por ejemplo external-link), atributos de seguridad y texto accesible. A continuación un ejemplo completo usando DOMDocument que puedes añadir a functions.php o a un plugin propio.

/ Añadir a functions.php o a un plugin personalizado /
/ Marca enlaces externos en the_content con la clase external-link y atributos útiles /
function wp_add_external_link_class( content ) {
    if ( is_admin()  empty( content ) ) {
        return content
    }

    site_host = parse_url( home_url(), PHP_URL_HOST )
    libxml_use_internal_errors( true )

    doc = new DOMDocument()
    // Forzar UTF-8 para evitar problemas con caracteres especiales
    doc->loadHTML(  . content, LIBXML_HTML_NOIMPLIED  LIBXML_HTML_NODEFDTD )

    anchors = doc->getElementsByTagName( a )
    foreach ( anchors as a ) {
        href = a->getAttribute( href )
        if ( ! href ) {
            continue
        }

        // Sólo enlaces absolutos HTTP(S)
        if ( ! preg_match( #^https?://#i, href ) ) {
            continue
        }

        link_host = parse_url( href, PHP_URL_HOST )
        if ( link_host  strcasecmp( link_host, site_host ) !== 0 ) {
            // Clase adicional
            existing_class = a->getAttribute( class )
            a->setAttribute( class, trim( existing_class .  external-link ) )

            // Añadir atributos de seguridad y UX
            rel = a->getAttribute( rel )
            rels = array_filter( array_map( trim, explode(  , rel ) ) )
            rels = array_unique( array_merge( rels, array( noopener, noreferrer, external ) ) )
            a->setAttribute( rel, implode(  , rels ) )

            // Abrir en nueva ventana — opcional: puedes omitir si no quieres target=_blank
            a->setAttribute( target, _blank )

            // Añadir texto accesible para lectores de pantalla si no existe
            // Esto añade una clase estándar de WordPress screen-reader-text si está disponible en el tema
            has_sr = false
            foreach ( a->childNodes as child ) {
                if ( child->nodeType === XML_ELEMENT_NODE  strtolower( child->nodeName ) === span ) {
                    cls = child->getAttribute( class )
                    if ( strpos( cls, screen-reader-text ) !== false ) {
                        has_sr = true
                        break
                    }
                }
            }
            if ( ! has_sr ) {
                sr = doc->createElement( span,  (se abre en ventana nueva) )
                sr->setAttribute( class, screen-reader-text )
                a->appendChild( sr )
            }
        }
    }

    html = doc->saveHTML()

    // El DOMDocument envuelve el contenido, intentamos devolver sólo el fragmento original
    // Eliminamos la cabecera  si existe
    html = preg_replace( /^s/, , html )

    return html
}
add_filter( the_content, wp_add_external_link_class, 20 )

Explicaciones clave del snippet:

4) Añadir la clase con JavaScript (solución frontend alternativa)

Si no quieres tocar PHP o necesitas marcar enlaces generados dinámicamente, usa JavaScript. Este código se puede poner en el footer o en un archivo JS encolado.

/ Ejecutar cuando el DOM esté listo /
(function() {
  var hostname = location.hostname
  var links = document.querySelectorAll(a[href^=http]:not([data-no-external]))
  for (var i = 0 i lt links.length i  ) {
    var a = links[i]
    var href = a.getAttribute(href)
    try {
      var linkHost = new URL(href).hostname
      if (linkHost !== hostname) {
        a.classList.add(external-link)
        a.setAttribute(rel, (a.getAttribute(rel)  )    noopener noreferrer external)
        // Opcional: abrir en nueva pestaña
        a.setAttribute(target, _blank)
        // Añadir texto para lectores si no existe
        if (!a.querySelector(.screen-reader-text)) {
          var span = document.createElement(span)
          span.className = screen-reader-text
          span.textContent =  (se abre en ventana nueva)
          a.appendChild(span)
        }
      }
    } catch (e) {
      / URL inválida, ignorar /
    }
  }
})()

5) Accesibilidad y seguridad

6) Manejo de enlaces que contienen imágenes

Si muchos enlaces son thumbnails o imágenes y no quieres el icono visible junto a ellas, puedes ocultarlo cuando el enlace contiene una imagen. Hay varias formas:

/ Si el enlace contiene una imagen, no mostrar el icono /
a.external-link:has(img):after {
  display: none
}
a.external-link.no-external-icon:after {
  display: none
}

7) Estilos avanzados y UX

Algunas recomendaciones visuales:

/ Ejemplo con hover, focus y motion reducido /
a.external-link:hover,
a.external-link:focus {
  text-decoration: underline
  color: #0a58ca
}

a.external-link:after {
  transition: transform 120ms ease, opacity 120ms ease
}
@media (prefers-reduced-motion: reduce) {
  a.external-link:after { transition: none }
}
a.external-link:hover:after,
a.external-link:focus:after {
  transform: translateY(-50%) scale(1.1)
  opacity: 1
}

8) Pruebas y despliegue

  1. Prueba en un entorno de staging antes de subir a producción.
  2. Verifica en distintos navegadores (Chrome, Edge, Firefox, Safari) y dispositivos móviles.
  3. Comprueba accesibilidad con lectores de pantalla y herramientas como Lighthouse o WAVE.
  4. Revisa el rendimiento: el PHP con DOMDocument en artículos largos está bien, pero si procesas muchos fragmentos en tiempo real, mide impacto. Alternativa: ejecutar en save_post y almacenar contenido procesado.

Conclusión técnica (resumen rápido)



Leave a Reply

Your email address will not be published. Required fields are marked *