ideasonpurpose/wp-svg-lib

Utilities for collecting and reusing inline SVG components

v3.0.0 2023-08-18 20:36 UTC

README

Version 3.0.0

A powerful utility library for including SVG files in WordPress sites.

Packagist codecov Coverage Status Maintainability styled with prettier

What it does

This helper library reads SVG files from a directory then provides helper functions for embedding the files into WordPress templates. Files can be embedded inline or converted to symbols to help conserve bandwidth.

The library also enables SVG shortcodes, which can directly place SVGs into the block editor.

Note: Version 2.0.0 changed the namespace from IdeasOnPurpose\SVG to IdeasOnPurpose\WP\SVG.

Instructions

Initialize the library from a theme's functions.php file. Starting with version 3, the library looks for SVG files in the theme's dist/images/svg directory by default, so instantiation can look like this:

new IdeasOnPurpose\WP\SVG;

// or use a custom path
new IdeasOnPurpose\WP\SVG(get_theme_directory() . '/icons/svg');

All SVG files below the directory will be registered and available to template files. The library will inject an $SVG query var so SVGs can be accessed from inside get_template_part() includes with no additional code.

Install from Packagist, require it in composer.json or tell Composer to load the package:

$ composer require ideasonpurpose/wp-svg-lib

Embedding SVGs

Embedding images is the same as pasting the SVG files into the HTML source. Most registered SVG files can be inserted using just their name, so a file named logo.svg can embedded like this:

<div><?= $SVG->logo ?></div>

That code outputs something like this:

<div><svg viewBox="0 0 25 10">...</svg></div>

The library normalizes all file names to camelCase to help with embedding. Directory separators will be replaced with double-underscores. Some examples:

// the file 'icons/email-circle.svg' can be embedded as:
$SVG->icons__emailCircle;

For SVG files whose names aren't compatible with PHP's property syntax, there's also an embed command which also works with nested directories:

<li><?= $SVG->embed('arrow-left') ?></li>
<li><?= $SVG->embed('icons/email') ?></li>

For convenience, SVG files can be embedded with or without their file extension. So the previous embeds could also work like this:

<li><?= $SVG->embed('arrow-left.svg') ?></li>
<li><?= $SVG->embed('icons/email.svg') ?></li>

Note that name resolution is bi-directional. An SVG file named dash-case.svg can be embedded by either dash-case or dashCase. Likewise, a file named camelCase.svg will be accessible by either camelCase or camel-case.

Inlining SVG Symbols

SVGs can also be injected as linked symbols, where most all of the markup only appears once. This can be useful for simple elements which appear repeatedly:

<a href="#"><?= $SVG->use('arrow') ?>Go!</a>

The library keeps a record of which files have been included like this, then injects a symbol reference from the wp_footer hook. Together, the above code and symbol library look like this:

<a href="#"><svg class="arrow"><use xlink:href="#arrow" href="#arrow" /></svg>Go!</a>

<svg xmlns='http://www.w3.org/2000/svg' style='display: none;'>
    <symbol id="arrow" viewBox="0 0 50 50">...</symbol>
</svg>
</body>

REST API

This library adds the /ideasonpurpose/v1/svg endpoint to the WP-JSON API.

Files can be requested by name like this:

Dimensions, classes and IDs can be injected using query vars:

A listing of all registered SVGs is here:

If either height or width are 'auto' then that value will be calculated from the aspect ratio and the opposite dimension.

Well-formed SVG files should return a data object like this:

{
  "svg": "<svg viewBox=\"0 0 25 10\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" d=\"M0 5.57.01 4.4c12.59.08 18.84.08 18.77 0V0L25 4.99 18.77 10l.01-4.43H0Z\"/>\n</svg>",
  "innerContent": "<path fill-rule=\"evenodd\" d=\"M0 5.57.01 4.4c12.59.08 18.84.08 18.77 0V0L25 4.99 18.77 10l.01-4.43H0Z\"/>\n",
  "width": 25,
  "height": 10,
  "aspect": 2.5,
  "attributes": {
    "viewBox": "0 0 25 10"
  },
  "__srcPath": "/var/www/html/wp-content/themes/example/dist/images/svg/arrow.svg",
  "_links": {
    "self": "https://example.com/wp-json/ideasonpurpose/v1/svg/arrow",
    "collection": "https://example.com/wp-json/ideasonpurpose/v1/svg",
    "svg": "https://example.com/wp-json/ideasonpurpose/v1/svg/arrow?svg=1",
    "src": "https://example.com/wp-content/themes/example/dist/images/svg/arrow.svg"
  }
}

Properties:

  • svg - A rewrapped SVG with a cleaned subset of attributes
  • innerContent - The contents of the SVG with enclosing tags stripped off. Used in the Block Editor in place of pre-processed SVGR objects.
  • width - Derived width of the file, either extracted from viewBox or read from attributes.
  • height - Derived height of the file, either extracted from viewBox or read from attributes.
  • aspect - Convenience value, derived width divided by derived height.
  • attributes - Array of attributes to appear in the <svg> tag. Valid attributes include: id, class, height, width and viewBox
  • _links - Array of related URLs:
    • self
    • collection (all available SVGs)
    • svg - Returns with Content-type: image/svg+xml headers and can be used to display the SVG file directly in the browser.
    • src - Direct link to the unmodified source SVG file
  • original_attributes - The unmodified array of cleaned attributes. Only appears for requests with modified attributes.
  • __srcPath - Filesystem path of the source SVG. [Debug only]

Removed Attributes and Optimization

All attributes except viewBox and xmlns are removed fromclean valid SVG files, but the unmodified src files are also available.

Invalid SVGs pass through to src without modification. Error details will be added to the JSON data object.

Other than the opening <svg> tag, vector data is not optimized in any way. Please use something like svgo to optimize SVG files.

Shortcodes

In Progress

SVGs can be included by authors and for Full Site Editing using shortcodes.

[svg file-slug]
[svg file-slug height="23" width="auto"]
[svg src="fileSlug" height="23" width="auto" class="hello there"]

A single bare attribute will be treated as the source, but the shortcode prefers named attributes and if a shortcode contains both, the named src attribute will override the positional info.

In this example, the square SVG will be shown instead of circle:

[svg circle src="square"]

Notes

  • using svg as the Shortcode name may come back to haunt us. But I'd rather keep the shortcode simple and memorable.
  • Is it necessary to quote shortcode attributes?
  • What happens to invalid SVGs?

    • A. No idea? Pass through unchanged? There should be some notification, no quiet failures. (Is that a failure? -- Yes, any deviation from expected behavior should be explained)
  • What happens if there's no viewBox?

    • ViewBox will be added if it can be derived from supplied height and width attributes. If there are no dimensions and no viewBox, nothing will be added to the opening <svg> tag.

Cleaning Quirks

<svg></svg is a valid, though useless SVG document. Internally, the cleaner will returned zero for width and height, with an aspect ratio of 1.