The Beauty of Simple Bookmarklets

Jeremy Keith posted about bookmarklets that he uses for testing websites where he specifically likes those that just pass on the current URL to a service. Those bookmarklets typically have a structure like:

javascript:location.href='https://example.com?s='+escape(location.href)

I use those for my Friends WordPress plugin, too. That’s the one where you can follow people via RSS or ActivityPub and see the feed in a private section of your blog or even in Mastodon apps.

A screenshot of my WordPress tools section.

So, to follow the current website, you’d click on a bookmarklet like this:

javascript:location.href='https://example.com?add-friend='+escape(location.href)

I have another WordPress plugin called Post Collection, where you can save articles to your blog. Both to be able to search them later, or, with my Send to E-Reader plugin, to send them to your favorite reading device as a compiled e-book with chapters. Although the bookmarklet that you’d typically install has some logic to post the whole current page body so that it also works on non-public posts, there is also a version that looks like this:

javascript:location.href='https://example.com?user=123&collect-post='+escape(location.href)

One particularly nice thing about these style of bookmarklets, is that while unfortunately they don’t (or didn’t?) work on Firefox Mobile, you can use an Android app called URL Forwarder to share a URL from any other app which comes in quite handy when you use other apps to discover interesting content (such as awesome the Glider app for Hacker News).

I have only added my two bookmarklets here, but most of the ones Jeremy mentioned could also be added.

By the way, I have some history with bookmarklets. In 2005, I created a bookmarklet manager called Blummy. It’s still alive but dormant (ping me if you want to try it, signups have been spammed to death).

Bookmarklets have come out of fashion but were very important back then. I wished browsers would support them better and make installing them a little less awkward. They are always like a little swiss army knife to me.

Posted in Web

My FOSDEM 2024 Talk: Migrating the WordPress Community from Slack to Matrix

When I submitted my application for a talk at FOSDEM 2024, we were still on for migrating the WordPress community to Matrix.

Alas, there were many factors that led us to pause the transition indefinitely, announced by Matt at the Q&A of State of the Word 2023. The most important factors were accessibility problems, some important feature-imparity compared with Slack, and the license changes at Element (to AGPL, with the requirement to sign a CLA when contributing).

The WordPress community has collected their issues in a Github repository. We tried hard to overcome the issues, through documentation, education (some things just work differently in a federated environment), and upstream patches (for example to address some of the accessibility problems).

In the end, I did not cancel but held my talk on February 4 at FOSDEM 2024 in Brussels, explaining all the things we did to lower the barrier of entry:

As well as bots and integration we created to fulfill the specific needs, such as these Maubot plugins:

  • Post to room: post messages via webhook
  • Relay: an integration can react to room messages via webhook
  • Group mentions: upon command a bot mentions many people
  • Watchdog: alert about community created rooms

Also, we held weekly meetings in the WordPress meta chat throughout the year, and published meeting notes afterwards.

There is a lot more in my presentation, I hope that my presentation slides can be helpful to other communities (or companies) trying to migrate from Slack to Matrix. Maybe some things that were a blocker for the WordPress community are not so important for other communities.

Finally, here is the video of the ~30 minutes presentation:

FOSDEM 2024 talk by Alex Kirk: Embracing Matrix for Enhanced Communication: Migrating the WordPress Community from Slack to Matrix

Kudos to my colleagues Paulo Pinto and Ashish Kumar who did a lot of the heavy lifting in the effort. Together we submitted around 40 upstream pull requests (on Synapse (pre-license change), Element-Web, Slack bridge, and more).

Keeping A Family Wiki

Members of my (some of them extended) family recently entered and left life, which is always an opportunity to think about my family. I’ve written before about my own efforts to keep family history in a wiki which is powered by my Family Wiki WordPress plugin (Github).

Every relative gets their own page, like on Wikipedia, just in private. This is why I am also not sharing screenshots, the plugin page has a few fake ones. Here is one screenshot of the editing page though (you can scroll away the bottom when you enter text):

It is not a very elaborate plugin but it was based on a born and died shortcode to create something like a family birthday calendar as well as a generally notable-dates calendar for your family.

In order to add some structure to this, I have now (manually) migrated this metadata to use Advanced Custom Fields through which you’d now not only enter the birth and death date but also parents and children.

