WP Manifestindependent plugin directory
manifest / admin / fb-mind-map

FB Mind Map

Create, edit and organise interactive mind maps inside the WordPress admin. Open source, no build step, no external services, no API keys, no tracking.

by Fatih Bora — FB Software Solutions · github.com/fatihborasoftware-sudo/fb-mind-map · website

4stars
8release downloads
0forks

Install

The author publishes release zips, so WP-CLI can install straight from GitHub:

wp plugin install https://github.com/fatihborasoftware-sudo/fb-mind-map/releases/download/v0.3.0/fb-mind-map-0.3.0.zip

Readme

FB Mind Map

Create, edit and organise interactive mind maps inside the WordPress admin.

No external services, no API keys, no tracking, no build step. Download the plugin, upload it, and it works.


What 0.3.0 does

  • A Mind Maps menu in wp-admin with a proper WordPress list table — search, sorting, pagination, node counts, duplicate and trash.
  • Create a map from a one-field form: a single root node, a blank canvas, or an example structure to poke at.
  • A full-screen editor inside wp-admin: toolbar, canvas, node inspector, navigator and status bar.
  • Nodes — root, child and sibling; rename inline; delete a branch; drag a node and its whole subtree; collapse and expand with a visible child count.
  • Automatic layout with branches balanced left and right of the root, per-branch colours inherited by descendants, and curved connectors.
  • Pan and zoom, fit-to-screen, and a navigator that frames your content rather than an arbitrary giant canvas.
  • Undo and redo, and copy / cut / paste of whole branches.
  • Save and reload, with autosave on by default and a warning if you try to leave with unsaved work.
  • Movable panels — drag the inspector or the navigator anywhere by its header, minimise either to its title bar. Where you put them is remembered for you alone.
  • Double-click empty canvas to add a child of the selected node, dropped exactly where you clicked and already in rename mode.
  • Notes, made of blocks: text, HTML with a sandboxed live preview, an AI prompt stored for later, images or files from your Media library, and a video from YouTube or Vimeo. A small ✎ on the node opens a peek; Open takes you to a full-screen workspace with a sidebar of every note in the map, search and an outline.
  • The video comes up with the note, in its own window placed on whichever side of the note has room — right, left, below or above — joined to it by a short tether. Drag it by its header, resize it with − and +, push it to full screen, or close it with Esc. The note stays open behind it, so you can read and watch at once.
  • English and Türkçe, with a finished Turkish translation in the box and a switcher in the toolbar for people who want the plugin in a different language from the rest of the site.
  • The admin menu folds while a map is open, and unfolds everywhere else.
  • An example map you cannot delete, created once on activation. Its content is how this plugin was actually built — seven stages in the order they happened, mistakes included — and every stage's note carries the prompt that produces it. It is made out of the plugin's own block types, so opening it is also a tour of notes, the workspace and the video box. Edit it freely; Reset on its row puts it back.
  • An author credit at the foot of the plugin's own screens — three styles or off — plus Settings / YouTube / GitHub / Support on its Plugins row, and a welcome panel on an empty map list. Nothing on the Dashboard, no banners, no review nag.

What 0.3.0 deliberately does not do

Node links, icons, drawing, cross-branch connectors, free-floating nodes, templates, import/export, AI generation (prompts are stored, never run), front-end display, real-time collaboration. The inspector shows greyed-out rows for links and icons so the shape is visible — nothing behind them is built yet.


Install

From a zip

  1. Plugins → Add New → Upload Plugin
  2. Choose fb-mind-map.zip
  3. Install, then Activate
  4. A Mind Maps item appears in the admin menu

From git

cd wp-content/plugins
git clone https://github.com/fatihborasoftware-sudo/fb-mind-map.git

Then activate it from the Plugins screen. There is nothing to build and nothing to install — no npm, no Composer.


How it is put together

