Skip to content
Dee Wan 1.0 is not yet released (pre-MVP). See the 1.0 product boundary.

Plugins for site administrators

A plugin is a remote service. It runs on its own server, with its own data. Reviewed embedded UI runs in an isolated frame. Server operations use HTTPS. It works on one site, within the access grant you choose. This guide is for the person who installs and manages plugins. To build one, see Writing a plugin.

Open Settings → Plugins. You need the site:plugins permission. The built-in admin role has it, and so does a superadmin. The section has three cards:

  • Installed plugins: each plugin on this site, its state, grant and actions.
  • Discover plugins: plugins listed by this server’s catalogues.
  • Install a plugin: install from a manifest URL.

Each site has its own installations. Installing a plugin on one site gives it nothing on another.

  1. Get the plugin’s manifest URL and a one-time activation code from the plugin’s operator.
  2. Either press Review on a listing under Discover plugins, or type the Manifest URL under Install a plugin and press Review. The URL must start with https://.
  3. Read the review: name, version, plugin id and the server it runs on. Adds to the editor lists the cards and field editors it adds.
  4. Under Capabilities, tick only what this plugin needs. You can choose only what it asks for.
  5. Under Models, tick the content types it may work on. No model selected means no content access.
  6. Enter the Activation code and press Install.

Discover plugins says No plugin catalogue is set up on this server. Install by manifest URL below. when the operator configured no catalogue. A listing grants nothing. Install fetches and checks the manifest again, exactly as for a typed URL.

Install fails when the deployment has no public address set, because the plugin could not reach Dee Wan. It also fails when the plugin refuses the activation code. Nothing is installed in either case.

A plugin acts only on the models you granted. Every write is made on behalf of the person who started it from Dee Wan, and that person’s current permissions still apply. If the person loses access, or you narrow the grant, the plugin loses that power too.

Capability Shown as What the plugin can do
content:read Read content summaries Read summaries; with a live delegation, read saved values and retained revisions within the person’s current grants.
workflow:read Read workflow state Read the workflow state and the available workflow transitions.
workflow:publish Publish Publish a pinned version.
workflow:unpublish Unpublish Take a published version offline.
workflow:locale Publish or unpublish one language Move one language instead of the whole translation group. A move notifies people exactly as the same move made in the editor does, see feedback and notifications.
content:write Save existing entries Save values, relations and media on existing entries through the delegating person’s lifecycle checks.
content:create Create entries Create entries through the delegating person’s normal create checks.
content:delete Move entries to Trash Trash existing entries through the delegating person’s normal delete checks.
draft:write Read and change that person’s unsaved drafts Read, write and discard that person’s working drafts.
media:write Upload files Upload files within the person’s current upload authority.
media:read Read existing media Read metadata and bytes within the person’s current media read authority.
media:update Edit media metadata Edit existing metadata within the person’s current media update authority.
content:propose Propose changes for an editor to review Create proposals. An editor applies or dismisses them in the entry.
media:source Offer its files in the media picker List its own files in the media picker.

Creation, deletion, existing-media reads and metadata edits each need their own reviewed capability. Existing content:write and media:write grants do not gain these powers. Changed relation targets, including links inside components, must fit both the installation’s model grant and the launch delegation’s model list. An unchanged opaque link can remain during another edit.

A plugin cannot read users, roles, sessions, settings or the audit log. Embedded code runs inside an isolated frame; it cannot execute in the parent admin document or reach the database directly. Details: Plugin security.

A plugin can declare content checks. They appear under Content checks on its row, along with when they run: On save, On publish, On restore, On delete, On unpublish or On workflow move. A check runs on each matching write to a model in the plugin’s grant, from every path: the editor, bulk actions, spreadsheets, imports, the management API and other plugins.

Be aware of what a check can do:

  • It sees the facts of the write it is asked about, including the new values, even without content:read.
  • It can warn, or refuse the write.
  • An On save or On restore check can also change the content being saved: values, links, media and search settings. Dee Wan saves the result through the same rules that apply to a person’s edit. The editor then shows which fields changed, and the version history names the plugin.

Each check has a switch Block changes if it does not answer. Off (the default): a timeout or an outage lets the change through with a warning. On: the change is refused. A real refusal always stops the change. A check shows Needs more access when the grant lacks a capability it needs, and Plugin is off while the plugin is disabled.

Install only plugins you trust with the content of the models you grant.

