Webmention es una recomendación del W3C que describe un protocolo simple para notificar cualquier URL cuando un sitio web se vincula a él, y para que las páginas web soliciten notificaciones cuando alguien se vincula a ellas. Webmention se desarrolló originalmente en la comunidad IndieWebCamp y se publicó como borrador de trabajo del W3C el 12 de enero de 2016. A partir del 12 de enero de 2017, es una recomendación del W3C. Webmention permite a los autores realizar un seguimiento de quién enlaza, hace referencia o comenta sobre sus artículos. Al incorporar dichos comentarios de otros sitios, los propios sitios proporcionan una funcionalidad de comentarios federados.
Conociendo ya de que trata esto de las webmentions me dediqué a buscar como hacerlo funcionar con laravel y encontré un post de Tom Witkowski donde explica como hizo un componente de blade para gestionar sus webmentions. Les recomiendo que vayan y vean el artículo original para que entiendan lo que hizo Tom y comparen con los cambios que yo hice.
Todo el componente es esto:
<?php
namespace App\View\Components\Front\Webmentions;
use Illuminate\View\Component;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
class Webmentions extends Component
{
public Collection $likes;
public Collection $reposts;
public Collection $comments;
public function __construct(?string $url = null)
{
$url ??= request()->url();
$webmentions = collect();
$page = 0;
do {
$entries = Http::get('https://webmention.io/api/mentions.jf2', [
'token' => config('services.webmention.token'),
'domain' => parse_url($url, PHP_URL_HOST),
'per-page' => 100,
'page' => $page,
])->json()['children'] ?? [];
$webmentions->push(...$entries);
$page++;
} while (count($entries) >= 100);
$webmentions = $webmentions
->filter(fn (array $entry): bool => trim(parse_url($entry['wm-target'], PHP_URL_PATH), '/') === trim(parse_url($url, PHP_URL_PATH), '/'));
$key = 'article_likes_'.$url;
if (config('app.env') != 'local') {
$this->likes = \Illuminate\Support\Facades\Cache::remember($key, 21600, function () use ($webmentions) {
return $this->getLikes($webmentions);
});
}
$key = 'article_reposts_'.$url;
if (config('app.env') != 'local') {
$this->reposts = \Illuminate\Support\Facades\Cache::remember($key, 21600, function () use ($webmentions) {
return $this->getRepost($webmentions);
});
}
$key = 'article_comments_'.$url;
if (config('app.env') != 'local') {
$this->comments = \Illuminate\Support\Facades\Cache::remember($key, 21600, function () use ($webmentions) {
return $this->getComments($webmentions);
});
}
}
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|string
*/
public function render()
{
return view('components.front.webmentions.webmentions');
}
private function getComments($webmentions)
{
return $webmentions
->filter(fn (array $entry): bool => in_array($entry['wm-property'], ['mention-of', 'in-reply-to']))
->reject(fn (array $entry): bool => empty($entry['content']['text']));
}
private function getLikes($webmentions)
{
return $webmentions
->filter(fn (array $entry): bool => $entry['wm-property'] === 'like-of');
}
private function getRepost($webmentions)
{
return $webmentions->filter(function (array $entry): bool {
if ($entry['wm-property'] === 'repost-of') {
return true;
}
if ($entry['wm-property'] === 'mention-of') {
return empty($entry['content']['text']);
}
return false;
});
}
}
Ok, y que fue lo que cambió?
Bueno, básicamente lo que hice fue guardar en cache la respuesta de los "likes", "comments" y "repost" de la siguiente forma:
$key = 'article_likes_'.$url;
if (config('app.env') != 'local') {
$this->likes = \Illuminate\Support\Facades\Cache::remember($key, 21600, function () use ($webmentions) {
return $this->getLikes($webmentions);
});
}
$key = 'article_reposts_'.$url;
if (config('app.env') != 'local') {
$this->reposts = \Illuminate\Support\Facades\Cache::remember($key, 21600, function () use ($webmentions) {
return $this->getRepost($webmentions);
});
}
$key = 'article_comments_'.$url;
if (config('app.env') != 'local') {
$this->comments = \Illuminate\Support\Facades\Cache::remember($key, 21600, function () use ($webmentions) {
return $this->getComments($webmentions);
});
}
Tambien hice 3 metodos que se encargan de cada respuesta otorgada por las webmentions
private function getComments($webmentions)
{
return $webmentions
->filter(fn (array $entry): bool => in_array($entry['wm-property'], ['mention-of', 'in-reply-to']))
->reject(fn (array $entry): bool => empty($entry['content']['text']));
}
private function getLikes($webmentions)
{
return $webmentions
->filter(fn (array $entry): bool => $entry['wm-property'] === 'like-of');
}
private function getRepost($webmentions)
{
return $webmentions->filter(function (array $entry): bool {
if ($entry['wm-property'] === 'repost-of') {
return true;
}
if ($entry['wm-property'] === 'mention-of') {
return empty($entry['content']['text']);
}
return false;
});
}
En líneas generales lo que hice fue ordenar un poco el componente inicial creado por Tom y lo adapté a como quería.
Luego haré un post de como mostrar todo esto usando otro componente ;)