Setseasy_svg_pro_set_icons_written

easy_svg_pro_set_icons_written

Run your own code every time an icon set's icons are saved, from the editor, bulk edits, imports, presets, WP-CLI, client mode or an AI agent.

Action · Easy SVG Pro · Status: Stable

An icon set keeps all its icons in one stored value. Many screens and tools change that value: the set editor, bulk editing, the importers, presets, WP-CLI, client mode and the abilities for AI agents. They all save through one function, and that function fires this action right after the save. Hook it once and you hear about every change, whichever path made it.

Usage

do_action( 'easy_svg_pro_set_icons_written', int $post_id, array $icons )

Fired in includes/editor/sets.php, at the end of the internal function write_set_icons(), after the post meta _easy_svg_set_icons has been updated.

add_action( 'easy_svg_pro_set_icons_written', 'acme_on_set_saved', 10, 2 );

Pass 2 as the fourth argument, or your callback only receives $post_id.

When to use it

  • You cache something built from a set: a sprite sheet, a JSON file for a JavaScript app, a page cache that prints the icons. Clear it here.
  • You mirror a set somewhere else: a design system repository, a CDN bucket, another site.
  • You want an audit trail: who changed which set, and when.
  • You want to notify a person or a channel when a client swaps an icon in client mode.

Do not use it when:

  • You want to change or refuse the icons. This is an action that fires after the save; nothing you return is used. Clean markup before it reaches Easy SVG Pro, or use the configurator.
  • You want to know when a set is created, renamed, trashed or restored. Those change the post, not its icons, and do not fire this action (see Pitfalls).
  • You want to react to folder or theme collections. They are read from disk and never saved through this function. See easy_svg_pro_registered_collection.

Parameters

body
$post_idint
Required

The ID of the easy_svg_set post whose icons were just stored. This is the post ID, not the collection slug a template uses. See the third example for turning it into a slug.

body
$iconsarray
Required

Every icon the set holds after the save, keyed by icon slug: array( 'arrow' => array( 'label' => 'Arrow', 'markup' => '<svg ...>' ) ). The markup is already sanitized and hardened. After a removal it holds what is left; an empty array means the set is now empty. You never get the previous state or a list of what changed.

Return value

returnvoid

Nothing. It is an action, so any return value is ignored.

Default

Easy SVG Pro hooks it itself only when Icon history is on under Icons → Features: its callback asks WordPress for a revision with wp_save_post_revision(). Nothing else listens by default.

Examples

Clear a cache built from the set

/**
 * The theme builds an SVG sprite per set and keeps it in a transient.
 */
function acme_flush_icon_sprite( $post_id, $icons ) {
	delete_transient( 'acme_icon_sprite_' . (int) $post_id );
}
add_action( 'easy_svg_pro_set_icons_written', 'acme_flush_icon_sprite', 10, 2 );

Tell the agency when a client changes an icon

Client mode lets a client replace drawings. Many agencies want to know when that happens.

/**
 * Mail the site admin when someone other than an administrator saves a set.
 */
function acme_notify_on_client_swap( $post_id, $icons ) {
	if ( current_user_can( 'manage_options' ) ) {
		return;
	}

	$user = wp_get_current_user();
	$set  = get_the_title( $post_id );

	wp_mail(
		get_option( 'admin_email' ),
		sprintf( 'Icon set "%s" was changed', $set ),
		sprintf( '%s saved the set "%s". It now holds %d icons.', $user->display_name, $set, count( $icons ) )
	);
}
add_action( 'easy_svg_pro_set_icons_written', 'acme_notify_on_client_swap', 10, 2 );

WP-CLI and cron run without a logged in user, so current_user_can() is false there and they would mail too. Add if ( wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) ) { return; } if you only care about people.

Find out which icons changed

The action only hands over the new state. Keep a fingerprint per icon in your own post meta and compare.

/**
 * Log added, changed and removed icons per save.
 */
