Spotify and YouTube extensions for CommonMark

In a recent blog post, I wanted to use the Spotify embed code, so I could easily showcase the music about the bands I was talking about. However, I stumbled across a massive problem.

My blog posts are stored as Markdown, more specifically the standardised version called CommonMark. This website is powered by the PHP framework Laravel which uses CommonMark for PHP to convert Markdown to HTML.

Markdown supports the ability to mix and match its syntax with plain HTML. The embed code for Spotify (and YouTube) is an <iframe>. I pasted the code into my blog post… and it just rendered the code.

The flavour of Markdown parsing I use, called GitHub Flavoured Markdown, applies rules from DisallowedRawHtmlExtension. The reason is to stop malicious code from being introduced. This means you can't use iframes, as they're automatically escaped when rendering raw HTML.

Luckily CommonMark provides the ability to write extensions which can be used to work around this problem.

YouTube Extension

I couldn't find a Spotify extension, but there was an extension for YouTube. It allowed you to embed videos using the Link Markdown syntax. It supported short and long URLs, including the timestamp parameter. For example, the following Markdown would render the iframe code needed.


When setting up this extension, you could also choose the height and width for all your embedded videos. The project looked like a great starting place, so I forked this project and started working on a version which supported Spotify URLs.

Spotify Extension

I took the fundamentals of the existing plugin and worked up a solution which showed the iframe embed for an artist. I then applied some best practices I have been using on my PHP projects, including configuring scripts to run PHPStan and CodeSniffer and tidying up the code. I wrote unit tests for each part of the codebase and integration tests to cover the use case.

The Spotify embed has options for size and theme, so I implemented these in a similar way that the YouTube extension supported height and width. After this I was quickly able to support the other embed types, so you can embed track, album and artist iframes. There was some duplication at this point, as each URL was very similar, so I refactored it into a more streamlined solution.

In the end, my Spotify CommonMark Extension supports four different embed URLs, the ability to set the theme and configure the size. Finally, I updated the readme with examples and testing information and created changelog documentation.

Once the extension is installed and configured, you're able to use the Spotify embed by creating the following Markdown;


Updating the YouTube Extension

I now had a version of a Markdown extension that used modern PHP, followed best practices and had a robust test suite. I went back and applied all the same concepts and created my YouTube CommonMark Extension. As well as supporting the two URLs, it also included the ability to set the height and width on a per video basis.


Supporting CommonMark v2

Since Laravel 9, the framework only supports version 2 of CommonMark. This required some changes to the extensions. Although they were relatively minor, such as namespaces and converting a few methods, these were not backwards compatible. It also meant updating to PHP 8, which allowed more streamlining of properties.

Luckily, you cam "tag" different releases/versions. If you're using CommonMark v1, then you can install v1 of these extensions. If you're using CommonMark v2 then you can install v2 of the extensions. Each of these extensions is tagged on GitHub.

If you use CommonMark v1, then install YouTube Extension v1 and Spotify Extension v1. If you use Laravel 9 or CommonMark 2, then you need to install YouTube Extension v2 and Spotify Extension v2.

This was an interesting exercise, scratching my itch of needing to use the Spotify embedded <iframe>. It involved going down a rabbit hole of investigating an existing implementation, rewriting and improving the codebase to support my needs and finally supporting multiple versions.