HTML to Gutenberg Blocks Converter

Turn pasted HTML into real block markup: headings, lists, images, quotes, tables and groups, with anything else kept as a custom HTML block.

Enable JavaScript to convert your own HTML; the blocks below are the example.

Nothing is uploaded. The conversion happens in this tab.

15 blocks: 1 code, 1 group, 2 heading, 1 html, 1 image, 1 list, 3 list-item, 3 paragraph, 1 quote, 1 table. Dropped 1 <script>, which a block cannot carry past kses.

  1. heading <h1>Release 2.4
  2. paragraph <p>Some bold text and a link.
  3. list <ul>One Two Nested
  4. image <figure>The settings screen
  5. quote <blockquote>A quote, with its own paragraph.
  6. code <pre>if ( a < b ) { run(); }
  7. table <table>SettingDefaultcacheon
  8. group <div>In a wrapperNested content.
  9. html <iframe>
blocks.html
<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading">Release 2.4</h1>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Some <strong>bold</strong> text and a <a href="https://example.com">link</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul class="wp-block-list">
<!-- wp:list-item -->
<li>One</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>Two
<!-- wp:list -->
<ul class="wp-block-list">
<!-- wp:list-item -->
<li>Nested</li>
<!-- /wp:list-item -->
</ul>
<!-- /wp:list -->
</li>
<!-- /wp:list-item -->
</ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="/wp-content/uploads/shot.png" alt="A screenshot" width="1200" height="800" /><figcaption class="wp-block-image__caption">The settings screen</figcaption></figure>
<!-- /wp:image -->

<!-- wp:quote -->
<blockquote class="wp-block-quote">
<!-- wp:paragraph -->
<p>A quote, with its own paragraph.</p>
<!-- /wp:paragraph -->
</blockquote>
<!-- /wp:quote -->

<!-- wp:code -->
<pre class="wp-block-code"><code>if ( a < b ) { run(); }</code></pre>
<!-- /wp:code -->

<!-- wp:table -->
<figure class="wp-block-table"><table><thead><tr><th>Setting</th><th>Default</th></tr></thead><tbody><tr><td>cache</td><td>on</td></tr></tbody></table></figure>
<!-- /wp:table -->

<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:heading -->
<h2 class="wp-block-heading">In a wrapper</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Nested content.</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:group -->

<!-- wp:html -->
<iframe src="https://www.youtube.com/embed/x" width="560" height="315"></iframe>
<!-- /wp:html -->

Pasting HTML into the WordPress editor gives you one enormous custom HTML block, or a pile of paragraphs with the structure flattened out of them. Block markup is what the editor actually stores: HTML with a comment in front of each piece saying which block it is. This writes those comments.

Paste it into the editor’s code editor view and every block is a real block: editable, movable, styled by the theme.

How to use

  1. Paste the HTML. A whole page, one section, or a fragment from an old post.
  2. Leave Keep wrappers as groups on if the layout matters, off if you want the contents of a div to become top-level blocks. Off is usually right when moving one section out of an old theme.
  3. Read the report. It says how many of each block came out, and names anything that was dropped or stripped.
  4. Copy the markup. In the post editor, open the options menu (three dots, top right), choose Code editor, paste, then switch back to the visual editor.

Example

This HTML:

<ul>
  <li>One
  <li>Two
    <ul><li>Nested</li></ul>
</ul>

becomes this:

<!-- wp:list -->
<ul class="wp-block-list">
<!-- wp:list-item -->
<li>One</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>Two
<!-- wp:list -->
<ul class="wp-block-list">
<!-- wp:list-item -->
<li>Nested</li>
<!-- /wp:list-item -->
</ul>
<!-- /wp:list -->
</li>
<!-- /wp:list-item -->
</ul>
<!-- /wp:list -->

Three things happened there that a search and replace could not do. The unclosed <li> elements were closed, because HTML says an <li> closes the one before it. Each item became its own wp:list-item block, which is what makes items draggable in the editor. And the nested list went inside its parent item rather than beside it, which is the shape the list block requires; put it beside and the editor shows the whole list as invalid content.

Pitfalls

<script> and <style> are dropped. Not converted, dropped, and the report says how many. WordPress strips both from post content on save for anyone without unfiltered_html, so a block that carried them would lose them the first time the post was updated. Put scripts in the theme or a plugin.

Inline event handlers and unsafe links go too. onclick, and any href or src whose scheme is not http, https, mailto, tel or a relative path. Same reason: kses would remove them, and a block whose saved markup differs from its stored markup is a block the editor flags as invalid.

Classes are dropped by default. A pasted class="lead" means nothing without the stylesheet it came from. Turn Keep class attributes on if you are bringing the CSS too.

A custom HTML block is a real answer. An <iframe>, a <video>, a <form>: there is no core block that holds them with their attributes intact, so they become wp:html. That is what the editor’s own “convert to HTML” does, and it is better than dropping the element.

The markup is not validated against your block versions. It targets core blocks as they are in WordPress 6.5 and later. A block plugin that replaces core/list may parse it differently.

Compatibility

Block markup is stable: the comment format has not changed since Gutenberg shipped in WordPress 5.0, and the attributes used here (level on a heading, ordered on a list, layout on a group) are all current in WordPress 6.5 through 6.8.

The conversion happens in the browser and nothing is uploaded, so an unpublished page can be converted without leaving the tab.

Blocks produced: paragraph, heading, list, list-item, image, quote, code, separator, table, buttons, button, group and html. Elements with no block of their own become html rather than disappearing.

Frequently asked questions

Where do I paste the result?
In the post or page editor, open the three-dot options menu and choose Code editor. Paste there, then switch back to the visual editor; the blocks appear as blocks. Pasting into the visual editor gives you one HTML block instead.
Why did my <div> disappear?
Keep wrappers as groups was off, so its children were promoted to top-level blocks. Turn it on to get a wp:group with the layout attribute instead.
Can I convert a whole exported page?
Yes, and the <head>, <script> and <style> parts of it will be dropped rather than converted. What comes out is the content, which is what a post can hold.
What about ACF or a page builder’s markup?
Whatever is plain HTML converts. Shortcodes are left as text in a paragraph, which is correct: WordPress runs them at render time. A builder’s own <!-- wp:acf/... --> comments are not read as blocks, because the input is treated as HTML, not as block markup.
Does it round-trip?
No, and it is not meant to. Feeding block markup back in would read the block comments as HTML comments and drop them. Convert once, then edit in the editor.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.