Iconseasy_svg_update_icon_markup()

easy_svg_update_icon_markup()

Replace the drawing of a stored icon through the site's SVG sanitizer and upload limits, keeping its slug and name, and get back a status word.

Function · Easy SVG · Status: Stable

easy_svg_update_icon_markup() gives an existing icon a new drawing. The new SVG goes through the same checks as an upload (size limit, complexity guard, the site's sanitizer and the icon hardener), then replaces the stored markup. The icon keeps its slug and its name, so every template, shortcode and saved Icon block that uses it shows the new drawing.

Usage

easy_svg_update_icon_markup( int $id, string $markup ): string

When to use it

  • An add-on repairs or optimises icons (for example removing hard-coded colours) and writes them back.
  • An import or sync script updates icons from a design system without changing their addresses.
  • A custom admin screen lets a designer swap the artwork of an icon.

When not to use it:

  • To add a new icon. Use the Icons screen or the panel's REST route; this function only changes existing ones.
  • To change the name. Use easy_svg_rename_icon().
  • To change what only the Icon block shows. Use easy_svg_registrable_icons; it leaves the stored file alone.

Parameters

body
$idint
Required

The post ID of the icon (post type esw_icon). Cast to an integer; zero, negative values, missing posts and posts of any other type all answer not_found. You get the ID from the library payload of the panel's REST API, from easy_svg_stored_icons(), or with get_page_by_path( $slug, OBJECT, 'esw_icon' ).

body
$markupstring
Required

The new SVG, raw, as you received it. Do not sanitize it yourself first; the function does that with the site's own allow-list. Empty or whitespace-only markup answers no_markup. It must have exactly one svg root and at least one drawing element left after cleaning.

Return value

returnstring

One word. It never returns a WP_Error and never throws.

  • updated: the new markup is stored and the cached icon list is dropped.
  • not_found: no esw_icon post with that ID.
  • no_markup: $markup is empty or only whitespace.
  • refused: the sanitizer library is not loaded, or the file failed a check: larger than easy_svg_max_bytes(), too complex (easy_svg_svg_too_complex()), not an SVG the sanitizer accepts, nothing drawable left after hardening, or the icon's current title cannot be turned into a valid icon name (see Pitfalls).
  • failed: wp_update_post() returned an error or 0.

Examples

Basic

$state = easy_svg_update_icon_markup( $icon_id, $new_svg );

if ( 'updated' !== $state ) {
	error_log( sprintf( 'Icon %d not replaced: %s', $icon_id, $state ) );
}

Replace an icon by slug from a file

function myplugin_replace_icon_from_file( $slug, $file ) {
	if ( ! current_user_can( 'edit_theme_options' ) ) {
		return 'forbidden';
	}

	$post = get_page_by_path( $slug, OBJECT, 'esw_icon' );
	if ( ! $post || 'esw_icon' !== $post->post_type ) {
		return 'not_found';
	}

	if ( ! is_readable( $file ) ) {
		return 'no_markup';
	}

	return easy_svg_update_icon_markup( (int) $post->ID, (string) file_get_contents( $file ) );
}

The capability check is yours. edit_theme_options is the capability the esw_icon post type requires (EASY_SVG_ICON_CAP); the plugin's own library REST routes are stricter and require manage_options.

Turn the status into a message

$messages = array(
	'updated'   => __( 'Icon replaced.', 'myplugin' ),
	'not_found' => __( 'That icon no longer exists.', 'myplugin' ),
	'no_markup' => __( 'The file was empty.', 'myplugin' ),
	'refused'   => __( 'That file is not an SVG this library can use.', 'myplugin' ),
	'failed'    => __( 'The icon could not be saved. Please try again.', 'myplugin' ),
);

$state = easy_svg_update_icon_markup( $icon_id, $markup );
add_settings_error( 'myplugin', 'icon-' . $state, $messages[ $state ] ?? $messages['failed'], 'updated' === $state ? 'success' : 'error' );

Defensive: check the contract version

The function exists since EASY_SVG_ICONS_API 3 (Easy SVG 5.4.0).

if ( defined( 'EASY_SVG_ICONS_API' ) && EASY_SVG_ICONS_API >= 3 && function_exists( 'easy_svg_update_icon_markup' ) ) {
	$state = easy_svg_update_icon_markup( $icon_id, $markup );
} else {
	$state = 'unsupported';
}

The function does not check capabilities or nonces. It is safe against bad markup (the sanitizer and hardener run), but not against the wrong person calling it. Before you call it for a request, check a capability (edit_theme_options at least; the plugin's REST route asks for manage_options) and verify a nonce. A replaced icon is inlined on every page that uses it.

How it works

  1. Lookup. get_post() with the ID; the post type must be esw_icon.
  2. Checks before parsing. easy_svg_accept_icon() refuses a file over the byte limit (the size set under Icons, Settings, filterable with easy_svg_max_bytes) and a file the complexity guard flags, before the sanitizer ever sees it.
  3. Cleaning. The site's sanitizer (with esw_svg_allowed_tags and esw_svg_allowed_attributes applied) cleans the markup. A result without an svg root is refused. Then easy_svg_harden_icon_markup() removes script, style, foreignObject, iframe, embed, object, the animation elements, every on attribute and every external href.
  4. The write. WordPress's kses filter does not know SVG, so for a user without unfiltered_html it would empty the icon. The function turns kses off for exactly this one write, if it was on, and turns it back on in a finally block. Only post_content changes; post_name and post_title stay.
  5. Cache. easy_svg_forget_icons() raises the option easy_svg_icons_version and deletes the transient easy_svg_icons, so the next request registers the new drawing with the Icon block. It is called directly because the save_post_esw_icon hook that would also do it is only registered while the icon library is switched on.

Pitfalls

  • refused because of the title. The checks derive a name from the icon's current title, and refuse when it cannot become a valid slug. An icon renamed to a title without letters or digits (for example !!!), or to a title in a script like Cyrillic or Japanese that sanitize_title() turns into percent-encoding, can no longer receive new markup. Rename it to a Latin title first, then update.
  • refused covers five causes. You cannot tell "too large" from "not an SVG" from the return value. If you need to, run easy_svg_max_bytes() and easy_svg_svg_too_complex() yourself before the call.
  • Hooks fire. Like any wp_update_post(), the call fires save_post, save_post_esw_icon and related hooks. Code that reacts to those runs too.
  • Templates see it at once, the block on the next request. easy_svg_icon() reads the post directly; the Icon block reads the registry, which is rebuilt on the next init.
  • Do not write post_content yourself. A direct wp_update_post() skips the sanitizer, empties the icon for users without unfiltered_html, and leaves a stale cached list for up to a day.