With a new [name_with_bio] shortcode, you’ll then receive automatic output like this:

Name (born as Maiden name on January 1, 1900 in Place, died on March 31, 2000 (aged: 100) in Other Place; daughter of Father and Mother; sibling of Brother and Sister; parent of Daughter and Son)

This metadata might make it possible to render a family tree later on, since now the pages are interconnected with each other. Maybe something like this already exists for ACF, I looked a while back and there wasn’t.

Just to recap: my personal mission is to keep stories of my relatives alive, where and what they worked on, who they visited, what adventures they might have encountered. In general: anecdotes, maybe with some pictures. Also, for living relatives, their contact data.

This is why I deem a wiki format to be superior to all those geneaology sites. I don’t value the huge amout of connections to some far-removed relatives that they encourage to build. I care about those that I might have got to know or just missed.

And, having a WordPress blog (network) already, it’s easy to put this on WordPress vs. using a dedicated wiki (and actually it’s quite easy to find cheap WordPress hosting). I had the original versions on a Mediawiki but it was quite a hassle to maintain, now the data is just in a WordPress. Should my plugin no longer work, nothing is lost since the wiki pages are just plain WordPress pages. Some of the nicities will go away but the meat is in the writing.

Oh, and of course a benefit of a wiki is that other relatives can also contribute. In reality, it’s hard to get them to contribute but when they do, they add some details I didn’t know and that’s just worth so much for me!

I can highly recommend to try keeping family history in such a way. It’s a really nice way to pass this on to further generations of your family, and also for my own reference when my poor memory strikes again.

Posted in Web

Mastodon API Tester

tldr: Use the Mastodon API Tester to play with the Client API of Mastodon.

I’ve created the WordPress plugin called Enable Mastodon Apps which does a seemingly small but powerful thing: it enables you to access your WordPress blog using Mastodon apps like Tusky or Ivory. This can be used to browse your own blog and post to it. If you also have the Friends plugin and the ActivityPub plugin installed, this will actually make your WordPress blog behave like a Mastodon instance.

It does this be re-implementing the Mastodon API (unfortunately, Mastodon didn’t opt to implement the ActivityPub client-server API so this is not based on a standard) which can be tricky: it uses REST API endpoints in the (virtual) directories /oauth and /api which are so generic that they are prone to conflicts.

Additionally, although the API is well documented, many apps were created based on assumptions that are true for Mastodon itself (which caused a lot–sometimes hard to reproduce–of issues for the plugin). For example, the id of a post or a user is defined as a string but many apps crash when you put a non-number there. Or that a boosted toot needs to have a different id than the virtual “wrapping” toot (Ivory!). In such cases, apps would crash but work fine with Mastodon itself.

Even more complicated are interactions with other WordPress plugins. It can be hard to understand if the plugin is working correctly, if another plugin is interfering, the hosting provider acts quirky, or if the Mastodon app has an incompatibilty with my implementation.

Thus I have created a simple one-page JS app called Mastodon API Tester hosted on Github pages (source on Github):

I hope that this tool will help identify issues better in future, it can also be used with GotoSocial or a “real” Mastodon instance. Feel free to report issues you might encounter.

PS: the Enable Mastodon Apps plugin will be worked on at the Cloudfest Hackathon, thanks Matthias Pfefferle for taking the lead on this! (Unfortunately, I cannot make it there because I’ll be speaking at WordCamp Asia in Taipei just the weekend before that.)

PPS: Happy Birthday, Matt!

Prototype: Create a Website from a Screenshot and Refine It, All in the Browser

I’ve been working on this experiment, combining OpenAI’s gpt-4-vision-preview with WordPress Playground to create a website based on a screenshot.

This follows on the heels of Matt Mullenweg’s announcement at the 2023 State of the Word that in 2024, the WordPress project wants to work on Data Liberation.

While the typical approach to migrating data is to build importers for specific services, a truely universal migration could happen through screenshots. With AI vision this might now be in reach.

So I built this prototype that combines a OpenAI-powered chat interface with WordPress Playground. First a screenshot, a screen recording further down.

So this is only a start. The website somewhat resembles the screenshot but it’s far from being pixel perfect.