A plugin can declare checks that run before Dee Wan accepts something. They appear under Checks before accepting on its row, each with Use this check, and every one is off until you turn it on. Declaring a check sends nothing.

  • Before a file is uploaded asks the plugin about each new library file. It sees the file’s name, type, size, folder and alt texts. It never sees the file itself or who uploads it. It can approve the file, tidy its name (the file type stays the same) and alt texts, or refuse it with its own reason, which the uploader reads.
  • Before a comment is stored asks the plugin about each visitor comment. It sees the entry, the author’s name and website, and the text. It never sees the email address. It can approve the comment, leave it for a moderator, or reject it.

A check that does not answer never approves. If it times out (5 seconds), cannot be reached, or answers something Dee Wan does not accept, the upload is refused with “The upload check did not answer” and nothing is saved, and the comment waits for a moderator as it does when no check is on. The same file sent again with the same details gets the check’s first answer back for 24 hours, so a retry does not ask twice. After a failed attempt it asks again.

Turning a check on or off needs the same permission as changing the grant (site:plugins) and is recorded in the history as Plugin check setting changed. A check shows Needs more access when the grant lacks a capability it needs, and Plugin is off while the plugin is disabled. Media that an import brings in does not pass through upload checks, so a check never sees imported files. Every other way a new file arrives does: the library upload, the management API, a plugin, AI-generated images, files copied from an external source and the content planner.

A plugin with media:source adds files to the media picker. In the picker, Where to pick from offers Library and Sources. The person needs media:upload.

  • Add copies the file into the site’s library. It becomes an ordinary site file and keeps working if the plugin goes away.
  • Link without copying keeps the file on the plugin’s server. Pages use its address as it is. Dee Wan cannot edit or replace the file. If the plugin is disabled or removed, existing pages keep the address and the media details say The source is not available now.

Disabling the plugin or removing media:source from the grant hides its sources at once.

A plugin can add a column to the content list of a model in its grant, and actions for the entries you select. Dee Wan renders both. The plugin supplies only text and, for a link, an https:// address.

  • Columns. A cell is plain text, a coloured label or a link. The plugin is asked about the rows on the current page only, at most 50 at a time, and it is sent the model and the ids of the rows you can read, never their values. A row with nothing to show has a dash. When the plugin does not answer, its column shows a dash and {plugin} could not fill this column., and the rest of the list works as usual. Opening the list writes nothing to the audit log.
  • Actions. Select entries and open Plugin actions. The menu lists what plugins offer for this model, each marked From {plugin}. Choose one, fill in its form if it has one, and press Run. It runs once for each selected entry, at most 25. Dee Wan then shows how many were done and how many were not, with a result for each entry. A refusal on one entry does not stop the others. Each entry is checked against your permissions at that moment, and an action that can change data asks you to confirm first.
  • A column or action appears only while the plugin is active, the model is in its grant and the grant holds every capability it needs. Disabling the plugin removes both at once.

A plugin can offer an editor that shows one JSON field as a small form of named values: text, number, switch and choice. In the model builder, open the field’s UI tab and choose it under Plugin editor. Choosing it writes the allowed values onto the field: which values are required, their limits and the allowed choices. Dee Wan checks every save against them, like any other field rule. If the plugin is disabled or uninstalled, the field keeps those rules and its values, and the standard JSON editor shows them.

A reviewed plugin may add navigation pages and Dashboard views. Their isolated frames use the same declared operations as plugin cards. A view appears only while the installation is active, its reviewed capabilities are granted, and your current model and system permissions allow them. Opening its URL directly grants no access. New capabilities requested by an upgrade remain ungranted.

An administrator with site:plugins configures Email templates on a plugin row. Recipient selects Approved addresses, Entry author or Assigned reviewer. Fixed addresses accept 1–8 recipients; contextual choices use the account that created the selected CMS entry (created_by_id) or its current workflow assignee. Entry author does not mean a public Blog author/profile relation or the last editor. The account must be active, have current site access and still be able to read the entry; an active superadministrator may qualify without an explicit site membership. An absent or ineligible recipient refuses the send.

Review the recipient rule, subject and message before saving. A plugin with mail:send chooses a declared template and supplies its declared substitutions. For contextual mail it also names an entry inside its granted models and delegated item scope. It cannot choose an email address, account, recipient rule or arbitrary message. Sending requires the person’s current site:plugins permission; fixed mail uses a manage delegation, while contextual mail also accepts a matching content-action delegation.

Retries with the same key keep the accepted recipient and message, even after reassignment. They recheck the actor’s access and the original recipient’s active account, site/entry access and unchanged address. If that account is no longer eligible, delivery is refused rather than redirected. Provider acceptance is not proof of inbox arrival; an interrupted send is not proof that nothing was delivered.

