Setseasy_svg_pro_set_write_context

easy_svg_pro_set_write_context

Decide whether a request takes the icon set lock before it reads a set, so your cron job or form handler cannot undo another write to the same set.

Filter · Easy SVG Pro · Status: Stable

A set stores all its icons as one value. Every change reads that value, changes its copy and writes the whole thing back. If two requests do this at the same time, the second one writes back a copy that does not contain the first one's change. Easy SVG Pro prevents that with a lock, but only in requests it knows will write. This filter tells it that your request writes too.

Usage

apply_filters( 'easy_svg_pro_set_write_context', bool $writes )

Applied in includes/editor/sets.php, inside the internal function set_write_context(). It is asked every time a set is read or written, until the lock has been taken once in that request.

When to use it

  • A cron job of yours changes sets, for example a nightly sync from a design system.
  • A form handler on admin-post.php, an AJAX action or a webhook endpoint that is not a REST route changes sets.
  • You run the abilities from PHP (wp_get_ability( ... )->execute()) outside a REST request, for example from your own queue worker.

Do not use it when:

  • Your code only reads sets. Reading needs no lock, and taking one makes every other writer wait.
  • Your code runs as a REST request with POST, PUT, PATCH or DELETE, or under WP-CLI. Those are already a write context.

Parameters

body
$writesbool
Required

true when the request is a REST request (REST_REQUEST is defined and true) whose method is not GET, or when it runs under WP-CLI. false otherwise, including cron, admin-ajax.php, admin-post.php and normal page loads.

Return value

returnbool

true to take the lock before the first set read of this request. The value is cast to a boolean.

Default

true for REST requests that are not GET and for WP-CLI, false for everything else.

Examples

A cron job that changes sets

/**
 * The nightly icon sync writes sets, so it must hold the set lock.
 */
function acme_lock_sets_in_cron( $writes ) {
	return $writes || wp_doing_cron();
}
add_filter( 'easy_svg_pro_set_write_context', 'acme_lock_sets_in_cron' );

Only for your own admin-post handler

Narrow it to the one action that writes, so other admin requests are not slowed down.

/**
 * Our "Sync brand icons" button posts to admin-post.php?action=acme_sync_icons.
 */
function acme_lock_sets_for_sync( $writes ) {
	if ( $writes ) {
		return true;
	}

	// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- routing only, the handler checks the nonce.
	$action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : '';

	return is_admin() && 'acme_sync_icons' === $action;
}
add_filter( 'easy_svg_pro_set_write_context', 'acme_lock_sets_for_sync' );

Running the abilities from a queue worker

/**
 * Our worker runs as a plain PHP request and calls the set abilities directly.
 */
function acme_lock_sets_in_worker( $writes ) {
	return $writes || ( defined( 'ACME_ICON_WORKER' ) && ACME_ICON_WORKER );
}
add_filter( 'easy_svg_pro_set_write_context', 'acme_lock_sets_in_worker' );

function acme_worker_add_icons( $set_id, array $icons ) {
	if ( ! function_exists( 'wp_get_ability' ) ) {
		return new WP_Error( 'acme_no_abilities', 'The Abilities API is not available.' );
	}

	$ability = wp_get_ability( 'easy-svg-pro/add-icons-to-set' );
	if ( null === $ability ) {
		return new WP_Error( 'acme_no_ability', 'Turn on AI agent abilities and the Icon set editor.' );
	}

	return $ability->execute(
		array(
			'set_id' => (int) $set_id,
			'icons'  => $icons,
		)
	);
}

The ability checks permissions, so the worker has to run as a user with manage_options (wp_set_current_user()).

Defensive: never turn the lock off by accident

/**
 * Add our context, never remove the one Easy SVG Pro decided.
 */
function acme_safe_write_context( $writes ) {
	return (bool) $writes || apply_filters( 'acme_is_icon_job', false );
}
add_filter( 'easy_svg_pro_set_write_context', 'acme_safe_write_context', 20 );

Returning false while $writes is true takes the protection away from the plugin's own REST routes and WP-CLI. Always combine with ||.

How it works

  1. Every read and every write of a set asks the filter (through set_write_context()).
  2. The first time the answer is true in a request, Easy SVG Pro runs SELECT GET_LOCK('easy_svg_pro_sets', 10). It waits up to ten seconds for another request to finish.
  3. It registers RELEASE_LOCK on shutdown. MySQL also frees the lock when the connection closes.
  4. For each set it then deletes that post's meta from the object cache once, so it reads what is really stored and not what another request cached a moment ago.

There is one lock for all sets, not one per set: a bulk move writes two sets, and two per-set locks could wait on each other forever. The lock is held until the request ends, not only during the write.

Pitfalls

  • Decide early. Once the first set has been read without the lock, that read is already done. Hook the filter before anything reads a set, ideally when your plugin loads.
  • Ten seconds, then it goes on anyway. The result of GET_LOCK is not checked. If another request holds the lock longer than ten seconds, your request continues without it. Keep set writes short.
  • MySQL and MariaDB only. On a database without GET_LOCK (for example the SQLite integration) the lock does nothing, and the object cache flush is the only protection left.
  • It slows down every writer. While your request holds the lock, every other write to any set waits. Do not return true for page views or long running reports.
  • Direct meta writes are never locked. This filter only affects reads and writes that go through Easy SVG Pro. update_post_meta() on _easy_svg_set_icons skips the lock, the sanitizer and the easy_svg_pro_set_icons_written action.
  • Cron and AJAX are not covered by default. If you write sets there and do not add this filter, two runs at the same time can lose icons silently.