SVG icons are lightweight, scalable, and easy to style with CSS. But by default, many WordPress themes and plugins load SVGs as <img>
tags or background images β which limits styling and accessibility.
In this post, I'll show you how to render SVG icons with a custom function into your WordPress templates, allowing full control over their appearance and behavior.
Rendering SVG as inline code gives you:
Full CSS control (fill, stroke, hover effects)
Better accessibility options
No extra HTTP requests
Animation capabilities
theme_get_svg()
Letβs walk through this function step by step so you understand how each part works.
function theme_get_svg($icon, $url = null, $args = [])
{
$defaults = [
"class" => "",
"width" => "24",
"height" => "24",
];
$args = wp_parse_args($args, $defaults);
// Determine the icon path
if (!empty($url)) {
// Fetch the SVG from an external URL (WordPress Media Library or external source)
$response = wp_remote_get($url);
if (
is_wp_error($response) ||
wp_remote_retrieve_response_code($response) !== 200
) {
return "";
}
$svg = wp_remote_retrieve_body($response);
} else {
// Fetch the SVG from theme assets
$icon_path =
get_template_directory() . "/assets/icons/" . $icon . ".svg";
if (!file_exists($icon_path)) {
return "";
}
$svg = file_get_contents($icon_path);
}
$svg = preg_replace(
"/<svg/",
sprintf(
'<svg class="%s" width="%s" height="%s"',
esc_attr($args["class"]),
esc_attr($args["width"]),
esc_attr($args["height"])
),
$svg,
1
);
return $svg;
}
$defaults = [
"class" => "",
"width" => "24",
"height" => "24",
];
$args = wp_parse_args($args, $defaults);
We start by defining default attributes for the SVG β such as class, width, and height. The wp_parse_args()
function merges the defaults with any custom attributes you pass when calling theme_get_svg()
.
π This makes the function flexible: you can override only what you need.
// Determine the icon path
if (!empty($url)) {
// Fetch the SVG from an external URL (WordPress Media Library or external source)
$response = wp_remote_get($url);
if (
is_wp_error($response) ||
wp_remote_retrieve_response_code($response) !== 200
) {
return "";
}
$svg = wp_remote_retrieve_body($response);
} else {
// Fetch the SVG from theme assets
$icon_path =
get_template_directory() . "/assets/icons/" . $icon . ".svg";
if (!file_exists($icon_path)) {
return "";
}
$svg = file_get_contents($icon_path);
}
This section determines where the SVG should come from:
If you provide a $url
, it fetches the SVG from a remote location (like WordPress Media Library).
Otherwise, it looks for a local file in your themeβs /assets/icons/
folder.
Both approaches include error handling:
For remote files, it checks for request errors or HTTP failures.
For local files, it checks if the file exists.
<svg>
Tag$svg = preg_replace(
"/<svg/",
sprintf(
'<svg class="%s" width="%s" height="%s"',
esc_attr($args["class"]),
esc_attr($args["width"]),
esc_attr($args["height"])
),
$svg,
1
);
This is where the magic happens. Instead of echoing a plain SVG, we inject our attributes into the first <svg>
tag in the file, using preg_replace()
with a limit of 1.
This gives us full control over:
CSS styling (class
)
Size (width
and height
)
Accessibility (aria-*
, role
, etc.)
You can now use it anywhere in your theme templates, just like this:
echo theme_get_svg(
"iconname",
null,
array(
"class" => "custom-class",
"width" => "30",
"height" => "30"
),
);
Rendering SVG icons directly as inline code in WordPress gives you full control over styling, accessibility, and performance β without relying on external libraries or icon fonts.
With this function, you can streamline your workflow, improve page speed, and build a more maintainable front-end. Whether you're working on a custom theme or a client project, this approach keeps your codebase clean and flexible.
Feel free to tweak the function to suit your needs β and if you found this useful, consider sharing it with fellow developers!
Want to grab the full code? Check out the complete function on GitHub Gist:
Interested in collaborating or have questions about my work? Feel free to reach out using the options below. I'm always excited about new opportunities and ready to discuss how we can bring your next project to life together. I look forward to hearing from you!