Angel Cruz

nano /var/log/laravel.log

Coding, life & stuff.

Similar al pingback, Webmention es uno de los cuatro tipos de enlaces de retorno, pero fue diseñado para ser más simple que el protocolo XML-RPC en el que se basa el pingback, y en su lugar solo usa contenido HTTP y x-www-urlencoded. Más allá de los protocolos de enlace de retorno anteriores, Webmention también especifica los detalles del protocolo para cuando una página que es la fuente de un enlace se elimina, se actualiza con nuevos enlaces o se eliminan los enlaces existentes.

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 ;)

Link to, or bookmark, here using this permalink.

Angel's avatar
Watagatapitusberry... !!
  • Tom Witkowski

1 like

1 repost

Comments

  1. Tom Witkowski Tom Witkowski
    Following your code and google translate you've added a cache to prevent requesting the webmention API every request for "normally" running Laravel apps!? Good job! A different solution to remember forever and use a scheduled command to load them never on request.
  2. ángel ángel
    En base al articulo de @devgummibeer hice este otro: "Como integrar #webmentions usando #laravel." Básicamente fue ajustar lo que hizo Tom a algo más funcional y adaptado a lo que necesitaba. Si te interesa el tema pasa por acá: angelcruz.dev/post/como-inte…