Drupal 9: Using And Adding oEmbed Providers

Drupal has had the ability to use oEmbed in core since version 8.6.0. It was included along with the other media changes that went into core in that version. 

I have used some of the Drupal core oEmbed functionality to include YouTube videos into content, but I've never dug deeper to see what else I could do with it. Although Drupal comes with Vimeo and YouTube services available there are many more services to include, you just need to enable them.

In this article I will show what oEmbed is, how to use it out of the box, and then how to add more services to your system. 

First, let's cover some groundwork and address what oEmbed is.

What is oEmbed?

oEmbed is a standard that allows a client to ask a service for information on how to embed a resource. Essentially a website will expose a service that you can call to get information on what markup to create in order to embed that item; including some metadata about that resource. This means that you don't need to sign into a complex API, or scrape content from a page, it's all handed to you.

A good example is YouTube, since that is well understood and built into Drupal's default oEmbed providers. Take the following URL of a video on the YouTube.

https://www.youtube.com/watch?v=uzRQ93UEOe0

You would ask YouTube for information on how to embed that video using the YouTube oEmbed service.

https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=uzRQ93UEOe0

YouTube responds with a JSON response containing information about that video, including title, duration, dimensions, a thumbnail image and the code used to embed that video.

{
"title": "SVALBARD In The K! Pit",
"author_name": "KERRANG!",
"author_url": "https://www.youtube.com/c/KERRANGofficial",
"type": "video",
"height": 113,
"width": 200,
"version": "1.0",
"provider_name": "YouTube",
"provider_url": "https://www.youtube.com/",
"thumbnail_height": 360,
"thumbnail_width": 480,
"thumbnail_url": "https://i.ytimg.com/vi/uzRQ93UEOe0/hqdefault.jpg",
"html": "<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/uzRQ93UEOe0?feature=oembed\"
 frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>"
}

You would then take this information and embed the HTML within your site. The "html" element of the response is essentially everything you need but you also have access to other metadata about the video, including the thumbnail and original channel. The video link isn't in the data since that was used to request the data.

Look at the oEmbed website for more information about the standard.

Does every website have an oEmbed service? Well, it turns out that there is a standard list of oEmbed providers contained on the page at https://oembed.com/providers.json. By default, Drupal will not let you deviate from this official list of providers, which is a good thing as you are essentially putting a great deal of trust into the embedded information.

Using Drupal's Default oEmbed

Let's use Drupal to embed a oEmbed service. I'll continue to use YouTube since we now know how that system works.

First, we need to create a media type that will accept YouTube links as a source. To do this we create the media item type in the usual way by going to Structure > Media types and clicking on "Add media type". Here is the form.

Drupal media entity type creation, showing YouTube oEmbed setup.

There are some extra mapping options on this page, you just need to ensure that "Name" is mapped to "Resource Title" so that the title is added to the right place in Drupal.

Note that you can select Vimeo here and allow YouTube and Vimeo videos to be uploaded to the same media type.

Next you need to allow the media to be embedded into your content. This would either be through the media upload in text editor interface, or via a field connected to an entity. In both situations when you start to embed this type of media you would see the following dialog.

Drupal media entity creation, showing the YouTube video being added.

Clicking "Insert selected" will create the Drupal media item and pull in the metadata from YouTube using the oEmbed service. This will add the name and thumbnail of the video to your system.

Drupal YouTube media item, using oEmbed to pull through the thumbnail.

When you save the post it will use the provided HTML to embed the YouTube video correctly.

A Drupal page, showing an embedded YouTube video.

Now that we can create oEmbed providers in Drupal let's look at adding new oEmbed services to the list.

Adding New oEmbed Services

As I said previously, Drupal comes with two oEmbed integrations that allow you to embed YouTube and Vimeo content. It is also possible to add oEmbed services to Drupal to expand the sort of things you can embed.

Remember that you cannot deviate from any provider not on the official list so you are stuck with the list https://oembed.com/providers.json. At least, not without installing the oEmbed Providers Drupal module, which is perhaps beyond the scope of this article.

Since we are restricted to the official list, let's pick a well known provider like Twitter, which I assume everyone knows about. The entry for Twitter in the providers list is looks like this.

    {
        "provider_name": "Twitter",
        "provider_url": "http://www.twitter.com/",
        "endpoints": [
            {
                "schemes": [
                    "https://twitter.com/*/status/*",
                    "https://*.twitter.com/*/status/*"
                ],
                "url": "https://publish.twitter.com/oembed"
            }
        ]
    }