function acme_log_icon_changes( $post_id, $icons ) {
	$before = get_post_meta( $post_id, '_acme_icon_hashes', true );
	$before = is_array( $before ) ? $before : array();

	$after = array();
	foreach ( $icons as $slug => $icon ) {
		$after[ $slug ] = md5( (string) ( $icon['markup'] ?? '' ) );
	}

	$added   = array_keys( array_diff_key( $after, $before ) );
	$removed = array_keys( array_diff_key( $before, $after ) );
	$changed = array();
	foreach ( array_intersect_key( $after, $before ) as $slug => $hash ) {
		if ( $before[ $slug ] !== $hash ) {
			$changed[] = $slug;
		}
	}

	// The collection slug templates use. A brand new set may not be recorded yet.
	$slugs      = get_option( 'easy_svg_pro_set_collection_slugs', array() );
	$collection = is_array( $slugs ) && ! empty( $slugs[ (string) $post_id ] )
		? $slugs[ (string) $post_id ]
		: get_post_field( 'post_name', $post_id );

	error_log( sprintf( '[icons] %s: +%s ~%s -%s', $collection, implode( ',', $added ), implode( ',', $changed ), implode( ',', $removed ) ) );

	update_post_meta( $post_id, '_acme_icon_hashes', $after );
}
add_action( 'easy_svg_pro_set_icons_written', 'acme_log_icon_changes', 10, 2 );

Writing your own post meta here is fine. It is a different key, so it does not fire the action again.

Defensive: only when Easy SVG Pro is there, and never twice in one request

function acme_push_set_to_cdn( $post_id, $icons ) {
	static $done = array();

	// A bulk move writes two sets, and one request can save the same set twice.
	if ( isset( $done[ $post_id ] ) ) {
		return;
	}
	$done[ $post_id ] = true;

	wp_schedule_single_event( time() + 30, 'acme_upload_icon_set', array( (int) $post_id ) );
}

add_action(
	'plugins_loaded',
	function () {
		if ( defined( 'EASY_SVG_PRO_FILE' ) ) {
			add_action( 'easy_svg_pro_set_icons_written', 'acme_push_set_to_cdn', 10, 2 );
		}
	}
);

The upload itself runs later in cron, so a slow CDN does not slow down the save the person is waiting for.

How it works

Every write path ends in the same internal function. In order:

  1. The caller has already sanitized and hardened every icon (through the free Easy SVG Support plugin) and merged its change with what is stored.
  2. In a write context (a REST request that is not a GET, or WP-CLI) the request holds the set lock. See easy_svg_pro_set_write_context.
  3. The whole set is saved as one JSON string in the post meta _easy_svg_set_icons.
  4. This action fires with the post ID and the same array that was saved.

These paths come through here:

PathWhen
Set editorSaving a set (POST /sets/{id})
Adding and removing iconsPOST /sets/{id}/icons/add and /icons/remove, also used by the abilities
Relabelling one iconPOST /sets/{id}/icons/label, only when the label really changed
Bulk editingRename, copy and move between sets (a move fires once for each set)
Moving library icons into a setPOST /library/move
Pack import, Font Awesome import, presetsAfter the new set post is created
WP-CLIwp easy-svg pack import
Client modeSwapping a drawing
Icon historyRestoring an older drawing
SVG cleanerCleaning an icon stored in a set

The action is not tied to a feature flag. If the code path runs, the action fires. Your callback runs inside the same request, so anything slow you do here delays that save.

Pitfalls

  • It fires even when nothing changed. Adding icons that all already exist, or removing names the set does not hold, still saves the set and fires the action. Compare the content yourself (third example) if a "real" change matters.
  • No previous state. $icons is the new state only. Keep your own snapshot, or turn on Icon history and read the previous revision with wp_get_post_revisions().
  • Trash, delete, restore and rename do not fire it. Those change the post, not the icon meta. If you build caches, also hook wp_trash_post, untrashed_post, deleted_post and post_updated for easy_svg_set posts.
  • Recursion. Saving the same set's icons again from your callback (for example through an internal REST request) fires the action again. Guard with a static flag as in the last example.
  • Post ID is not the collection slug. Templates call acme/arrow, not 42/arrow. Read easy_svg_pro_set_collection_slugs (keyed by post ID) and fall back to post_name. A set created in this very request may not be in that option yet, and on sites that ran older versions the slug can end in -x.
  • Direct meta writes are invisible. Code that calls update_post_meta( $id, '_easy_svg_set_icons', ... ) itself, a WXR import or a migration plugin skips this action, the lock and the sanitizer. Easy SVG Pro hardens the markup again when reading, but your listener never hears about it.

$icons is sanitized and hardened, so it is safe to print. Do not run it through your own string replacement and print the result: a careless replacement can create markup the sanitizer would have refused.