flowedit.
FLOWEDIT DOCUMENTATION

Configuration reference

From the plugin documentation · View source ↗

General settings live under Admin2 → Plugins → FlowEdit (or user/config/plugins/flow-edit.yaml). Defaults ship in flow-edit.yaml.

Manage reusable block types under FlowEdit → Blocks. The plugin settings link to the block library; definitions still live in custom_blocks. Their layout, archive and retirement metadata survives normal configuration saves.

enabled: true
builtin_blocks: { … }   # per-command slash menu visibility
allow_svg: false         # SVG uploads in the image picker
custom_blocks: [ … ]    # structured block definitions

Built-in slash commands (builtin_blocks)

Each key toggles one / menu entry:

Key Command Key Command
paragraph Paragraph code Code block
h1 / h2 / h3 Headings 1–3 hr Divider
bullet Bulleted list table Table
ordered Ordered list columns Columns (2–4)
quote Quote image Image
gif GIF
youtube YouTube
embed Embed (X/Twitter, Gist, Spotify, Maps)
gallery Gallery
video Video (MP4, WebM, Ogg, or Vimeo)

Disabling a built-in command only hides it from the slash menu. Authors can still type the equivalent Markdown or use the bubble toolbar, and existing page content keeps rendering on the front end.

Allow SVG uploads (allow_svg)

Default false. When enabled, SVG files become selectable/uploadable in the image picker. This widens the editor-side accept list only — uploads still go through Grav’s core page-media endpoint and its server-side validation applies; FlowEdit adds no extra server-side SVG gate (the crop endpoint never accepts SVG at all). SVGs are never inlined — the front end renders them as <img src="…"> only.

Stock photo search (stock_provider, stock_api_key)

Both provider keys use password fields. The required API plugin masks nonempty keys on generic plugin-config reads; sending that unchanged mask back preserves the saved value. Enter a new key to replace it or clear the field to remove it. The editor-specific settings response contains availability flags, never the keys. Keys are stored in the site’s server configuration, so protect config files and backups like other site credentials.

With a provider selected (Pexels, Pixabay, or Unsplash) and a valid API key, the image media modal gains a Stock photos section: authors search free stock photos, page through results, and click one to download it into the page’s media folder — the editor then references the local file (no hotlinking, re-picking the same photo reuses the file).

  • The API key stays server-side; the browser only talks to FlowEdit’s own endpoints (GET /flow-edit/stock, POST /flow-edit/stock/download).
  • Downloads come only from allow-listed provider hosts (images.pexels.com, pixabay.com/cdn.pixabay.com, images.unsplash.com), are content-type checked (jpeg/png/webp), and capped at 20 MB. Unsplash downloads additionally trigger the provider’s download event so the photographer gets credited per their API guidelines.
  • Without a key (or with the provider set to None) the section simply does not appear in the editor. Unsplash uses its access key with Client-ID auth; Pexels and Pixabay use their regular API keys.
  • Search requires api.pages.write; downloading requires update rights on the page, same as cropping.

Klipy GIF search (klipy_api_key)

With a Klipy app key (free tier from the Klipy partner panel), the GIF media modal gains a Klipy GIFs section: authors get trending GIFs immediately (the empty query shows trending), search Klipy’s library, and click one to download it into the page’s media folder — the editor then references the local file (no hotlinking, re-picking the same GIF reuses the file).

  • The app key stays server-side; the browser only talks to FlowEdit’s own endpoints (GET /flow-edit/gifs, POST /flow-edit/gifs/download).
  • Per Klipy’s attribution guidelines the search placeholder is literally “Search KLIPY”, and the section carries a Powered by Klipy mark.
  • Every search runs with Klipy’s medium content filter; downloads come only from static.klipy.com, are content-type checked (gif/webp), and capped at 20 MB. Picking a GIF fires Klipy’s share trigger (best-effort, server-side) so the pick is counted in their analytics. Media comes from Klipy’s static delivery hosts (static.klipy.com, static1.klipy.com, static2.klipy.com).
  • Without a key the section simply does not appear in the editor.
  • Search requires api.pages.write; downloading requires update rights on the page, same as stock photos.

