# `MishkaCmsMigration.Sources.WordPress.Content`
[🔗](https://github.com/mishka-group/mishka_cms_migration/blob/v0.0.1/lib/mishka_cms_migration/sources/__wordpress/content.ex#L5)

A WordPress post's or page's `content.raw` as its item's content pieces
(`MishkaCmsMigration.Source.Item`): `%{html: ...}` for what is converted here, and
`%{name: ..., attrs: ..., raw: ...}` for a block or shortcode left to `migration:content:convert`
(`MishkaCmsMigration.Events`), in the order they come. `call/2` reads the content with LazyHTML,
an HTML5 parser, so its markup is never edited as text; only a shortcode, which is text, is read
with a pattern.

## Blocks

A block is what its `<!-- wp:name {attrs} -->` and `<!-- /wp:name -->` comments enclose, or a
`<!-- wp:name {attrs} /-->` alone. A core block (`core/…`, the name without a namespace) becomes
its own saved markup, which is already semantic HTML: headings, lists, quotes, tables,
`<pre><code>`, `<figure>` with its `<img>` and `<figcaption>`, a gallery's figures inside one
`<figure>`, `<hr>`. The markup loses WordPress's `class` and `style`, which no theme here reads,
and the block comments; the blocks inside it are converted the same way. Some take a shape of
their own:

  * `core/columns` and `core/media-text` — a `<div class="grid gap-6 md:grid-cols-N">`, one
    column per inner block, and `core/group` a `<div class="grid gap-6">`;
  * `core/embed` — a `<figure>` with the player of a YouTube or Vimeo video (below), or with a link
    to its address for any other;
  * `core/html` — the author's markup as it is, classes kept, without its comments;
  * `core/shortcode` — its shortcodes, below;
  * `core/block`, a reusable block — the content of the reusable block it names, read from
    WordPress with the `fetch` `call/2` is handed (`/wp/v2/blocks`) and converted the same way; a
    reusable block inside it, or one WordPress does not answer, is a piece named `core/block`
    with its `"ref"`.

A block of another namespace (`acme/callout`) and a block with no saved markup, which WordPress
draws as the page is served (`core/latest-posts`), are pieces named by the block, with its attrs
and its markup, comments included, as `raw`.

## Classic content and shortcodes

What sits outside any block, all of a post written in the classic editor, has its paragraphs
made as WordPress makes them when it shows the post: a blank line ends one, a line break inside
one is a `<br>`, and a block element (a heading, a list, a figure) stands on its own. Its
shortcodes, and those of a `core/shortcode` block, become HTML:

  * `[caption]` — a `<figure>` with the image and its caption;
  * `[gallery ids="…"]` — a `<figure>` of a figure per image, each image read from WordPress
    (`/wp/v2/media`) and linked to its file (`link="file"`), to nothing (`link="none"`) or to its
    attachment page;
  * `[embed]` — a `<figure>` with the player of the YouTube or Vimeo video it encloses, or with a
    link to any other address;
  * `[video src="…"]` — a `<video>` with its controls.

Any other shortcode, and a gallery none of whose images WordPress answers, is a piece named by the
shortcode (no namespace, so never mistaken for a block), with its attributes and its text as
`raw`. A shortcode inside a block other than `core/shortcode` is left as text.

A YouTube or Vimeo address alone on its line, which WordPress embeds by itself (oEmbed), is the
video's player too; any other address on its line stays text.

Images and links keep the addresses WordPress gave them. The links to the site's own posts are
named in the item's `links`, the links to its pages in its `pages`, and the files of its media
library they show or link to in its `media` (`MishkaCmsMigration.Sources.WordPress`), for the
target to point them at where the posts, the pages and the files move.

An address that runs code or carries a document of its own is dropped, its element kept without
it, wherever the content has it (`pieces/1`): a `javascript:` or `vbscript:` address, and a
`data:` one but an image's `src`, in an `href`, `src`, `action`, `formaction`, `poster` or
`xlink:href`, read as a browser reads it, whatever its case and the spaces, tabs and line breaks
in it.

## Players

A YouTube video (`youtube.com/watch?v=`, `youtu.be/`, `/embed/`, `/shorts/`, `/live/`) is played
by `https://www.youtube-nocookie.com/embed/<id>`, which sets no cookie until it plays, and a
Vimeo video (`vimeo.com/<id>`, its unlisted `vimeo.com/<id>/<hash>`, a channel's, and
`player.vimeo.com/video/<id>`) by `https://player.vimeo.com/video/<id>`: an `<iframe>` with a
title, 560 by 315, lazily loaded and allowed to go full screen. An `<iframe>` the author wrote,
in a `core/html` block or in classic content, keeps its own address. The targets that write the
content allow the players' origins on the site (`MishkaCmsMigration.Targets.Helpers.Frames`).

# `content_node`

```elixir
@type content_node() :: LazyHTML.Tree.html_node() | {:piece, map()}
```

A converted node: a `LazyHTML.Tree` node, or `{:piece, piece}` where a piece is left to
`migration:content:convert`.

# `fetch`

```elixir
@type fetch() :: (String.t(), [pos_integer()] -&gt; %{optional(pos_integer()) =&gt; map()})
```

How `call/2` reads more of WordPress: the rows of a REST route (`"/wp/v2/blocks"`,
`"/wp/v2/media"`) with these ids, by id, or `%{}` when it cannot.

# `blocks_in`

```elixir
@spec blocks_in(String.t() | [LazyHTML.Tree.html_node()]) :: [tuple()]
```

The blocks at the top of `raw`, an HTML string, or of a block's inner nodes, as
`{:block, name, attrs, inner, raw}` with the name's namespace (`"core/navigation-link"`), its
attributes as the block comment's JSON says them, the nodes it encloses (`nil` for a block with
no end comment) and its source nodes. What lies between blocks is dropped. For a reader of a
block tree other than content, such as a block navigation
(`MishkaCmsMigration.Sources.WordPress.Navigation`).

# `call`

```elixir
@spec call(String.t(), fetch()) :: [map()]
```

The pieces `raw` is made of, reading the reusable blocks and the gallery images it names with
`fetch`.

# `embed`

```elixir
@spec embed(String.t()) :: LazyHTML.Tree.html_node()
```

A `<figure>` with the player of the YouTube or Vimeo video at `url` (see "Players"), or with a
link to any other address.

# `nodes`

```elixir
@spec nodes(String.t(), fetch()) :: [content_node()]
```

`raw` converted as `call/2` converts it, as nodes, for a converter that places the converted
content inside markup of its own before it makes the pieces (`pieces/1`), such as the text of an
Elementor widget (`MishkaCmsMigration.Sources.WordPress.Elementor`).

# `pieces`

```elixir
@spec pieces([content_node()]) :: [map()]
```

The content pieces of `nodes`, in order: the HTML around each `{:piece, piece}`, and the piece,
without an address that runs code or carries a document of its own (`javascript:`, `vbscript:`,
and `data:` but an image's).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
