The inline editor works on the live DOM, so saved content must be scrubbed of editor scaffolding without ever touching real content. This is devani_page_editor_sanitize_content() in devani/page-editor.php — the most safety-critical function in the save path.
The unified artifact convention
Every editor feature must mark its artifacts one of three ways, so the sanitizer never needs per-feature rules:
- Editor-only elements (overlays, toolbars, drag handles) carry
data-devani-ephemeral→ the whole node is removed. - Editor state attributes are namespaced
data-devani-*→ stripped. - Editor CSS classes are prefixed
devani-inline*ordevani-ed*→ stripped from class lists.
Plus contenteditable and draggable, which the editor toggles live, are always removed.
The content-module allowlist
The data-devani-* namespace is shared: editor state (strip) and content modules (keep). Module markers are explicitly allowlisted and never stripped:
data-devani-module // module wrapper (forms, embeds)
data-devani-column-wrapper // multi-column layout wrapper
data-devani-shop-* // shop listing module attributes
If you build a module block, follow this pattern: mark the wrapper with data-devani-module="yourmodule", put module data in attributes outside the devani namespace (e.g. data-sendl-form), and prefix module classes with something that isn't devani-inline/devani-ed (e.g. devani-sendl-form is safe). Mirror the exact markup between the editor block and any MCP insert tool so both paths render identically.
Other properties worth knowing
- UTF-8 safe: the DOM pass declares encoding explicitly, so em dashes, quotes, and emoji survive repeated saves without mojibake.
- Idempotent: sanitizing already-clean content is a byte-identical no-op — verified by the test suite.
- Permissive about content: inline event handlers, custom
data-*, embedded scripts in content are allowed. The one hard rejection is PHP: content containing<?never gets written.
The regression suite
php tests/sanitizer-test.php (in the repo root's tests/, outside the shipped app) asserts all of the above — artifacts stripped, modules preserved, idempotence. Run it after any change to the editor or sanitizer. If you add a module, add assertions for it.