2

Blade-Component: Webmentions

 3 years ago
source link: https://gummibeer.dev/blog/2020/blade-component-webmentions/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Blade-Component: Webmentions

Photo by NordWood Themes on Unsplash

Blade-Component: Webmentions

While developing my new website including this blog I've decided to go with a static site and don't want to handle comments and so on. But I still wanted to include user contributed content below the articles.

So I searched for solutions and found some articles by my friends at Spatie how they've implemented webmention.io.

As I've created this site with Laravel 7 I wanted to create a simple to use Blade Component that will do everything for me. The result is a PHP file that loads the webmentions and maps them into three collections - likes, reposts and comments - and a blade file that renders them.

The approach is pretty simple as webmention does the hard job for us. At first I load all webmentions for the given or current URL. As the API is paginated I'm using a do-while loop to load all pages. After that I'm splitting the results in three collections.

app/View/Components/Webmentions.php
namespace App\View\Components;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Illuminate\View\Component;

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), '/'));

        $this->likes = $webmentions
            ->filter(fn (array $entry): bool => $entry['wm-property'] === 'like-of')
            ->mapInto(Like::class)
            ->sortByDesc('date');

        $this->reposts = $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;
            })
            ->mapInto(Repost::class)
            ->sortByDesc('date');

        $this->comments = $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']))
            ->mapInto(Comment::class)
            ->sortBy('date');
    }

    public function render()
    {
        return view('components.webmentions');
    }
}

And the Blade view is super opinionated so I will reduce it to the important part. You automatically have access to all public properties of the component class. To use autocompletion in my blade files I'm always adding the variables to the top of the blade file as a doc-comment.

resources/views/components/webmentions.blade.php
<?php /** @var \Illuminate\View\ComponentAttributeBag $attributes */ ?>
<?php /** @var \Illuminate\Support\Collection|\App\Webmentions\Like[] $likes */ ?>
<?php /** @var \Illuminate\Support\Collection|\App\Webmentions\Repost[] $reposts */ ?>
<?php /** @var \Illuminate\Support\Collection|\App\Webmentions\Comment[] $comments */ ?>

With this you can loop over the items and render them however you want. And can use the new blade component wherever you need it.

<x-webmentions :url="$url" />
  • Hardik Shah
  • Alex
  • Niko Halink
  • Sidrit Trandafili
  • Noel
  • Florian Wartner

17 likes

5 reposts

Comments

  1. πŸ”— A Blade component to render Webmentions (by @devgummibeer)
    gummibeer.dev/blog/2020/blad…
    #laravel #blade #webmentions

  2. Thanks for sharing! 🀩πŸ₯³
    Could be that a package for this is incoming. πŸš€

  3. It was worth the read just for learning that you can use phpdoc in blade files. 😍

  4. See kids, if you procrastinate long enough someone else will do it for you πŸ‘

  5. There's a typo in the tweet (additional s): webmention.io 😊

  6. Twitter should do a ping check for links in tweets. πŸ˜…
    Thanks! πŸ‘


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK