Best Practice: SVG Wordpress like a Boss

Last summer I made a mention of my SVG process in a thread.

That’s funny you say Compass was well known for it’s sprite generator because I’ve heard that as well. And when I heard that I thought– why would I need to use sprites? I use almost strictly SVG nowadays.

SVGs can be tricky, but I’ve got a system that works for me. It’s primarily based on Chris Coyier’s Using SVG article, mixed with Treehouse’s method for The Perfect WordPress Inline SVG Workflow.

This implies that SVGs are better than sprites. If anyone has any counter arguments to that, I’d love to hear it.

My process has changed a bit since I posted that, so here’s my current process:

  1. Open vector graphic in Adobe Illustrator

  2. Tip: Make sure everything gets turned into a path (unless you want to retain actual text, but I’m not sure Google can crawl a word within an SVG so I don’t suggest doing this on important keywords). You can do this by:

    For strokes: Object > Path > Outline Stroke
    For text/fonts: Right click > Create Outlines

  3. Now save it as an SVG (I save mine to Sage/assets/svg/originals).

  4. Install SVGO

  5. Optimize your /originals. Run: $ svgo -f Sage/assets/svg/originals -o Sage/assets/svg (This will save the optimized versions to your svg folder, but retain the originals, which is important because over optimizing them can screw everything up as you’ll see in my video below).

  6. Now rename your newly optimized SVGs with inline- as a prefix to the file name and add .php after the .svg extension. So logo.svg becomes inline-logo.svg.php.

  7. Now add this line of php to your desired php page: <svg><?php get_template_part( 'assets/svg/inline', 'logo.svg' ); ?></svg>

Now you have inline SVGs, which make it SO much cleaner to work with in my opinion. You can even animate them or alter the styles in CSS.

Here it is in practice:

We’re almost there, but I’ve found it usually takes a little bit of tweaking in the CSS to make sure SVGs don’t start over-writing the other SVGs CSS styles (which are usually called .st0, .st1, .st2, etc).

Here’s a video of me trouble shooting the issue and fixing it. (0-7 minutes: the frustrating issue – 7-12 minutes: the easy solution)

I hope that helps you guys streamline an SVG process that works for you. If anyone has alternate methods or tips, I would LOVE to hear them. Thanks!

Edit: I noticed roots.io uses icomoon. I’ve used their icons packs, but never the custom SVGs. It would be cool to hear a pro/con list of icomoon vs. inline-svgs.

12 Likes

That’s almost exactly what I’m doing right now, but I wonder if anyone extended their Webpack2/Sage 9 setup to automatize this in some way?

2 Likes

Great. I’ll try it. At the moment I’m using javascript to convert included img svg in svg inline code. This is the script:

$('img.svg').each(function(){
  var $img = $(this);
  var imgID = $img.attr('id');
  var imgClass = $img.attr('class');
  var imgURL = $img.attr('src');
  $.get(imgURL, function(data) {
      // Get the SVG tag, ignore the rest
      var $svg = $(data).find('svg');
      // Add replaced image's ID to the new SVG
      if(typeof imgID !== 'undefined') {
          $svg = $svg.attr('id', imgID);
      }
      // Add replaced image's classes to the new SVG
      if(typeof imgClass !== 'undefined') {
          $svg = $svg.attr('class', imgClass+' replaced-svg');
      }

      // Remove any invalid XML tags as per http://validator.w3.org
      $svg = $svg.removeAttr('xmlns:a');

      // Check if the viewport is set, if the viewport is not set the SVG wont't scale.
      if(!$svg.attr('viewBox') && $svg.attr('height') && $svg.attr('width')) {
          $svg.attr('viewBox', '0 0 ' + $svg.attr('height') + ' ' + $svg.attr('width'));
      }
      // Replace image with new SVG
      $img.replaceWith($svg);
  }, 'xml');

});

2 Likes

That’s cool. So what’s the PHP implementation look like exactly? Also where do you place that JS?

Inside Common.js and execute it inside init function.

This looks nice!

Only problem is that the assets folder doesn’t exist on a staging / production server, only the compiled dist folder. So this won’t work in Sage 9:

get_template_part( 'assets/svg/inline', 'logo.svg' );

Why do you need the .php extension? Couldn’t you use something like this:

file_get_contents(asset_path('svg/inline'. 'logo.svg'));

@Twansparant, good point. That would probably work.

In Sage 9 I’ve started doing it a little different.

First, I optimize the SVG and put it in templates/svg/logo.php. (No .svg extension)

Then I use this to pull it inline: @include('svg.logo')

Thanks for your workflow @masoninthesis. I’m using this as well currently.

Still I feel there should be a better way to incorporate SVG embedding in Sage 9.

Update:
This looks like a nice solution.

1 Like

Would love to see an example of how we use packages like blade-svg with Sage 9’s implementation of Blade.

@QWp6t? :slight_smile:

Otherwise, I’m going to take a shot at it tomorrow when I get up. I’d like to get this working to optimize a couple sites I’m working on verse using an icon font where I only use 5% of the icon’s in a single project. If the project really needs the optimization, in the past I’d just strip the icon font using icomoon but this seems a lot more sane for the future.

1 Like

Blade SVG for Sage
Since Sage 9 uses sage() as it’s container instead of app(), we are unable to use a majority of Laravel’s service providers.

For that reason, I’ve reworked Blade SVG and turned it into a WordPress plugin to be used solely with Sage 9.

It’s still quite early, but I’d appreciate anyone testing it out and reporting any issues. I also added some filters to be able to control configuration.

3 Likes

Awesome, I’ll give it a try next time I’m doing some SVG heavy work (shouldn’t be too long until then).

Hey, thanks for your work! Could you give some more input on how to use it?

I’m installed your plugin via composer, but @svg() directives still get rendered as plain old text.
Is there any additional configuration i need to do?
A small example in your Readme would be highly appreciated.

// app/helpers.php

if (! function_exists('svg_path')) {
    /**
     * Path to a certain SVG file in our assets folder
     *
     * @param  string  $file
     * @return string
     */
    function svg_path(string $file) : string
    {
        return get_template_directory()."/assets/svg/{$file}";
    }
}

And in your files

<?php include App\svg_path('name.svg'); ?>

or

@php (include App\svg_path('name.svg'))

This way you can style the svg from css as well…

Corrected as per @shoetten’s remark. Thanks
It’s the way I have it in my blade file; I mainly use Laravel and my helpers file is not namespaced, that’s why I forgot about adding the App namespace :slight_smile:

4 Likes

Thanks, that’s a decent way to do this. Something like blade svg would still be cool though, so i can add custom classes to the svg markup for example or use svg sprites, if that’s better suited for the project than inlining everything.

PS: Just a little note for future reference: You need to specify the namespace in your view, to make this work. So it would be:
@php(include App\svg_path('file.svg'))

1 Like

I ended up writing a custom blade directive:

In setup.php:

/**
 * Create @svg() Blade directive
 */
sage('blade')->compiler()->directive('svg', function ($arguments) {
    // Accept multiple arguments
    list($path, $class) = array_pad(explode(',', trim($arguments, "() ")), 2, '');
    $path = trim($path, "' ");
    $class = trim($class, "' ");

    // Create the DOM document to remove the XML version element
    $svg = new \DOMDocument();
    $svg->load(svg_path($path));
    $svg->documentElement->setAttribute("class", $class);
    $output = $svg->saveXML($svg->documentElement);

    return $output;
});

Working together with your helper function in helpers.php

/**
 * Return path of requested svg file
 * @param  string $file File name
 * @return string       file path
 */
function svg_path($file)
{
    return get_template_directory() . '/assets/svg/' . $file;
}

To be used in your views like this:

@svg('something.svg', 'your-custom-class')

Credit: https://stackoverflow.com/a/43117258/4500049

Similar to asset_path and @asset. Might be worth including something like this into sage?

No automatic optimisation with webpack or anything fancy like that, but it works very nicely apart from that and is capable of adding a custom class to your svg.

8 Likes

The directive is actually @icon()– he appears to of changed it to @svg() as of recent so I will try to update that in the near future.

Sorry for the confusion.

@shoetten After I add the snippets to helpers.php successfully, I add the snippet to setup.php and get this error:

Fatal error: Uncaught ReflectionException: Class sage.blade does not exist in…

Is there something else I need to avoid this error? Also, in what directory do you save your svgs?

Hey @shaimoom,
hmm, i never experienced this error.
But i haven’t tried this with the most recent version of sage. It is possible that an update broke something…

I store my svgs in web/app/themes/<YOUR_THEME_FOLDER>/resources/assets/svg, but you can configure that in helpers.php as you like…

If you can upload a minimal reproduction in a git repo somewhere, i can have a quick look into your code, if you want.

@shaimoom This came up in another SVG thread, and appears that you may be using Sage 8. The directives are for Blade which is part of Sage 9.

@shoetten Thanks for offering to inspect my code, but it was my mistake: I inserted the directive outside of the “Setup Sage options” function that starts with

add_action('after_setup_theme', function ()...

After putting it inside the function, the directive worked as expected! Thanks.

2 Likes