embeds.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. .. _embedded_content:
  2. ================
  3. Embedded content
  4. ================
  5. Wagtail supports generating embed code from URLs to content on external
  6. providers such as Youtube or Twitter. By default, Wagtail will fetch the embed
  7. code directly from the relevant provider's site using the oEmbed protocol.
  8. Wagtail has a built-in list of the most common providers and this list can be
  9. changed :ref:`with a setting <customising_embed_providers>`. Wagtail also supports
  10. fetching embed code using `Embedly`_ and :ref:`custom embed finders <custom_embed_finders>`.
  11. Embedding content on your site
  12. ==============================
  13. Wagtail's embeds module should work straight out of the box for most providers.
  14. You can use any of the following methods to call the module:
  15. Rich text
  16. ---------
  17. Wagtail's default rich text editor has a "media" icon that allows embeds to be
  18. placed into rich text. You don't have to do anything to enable this; just make
  19. sure the rich text field's content is being passed through the ``|richtext``
  20. filter in the template as this is what calls the embeds module to fetch and
  21. nest the embed code.
  22. ``EmbedBlock`` StreamField block type
  23. -------------------------------------
  24. The :class:`~wagtail.embeds.block.EmbedBlock` block type allows embeds
  25. to be placed into a ``StreamField``.
  26. The ``max_width`` and ``max_height`` arguments are sent to the provider when fetching the embed code.
  27. For example:
  28. .. code-block:: python
  29. from wagtail.embeds.blocks import EmbedBlock
  30. class MyStreamField(blocks.StreamBlock):
  31. ...
  32. embed = EmbedBlock(max_width=800, max_height=400)
  33. ``{% embed %}`` tag
  34. -------------------
  35. Syntax: ``{% embed <url> [max_width=<max width>] %}``
  36. You can nest embeds into a template by passing the URL and an optional
  37. ``max_width`` argument to the ``{% embed %}`` tag.
  38. The ``max_width`` argument is sent to the provider when fetching the embed code.
  39. .. code-block:: html+Django
  40. {% load wagtailembeds_tags %}
  41. {# Embed a YouTube video #}
  42. {% embed 'https://www.youtube.com/watch?v=Ffu-2jEdLPw' %}
  43. {# This tag can also take the URL from a variable #}
  44. {% embed page.video_url %}
  45. From Python
  46. -----------
  47. You can also call the internal ``get_embed`` function that takes a URL string
  48. and returns an ``Embed`` object (see model documentation below). This also
  49. takes a ``max_width`` keyword argument that is sent to the provider when
  50. fetching the embed code.
  51. .. code-block:: python
  52. from wagtail.embeds.embeds import get_embed
  53. from wagtail.embeds.exceptions import EmbedException
  54. try:
  55. embed = get_embed('https://www.youtube.com/watch?v=Ffu-2jEdLPw')
  56. print(embed.html)
  57. except EmbedException:
  58. # Cannot find embed
  59. pass
  60. .. _configuring_embed_finders:
  61. Configuring embed "finders"
  62. ===========================
  63. Embed finders are the modules within Wagtail that are responsible for producing
  64. embed code from a URL.
  65. Embed finders are configured using the ``WAGTAILEMBEDS_FINDERS`` setting. This
  66. is a list of finder configurations that are each run in order until one of them
  67. successfully returns an embed:
  68. The default configuration is:
  69. .. code-block:: python
  70. WAGTAILEMBEDS_FINDERS = [
  71. {
  72. 'class': 'wagtail.embeds.finders.oembed'
  73. }
  74. ]
  75. .. _oEmbed:
  76. oEmbed (default)
  77. ----------------
  78. The default embed finder fetches the embed code directly from the content
  79. provider using the oEmbed protocol. Wagtail has a built-in list of providers
  80. which are all enabled by default. You can find that provider list at the
  81. following link:
  82. https://github.com/wagtail/wagtail/blob/main/wagtail/embeds/oembed_providers.py
  83. .. _customising_embed_providers:
  84. Customising the provider list
  85. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  86. You can limit which providers may be used by specifying the list of providers
  87. in the finder configuration.
  88. For example, this configuration will only allow content to be nested from Vimeo
  89. and Youtube. It also adds a custom provider:
  90. .. code-block:: python
  91. from wagtail.embeds.oembed_providers import youtube, vimeo
  92. # Add a custom provider
  93. # Your custom provider must support oEmbed for this to work. You should be
  94. # able to find these details in the provider's documentation.
  95. # - 'endpoint' is the URL of the oEmbed endpoint that Wagtail will call
  96. # - 'urls' specifies which patterns
  97. my_custom_provider = {
  98. 'endpoint': 'https://customvideosite.com/oembed',
  99. 'urls': [
  100. '^http(?:s)?://(?:www\\.)?customvideosite\\.com/[^#?/]+/videos/.+$',
  101. ]
  102. }
  103. WAGTAILEMBEDS_FINDERS = [
  104. {
  105. 'class': 'wagtail.embeds.finders.oembed',
  106. 'providers': [youtube, vimeo, my_custom_provider],
  107. }
  108. ]
  109. Customising an individual provider
  110. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  111. Multiple finders can be chained together. This can be used for customising the
  112. configuration for one provider without affecting the others.
  113. For example, this is how you can instruct Youtube to return videos in HTTPS
  114. (which must be done explicitly for YouTube):
  115. .. code-block:: python
  116. from wagtail.embeds.oembed_providers import youtube
  117. WAGTAILEMBEDS_FINDERS = [
  118. # Fetches YouTube videos but puts ``?scheme=https`` in the GET parameters
  119. # when calling YouTube's oEmbed endpoint
  120. {
  121. 'class': 'wagtail.embeds.finders.oembed',
  122. 'providers': [youtube],
  123. 'options': {'scheme': 'https'}
  124. },
  125. # Handles all other oEmbed providers the default way
  126. {
  127. 'class': 'wagtail.embeds.finders.oembed',
  128. }
  129. ]
  130. .. topic:: How Wagtail uses multiple finders
  131. If multiple providers can handle a URL (for example, a YouTube video was
  132. requested using the configuration above), the topmost finder is chosen to
  133. perform the request.
  134. Wagtail will not try to run any other finder, even if the chosen one didn't
  135. return an embed.
  136. .. _facebook_and_instagram_embeds:
  137. Facebook and Instagram
  138. ----------------------
  139. As of October 2020, Facebook deprecated their public oEmbed APIs. If you would
  140. like to embed Facebook or Instagram posts in your site, you will need to
  141. use the new authenticated APIs. This requires you to set up a Facebook
  142. Developer Account and create a Facebook App that includes the `oEmbed Product`.
  143. Instructions for creating the necessary app are in the requirements sections of the
  144. `Facebook <https://developers.facebook.com/docs/plugins/oembed>`_
  145. and `Instagram <https://developers.facebook.com/docs/instagram/oembed>`_ documentation.
  146. As of June 2021, the `oEmbed Product` has been replaced with the `oEmbed Read`
  147. feature. In order to embed Facebook and Instagram posts your app must activate
  148. the `oEmbed Read` feature. Furthermore the app must be reviewed and accepted
  149. by Facebook. You can find the announcement in the `API changelog
  150. <https://developers.facebook.com/docs/graph-api/changelog/version11.0/#oembed>`_.
  151. Apps that activated the oEmbed Product before June 8, 2021 need to activate
  152. the oEmbed Read feature and review their app before September 7, 2021.
  153. Once you have your app access tokens (App ID and App Secret), add the Facebook and/or
  154. Instagram finders to your ``WAGTAILEMBEDS_FINDERS`` setting and configure them with
  155. the App ID and App Secret from your app:
  156. .. code-block:: python
  157. WAGTAILEMBEDS_FINDERS = [
  158. {
  159. 'class': 'wagtail.embeds.finders.facebook',
  160. 'app_id': 'YOUR FACEBOOK APP_ID HERE',
  161. 'app_secret': 'YOUR FACEBOOK APP_SECRET HERE',
  162. },
  163. {
  164. 'class': 'wagtail.embeds.finders.instagram',
  165. 'app_id': 'YOUR INSTAGRAM APP_ID HERE',
  166. 'app_secret': 'YOUR INSTAGRAM APP_SECRET HERE',
  167. },
  168. # Handles all other oEmbed providers the default way
  169. {
  170. 'class': 'wagtail.embeds.finders.oembed',
  171. }
  172. ]
  173. By default, Facebook and Instagram embeds include some JavaScript that is necessary to
  174. fully render the embed. In certain cases, this might not be something you want - for
  175. example, if you have multiple Facebook embeds, this would result in multiple script tags.
  176. By passing ``'omitscript': True`` in the configuration, you can indicate that these script
  177. tags should be omitted from the embed HTML. Note that you will then have to take care of
  178. loading this script yourself.
  179. .. _Embedly:
  180. Embed.ly
  181. --------
  182. `Embed.ly <https://embed.ly>`_ is a paid-for service that can also provide
  183. embeds for sites that do not implement the oEmbed protocol.
  184. They also provide some helpful features such as giving embeds a consistent look
  185. and a common video playback API which is useful if your site allows videos to
  186. be hosted on different providers and you need to implement custom controls for
  187. them.
  188. Wagtail has built in support for fetching embeds from Embed.ly. To use it,
  189. first pip install the ``Embedly`` `python package <https://pypi.org/project/Embedly/>`_.
  190. Now add an embed finder to your ``WAGTAILEMBEDS_FINDERS`` setting that uses the
  191. ``wagtail.embeds.finders.oembed`` class and pass it your API key:
  192. .. code-block:: python
  193. WAGTAILEMBEDS_FINDERS = [
  194. {
  195. 'class': 'wagtail.embeds.finders.embedly',
  196. 'key': 'YOUR EMBED.LY KEY HERE'
  197. }
  198. ]
  199. .. _custom_embed_finders:
  200. Custom embed finder classes
  201. ---------------------------
  202. For complete control, you can create a custom finder class.
  203. Here's a stub finder class that could be used as a skeleton; please read the
  204. docstrings for details of what each method does:
  205. .. code-block:: python
  206. from wagtail.embeds.finders.base import EmbedFinder
  207. class ExampleFinder(EmbedFinder):
  208. def __init__(self, **options):
  209. pass
  210. def accept(self, url):
  211. """
  212. Returns True if this finder knows how to fetch an embed for the URL.
  213. This should not have any side effects (no requests to external servers)
  214. """
  215. pass
  216. def find_embed(self, url, max_width=None):
  217. """
  218. Takes a URL and max width and returns a dictionary of information about the
  219. content to be used for embedding it on the site.
  220. This is the part that may make requests to external APIs.
  221. """
  222. # TODO: Perform the request
  223. return {
  224. 'title': "Title of the content",
  225. 'author_name': "Author name",
  226. 'provider_name': "Provider name (eg. YouTube, Vimeo, etc)",
  227. 'type': "Either 'photo', 'video', 'link' or 'rich'",
  228. 'thumbnail_url': "URL to thumbnail image",
  229. 'width': width_in_pixels,
  230. 'height': height_in_pixels,
  231. 'html': "<h2>The Embed HTML</h2>",
  232. }
  233. Once you've implemented all of those methods, you just need to add it to your
  234. ``WAGTAILEMBEDS_FINDERS`` setting:
  235. .. code-block:: python
  236. WAGTAILEMBEDS_FINDERS = [
  237. {
  238. 'class': 'path.to.your.finder.class.here',
  239. # Any other options will be passed as kwargs to the __init__ method
  240. }
  241. ]
  242. The ``Embed`` model
  243. ===================
  244. .. class:: wagtail.embeds.models.Embed
  245. Embeds are fetched only once and stored in the database so subsequent requests
  246. for an individual embed do not hit the embed finders again.
  247. .. attribute:: url
  248. (text)
  249. The URL of the original content of this embed.
  250. .. attribute:: max_width
  251. (integer, nullable)
  252. The max width that was requested.
  253. .. attribute:: type
  254. (text)
  255. The type of the embed. This can be either 'video', 'photo', 'link' or 'rich'.
  256. .. attribute:: html
  257. (text)
  258. The HTML content of the embed that should be placed on the page
  259. .. attribute:: title
  260. (text)
  261. The title of the content that is being embedded.
  262. .. attribute:: author_name
  263. (text)
  264. The author name of the content that is being embedded.
  265. .. attribute:: provider_name
  266. (text)
  267. The provider name of the content that is being embedded.
  268. For example: YouTube, Vimeo
  269. .. attribute:: thumbnail_url
  270. (text)
  271. a URL to a thumbnail image of the content that is being embedded.
  272. .. attribute:: width
  273. (integer, nullable)
  274. The width of the embed (images and videos only).
  275. .. attribute:: height
  276. (integer, nullable)
  277. The height of the embed (images and videos only).
  278. .. attribute:: last_updated
  279. (datetime)
  280. The Date/time when this embed was last fetched.
  281. Deleting embeds
  282. ---------------
  283. As long as your embeds configuration is not broken, deleting items in the
  284. ``Embed`` model should be perfectly safe to do. Wagtail will automatically
  285. repopulate the records that are being used on the site.
  286. You may want to do this if you've changed from oEmbed to Embedly or vice-versa
  287. as the embed code they generate may be slightly different and lead to
  288. inconsistency on your site.