Webmention es una recomendación del W3C publicada por última vez el 12 de enero de 2017. ¿Y qué es exactamente una Webmention? Se describe como…
[…] una forma sencilla de notificar cualquier URL cuando la mencionas en tu sitio. Desde la perspectiva del receptor, es una forma de solicitar notificaciones cuando otros sitios lo mencionan.
En pocas palabras, es una forma de hacerle saber a un sitio web que ha sido mencionado en alguna parte, por alguien, de alguna manera. La especificación Webmention también lo describe como una forma en que un sitio web permite que otros sepan que los citó. A lo que básicamente se reduce es a que su sitio web es un canal de redes sociales activo, que canaliza la comunicación de otros canales (p. ej., Twitter, Instagram, Mastodon, Facebook, etc.).
¿Cómo implementa un sitio Webmentions? En algunos casos, como WordPress, es tan sencillo como instalar un par de complementos. Otros casos pueden no ser tan simples, pero aún así es bastante sencillo. De hecho, ¡hagámoslo ahora!
Aquí está nuestro plan
- Declarar un punto final para recibir Webmentions
- Procesar interacciones de redes sociales a Webmentions
- Obtener esas menciones en un sitio web/aplicación
- Establecer las menciones web salientes
Afortunadamente para nosotros, existen servicios que hacen las cosas extremadamente simples. Bueno, excepto el tercer punto, pero oye, no es tan malo y explicaré cómo lo hice en mi propio sitio atila.io.
Mi sitio es un blog del lado del servidor que está renderizado previamente y escrito con NextJS. He optado por hacer solicitudes de Webmention del lado del cliente; por lo tanto, funcionará fácilmente en cualquier otra aplicación de React y con muy poca refactorización en cualquier otra aplicación de JavaScript.
Paso 1: declarar un punto final para recibir Webmentions
Para tener un punto final que podamos usar para aceptar Webmentions, debemos escribir el script y agregarlo a nuestro propio servidor, o usar un servicio como Webmention.io (que es lo que hice).
Webmention.io es gratuito y solo necesita confirmar la propiedad del dominio que registra. La verificación puede ocurrir de varias maneras. Lo hice agregando un rel="me"
atribuir a un enlace en mi sitio web a mis perfiles de redes sociales. Solo se necesita uno de esos enlaces, pero seguí adelante y lo hice para todas mis cuentas.
<a
href="https://twitter.com/atilafassina"
target="_blank"
rel="me noopener noreferrer"
>
@AtilaFassina
</a>
Al verificar de esta manera, también debemos asegurarnos de que haya un enlace que apunte a nuestro sitio web en ese perfil de Twitter. Una vez que hayamos hecho eso, podemos regresar a Webmention.io y agregar la URL.
¡Esto nos da un punto final para aceptar Webmentions! Todo lo que tenemos que hacer ahora es conectarlo como <link>
etiquetas en el <head>
de nuestras páginas web para recoger dichas menciones.
<head>
<link rel="webmention" href="https://webmention.io/{user}/webmention" />
<link rel="pingback" href="https://webmention.io/{user}/xmlrpc" />
<!-- ... -->
</head>
Recuerda reemplazar {user}
con tu nombre de usuario de Webmention.io.
Paso 2: Procese las interacciones de las redes sociales en Webmentions
¡Estamos listos para que las Webmenciones comiencen a fluir! Pero espera, tenemos un pequeño problema: en realidad nadie los usa. Quiero decir, yo sí, tú sí, Max Bock lo hace, swyx lo hace, y… eso es todo. Entonces, ahora debemos comenzar a convertir todas esas jugosas interacciones de las redes sociales en Webmentions.
¿Y adivina qué? Hay un increíble servicio gratuito para ello. Sin embargo, una advertencia justa: será mejor que empieces a amar IndieWeb porque estamos a punto de involucrarnos.
Bridgy conecta todo nuestro contenido sindicado y lo convierte en Webmentions adecuadas para que podamos consumirlo. Con un SSO, podemos alinear cada uno de nuestros perfiles, uno por uno.
Paso 3: Obtener esas menciones en un sitio web/aplicación
Ahora es nuestro turno de hacer algo de trabajo pesado. Claro, los servicios de terceros pueden manejar todos nuestros datos, pero aún depende de nosotros usarlos y mostrarlos.
Vamos a dividir esto en varias etapas. Primero, obtendremos el número de Webmentions. A partir de ahí, buscaremos las menciones en sí. Luego conectaremos esos datos a NextJS (pero no es necesario) y los mostraremos.
Obtener el número de menciones
type TMentionsCountResponse = {
count: number
type: {
like: number
mention: number
reply: number
repost: number
}
}
Ese es un ejemplo de un objeto que obtenemos del punto final de Webmention.io. He formateado un poco la respuesta para que se adapte mejor a nuestras necesidades. Explicaré cómo lo hice en un momento, pero aquí está el objeto que obtendremos:
type TMentionsCount = {
mentions: number
likes: number
total: number
}
El punto final se encuentra en:
https://webmention.io/api/count.json?target=${post_url}
La solicitud no fallará sin él, pero los datos tampoco llegarán. Ambos Max Bock y swyx combine me gusta con reenvíos y menciones con respuestas. En Twitter, son análogos.
const getMentionsCount = async (postURL: string): TMentionsCount => {
const resp = await fetch(
`https://webmention.io/api/count.json?target=${postURL}/`
)
const { type, count } = await resp.json()
return {
likes: type.like + type.repost,
mentions: type.mention + type.reply,
total: count,
}
}
Obtener las menciones reales
Antes de llegar a la respuesta, tenga en cuenta que la respuesta está paginada, donde el punto final acepta tres parámetros en la consulta:
page
: la página solicitadaper-page
: el número de menciones para mostrar en la páginatarget
: la URL donde se obtienen las menciones web
Una vez que golpeamos https://webmention.io/api/mentions
y pase estos parámetros, la respuesta exitosa será un objeto con una sola clave links
que es un array
de menciones que coinciden con el tipo siguiente:
type TMention = {
source: string
verified: boolean
verified_date: string // date string
id: number
private: boolean
data: {
author: {
name: string
url: string
photo: string // url, hosted in webmention.io
}
url: string
name: string
content: string // encoded HTML
published: string // date string
published_ts: number // ms
}
activity: {
type: 'link' | 'reply' | 'repost' | 'like'
sentence: string // pure text, shortened
sentence_html: string // encoded html
}
target: string
}
Los datos anteriores son más que suficientes para mostrar una lista de secciones similar a un comentario en nuestro sitio. Así es como se ve la solicitud de recuperación en TypeScript:
const getMentions = async (
page: string,
postsPerPage: number,
postURL: string
): { links: TWebMention[] } => {
const resp = await fetch(
`https://webmention.io/api/mentions?page=${page}&per-page=${postsPerPage}&target=${postURL}`
)
const list = await resp.json()
return list.links
}
Conéctelo todo en NextJS
Vamos a trabajar en NextJS por un momento. Todo está bien si no está utilizando NextJS o incluso no tiene una aplicación web. Ya tenemos todos los datos, por lo que aquellos de ustedes que no trabajen en NextJS pueden simplemente avanzar al Paso 4. El resto de nosotros nos encontraremos allí.
A partir de la versión 9.3.0, NextJS tiene tres métodos diferentes para obtener datos:
getStaticProps
: obtiene datos sobre el tiempo de compilacióngetStaticPaths
: especifica rutas dinámicas para renderizar previamente en función de los datos obtenidosgetServerSideProps
: obtiene datos en cada solicitud
Ahora es el momento de decidir en qué momento realizaremos la primera solicitud de obtención de menciones. Podemos renderizar previamente los datos en el servidor con el primer lote de menciones, o podemos hacer todo del lado del cliente. Opté por ir del lado del cliente.
Si también va del lado del cliente, le recomiendo usar SWR. Es un enlace personalizado creado por el equipo de Vercel que proporciona buenos estados de almacenamiento en caché, error y carga, e incluso admite React.Suspense
.
Mostrar el recuento de Webmention
Muchos blogs muestran la cantidad de comentarios en una publicación en dos lugares: en la parte superior de una publicación de blog (como esta) y en la parte inferior, justo encima de una lista de comentarios. Sigamos el mismo patrón para Webmentions.
En primer lugar, vamos a crear un componente para el conteo:
const MentionsCounter = ({ postUrl }) => {
const { t } = useTranslation()
// Setting a default value for `data` because I don't want a loading state
// otherwise you could set: if(!data) return <div>loading...</div>
const { data = {}, error } = useSWR(postUrl, getMentionsCount)
if (error) {
return <ErrorMessage>{t('common:errorWebmentions')}</ErrorMessage>
}
// The default values cover the loading state
const { likes="-", mentions="-" } = data
return (
<MentionCounter>
<li>
<Heart title="Likes" />
<CounterData>{Number.isNaN(likes) ? 0 : likes}</CounterData>
</li>
<li>
<Comment title="Mentions" />{' '}
<CounterData>{Number.isNaN(mentions) ? 0 : mentions}</CounterData>
</li>
</MentionCounter>
)
}
Gracias a SWR, aunque estamos usando dos instancias del WebmentionsCounter
componente, solo se realiza una solicitud y ambos se benefician del mismo caché.
Siéntase libre de echar un vistazo a mi código fuente para ver qué está pasando:
WebmentionsCounter
(el componente)getMentionsCount
(la función auxiliar)Post layout component
(donde estamos usando el componente)
Mostrar las menciones
Ahora que hemos colocado el componente, ¡es hora de hacer fluir todo ese jugo social!
En el momento de escribir este artículo, useSWRpages
no está documentado. Agregue a eso el hecho de que el punto final de webmention.io no ofrece información de recopilación en una respuesta (es decir, sin desplazamiento o número total de páginas), no pude encontrar una manera de usar SWR aquí.
Entonces, mi implementación actual usa un estado para mantener almacenada la página actual, otro estado para manejar las menciones array
, y useEffect
para atender la solicitud. El botón “Cargar más” se desactiva una vez que la última solicitud devuelve una matriz vacía.
const Webmentions = ({ postUrl }) => {
const { t } = useTranslation()
const [page, setPage] = useState(0)
const [mentions, addMentions] = useState([])
useEffect(() => {
const fetchMentions = async () => {
const olderMentions = await getMentions(page, 50, postUrl)
addMentions((mentions) => [...mentions, ...olderMentions])
}
fetchMentions()
}, [page])
return (
<>
{mentions.map((mention, index) => (
<Mention key={mention.data.author.name + index}>
<AuthorAvatar src={mention.data.author.photo} lazy />
<MentionContent>
<MentionText
data={mention.data}
activity={mention.activity.type}
/>
</MentionContent>
</Mention>
))}
</MentionList>
{mentions.length > 0 && (
<MoreButton
type="button"
onClick={() => {
setPage(page + 1)
}}
>
{t('common:more')}
</MoreButton>
)}
</>
)
}
El código se simplifica para permitir centrarse en el tema de este artículo. Nuevamente, siéntase libre de echar un vistazo a la implementación completa:
Webmention
componentegetMentions
ayudante- Componente de diseño de publicaciones
Paso 4: Manejo de menciones salientes
Gracias a Remy Sharp, manejar las menciones salientes de un sitio web a otros es bastante fácil y ofrece una opción para cada caso de uso o preferencia posible.
La forma más rápida y sencilla es dirigirse a Webmention.app, obtener un token de API y configurar un enlace web. Ahora, si tiene una fuente RSS, lo mismo es igual de fácil con un subprograma IFTT, o incluso un enlace de implementación.
Si prefiere evitar el uso de otro servicio de terceros para esta función (que entiendo totalmente), Remy ha abierto un paquete CLI llamado wm que se puede ejecutar como un script posterior a la compilación.
Pero eso no es suficiente para manejar las menciones salientes. Para que nuestras menciones incluyan más que simplemente la URL de origen, debemos agregar microformatos a nuestra información. Los microformatos son clave porque es una forma estandarizada para que los sitios distribuyan contenido de una manera que los sitios habilitados para Webmention puedan consumir.
En su forma más básica, los microformatos son un tipo de notaciones basadas en clases en el marcado que brindan un significado semántico adicional a cada pieza. En el caso de una entrada de blog, utilizaremos dos tipos de microformatos:
h-entry
: la entrada de correosh-card
: el autor de la publicación
La mayor parte de la información requerida para h-entry
generalmente se encuentra en el encabezado de la página, por lo que el componente del encabezado puede terminar luciendo así:
<header class="h-entry">
<!-- the post date and time -->
<time datetime="2020-04-22T00:00:00.000Z" class="dt-published">
2020-04-22
</time>
<!-- the post title -->
<h1 class="p-name">
Webmentions with NextJS
</h1>
</header>
Y eso es. Si está escribiendo en JSX, recuerde reemplazar class
con className
, ese datetime
es camelCase (dateTime
), y que puede utilizar el nuevo Date('2020-04-22').toISOString()
función.
Es bastante similar para h-card
. En la mayoría de los casos (como el mío), la información del autor se encuentra debajo del artículo. Así es como se ve el pie de página de mi página:
<footer class="h-card">
<!-- the author name -->
<span class="p-author">Atila Fassina</span>
<!-- the authot image-->
<img
alt="Author’s photograph: Atila Fassina"
class="u-photo"
src="https://css-tricks.com/images/internal-avatar.jpg"
lazy
/>
</footer>
Ahora, cada vez que enviemos una mención saliente desde esta publicación de blog, se mostrará la información completa a quien la reciba.
Terminando
Espero que esta publicación te haya ayudado a conocer más sobre Webmentions (o incluso sobre IndieWeb en general), y tal vez incluso te haya ayudado a agregar esta función a tu propio sitio web o aplicación. Si lo hizo, considere compartir esta publicación en su red. estare super agradecida! 😉
Referencias
- Uso de menciones web en sitios estáticos (Max Böck)
- Menciones web del lado del cliente (Swyx)
- Enviar menciones web salientes (Remy Sharp)
- Tu primera mención web (Aaron Parecki)
Otras lecturas
- Webmention Especificación W3C (Recomendación)
- Webmention.io
- Webmention.Aplicación
- CLI de WebMentions saliente
- puente
- Microformatos.org
- IndieWeb