Visor for Craft CMS

Free · Pro $49, $29/year renewal

A list of dates is not a history

Craft stores a complete copy of your entry every time you save it — and then shows you four columns: number, date, author, notes. To find out what actually changed you open two revisions in two tabs and read. To put back the one paragraph somebody broke, you revert the whole entry and lose everything else that was fixed since. Visor turns that list into something you can read, act on, and keep under control.

Visor

Two commands, and your existing history is readable

There is nothing to backfill and no waiting for new saves. A revision in Craft is a complete duplicated element rather than a delta, so a comparison is "load two elements and walk one field layout" — which works just as well on history written years before Visor was installed.

composer require justinholtweb/craft-visor
php craft plugin/install visor

{# Nothing needs to go in a template. The comparison screen and the sidebar
   panel are there as soon as it is installed. But if you want the history: #}
{% for revision in craft.visor.history(entry, 10) %}
  {{ revision.label() }} — {{ revision.dateCreated|datetime }} by {{ revision.creatorName }}
{% endfor %}

{% set diff = craft.visor.compare(entry, revisionId) %}
{{ diff.changedCount() }} fields changed

{# craft.visor is read-only by design. Nothing on it deletes, restores or pins:
   a template rendering a page is not the place to change history. #}

Features

Everything Craft's revision screen leaves you to work out for yourself.

Compare any two versions

Field by field, with word-level highlighting — including a revision against what is currently live, which Craft cannot do at all. The screen opens on that comparison, because it is the one you almost always wanted.

  • Only the fields that moved, biggest change first
  • A forty-field entry with one edit is one row, not forty

Matrix blocks, aligned by content

A revision owns copies of its blocks with brand-new IDs, so there is nothing to match two revisions' blocks on. Visor aligns them by content instead, in three passes.

  • An edit reads as changed, a reorder as moved
  • Without the third pass a rotation reads as delete plus insert

Restore one field, not the entry

Tick the fields you want and Visor writes only those onto the live element. Everything you leave unticked stays exactly as it is — including the six things somebody else fixed this morning.

  • Previewed as what will be overwritten, before it writes
  • An ordinary save, so the restore is itself undoable

Retention as policy, not one number

Craft has a single global maxRevisions. Visor resolves policy across element type, section and site, most specific first — and stores it in project config, so it deploys with the site and can be reviewed in a pull request.

  • A minKeep floor, so an untouched entry never empties out
  • No policy matching means Craft's own default, untouched

Pins that outlive every policy

Pin a revision and no prune will remove it — not Visor's, and not Craft's own PruneRevisions job. Retention policy and editorial value are different things, and a tool that only understands the first will eventually delete the second.

  • Re-checked on every batch, so a late pin still wins
  • "Keep the last twenty" is storage; "keep the relaunch" is not

A preview that is the deletion

One resolver decides what gets pruned, and apply() deletes exactly the list it was handed — a preview that built its own query would be a preview of a different deletion. Every run is recorded with what it planned alongside what it did.

  • Drift is visible in the ledger rather than absorbed
  • A storage report showing which two sections are the problem

Frequently Asked Questions

The questions worth answering before you install it.

Read your history, then keep it honest

Free for the comparison screen Craft should have shipped. $49 for policy across the whole site. Both work on the history you already have, from the moment you install it.