Skip to content

Adding an OPML Endpoint to My Aperture Instance

I’ve previously mentioned Aperture, the social feed aggregator, and OPML, and how I’m using this WordPress plugin to keep my Links list in sync with my feed reader’s OPML endpoint—I’m on a self-hosted Miniflux instance, although I might move everything over to Aperture later.

I was looking for a way to easily import feeds into Aperture, actually, and then I realized it’s not hard at all to add an export endpoint instead. It’s nowhere near perfect, though, because it currently only works on my single-user instance, and kind of ignores JSON feeds.

I’m no OPML expert, either, and kind of arbitrarily decided to add an xmlUrl attribute to Atom and RSS feeds’ outline elements, and an htmlUrl to HTML/Microformats feeds. (I wouldn’t know where to put JSON, which is neither XML nor HTML.)

Unlike Miniflux, Aperture doesn’t (seem to) support site—“HTML”—URLs (next to feed URLs), unless of course they’re the same, like for Microformats feeds.

The end result’s, well, rather simple, but at least allows me to automatically (and continuously) import the various entries into my blogroll.

So, uh, here’s how it works. There’s one extra route inside web.php’s web middleware group:

Route::get('opml', function () {
  $channels = \App\Channel::with('sources')->where('hide_in_demo_mode', '!=', 1)->get();
  $channels = $channels->sortBy('name');

  return new \Illuminate\Http\Response(
    view('layouts.opml', compact('channels')),
    ['Content-Type' => 'text/xml; charset=utf-8']

And, as you can see, I’m using a brand new Blade template, at resources/views/layouts/opml.blade.php:

<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<opml version="2.0">
    @foreach ($channels as $channel)
    <outline text="{{ $channel->name }}" title="{{ $channel->name }}">
      @foreach ($channel->sources as $source)
        text="{{ $source->pivot->name }}"
        title="{{ $source->pivot->name }}"
        type="{{ $source->format }}"
        {!! (in_array($source->format, ['microformats'], true) ? 'htmlUrl="' . htmlspecialchars($source->url) . '"' : '') !!}
        {!! (in_array($source->format, ['atom', 'rss'], true) ? 'xmlUrl="' . htmlspecialchars($source->url) . '"' : '') !!}

Note: It shouldn’t be hard to get this to work with multi-user instances, and allow for a user ID to be passed along, but then you’d also want to store whether said user wanted their OPML endpoint to be publicly accessible, which requires changes to the database, and so on, so yeah. I’ve now done exactly that on my own install, but haven’t yet updated the code example in this post.


  1. Jan Boddez on

    […] things a little further and added a very experimental OPML importer. Like, do not expect this to work with files that haven’t been carefully tweaked beforehand. The feed format, especially, needs […]

    Via, in reply to Adding an OPML Endpoint to My Aperture Instance.

  2. Jan Boddez on

    […] written about Aperture before, and how I’ve added some experimental features to it, and about wanting to write my own, simpler Microsub server. (For those not in the know, a Microsub server is a sort of feed aggregator, and […]

    Via, in reply to Adding an OPML Endpoint to My Aperture Instance.