fb-mind-map/
├── fb-mind-map.php                 bootstrap: constants, includes, hooks
├── uninstall.php                   opt-in data removal on delete
├── includes/
│   ├── class-fb-mind-map-capabilities.php   who may do what
│   ├── class-fb-mind-map-demo.php           the example map and its protection
│   ├── class-fb-mind-map-post-type.php      the fb_mind_map CPT
│   ├── class-fb-mind-map-data.php           the map JSON: defaults + sanitising
│   └── class-fb-mind-map-rest.php           GET and POST /maps/<id>
├── admin/
│   ├── class-fb-mind-map-admin.php          menus, screens, asset loading
│   ├── class-fb-mind-map-list-table.php     the All Mind Maps table
│   └── views/
│       ├── list.php
│       ├── new.php
│       └── editor.php
├── assets/
│   ├── css/
│   │   ├── fb-mind-map-admin.css
│   │   └── fb-mind-map-editor.css
│   └── js/
│       ├── fb-mind-map-engine.js   the canvas: layout, drawing, interaction
│       ├── fb-mind-map-notes.js    the note popover and note workspace
│       └── fb-mind-map-editor.js   the wp-admin glue: toolbar, panels, saving
└── languages/
    ├── fb-mind-map.pot
    ├── fb-mind-map-tr_TR.po
    └── fb-mind-map-tr_TR.mo

includes/ also holds class-fb-mind-map-settings.php (site options and the per-user editor layout) and class-fb-mind-map-i18n.php (the language override), and admin/views/settings.php is the settings screen.

The three JavaScript files, and why they are separate

fb-mind-map-engine.js knows how to draw and edit a mind map. It knows nothing about WordPress — no REST, no nonces, no admin markup. You can drop it into a plain HTML page and work on the canvas on its own.

fb-mind-map-notes.js is the note popover and the full-screen note workspace. It owns the block editor and the media library integration.

fb-mind-map-editor.js is the only file that talks to WordPress. It starts the engine, wires the toolbar, manages the floating panels, draws the inspector and the right-click menu, saves over REST, and stores the language choice.

That line exists so the drawing half can be replaced — with a third-party library, or with a rewrite — without touching the WordPress half.

Where a map is stored

One mind map is one fb_mind_map post. The post title is the map's name. The structure lives in post meta under _fb_mind_map_data as a JSON string:

{
  "version": 2,
  "root": {
    "id": "n1",
    "text": "Central idea",
    "side": "",
    "color": "",
    "collapsed": false,
    "dx": 0,
    "dy": 0,
    "blocks": [],
    "children": []
  }
}

A note is the blocks array on a node:

{ "type": "text",   "text": "plain text, newlines kept" }
{ "type": "html",   "text": "<p>markup, wp_kses_post on save</p>" }
{ "type": "prompt", "text": "stored, never executed" }
{ "type": "image",  "attachment": 42, "caption": "…" }
{ "type": "file",   "attachment": 43, "caption": "…" }
{ "type": "video",  "url": "https://www.youtube.com/watch?v=…", "caption": "…" }

Media is stored as an attachment ID, never a URL. The filename, size and URL are looked up from the media library each time the editor loads, so replacing a file in Media updates every note that references it.

side and color are only meaningful on first-level branches. dx / dy are the manual offset from the automatic layout — which is what lets "Auto layout" put everything back.

One JSON document rather than a table of node rows, because a mind map is always read and written whole. There is no query like "find every node named X" that would justify the extra tables, and one document keeps saving atomic.

The REST API

GET  /wp-json/fb-mind-map/v1/maps/<id>     read one map
POST /wp-json/fb-mind-map/v1/maps/<id>     save one map
POST /wp-json/fb-mind-map/v1/prefs/ui      remember this user's panel layout
POST /wp-json/fb-mind-map/v1/prefs/locale  remember this user's language

The map routes require edit_fb_mind_map on that specific map; the preference routes require edit_fb_mind_maps. All of them require a valid X-WP-Nonce header.

POST /maps/<id> body:

{ "title": "My map", "data": { "version": 2, "root": { … } } }

Security notes

