esw_svg_remove_remote_references
Decide whether Easy SVG strips absolute URLs, remote CSS and @import rules from SVGs. On by default, so a stored file cannot load anything from elsewhere.
Filter · Easy SVG · Status: Stable
An SVG can load things from other servers: an image, a stylesheet, a font. Every visitor's browser then contacts that server, which can log who looked at your page. Easy SVG removes those references by default. This filter lets you switch that off, or make sure it stays on.
Usage
apply_filters( 'esw_svg_remove_remote_references', bool $remove )
add_filter( 'esw_svg_remove_remote_references', '__return_false' );
When to use it
- Your SVGs are infographics with clickable links (
a href="https://..."). With the default, those links lose theirhrefon upload. - A trusted import, for example a migration from another site, brings SVGs that load a web font or a bitmap from a CDN, and you want them stored as they are.
- You run a hardened site and want to guarantee that no other plugin switches the removal off. Return
truelate.
Do not use it:
- Because one file looks wrong. Embed the image or font into the file (or host it as a separate media item) instead of opening every upload to remote loading.
- To change what the icon library keeps. Icons drop every
hrefthat does not start with#anyway, whatever this filter says.
Parameters
true (the default) removes remote references, false keeps them. The return value is cast to bool, so 0, '' and null count as false.
Return value
true strips remote references from every SVG cleaned after this point, false keeps them.
Default
true. Easy SVG 5.0.0 introduced this; up to 4.1 remote references were kept. The bundled library itself defaults to false, so the plugin always sets the value explicitly.
What true removes:
| Where | What happens |
|---|---|
Any attribute whose value is an absolute URL (http:, https:, ftp:, file:) or protocol-relative (//host/...) | The whole attribute is removed. This includes href on a and image. |
Any attribute containing a remote url(...) or @import | The whole attribute is removed. |
A style attribute with a remote reference hidden behind CSS escapes or comments, or in image-set() | The whole attribute is removed. |
Text inside a style element | Remote url(...) and image-set(...) tokens are cut out, and every @import rule is removed, local ones included. The rest of the CSS stays. |
What stays: fragment references (#gradient, url(#clip)), root-relative paths (/wp-content/uploads/a.png), relative paths inside CSS (url(images/a.png)) and the data:image/png, gif and jpeg URIs the href check accepts. A relative href such as images/a.png is removed either way: the separate href check, which this filter does not control, only accepts fragments, paths starting with /, http(s) and those data: types.
Examples
Keep remote references everywhere
// Links and remote images in uploaded SVGs are kept from now on.
add_filter( 'esw_svg_remove_remote_references', '__return_false' );
Keep them only during a trusted import
The value is read each time a sanitizer is built, so you can switch it off for one job and back on afterwards.
/**
* Import SVGs from a folder we trust, keeping their remote references.
*
* @param string[] $paths Absolute paths of SVG files.
* @return int[] New attachment IDs.
*/
function myplugin_import_trusted_svgs( array $paths ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$ids = array();
add_filter( 'esw_svg_remove_remote_references', '__return_false' );
try {
foreach ( $paths as $path ) {
$tmp = wp_tempnam( basename( $path ) );
if ( ! $tmp || ! copy( $path, $tmp ) ) {
continue;
}
$id = media_handle_sideload(
array(
'name' => basename( $path ),
'tmp_name' => $tmp,
),
0
);
if ( is_wp_error( $id ) ) {
wp_delete_file( $tmp );
continue;
}
$ids[] = $id;
}
} finally {
remove_filter( 'esw_svg_remove_remote_references', '__return_false' );
}
return $ids;
}
media_handle_sideload() runs the same check as the uploader (wp_handle_sideload_prefilter), and the new-attachment check runs right after it. Both build their sanitizer while your filter is active, so both keep the references. The finally block makes sure a failing file cannot leave the filter on for the rest of the request.
Make sure nobody switches it off
/**
* Force remote reference removal, whatever other plugins return.
*/
function myplugin_force_remote_reference_removal() {
add_filter( 'esw_svg_remove_remote_references', '__return_true', PHP_INT_MAX );
}
add_action( 'plugins_loaded', 'myplugin_force_remote_reference_removal' );
Stricter for your add-on only
easy_svg_sanitizer() returns a new instance on every call, so an add-on can tighten its own copy without touching the site setting.
$sanitizer = function_exists( 'easy_svg_sanitizer' ) ? easy_svg_sanitizer() : null;
if ( null !== $sanitizer ) {
// Our own content never needs remote references, whatever the site allows.
$sanitizer->removeRemoteReferences( true );
}
With false, an uploaded SVG can make the browser of every visitor, and of every administrator who opens the media library, request a URL on a server you do not control. That server learns IP addresses, browsers and which page was viewed, and can change what it returns at any time. Only turn this off when you trust every person who can upload SVGs.
How it works
easy_svg_sanitizer() applies the filter on every call (easy-svg.php, line 294) and passes the result to the library's removeRemoteReferences():
Because the filter is applied after cloning the legacy global, it always wins. A site snippet from the 4.x days that called $sanitizer->removeRemoteReferences( false ) on the global no longer has any effect; the library cannot tell a deliberate false from its own default, so the plugin decides through the filter alone.
Every path that cleans SVG calls easy_svg_sanitizer(): media uploads and sideloads, the wp_upload_bits check used by XML-RPC, the check on every new attachment, the icon library and add-ons. On the wp_upload_bits path a file is refused instead of cleaned, so with the default a file containing a remote reference is rejected there.
Pitfalls
- Your own domain counts as remote. The check looks at the URL form, not the host.
https://your-site.example/wp-content/uploads/a.pngis removed just like a third-party URL. Use root-relative paths (/wp-content/...) if a file must reference your own media. - Links lose their target.
a href="https://..."keeps theaelement and its content but loses thehref, so the link is dead. - Local
@importgoes too. Inside astyleelement every@importrule is removed, not only remote ones. - Old files are not re-checked. Changing the filter affects files cleaned afterwards. Files already stored stay as they are.
- The legacy global is ignored for this setting. Configure it through the filter only.
- Icons keep no external
hrefeither way. The icon hardener removes everyhrefthat does not start with#after sanitizing.