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
- Detectar enlaces externos (apuntan a otro dominio) y añadirles una marca visual.
- Colocar un icono automático (flecha o SVG) sin tocar cada enlace a mano.
- Preservar accesibilidad y buenas prácticas (rel, target, texto para lectores de pantalla).
- Ofrecer varias implementaciones para distintos niveles de control y compatibilidad.
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:
- Se usa DOMDocument para manipular HTML con fiabilidad frente a regex frágiles.
- Se compara el host de cada enlace con el host del sitio para detectar enlaces externos.
- Se añade clase external-link, atributos rel y target, y un texto oculto para lectores de pantalla.
- Se filtra sólo el contenido con the_content puedes ampliar a widgets o menús con filtros similares.
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
- rel=noopener noreferrer: obliga a que las nuevas ventanas no tengan acceso a window.opener (mitiga ataques de tipo reverse tabnabbing).
- target=_blank: cuando abras en nueva pestaña, informa a usuarios de lector de pantalla mediante texto adicional o aria-label.
- Usa screen-reader-text (clase que muchos temas de WP incluyen) o CSS propio para ocultar texto que sólo lean los lectores de pantalla.
- Evita añadir iconos que dependan sólo del color. Mantén contraste y usa texto alternativo para usuarios de tecnologías asistivas.
- Impresión: suprime iconos en @media print para no dañar legibilidad en papel.
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 tu CSS soporta :has(), úsalo así (soporte moderno):
/ Si el enlace contiene una imagen, no mostrar el icono /
a.external-link:has(img):after {
display: none
}
- Si no deseas depender de :has(), añade en PHP/JS una clase adicional (por ejemplo .no-external-icon) a enlaces que contengan imágenes y usa CSS para ocultar el icono:
a.external-link.no-external-icon:after {
display: none
}
7) Estilos avanzados y UX
Algunas recomendaciones visuales:
- Separación: usa padding-right para no solapar el icono con texto.
- Hover/focus: aumenta contraste, añade subrayado o transform en el pseudo-elemento para indicar interactividad.
- Preferencia del usuario: respeta media queries como prefers-reduced-motion para evitar animaciones en usuarios que las deshabilitan.
/ 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
- Prueba en un entorno de staging antes de subir a producción.
- Verifica en distintos navegadores (Chrome, Edge, Firefox, Safari) y dispositivos móviles.
- Comprueba accesibilidad con lectores de pantalla y herramientas como Lighthouse o WAVE.
- 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)
- Si quieres una solución rápida y simple: usa CSS con un icono Unicode.
- Si tu contenido se genera dinámicamente o necesitas robustez: añade la clase en servidor (PHP) o en cliente (JS). Para WordPress, la solución PHP es la más consistente y recomendable.
- Siempre incluye atributos de seguridad (rel) y considera la accesibilidad (texto para lectores de pantalla, evitar iconos en impresión, etc.).
Leave a Reply