New on the blog: why AI belongs in the feed →
View Categories

Cleanup on deactivation and deletion

Snippets can declare what they own and run cleanup without loading their main code. Cleanup works when the snippet is inactive or its runtime scope excludes the current request, including operations through the editor, bulk actions, Abilities API, collection removal and run-once completion.

Exact resource declarations #

Put declarations in the opening header docblock of the snippet file. This also works for files managed by a GitHub collection; the declarations travel with the source and its revisions.

<?php
/**
 * My site task.
 * @cleanup-cron mysite_daily, mysite_batch
 * @cleanup-option mysite_task_state
 * @cleanup-transient mysite_task_lock
 */

Scheduled hooks are removed, including events with arguments, when the snippet is deactivated, moved to Trash, orphaned, finishes running once, or is permanently deleted. Options and transients remain until permanent deletion by default. This preserves settings, opt-outs and progress while debugging or restoring from Trash.

Use @cleanup-on deactivate, delete to remove declared options and transients at both stages, or @cleanup-on deactivate to remove them when the snippet stops. This policy controls declared data only; scheduled hooks are always cleared at either stage. Use exact names: wildcards and prefix deletion are rejected. Each resource kind supports at most 50 names. Only the named options/transients are affected; post meta and custom tables require PHP cleanup.

Separate PHP sections #

PHP snippets can include either or both of these sections at file scope. The main code never executes these sections. Each section must have its own matching delimiters, without nesting or duplicates.

// BEGIN GOCSM DEACTIVATE
// Also runs for Trash, orphaning and run-once completion.
wp_unschedule_hook( 'mysite_daily' );
if ( 'run_once' === $reason ) {
    $delete_me();
}
// END GOCSM DEACTIVATE

// BEGIN GOCSM DELETE
// Also runs when the containing collection is deleted.
delete_option( 'mysite_task_state' );
// END GOCSM DELETE

The sections receive $snippet_id, $reason and a callable $delete_me. They also receive the snippet’s declared configuration values, with site overrides applied. Treat these three variable names as reserved. Cleanup runs in its own scope: variables, functions, imports and classes from the main code are not automatically available. Keep cleanup self-contained and repeat any needed use declarations inside the section.

$delete_me() in deactivate cleanup requests permanent deletion after that transition finishes. For example, a run-once snippet can delete itself after successful execution. Its delete section then runs, and its code, configuration and revisions are removed. The helper has no effect inside delete cleanup and does not remove snippets owned by a collection; their source of truth remains the collection.

Moving an inactive snippet to Trash still runs its deactivate section. Permanently deleting an inactive or trashed snippet runs its delete section. Directly deleting an active snippet runs deactivate then delete cleanup, with one cleanup event for the deletion operation. Restore and activation do not run cleanup. Write cleanup to tolerate resources that are already absent.

Recovery and visibility #

Safe mode and a snippet’s recorded execution failure skip its PHP cleanup while exact-name declarations still run. Caught PHP errors and exceptions are logged and do not block deactivation or deletion. Cleanup is trusted snippet code, with the same editing permission and API code-write approval requirements as the rest of the source. Avoid exit, die, unbounded work and deferred callbacks: cleanup must finish synchronously. Safe mode is the recovery path if cleanup itself prevents an operation from completing.

Individual and bulk snippet confirmations list declared resources and whether PHP cleanup will run. The Abilities API’s get-snippet result includes a read-only cleanup plan; inspect it before a destructive operation. Mutation responses include cleanup outcomes. The Sync Log records snippet_cleanup, its reason, attempted resources and any errors. Settings → Change notifications has an optional cleanup event that includes the same result in the signed webhook.

Cleanup applies to the current site’s snippet and resources. On multisite, each site has its own snippet tables and configuration; network activation does not create a network-scoped snippet. Deleting a collection on one site does not remove another site’s resources. A snippet that deliberately writes elsewhere must handle those resources explicitly in its own reviewed delete cleanup.

Stuck? Ask in GravityOps Help #

Search past answers or post your question, tagged "snippet-manager".