Custom blocks (custom_blocks)

Structured blocks insertable via the slash menu and rendered through a visual layout or Twig template. Create visual types in FlowEdit → Blocks; register new Twig types in configuration and manage their templates in code. Each entry:

Field Purpose
ID Stable slug (callout, max 64 characters) — used as shortcode type and default template basename. Fixed after saving.
Enabled Off = hidden from the slash menu and the front end renders nothing for this type.
Archived Hidden from new insertion; existing instances remain editable and render normally. Defaults to false.
Label / Keywords Slash menu name and search aliases.
Icon / Category Lucide selector for the block icon and a library/slash grouping label. Existing emoji icons remain supported.
Twig template Path matching flow-blocks/{name}.html.twig; blank falls back to flow-blocks/{id}.html.twig.
Fields Typed inputs (text, textarea, url, select, toggle, list, color, number, date, icon, image). One field can occupy the shortcode body. Saved fields can be retired, but not renamed, removed, or retyped.
Layout Optional {version: 1, nodes: [...]} visual definition. Omitting it retains Twig behavior. See the layout schema.

Six types ship enabled by default: callout, cta (call to action), pullquote, accordion, tabs, and toc (table of contents).

The full field schema, Twig variables, theme overrides, and the settings API are documented in Creating custom blocks.

Permissions, environments, and saves

The library requires api.config.read; saving definitions and rendering unsaved previews require api.config.write. Selecting a preview page additionally needs api.pages.read and permission to read that page. Media actions retain their own page/media permissions; configuration write permission alone does not grant them. The editor’s page search and route index require page-write permission and return only pages the caller may read and list, honoring inherited page rules and API-key scopes. A page-level read/list grant can supply access without a global read grant.

The library reads and patches /config/plugins/flow-edit, sending only the updated custom_blocks collection with If-Match and X-Config-Environment. Unrelated settings and unknown metadata are retained. The selected environment is included in the editor URL. Existing named targets can be chosen when the account can list environments. The public site uses its normal environment; saving another target does not switch the site’s environment.

API configuration validation rejects duplicate IDs/field names, incompatible bindings, unsupported layouts, extra content fields, deletion of saved types, and incompatible schema edits. Layout and lifecycle metadata also survive normal plugin-settings saves. Keep a config backup before developer-managed disk edits.

Snippets (snippets)

Reusable markdown chunks offered in the slash menu under Snippet. Each entry has a Label, optional Keywords (slash search aliases), and a Body — inserted at the cursor when picked. The body may contain any flow shortcodes ([flow-columns], [flow-block], …); they become real editor blocks on insert. Two examples ship by default: Two columns and Tip callout. Snippets are an authoring aid only — nothing renders them on the front end by itself.

Page starter templates (page_templates)

Bodies that pre-fill the editor when a new page is created in Admin2. Each entry has a Label, an optional Template name, optional Keywords, and a Body:

  • On the /admin/pages/new screen, the first starter whose Template name matches the page’s blueprint template (empty or * = any template) is inserted automatically when the editor is still empty — once per browser tab.
  • All starters are always listed in the slash menu under Starter, so they also work when the editor does not mount on the new-page screen.

Enable/disable semantics at a glance

Kind Toggle location Slash menu Front end
Built-in command builtin_blocks.* Hidden Unchanged
Custom block block’s Enabled Hidden [flow-block type="…"] renders empty
Archived block block’s Archived Hidden Unchanged; existing instances remain editable
Retired field field’s Retire field Type still available Existing values and rendering preserved; input hidden in author forms
Whole plugin enabled Editor not offered Shortcodes stop rendering — keep the plugin enabled while pages still store [flow-*] shortcodes