How to properly include inline SVGs in a WordPress theme

SVGs are used all the time in WordPress themes and for a good reason, they are scalable, small in size and if we include them inline we can change colours etc without needing another image. There is one thing that bugs me when I see this though, especially with user uploaded SVGs; the way they’re included in the theme.

There are 3 real ways that I’ve seen it done:

  1. Using get_template_part()
  2. Using an include() or require()
  3. Using file_get_contents()

They all look fine and they all work, so why is one better than the other two?

The Issues

As I’ve mentioned previously SVGs are actually more like standalone XML applications and they can therfore have quite a few different things embedded in them. One of the things we can embed into an SVG file is PHP script.

PHP in an SVG file

This doesn’t look too bad, but imagine if we had injected something a lot more malicious. For example, we could add code to steal cookies and send it back to ourselves, now there’s a lot more reason to worry about injected PHP.

If the svg is inlined in the wrong way, the potentially embedded PHP code will get executed and this is something we don’t want to happen!

Another issue is that if your SVG file has the XML declaration (see below) in place then it can cause a PHP error when it tries to load it.

<?xml version="1.0" encoding="utf-8"?>

How to not do it

When including an SVG inline we should steer clear of include() and require(). Both of these methods will execute PHP code if it has been embedded in the SVG file, you may also trigger the PHP error mentioned above if the XML declaration exists in the file.

That said, it’s not that often you see people using include() or require() in WordPress themes. That’s because WordPress has it’s own way of including files get_template_part().

I’ve seen quite a few tutorials saying that this is the correct way of loading an SVG inline because it’s the “WordPress way”. I’m happy to go on record and say that this is wrong!

If you’ve ever dug into this function (as I have) you’d be able to see that get_template_part() is actually a wrapper for locate_template() as you can see below:

locate_template($templates, true, false);

That second option you can see that’s passed as true is the $load option. This tells WordPress to load the template that’s being requested. This looks like:

if ( $load && '' != $located )
    load_template( $located, $require_once );

Ok, so we’re now calling load_template(), what happens in there?

You guessed, it uses a require() function…

if ( $require_once ) {
    require_once( $_template_file );
} else {
    require( $_template_file );
}

So by calling get_template_part() you are actually still loading the file via require() and therefore are still vulnerable to PHP code execution if it exists in your SVG.

How it should be done

Now as I’m sure you’ve worked out, the third option of file_get_contents() hasn’t been mentioned yet. That’s because it’s the safer way of loading an SVG inline.

It won’t execute and PHP that may be embedded in the SVG file and won’t cause you that PHP error if the XML declaration exists in the file. That makes it safer than both the other options!

Use it like this:

<?php echo file_get_contents( get_stylesheet_directory_uri() . '/img/icons/your-file.svg' ); ?>

Alternatively you can wrap it in a function to make loading your SVGs easier throughout the theme. Something like this should work!

<?php

/**
* Load an inline SVG.
*
* @param string $filename The filename of the SVG you want to load.
*
* @return string The content of the SVG you want to load.
*/
function load_inline_svg( $filename ) {

    // Add the path to your SVG directory inside your theme.
    $svg_path = '/images/svgs/';

    // Check the SVG file exists
    if ( file_exists( get_stylesheet_directory() . $svg_path . $filename ) ) {

        // Load and return the contents of the file
        return file_get_contents( get_stylesheet_directory_uri() . $svg_path . $filename );
    }

    // Return a blank string if we can't find the file.
    return '';
}


Note:
This is untested but should work 🙂

If you have a better way of handling inline SVGs or an improvement to this one then please do let me know in the comments 🙂

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.