To add Twitter as an available oEmbed service we need to use the hook_media_source_info_alter() hook. This takes the currently available sources on the system and allows us to add to or remove from that list. The most important part of the returned array is the "providers" section, which details which providers from the list of oEmbed providers should be a part of this source. This must match the provider from the list exactly, with the same sentence case.

In the following example we use the hook_media_source_info_alter() hook to add a new provider to the list and set up some sensible defaults for that provider.

/**
 * Implements hook_media_source_info_alter().
 */
function mymodule_media_source_info_alter(array &$sources) {
  $sources['oembed:twitter'] = [
    'id' => 'twitter',
    'label' => new TranslatableMarkup('Twitter'),
    'description' => new TranslatableMarkup('Embed a Tweet.'),
    'allowed_field_types' => ['string'],
    'default_thumbnail_filename' => 'no-thumbnail.png',
    'providers' => ['Twitter'],
    'class' => 'Drupal\media\Plugin\media\Source\OEmbed',
    'forms' => [
      'media_library_add' => OEmbedForm::class,
    ],
    'provider' => 'mymodule',
  ];
}

Note that in the example above we are setting this to just be Twitter, but there is nothing to stop us from adding in more items to the 'providers' array to add more media sources.

With this in place all we need to do (after a cache clear) is to create a new media type with Twitter as the media source. This works in exactly the same way as the remote video source we set up earlier.

Drupal oEmbed, showing adding Twitter as a media source.

In order to use this in our Drupal site we have two options.

The first is to use the standard media embed functionality that comes with CKEditor. To allow Tweets to be embedded into content we just need to go to the Text formats and editors administration area under the Content authoring menu. Here, we just need to add Twitter to the media types that are selectable in the media library when this interface is used.

Drupal oEmbed, showing adding Twitter as a embeddable source in the media embed options.

Once this page is saved we can embed Tweets into content in the same way as I showed YouTube videos being embedded above.

Secondarily, as this is a normal media entity we can also create a field to reference the Tweets. Since they are media items we just need a standard entity reference field that uses Media entities as the default reference entity.

Drupal oEmbed, showing a media field created to show Tweets.

The set up of this field is pretty standard, and involves us selecting the media item we need from the list. In this case it is the Twitter reference.

Drupal oEmbed, showing the media reference options in the media field.

We can now open up our content type (or paragraph) that we added the Twitter media reference to and embed tweets using just the URL of the tweet. This works in much the same way as the YouTube embed in that we get a lot of stuff for free. Below is a screenshot showing what the embedded Tweet looks like. Notice that it also has some interactivity so it allows users to automatically reply or like the Tweet directly from your site.

Drupal oEmbed, showing a rendered Tweet using a referenced media entity.

The only thing we don't get for free here is a thumbnail of the media item, but as long as you have the no-thumbnail in your Drupal install (which is installed as part of the media module) then it will produce a missing thumbnail icon. You could replace this with a Twitter logo if you like, but since that isn't a standard Drupal image you'll have to move it into the default location during your install process. It must go into the directory "public:/media-icons/generic/".

As for best practice, it's probably not a great idea to set you oEmbed providers up like this. Rather than directly referencing the provider you should probably reference the type of media you are embedding. Twitter is probably the exception as there aren't a lot of other providers doing the same thing. For things like images and videos you should create a generic image or video media item that referencing a group of providers. This gives you the ability to, for example, have YouTube, Vimeo, Wave.video, and CollegeHumor videos all controlled through a single interface. Adding more to this is then just a case of extending the list of providers referenced.

That's pretty much it for adding providers. I haven't talked about adding custom providers, or allowing Drupal to become an oEmbed provider itself, but that will be a topic for another article.

Comments

Biggest missing oembed provider, in my opinion are Wikidata and Wikipedia.
Sure you can write your own Sparql query (which module to use in D9?). Yet I find these queries very complex to understand and a 'simple' route via oembed would really be great.

Any idea if this is on the agenda?

Permalink

Hi Jan,

I don't know, sorry. I'm still learning about oEmbed myself. I plan on doing more research and writing more about oEmbed in the future, so I'll keep an eye out for that.

Name
Philip Norton
Permalink

Hi Philip,

It's a very useful article. 

I have a question, is it possible to use oEmbed to display a the Twitter timeline instead of a single tweet? If affirmative, is it updated automatically?

Thanks in advance,
Ruben B

Permalink

Hi Ruben,

Thanks for reading!

I don't think you can get a Twitter timeline, since that would be multiple items of data without a single resource ID. You're best off looking at API access for searching Tweets, although that's probably not going to happen at this point.

As for being updated automatically, if oEmbed did work with timelines then it would update every time the page was loaded since the oEmbed is a reference to the resource and not cached locally.

Name
Philip Norton
Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
1 + 4 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.