Sign in

The save pipeline & sanitizer

Updated Jul 3, 2026

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:

  1. Editor-only elements (overlays, toolbars, drag handles) carry data-devani-ephemeral → the whole node is removed.
  2. Editor state attributes are namespaced data-devani-* → stripped.
  3. Editor CSS classes are prefixed devani-inline* or devani-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.

Was this helpful?

Related articles

Powered by Subido