My idea is that you’ll work together with the assistant in refining the site. It can help you update, you can ask it questions. An import is rarely perfect from the start but you can see and test the result right away in the browser and refine it.

I imagine that when done, you can then transfer the site to a web hoster who from then on can host your website for everyone.

You can try this yourself here, you “just” need an OpenAI API key that will be stored in your local storage: https://akirk.github.io/website-liberator/

Source (very unpolished) at https://github.com/akirk/website-liberator/

Some notes on this first implementation:

  • Every message is a new conversation. Modifying a website can be token intense, so for now it cannot refer to previous messages.
  • It’s using function calling to allow OpenAI to gather more information to fulfil the request.
  • Chosing the right functions to provide can be tricky.
  • It uses different models depending on the task. gpt4-vision-preview for the screenshot, gpt-3.5-turbo for the rest. I need to experiment more with gpt-4 for the latter tasks.

Finally, a screen recording of an early iteration, I have since moved the chat to the right side.

As I’ve been working on the prototype, it has shown to be interesting to have the bot be there just for customizing sites, it can create and modify pages, update settings of the website. Maybe install plugins.

So starting with a basis from screenshots and imported data, it might just be able to assist you to arrive at a comparable WordPress website, and all with the ease and effortless setup of WordPress Playground. I wonder where we can take this!

Bonus

Some screenshots from a recent version:

cll: Adding unix pipe support

Today I’ve added a little feature to my cll tool (which I renamed again but I think now I’ll stick to this) so that it can process stdin so that you can do stuff like this:

echo 'a presentation about the friends plugin for wordpress' | cgt -s 'Please create a reveal.js presentation based on the following notes. Ensure to use short titles and short few words on each list item. Please load the moon theme and scripts from the cdn.jsdelivr.net domain, dont use any reveal.js plugins. Respond with just the HTML, no outside comments.' > presentation.html

Which creates a presentation.html file that contains a full Reveal.js presentation on the topic.

The systems prompt will tell the model how to behave so that you can also (granted it doesn’t always work but it’s gotten better) tell it to output JSON which you can then parse:

echo hello | cll -mllama2 -s 'please respond only in valid json' | jq .
{
  "message": "hello",
  "type": "text"
}

In “stdin mode,” it will only output the response from the LLM, you can turn that back on using -v (as in verbose) although that additional output will go to stderr.

Book: Pull Requests and Code Review: Best Practices for Developers

The book Pull Requests and Code Review: Best Practices for Developers has been pointed out to me by my colleague Paulo Pinto, and I liked it.

I always find it hard to express what a makes a good code review, this book attempts to describe it. There are probably lots of other opinions about and for better recommendations but I liked this one for it trying to give some advice that I can agree with.

You can buy the book for “name-your-price” or check out the Github repo and download or build the format you want to read it in.

Posted in Web

OpenAI Text-to-Speech

It has been a somewhat interesting coincidence that I am currently without voice because of a cold, and OpenAI has just released some really good Text-to-Speech voices with their Create speech API. So in preparation for a meeting today, I created a little script that will output the spoke audio what I typed.

Since the voice will read exactly what’s there, I added a spell fixer that will (through ChatGPT) automatically fix typos before it’s sent to the audio API.

$ php talk.php
Voice: echo
Fix spelling: off
Speed: 1.0
> hi everyone and welcoem to tis meetin
> sc
Fix spelling: on
> hi everyone and welcoem to tis meetin
Hi everyone and welcome to this meeting.
> s2
Speed: 2
> my voice is gone because of a pretty string cold that iv pickd up
My voice is gone because of a pretty strong cold that I've picked up.
> s1.1
Speed: 1.1
> my voice is gone because of a pretty string cold that iv pickd up
My voice is gone because of a pretty strong cold that I've picked up.
> turns out, even suing the streaming audio aip, typing and then waiting for the srsult is too lsow for a conversation. but it's been interesting
Turns out, even using the streaming audio API, typing and then waiting for the result is too slow for a conversation. But it's been interesting.
> sc
Fix spelling: off
> without spell fixer it's faster but for good intonation it only makes sense to send full sentences, not single words as soon as they have been typed. maybe that can also be solved, but that's for the next experiment

In any case, it’s been fun. Thanks Simon for highlighting the API.

Posted in Web