flowedit.
FLOWEDIT DOCUMENTATION

Stable storage contract

From the plugin documentation · View source ↗

Save protection uses a transport-only _flow_edit_revision property in the API JSON request. FlowEdit removes it in the pre-save hook; it is not Markdown, frontmatter, or a new on-disk format. Existing pages require no migration.

This contract freezes the supported 0.14 formats as the baseline for 1.0. FlowEdit stores content in the page’s normal Markdown body. There is no editor JSON document or separate block database to migrate.

Page body

  • Ordinary paragraphs, headings, lists, quotes, code, links, and tables use Markdown. Enable process.markdown: true for front-end rendering.
  • A full-width centered image without a caption uses ![alt](source). Other image layouts use [flow-image].
  • Rich content uses [flow-image], [flow-youtube], [flow-gallery] with [flow-slide], [flow-video], [flow-embed], [flow-columns] with [flow-column], and [flow-block] with optional [flow-item] children. Names, parameters, defaults, and examples are in the shortcode reference.
  • Aligned paragraphs/headings use <p style="text-align:center">…</p> or the equivalent heading tag. Inline formatting inside that HTML uses HTML tags (<strong>, <em>, <s>, <code>, <a>), so Grav renders it consistently.
  • Columns contain 2–4 column bodies, including empty ones. Text, images, galleries, video, supported embeds, and structured blocks render inside them. Hand-authored raw iframes/scripts do not gain permission from being in a column.
  • Media paths refer to existing page/site files or validated URLs. Crops create separate files; changing the crop naming algorithm does not invalidate older stored media paths or delete old derivatives.

Switching editor preferences does not convert the page. Keep FlowEdit and Shortcode Core enabled wherever [flow-*] content still needs to render.

Custom-block schema

Definitions remain in plugins.flow-edit.custom_blocks. Each definition has id, enabled, label, keywords, icon, category, template, and fields. The stable field schema consists of name, type, label, default, options, and content; supported types are text, textarea, url, select, toggle, list, color, number, date, and icon.

  • The block id becomes [flow-block type="id"]; non-content field names become attributes. Treat these names as persisted identifiers.
  • One content field maps to the body. List content uses up to 32 [flow-item title="…"]body[/flow-item] children.
  • Attribute values are strings; toggles use "1"/"0". Renderer validation and fallback behavior follow the field reference.
  • Rich-text body fields are sanitized prose, not arbitrary nested media or layout containers. A whole custom block can be placed inside a column.
  • Disabling a custom definition hides it from authors and suppresses its front-end output. Renaming a definition/field requires migrating its stored occurrences; changing a label does not.

Theme contract

The default template is flow-blocks/{id}.html.twig; configured alternatives must match flow-blocks/{name}.html.twig. A theme overrides it at:

user/themes/<theme>/templates/flow-blocks/<name>.html.twig

Column layout uses the same mechanism with columns.html.twig. The structured block template receives type, label, params, content, items, and uid. params and item titles are untrusted strings; keep Twig escaping enabled. Only sanitized content and item bodies are marked safe. Templates are trusted site code. See the Twig contract.

Legacy HTML policy

Legacy <!--flow-block:Label-->…<!--/flow-block--> blocks remain readable as read-only visual previews with a warning. The preview uses an inert HTML allow-list; its sanitized display is not written over the original body. The front end processes the original HTML under Grav’s HTML/security settings. This policy is an editor behavior, not an additional server security boundary.

New insertions use structured shortcodes. There is no automatic conversion: freeform HTML cannot reliably be mapped to named fields without author review. To replace a legacy block:

  1. Back up the page and inspect the original in Markdown mode.
  2. Define a structured block with the needed fields and a trusted Twig template, or select an existing shipped block.
  3. Insert it and copy the intended content into its fields.
  4. Preview, save, and reopen; remove the legacy block after checking the result.

Advanced authors can explicitly edit the original in Markdown mode. Visual edit/duplicate/snippet controls are unavailable on legacy cards.

Compatibility and migration rules

Changes must continue reading existing supported documents. Serializer output may normalize whitespace/attribute ordering; byte-for-byte preservation of every Markdown spelling is not promised. Unsupported Markdown/HTML constructs are outside this contract and should be checked in preview before saving.

Any incompatible shortcode, field, or template-contract change requires a CHANGELOG migration note before release, a documented conversion/rollback path, and fixtures proving old content is preserved or explicitly converted. Never silently rename stored identifiers or reinterpret their values. Additive features must have defaults compatible with existing documents. Security fixes that restrict formerly accepted unsafe content must also document the impact.

The stability changes following 0.14.0 require no page migration. Existing crop files and legacy markers remain valid; columns gain their intended nested output.