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-IDauth; 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
mediumcontent filter; downloads come only fromstatic.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/newscreen, 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 |