Zoo for Craft CMS

Configuration

Settings live at Settings → Plugins → Zoo, and can be overridden from config/zoo.php like any Craft plugin.

The defaults are the cautious ones. Zoo's first job is to tell you what nothing points at, and its second is to make deleting that safe; a default that widens what counts as an orphan makes the first job louder and the second riskier.

What counts as an orphan

urlCountsAsReachable — default true

Whether an element with its own public URL counts as reachable.

Leave it on. Turning it off finds pages linked from nowhere on the site, which is a real question and a completely different list — bookmarks, sitemaps, campaign emails and search results all point at pages without creating a row anywhere.

scanContent — default true

Reads every field on the site for reference tags and for markup naming an asset's URL or an entry's URI. With this off, Zoo will offer to delete images that are visibly on the page, because an image dragged into a rich-text field creates no relation row at all.

scanTemplates — default true

Reads templates/ and config/ for hard-coded element IDs, and for quoted literals matching a candidate's slug, URI or filename.

scanForeignKeys — default true

Reads the database's own schema for every column keyed into elements or users, and asks each one. The settings screen shows how many such columns exist on your install.

minimumAgeDays — default 7

How many days old something must be before Zoo will report it. Content made this morning has not been given a chance to be referenced yet, and an audit that reports work in progress is one people learn to close.

abandonedDraftDays — default 30

How long an autosaved draft must sit untouched before it counts as abandoned.

dormantUserDays — default 365

How long an account that has never been logged into must exist before it is reported.

enabledAudits — default []

Audit handles that run. An empty array means the default set, which is what a fresh install gets. Naming any audit switches to an explicit list, so anything not named is off.

'enabledAudits' => ['unused-assets', 'unrelated-entries', 'unused-tags'],

protectedSources — default []

Section, volume, category-group, tag-group and user-group handles Zoo never reports and never deletes, whatever a form says. Checked on the server, not in the browser.

'protectedSources' => ['legalDocuments', 'pressKit'],

Deleting

deleteMode — default 'trash'

What the ordinary delete button does: trash or purge.

requireConfirmation — default true

Whether a permanent delete has to be armed by typing the number of things selected.

backupBeforePurge — default true

Whether to take a database backup before the first permanent delete in a batch. If the backup fails, the delete does not happen.

staleAfterMinutes — default 60

How old a census may be and still be acted on.

maximumBatchSize — default 500

The most things one delete may remove. Larger selections are refused, not truncated.

keepRuns — default 25

How many census runs to keep. Older ones are pruned by garbage collection — except runs that deleted something, which are kept regardless.

A worked config

Read-only auditing on production, with nothing deletable and every probe on:

<?php
return [
    'scanContent' => true,
    'scanTemplates' => true,
    'scanForeignKeys' => true,
    'deleteMode' => 'trash',
    'maximumBatchSize' => 25,
    'protectedSources' => ['legalDocuments'],
    'enabledAudits' => [
        'unused-assets',
        'unrelated-entries',
        'orphaned-nested-entries',
        'unused-tags',
    ],
];

Pair that with giving editors View the census and Mark things to keep but not Move findings to the trash: they can see what the site is carrying and correct Zoo when it is wrong, without being able to remove anything.