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
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' ).
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
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: noesw_iconpost with that ID.no_markup:$markupis empty or only whitespace.refused: the sanitizer library is not loaded, or the file failed a check: larger thaneasy_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
- Lookup.
get_post()with the ID; the post type must beesw_icon. - Checks before parsing.
easy_svg_accept_icon()refuses a file over the byte limit (the size set under Icons, Settings, filterable witheasy_svg_max_bytes) and a file the complexity guard flags, before the sanitizer ever sees it. - Cleaning. The site's sanitizer (with
esw_svg_allowed_tagsandesw_svg_allowed_attributesapplied) cleans the markup. A result without ansvgroot is refused. Theneasy_svg_harden_icon_markup()removesscript,style,foreignObject,iframe,embed,object, the animation elements, everyonattribute and every externalhref. - The write. WordPress's kses filter does not know SVG, so for a user without
unfiltered_htmlit would empty the icon. The function turns kses off for exactly this one write, if it was on, and turns it back on in afinallyblock. Onlypost_contentchanges;post_nameandpost_titlestay. - Cache.
easy_svg_forget_icons()raises the optioneasy_svg_icons_versionand deletes the transienteasy_svg_icons, so the next request registers the new drawing with the Icon block. It is called directly because thesave_post_esw_iconhook that would also do it is only registered while the icon library is switched on.
Pitfalls
refusedbecause 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 thatsanitize_title()turns into percent-encoding, can no longer receive new markup. Rename it to a Latin title first, then update.refusedcovers five causes. You cannot tell "too large" from "not an SVG" from the return value. If you need to, runeasy_svg_max_bytes()andeasy_svg_svg_too_complex()yourself before the call.- Hooks fire. Like any
wp_update_post(), the call firessave_post,save_post_esw_iconand 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 nextinit. - Do not write
post_contentyourself. A directwp_update_post()skips the sanitizer, empties the icon for users withoutunfiltered_html, and leaves a stale cached list for up to a day.