Scrub for Craft CMS

Free for Craft 5

Find and replace you can actually watch first

Craft ships a Find and Replace utility. It matches every row of elements_sites with a LIKE, runs str_replace over it and writes the result back with raw SQL — every element type, every site, drafts and revisions included. No preview, no scope, no word boundaries, no undo, and because it bypasses the element save your search index is left describing content that no longer exists. Every part of Scrub is an answer to one of those sentences.

Scrub

The preview is the run

Not an estimate of what would happen. The same method, the same scan, the same matcher — with one boolean deciding whether the result gets written or thrown away. That is also why the console command previews by default and makes you ask for the write.

bash
# Previews. Writes nothing. This is the default.
php craft scrub/run/replace \
  --find="Acme Ltd" --replace="Acme Inc" \
  --mode=word --sources=section:3

  14 matches in 9 entries, 3 sites
  Homepage › body      …trusted by Acme Ltd since 1994…
                       …trusted by Acme Inc since 1994…

# The same command, asked properly.
php craft scrub/run/replace … --dry-run=0

The Replace screen, working

This is the preview, and it is computing for real — type something else, switch the mode, toggle the options and watch the match list and the counts recompute against the sample content. Try 'form' in plain mode and then in whole-word mode; the difference between those two results is the reason whole-word exists.

Scrub → Replace

Search form in plain text, then switch to whole words only: eight matches become four, because platform, information and transform stop counting. Search widget with case sensitivity off and keep the original capitalisation on, and one rule handles widget, Widget and WIDGET at once. Or switch to a regular expression and try (\d{4})-(\d{2})-(\d{2}) replaced with $3/$2/$1.

The count under the toolbar is what a run would change. Past maxUnitsInPreview the real screen stops listing and starts counting, so a run across four thousand entries still tells you the total.

And after you press Replace

The demo above is the preview. These are the three screens that come after it — real screens from a Craft 5 install with Scrub on Pro, not mockups.

A Scrub run detail screen showing 31 replacements across 12 places, with an Undo panel offering to restore 26 values and stating that anything edited since the run will be left alone and reported rather than overwritten
The Scrub history listing every replacement and undo with its status, the number of places changed, the number of matches, when it ran and whether it came from the console or the queue
The Scrub rules list showing four saved rules and when each one applies — to rendered output, on save, on save and weekly, and monthly

Same run in all three: 31 matches in 12 places, previewed, written, and then put back.

Features

A scanner with guardrails, a matcher that knows what a word is, and a ledger that can put it all back.

A preview you can trust

Preview and run are one method with one boolean between them, so what you are shown is the run with the last step skipped. Each match appears in context, old and new side by side.

  • Lists every place, then counts the rest
  • A mis-scoped rule is obvious before anything is written

Stops where you tell it to

Sections, volumes, groups, entry types, individual fields, specific sites, or an explicit list of IDs. Drafts, revisions and trashed elements are excluded until you ask for them.

  • Protected fields and sources are enforced by the scanner, so the console obeys them too
  • Rewriting a revision does not correct history, it falsifies it

Matches the way you meant

Plain, whole words only, or a regular expression with capture groups. Case sensitivity is yours to choose, and a case-preserving replacement handles widget, Widget and WIDGET from one rule.

  • Case preservation works word by word, so Acme Ltd becomes Acme Inc rather than acme inc
  • You never escape delimiters — Scrub picks one that is not in your pattern

Undoes itself, carefully

Every changed value is stored before and after, and undo restores the stored original rather than running the replacement backwards. It refuses anything edited since the run and tells you which ones it skipped.

  • A database restore cannot do this — it discards every edit made in between
  • Which is why nobody ever actually uses one

Writes properly

Elements are saved, so the search index updates, caches invalidate, afterSave fires in every plugin listening and entries get a revision. There is a fast path for very large sites, and it queues the re-index Craft's own utility forgets.

Rewrites output without touching the database

Real-time rules apply as pages render, so nothing stored changes and turning the rule off is the undo. The replacement is HTML-aware, which means class names, hrefs and attributes survive it.

  • For the rename legal has not signed off yet
  • Costs nothing when unused — the hook is never attached if no real-time rule exists

Frequently Asked Questions

The questions worth answering before you install it.

Start free, upgrade when you need to

Lite is the whole find-and-replace tool: preview, scope, history and undo, for nothing. Pro is $99 with a $79/year renewal, and adds regular expressions, case-preserving replacement, saved rules, real-time and on-save rules, asset and database targets.