Worth reading if you are learning from this plugin, because these are the places WordPress plugins usually get it wrong.

  • Node text is plain text, always. It is sanitised with sanitize_text_field() on the way in and written to the DOM with textContent on the way out — never innerHTML. Several mind map libraries offer an "allow HTML in nodes" option; that option is a stored-XSS hole.
  • Every REST route has a real permission_callback that checks the current user against this map. A permission_callback that returns true is the most common security bug in the plugin directory.
  • Every form and link that changes something carries a nonce, checked with check_admin_referer().
  • Custom capabilities, not manage_options. Mind maps can be given to an editor or an author without handing over the whole site.
  • HTML lives in exactly one place. Only an HTML block may contain markup, it goes through wp_kses_post() on save, and the editor previews it inside an iframe with an empty sandbox attribute — no scripts, no same-origin access. A note is written by one person and read by another; rendering its markup into the admin page would hand the author a script that runs as whoever opens the map next.
  • Uploads go through the WordPress media library, so they inherit its permissions and file-type rules, appear in Media like anything else, and are gated on upload_files. The attachment ID is re-checked on save: a block pointing at something that is not an attachment is dropped.
  • The document is bounded: at most 2000 nodes, 40 levels deep, 500 characters of text per node, 40 blocks per note, 20,000 characters per block. The sanitiser rebuilds every node field by field, drops unknown keys, rejects duplicate ids, and clamps coordinates — so a hand-crafted payload cannot exhaust memory in the recursive walk.
  • A video's address is never trusted. Only YouTube and Vimeo are recognised, by an allow-list of URL shapes; only the video id survives; and the src that reaches the iframe is rebuilt by the plugin from that id. The check is enforced in PHP on save (FB_Mind_Map_Data::parse_video()) — the copy in JavaScript exists so the editor can warn you as you type, and is not what protects the site. This is the same lesson as the HTML block: an attribute a user controls that ends up in a src is a hole unless you rebuild the value yourself.
  • Colours go through sanitize_hex_color() before they can reach a style attribute.
  • Almost nothing leaves your server. No CDN at runtime, no telemetry. The one exception is a video block: the poster still comes from YouTube's image host, and the player itself is loaded from youtube-nocookie.com when someone presses play. Mind Maps → Settings turns the poster off; a site that wants zero external requests should not use video blocks.

Keyboard shortcuts

Key Action
Tab Add a child of the selected node
Enter Add a sibling below
F2 Rename (double-click does the same)
Delete Delete the node and its branch
← ↑ ↓ → Walk parent, siblings, children
Ctrl+Z Undo · Ctrl+Shift+Z redo
Ctrl+C / X / V Copy, cut, paste a branch
N Add or edit this node's note
Ctrl+S Save
Ctrl+0 Fit to screen · Ctrl+± zoom

Mouse: click selects, double-click a node renames it, double-click empty canvas adds a child there, right-click opens a context menu, dragging a node moves its whole branch, dragging the canvas pans, the wheel zooms toward the cursor (and scrolls a panel when the pointer is over one), and clicking the navigator jumps the viewport. Both floating panels drag by their header.

Languages

The plugin follows WordPress: set Settings → General → Site Language, or one user's Profile → Language, and the plugin follows. A finished Turkish translation ships in languages/.

The switcher in the editor toolbar is for the exception — someone who wants the Mind Map screens in a different language from the rest of the site. It stores a per-user choice and applies it through the plugin_locale filter, so translations edited with Loco Translate still load normally.

That filter is necessary but, since WordPress 6.5, no longer sufficient. WP_Translation_Controller stores loaded files as [ locale ][ text domain ]. plugin_locale still picks the right file, but the controller files it under the chosen locale while every __() looks the domain up under the locale the site is running in — so the file loads and the lookups miss it, silently. The plugin therefore loads the chosen file a second time under the current locale; FB_Mind_Map_I18N::load_override() is a dozen lines with the whole story in a comment above it. Save Loco's output to wp-content/languages/plugins/ and it survives a plugin update.

Mind Maps → Settings turns the switcher off, sets a site-wide language, and sets the autosave default.


Read the full README on GitHub →

Releases

TagPublishedAssetDownloads
v0.3.0 Aug 31, 2026 fb-mind-map-0.3.0.zip 8