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:


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:


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:


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

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

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

Using Text Expansion for URL Completion

In my professional life on the web, I tend to visit lots of the same URLs frequently. While I have (most of) them bookmarked in my browser, I usually don’t navigate to the bookmark and click it.

I start typing in the URL field of my browser (Firefox) and since autosuggest also searches the bookmarks, those are often visible. I realized though that this is still often too slow and not straight forward enough: It happens that many URLs are very similar and have the same first part, such as on Github many repos are under the same organization.

So a while ago I started using Alfred’s snippets to expand URLs for me. By using / as a suffix1, this allows for speedy expansion of URLs I visit frequently. A bonus is that the same expansion works in other places where I need the URL, e.g. for linking it in blog posts.

So, for example, I have the snippet g/a/ to expand to If I then continue typing fr, my browser can autocomplete much more precisely because I have already entered part of the URL to which I often visit.

Hope this can serve as an inspiration!

  1. Although I natively speak German, I have switched to US (Intl for the inverted-L Enter key, I cannot let got of that one) keyboards a long time ago to benefit from dedicated keys for square and curly brackets, this also means I have a dedicated key for slash ↩︎

Letting ChatGPT Access the Internet

With the new Completions function calling API you can actually enable ChatGPT to access the internet. I did a few quick experiments where I provided it with a function called get_extracted_url_contents. See how it made use of it:

Get News


$ php get-news.php

Prompt: Get some news from a random US news website on the internet.
Fetching by request of ChatGPT.
AI (239 tokens used):
According to CNN, the breaking news is that the former US president has been arraigned on 37 federal charges involving the alleged mishandling of highly classified military documents. This is a historic first.

Or from a German website:

Prompt: Get some news from a random German news website on the internet. Please only respond in English.
Fetching by request of ChatGPT.
AI (1363 tokens used):
Here are some news headlines from SPIEGEL International:

  1. “Ukraine’s President Calls on NATO to Set Clear ‘Red Lines’ for Russia” – Ukrainian President Volodymyr Zelensky has urged NATO to establish clear “red lines” to deter further aggression from Russia. Zelensky made these remarks during a visit to Brussels.
  2. “German Cabinet Approves New COVID-19 Restrictions, Including Nationwide Vaccination Mandate” – The German government has approved new measures to combat the spread of COVID-19, including a nationwide vaccination mandate for certain groups of people. These measures come as Germany faces a surge in COVID-19 cases.
  3. “Turkey Summons German Ambassador Over ‘AfD-Led’ Turkish Ship Inspection” – Turkey has summoned the German ambassador to protest against the inspection of a Turkish ship by a German frigate in the Mediterranean Sea. The inspection was led by a member of the far-right Alternative for Germany (AfD) party.
  4. “European Court of Justice Rules Hungary’s NGO Law Violates EU Law” – The European Court of Justice has ruled that Hungary’s controversial law that restricts the activities of non-governmental organizations (NGOs) violates EU law. The law required NGOs that receive funding from abroad to register as “foreign-funded organizations.”

Please note that these are just a few selected headlines. For more information, you can visit the SPIEGEL International website.

One more try for a specific site:

Prompt: Get some news from ORF. Please only respond in English.
Fetching by request of ChatGPT.
AI (1286 tokens used):
Here are some news headlines from ORF:

  1. Document affair: Trump declares “not guilty”
  2. Babler presents his new team
  3. Johnson vs. Sunak: Insults keeping the British on edge
  4. Slovenia wants to keep borders with Croatia open
  5. WKStA secures data in the Chancellor’s Office
  6. Alaba is about to reach the next milestone
  7. Alpine climate in winter is significantly too mild
  8. IAEA “very concerned” about fighting near Zaporizhia nuclear power plant
  9. NATO hopes Ukrainian successes will force Moscow to negotiate

Please note that these are only the headlines and more details can be found on the ORF website.

Summarize URLs


$ php summarize-url.php
Fetching by request of ChatGPT.
AI (1340 tokens used):
Matrix is an open-source internet-based chat system that operates on a federated model similar to email. It allows users to send and receive messages through homeservers, which maintain up-to-date copies of chat rooms. Matrix rooms can be either unencrypted and openly discoverable or end-to-end encrypted and invite-only, with encryption keys shared between users’ client software. There is a wide selection of Matrix clients available for different platforms, and a WordPress plugin called Chatrix has been developed to embed Matrix into WordPress posts or pages.



Here it required several runs to get the right response since it tried to access a lot of invalid URLs. But it eventually managed.

$ php research.php
Prompt: Research on the internet who won the ATP French Open 2023 but don’t use a search engine.
Fetching by request of ChatGPT.
AI (1085 tokens used):
According to the information on the Wikipedia page for the 2023 French Open, Novak Djokovic won the ATP Men’s Singles championship.

Things also worked out in the end when I gave it the ability to do multipel requests:

$ php research.php
Prompt: Research on wikipedia who won the (both men’s and women’s) ATP French Open 2023. If you cannot find a result, ask for a subsequent a function call.
Fetching by request of ChatGPT.PHP Warning: file_get_contents( Failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found

Fetching by request of ChatGPT.PHP Warning: file_get_contents( Failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
Fetching by request of ChatGPT.
AI (1630 tokens used):
The winner of the men’s singles ATP French Open 2023 is Novak Djokovic, and the winner of the women’s singles ATP French Open 2023 is Iga Świątek.

This has been just a quick exploration following OpenAI’s announcement. Curious how we’ll leverage this better in future!

CLI ChatGPT Client in PHP

For my personal use, I created a CLI ChatGPT client a few months ago. It has been very useful for me to have it available in the CLI quickly whenever I needed it (caveat, you need an API key!).

Unfortunately, for larger responses it can feel very slow, whereas the web version feels quite fast. But this is perceived speed because it shows you each word as it arrives and not just the whole response when finished (after all it is a completion AI that generates the response word by word).

So now, I have added streaming support to it. It now feels almost too fast :) The CLI has a few nice things such as readline support (i.e. you can go back to old queries with the up key) and it keeps all of your conversation in a text file. All of this in only 100 lines of PHP.