Guide for writers

Writing posts with Pangolin Blocks

Every post is built from ready-made blocks: a summary, body text, quotes, images, videos and more. You pick a block and fill in the content. Colours, font sizes and layout are already designed for you.

Setting up a theme? Jump to Part 2: For developers.

1Pick a blockAdd the block that fits your content: text, images, a video…
2Fill it inType text, choose images, paste links. No design settings needed.
3ArrangeDrag, reorder, duplicate or remove blocks as you like.

Quick start

  1. Go to Posts → Add New to write a new post, or open an existing one.
  2. Type the post title.
  3. Click and choose a block from the Pangolin Blocks group.
  4. Fill in the block. Keep adding blocks in the order you want.
  5. Click Save draft to save, Preview to check it, and Publish or Update to go live.
Tip: You can use the same block as many times as you like in one post, for example several Paragraph blocks between image blocks.

Adding blocks

Click in the top-left corner of the editor, or between two blocks, to open the block list. The Pangolin Blocks group is at the top. You can also type a block's name in the search box.

IllustrationThe block list after clicking +. The real screen may look slightly different depending on your WordPress version.

Depending on how your site is set up, you may see only the Pangolin blocks plus WordPress's paragraph, heading and list blocks, or all WordPress blocks as well.

Move, duplicate, remove

Click a block to select it. A small toolbar appears above it.

IllustrationThe toolbar and ⋮ menu of a selected block.
Tip: Open List View (the three-lines icon in the top bar) to see every block in the post as a list, and drag blocks there to reorder long posts quickly.

The blocks

For each block: when to use it, what you fill in, and a screenshot of how it looks on the live site. Click a screenshot to see it full size.

Text

Summary

A short opening that sums up the post. Usually placed first, right under the title.

You fill in
  • The summary text
  • Keep it short: 1–3 sentences.
  • Press Shift + Enter for a new line.
Summary block on the site: larger text with a coloured bar on the left
On the site

Paragraph

The main body of the post: paragraphs, subheadings and lists.

You fill in
  • Paragraphs, subheadings and lists, inside the block's frame
  • Press Enter to start a new paragraph.
  • Select text to make it bold or italic, or to add a link.
  • Click + inside the frame to add a Heading or a List.
Paragraph block on the site: a subheading, a paragraph with bold text and a list
On the site

Quotes

Highlights a saying or a quotation.

You fill in
  • The quote
  • Author (optional)
  • Don't type quotation marks; the block adds them.
Quotes block on the site: a quote in a light box with the author underneath
On the site

Note

A tip or a heads-up that readers shouldn't miss.

You fill in
  • The note text
  • The ⓘ icon is added automatically.
  • Keep it short; use a Paragraph for longer text.
Note block on the site: a tinted box with an info icon
On the site
Images
Choosing images (all image blocks): click Upload to add an image from your computer, or Media Library to pick one that's already there. While the block is selected, each image has Replace and Remove buttons. The caption field appears once an image is chosen.

One Image

One large image, as wide as the text column.

You fill in
  • 1 image
  • Caption (optional)
  • Best for high-quality landscape images.
One Image block: Mui Ne sand dunes at full width, with a caption
On the site

Two Images

Two images side by side, for example to compare them.

You fill in
  • Image 1, image 2
  • A caption for each (optional)
  • Both images are cropped to the same height, so the top and bottom of portrait images may be cut off.
Two Images block: Sa Pa rice terraces and Ha Giang buckwheat flowers side by side
On the site

Three Images

Three images in a row. On phones they stack on top of each other.

You fill in
  • Image 1, image 2, image 3
  • This block has no captions.
Three Images block: three coastal photos in a row
On the site

Four Images

Four images in a 2 × 2 grid.

You fill in
  • Images 1 to 4
  • This block has no captions.
Four Images block: photos of Da Lat, Hoan Kiem Lake and Ninh Binh in a 2 by 2 grid
On the site

Gif Image

An animated GIF, for example to show a few steps.

You fill in
  • 1 .gif file
  • Only GIF files can be chosen.
  • GIFs are often large; keep them under a few MB so the page loads fast.
Gif Image block: one frame of the animation
On the siteA screenshot shows one frame only

Single Image

A smaller, centred image. Good for portrait images, or images that don't need the full width.

You fill in
  • 1 image
  • Caption (optional)
  • Unlike One Image, the image is narrower and centred.
Single Image block: a portrait photo of a waterfall in Cao Bang, centred, with a caption
On the site
Video, embeds, code

Video

A YouTube or Vimeo video, or a video file you upload.