The reviewed grant can also allow comment reads or moderation, redirect reads or writes, restoring entries from Trash, and deleting unused media. Each operation retains the owning CMS service’s permission, validation and concurrency checks. Redirect patterns require the ordinary reviewed digest before saving. Media deletion still refuses files in use.

Press Grant on the plugin’s row. Tick capabilities and models, then Save grant. You can pick only what the plugin’s manifest asks for, and at least one capability. A narrower grant applies at once, including to work the plugin queued earlier.

Disable stops the plugin at once: Dee Wan refuses its requests, and its cards, operations, media sources and content checks stop. Its content checks no longer run on writes while it is off. Enable turns it back on with the same token and grant.

Work the plugin scheduled may fail while it is off. For example, a schedule in the Scheduling plugin that comes due while the plugin is disabled is refused and not retried.

Use this when the plugin’s credential may have leaked, or when its operator asks.

  1. Get a new activation code from the plugin’s operator.
  2. Press Rotate on the plugin’s row, enter the New activation code and press Rotate token.

Rotation works only on an active plugin. If the plugin refuses or cannot be reached, nothing changes and the old token keeps working. After a successful rotation, the old token works for at most 10 more minutes, and stops as soon as the plugin uses the new one.

A new release published by the plugin changes nothing on your site until you accept it. Settings → Plugins offers Check for updates. Review the installed and proposed versions, feature changes, permissions and embedded origins. Press Confirm upgrade to accept the reviewed version. The server rechecks that version through POST /api/plugins/:id/upgrade; see Shipping a new release.

  • Accepting never widens the grant. It can narrow it, when the release stops asking for a capability.
  • When a release asks for a new capability, add it afterwards with Grant.
  • A release that changes the plugin id, its server or its protocol version cannot be accepted. Uninstall and install it again.

Uninstall asks first: Access is revoked now. Data the plugin keeps is deleted only by the plugin. The token stops working for good, and the plugin leaves the list.

What stays in Dee Wan:

  • versions it saved, publications it made, and their history entries
  • files it uploaded or that people copied from it
  • proposals still open on entries, which editors can still apply or dismiss
  • rich text blocks from the plugin. They stay stored, but public pages do not show them while no active plugin defines them. See Plugin blocks.
  • fields that used its field editor. They fall back to the standard editor and keep their values.

What stays on the plugin’s side: everything it stores. Ask its operator to delete it. For Scheduling, see Data, retention, uninstall.

Installing the same plugin again creates a new installation. Choose its grant again and get a new activation code. Content-check switches start at their defaults.

The Scheduling interface is in English. A release sends up to 25 items as one atomic CMS command. Done confirms the whole command. Failed means a definite refusal left every publication unchanged. Outcome unknown requires recovery of the same recorded command and key; it does not mean partial publication.

A release blocked at its scheduled time stays scheduled and lists the blocking items. Fix or remove them, then press Run now, or set a new time. Retry unfinished items checks a definite refusal again or recovers an uncertain command without inventing item successes. Stop remaining items cancels unsent work. Completed changes remain; an in-flight command cannot be undone. Schedules due after the plugin is disabled or uninstalled are refused.

Choose Version → Independent future version when adding an entry to a release to prepare separate campaign content. Edit it in the entry’s Future versions panel. Ordinary items use the latest ordinary saved draft; future items use their own exact revision when the command starts. Set different times for releases that change the same entry and overlapping languages. See future versions.

Full rules: Releases and Scheduling, end to end.

Developers: Writing a plugin, Protocol v1 and Plugin security.

Open Settings → Plugins → Check for updates. The host reads the installed manifest URL; it does not use a registry service. Review the installed and proposed versions, declared features, added or removed permissions, and embedded origins. Choose Confirm upgrade. The server fetches the manifest again and refuses the upgrade if the reviewed version has changed. New permissions remain ungranted; update the grant explicitly after the upgrade when needed. A failed upgrade keeps the current installation. After correcting the reported cause, check again.

Installed integrations can read saved content and history, create entries, save relations and media, move entries to Trash, read existing media and edit descriptions. The person’s current grants still apply. Embedded views run in an isolated frame. Field changes use the ordinary Save action. Vendor snippet scripts run inside isolated preview/site frames. The provider controls booking and form behavior; do not store provider secrets.


Unreleased / pre-MVP; no stable version
Source revision: fe23db481c422b40e317b92fc98116b4c0c26a87 (modified checkout)
Build date (UTC): 2026-10-18T09:22:34.630Z
Upgrade target: unavailable: modified checkout. Release notes