---
title: "Como integrar webmentions usando laravel."
excerpt: "Implementa Webmention en Laravel: alternativa simple a pingback usando HTTP. Guía paso a paso para enlaces de retorno modernos en tu aplicación."
date: "2021-01-08T21:46:27.000Z"
category: "Laravel"
seo_title: "Integrar Webmentions en Laravel con caché y cliente HTTP"
seo_description: "Implementa el protocolo Webmention en Laravel usando un Blade Component con caché de 6 horas. Gestiona likes, reposts y comentarios desde webmention.io de forma eficiente."
author:
  name: "angel cruz"
  picture: "https://angelcruzdevcdn.nyc3.cdn.digitaloceanspaces.com/images/me/angel-cruz.png"
ogImage:
  url: "/images/open-graph/laravel-opengraph-image.png"
---

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 ](https://gummibeer.dev/blog/2020/blade-component-webmentions/) 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
<?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:


```php
$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

```php
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 ;)

---

## Sitemap

Índice completo del sitio: [/sitemap.md](https://angelcruz.dev/sitemap.md)

Canónico HTML: [https://angelcruz.dev/post/como-integrar-webmentions-usando-laravel](https://angelcruz.dev/post/como-integrar-webmentions-usando-laravel)