You fill in
  • The source: YouTube / Vimeo link or Upload file
  • For a link: paste the video address into Video URL
  • For a file: click Choose video (mp4, mov, webm)
  • Copy the link straight from your browser's address bar, e.g. https://www.youtube.com/watch?v=…
  • A preview of the video appears in the editor.
Video block: a YouTube video about Ha Long Bay in a 16:9 frame
On the site

Iframe

Shows another page inside the post: a map, a form, a spreadsheet…

You fill in
  • Embed URL: the address of the page to show
  • Height (px): the frame height, 400 by default
  • Only administrators and editors can add this block. Iframes added by other users aren't shown on the site.
  • Use the "embed" link the other site provides. For Google Maps: Share → Embed a map, then copy the address inside src="…".
  • Some sites don't allow embedding; the frame then stays empty or shows an error.
Iframe block: a Google Map of Ha Long Bay embedded in the post
On the site

Code Editor

Shows a code snippet, keeping its spacing and line breaks.

You fill in
  • Language: e.g. php, js, css, json
  • The code
  • The Language field only shows while the block is selected.
  • Paste the code as is; no need to reformat it.
Code Editor block: a JSON snippet in a bordered box
On the site

On mobile

Nothing extra to do: blocks adapt to the screen on their own. For example, Three Images shows its images in a row on a computer and stacks them on a phone.

Top of the demo post on a computer: title, date and featured image
Computer: top of a post
Three Images block on a phone: three images stacked
Phone: Three Images

Tips

  • Empty blocks don't show on the site. If you add a block by mistake and leave it empty, readers won't see it, but it's tidier to delete it.
  • Image descriptions (Alt Text): fill them in in the Media Library when choosing an image. They help screen-reader users and search engines understand the image. If an image has no description, its caption is used instead.
  • Use large enough images, at least about 1200px wide for One Image, so they look sharp on big screens.
  • Older posts written in the old editor appear inside a Classic block. You can still edit them as usual. There's no need to click "Convert to blocks".
  • You can't change colours, font sizes or spacing, on purpose: every post keeps the same look as the rest of the site.
Note: If you need a layout that doesn't exist yet (a pricing table, an expandable FAQ…), ask the development team for a new block rather than building it out of the existing ones.

FAQ

I can't find the Pangolin Blocks group when I click +.

Try typing a block's name (for example "Quotes") into the block list's search box. If it still doesn't show, the Pangolin Blocks plugin may not be active: tell your administrator.

A block shows in the editor but not on the site.

Check that the block has content (empty blocks aren't shown) and that you clicked Update after editing. Then reload the post.

How do I move several blocks at once?

Hold Shift and click to select several blocks in a row, then use ▲ ▼ or drag them. For long posts, List View is quicker.

I deleted a block by mistake.

Press Ctrl + Z (Windows) or ⌘ + Z (Mac) to undo, or click the Undo button (curved arrow) in the top bar.

My video doesn't show.

Make sure the link points to a single video on YouTube or Vimeo (not a channel or a playlist), and that the video allows embedding.

Part 2

For developers: styling the blocks in your theme

Everything a theme developer needs to install Pangolin Blocks on a site and make the blocks match its design. No changes to the plugin are needed.

How it works

The plugin decides what each block contains: its fields and its HTML structure. Your theme decides how it looks, by giving a CSS class to each part of each block. The plugin never outputs colours, fonts or spacing of its own, except a plain fallback style.

PluginFields and HTML structure, e.g. a quote is a <blockquote> with a text part and an author part.
Your themepangolin-blocks.php gives each part a class: quote.text → "post-quote__text".
OutputThe same classes are used on the site and in the editor preview.

Each block is styled either entirely by your theme or entirely by the plugin's default style. The two are never mixed:

SituationClasses usedPlugin's default CSS
The block is listed in your theme fileOnly your classesNot loaded
The block is not listed, or there is no theme fileDefault classes (pangolin-quote, …)Loaded

If you list a block but leave out one of its parts, that part gets no class at all rather than the default one. You can style the blocks one at a time: the ones you haven't listed yet keep working with the default look.

Setup

  1. Check the requirements: WordPress 6.8 or newer, PHP 7.4 or newer, and the block editor enabled for posts. If the Classic Editor plugin is installed, set it to use the block editor.
  2. Install the plugin: copy the pangolin-blocks folder into wp-content/plugins/ and activate it. Include build/; node_modules/ and src/ are not needed on a live site. The blocks now work with the default style.
  3. Create pangolin-blocks.php in the root of your theme, next to functions.php. In a child theme, the child theme's file is used first.
  4. Optional: to give writers a focused editor with only Pangolin Blocks on posts, add add_filter( 'pangolin_blocks_restrict_inserter', '__return_true' ); to your theme's functions.php.
  5. Return an array of block → part → classes, and write the CSS for those classes in your theme's stylesheet (see example).
  6. Load your stylesheet in the editor so the editor preview matches the site (see Editor preview).

Example theme file

A starter file covering all 13 blocks. Keys are block names without the pangolin/ prefix. Values are plain class strings: use your own class names, BEM, Tailwind utilities, or anything else your CSS understands.

<?php
// wp-content/themes/your-theme/pangolin-blocks.php
return array(
  'summary' => array(
    'text' => 'post-lead',
  ),
  'paragraph' => array(
    'wrapper' => 'post-prose',
  ),
  'quote' => array(
    'wrapper' => 'post-quote',
    'text'    => 'post-quote__text',
    'author'  => 'post-quote__author',
  ),
  'note' => array(
    'wrapper' => 'post-note',
    'icon'    => 'post-note__icon',
    'text'    => 'post-note__text',
  ),
  'image-one' => array(
    'wrapper' => 'post-media',
    'figure'  => 'post-media__item',
    'image'   => 'post-media__img',
    'caption' => 'post-media__caption',
  ),
  'single-image' => array(
    'wrapper' => 'post-media post-media--narrow',
    'figure'  => 'post-media__item',
    'image'   => 'post-media__img',
    'caption' => 'post-media__caption',
  ),
  'image-two' => array(
    'wrapper' => 'post-media post-media--2',
    'figure'  => 'post-media__item',
    'image'   => 'post-media__img',
    'caption' => 'post-media__caption',
  ),
  'image-three' => array(
    'wrapper' => 'post-media post-media--3',
    'figure'  => 'post-media__item',
    'image'   => 'post-media__img',
  ),
  'image-four' => array(
    'wrapper' => 'post-media post-media--2',
    'figure'  => 'post-media__item',
    'image'   => 'post-media__img',
  ),
  'gif-image' => array(
    'wrapper' => 'post-media',
    'figure'  => 'post-media__item',
    'image'   => 'post-media__img',
  ),
  'video' => array(
    'wrapper' => 'post-video',
    'video'   => 'post-video__file',
  ),
  'iframe' => array(
    'wrapper' => 'post-embed',
    'iframe'  => 'post-embed__frame',
  ),
  'code-editor' => array(
    'pre'  => 'post-code',
    'code' => 'post-code__code',
  ),
);

Then style those classes in your theme's CSS, for example:

/* your-theme/style.css */
.post-quote {
  margin: 0 0 2rem;
  padding: 1.5rem;
  border-left: 4px solid var(--brand);
  background: #f6f6f8;
}
.post-quote__text  { font-size: 1.25rem; margin: 0 0 .5rem; }
.post-quote__author{ font-style: normal; color: #666; }

.post-media        { display: grid; gap: .75rem; margin: 0 0 2rem; }
.post-media--2     { grid-template-columns: repeat(2, 1fr); }
.post-media--3     { grid-template-columns: repeat(3, 1fr); }
.post-media--narrow{ max-width: 28rem; margin-inline: auto; }
.post-media__item  { margin: 0; }
.post-media__img   { width: 100%; height: auto; border-radius: 8px; }
.post-media__caption { font-size: .875rem; text-align: center; color: #666; }

Using Tailwind

Utility classes work the same way, for example 'text' => 'text-lg leading-relaxed border-l-4 border-brand pl-4'. Make sure Tailwind scans the theme file so those classes end up in the compiled CSS. A root-level './*.php' content pattern already covers it; otherwise add the file to content in tailwind.config.js and rebuild your CSS.

Using a filter instead of a file

The classes can also come from code, for example a site plugin. The filter receives the theme file's array, or an empty array when there is no file:

add_filter('pangolin_blocks_theme_classes', function ($classes) {
  $classes['note'] = array(
    'wrapper' => 'alert alert-info',
    'icon'    => 'bi bi-info-circle',
    'text'    => 'mb-0',
  );
  return $classes;
});
Add the filter early: in functions.php or in a plugin's main file. The classes are read once, when WordPress runs init, so a filter added later (inside a template, for example) is ignored.

Parts and markup reference

The HTML each block outputs on the site, with the part names in {braces}. Style these parts rather than bare elements: the editor adds its own wrappers and classes around blocks.

BlockMarkup on the site
summary<p class="{text}">…</p>
paragraph<div class="{wrapper}"> + core blocks: h2.wp-block-heading, p, ul.wp-block-list </div>
The inner text is not classed by the theme file: style it with your normal post typography, e.g. .post-prose h2, .post-prose ul.
quote<blockquote class="{wrapper}"><p class="{text}">“…”</p><cite class="{author}">— …</cite></blockquote>
The quotation marks and dash are added by the block. cite is omitted when there is no author.
note<div class="{wrapper}"><i class="{icon}" aria-hidden="true"></i><p class="{text}">…</p></div>
The <i> is only output when icon has a class, so an icon-font class (Remix Icon, Bootstrap Icons, …) works well there.
image-one, single-image, image-two<div class="{wrapper}"> one <figure class="{figure}"><img class="{image}"><figcaption class="{caption}">…</figcaption></figure> per image </div>
figcaption only when a caption is set. Images come from wp_get_attachment_image(), so they have srcset, width/height and lazy loading.
image-three, image-four, gif-imageSame as above, without captions. The GIF is output at full size so it stays animated.
video<div class="{wrapper}"> YouTube/Vimeo <iframe> from oEmbed, or <video class="{video}" controls> </div>
The oEmbed iframe has no class: size it through the wrapper, e.g. .post-video { aspect-ratio: 16/9 } .post-video iframe { width: 100%; height: 100% }.
iframe<div class="{wrapper}"><iframe class="{iframe}" style="height: …px" loading="lazy"></iframe></div>
The height comes from the editor's field; set the width in your CSS (usually width: 100%).
code-editor<pre class="{pre}"><code class="{code} language-…">…</code></pre>
language-… is always added, so highlight.js or Prism can pick it up. The plugin doesn't load a highlighter.

An empty block outputs nothing at all, so you don't need :empty rules.

Editor preview

The plugin sends your classes to the editor, so blocks there are built with the same classes as on the site. For them to look the same, your CSS must also be loaded inside the editor. The standard way:

// functions.php
add_action('after_setup_theme', function () {
  add_theme_support('editor-styles');
  add_editor_style('style.css'); // path relative to the theme folder
});
  • Editor styles are scoped to the editor content area automatically, so site-wide rules like body don't leak into the WordPress admin.
  • Load the fonts and icon fonts your classes rely on in the editor too. The enqueue_block_assets action loads assets into both the site and the editor.
  • In the editor, Video and Iframe show their input fields while selected, and Paragraph shows its inner blocks. Those parts use WordPress's own editor UI.

Using the default style

If you don't need a custom design, skip the theme file. The default style is deliberately plain: it inherits the site's font and text colour. Two CSS variables tint it:

:root {
  --pangolin-accent: #2563eb;              /* borders, note icon */
  --pangolin-surface: rgba(0, 0, 0, .04);  /* quote and note backgrounds */
}

The default classes, useful if you only want to adjust the default look with a few overrides, are listed under pangolinClasses in each block's block.json (e.g. pangolin-quote, pangolin-quote__text, pangolin-images--cols-2).

Hooks

FilterWhat it changes
pangolin_blocks_restrict_inserterReturn true to limit the inserter on posts to Pangolin Blocks plus a few core text blocks. Off by default.
pangolin_blocks_theme_classesThe whole block → part → classes array (see above).
pangolin_blocks_allowed_core_blocksWhen the inserter is restricted, which core blocks can be added next to Pangolin Blocks. Default: paragraph, heading, list, list item and Classic.
pangolin_blocks_orderThe order of the blocks in the inserter: a list of block names without the prefix.
// Also allow core images and tables on posts.
add_filter('pangolin_blocks_allowed_core_blocks', function ($blocks) {
  return array_merge($blocks, array('core/image', 'core/table'));
});

By default the plugin doesn't restrict the inserter. Once a theme opts in with pangolin_blocks_restrict_inserter, only posts are restricted; pages and custom post types keep every block, and Pangolin Blocks are available there too.

Troubleshooting

My classes aren't applied; blocks still show pangolin-… classes.

Check that the file is named exactly pangolin-blocks.php, sits in the root of the active theme (or child theme), and returns an array. The block key must be the name without the prefix, e.g. 'image-two', and its value must be an array.

The classes are there, but the block looks unstyled.

Your CSS for those classes isn't loaded, or (with Tailwind) the classes weren't compiled. Rebuild your CSS and check that the theme file is in Tailwind's content list.

The site looks right, but the editor doesn't.

Load your stylesheet into the editor with add_editor_style() (see Editor preview), then hard-reload the editor.

A new block from a plugin update looks different from the others.

It isn't in your theme file yet, so it uses the default style. Add an entry for it, with the part names from its block.json.

Can I change a block's HTML or fields?

Not from the theme: structure and fields belong to the plugin, so every site stays compatible with saved content. To add or change blocks, see the plugin's README.md.