6

I'm trying to output an SVG file in a template, and PHPCS is telling me I need to escape the output. So I tried with KSES and it doesn't seem to want to include the viewbox attribute.

 $allowed_html = array(
  'svg' => array(
    'xmlns' => array (),
    'viewBox' => true
  ),
  'path' => array(
    'd'=> array(),
  ),
);

 wp_kses(file_get_contents( $logo ), $allowed_html ) 

Any ideas why this doesn't work?

2 Answers 2

16

I found your question as I was searching for an answer. I tried experimenting a bit more with wp_kses() (code reference) found that lower-casing viewBox in the arguments seems to fix the issue. You do not have to put the actual attribute on the SVG in lowercase, just in the $allowed_html parameter that you pass to the function.

Here is an example that you can start with:

<?php
$kses_defaults = wp_kses_allowed_html( 'post' );

$svg_args = array(
    'svg'   => array(
        'class'           => true,
        'aria-hidden'     => true,
        'aria-labelledby' => true,
        'role'            => true,
        'xmlns'           => true,
        'width'           => true,
        'height'          => true,
        'viewbox'         => true // <= Must be lower case!
    ),
    'g'     => array( 'fill' => true ),
    'title' => array( 'title' => true ),
    'path'  => array( 
        'd'               => true, 
        'fill'            => true  
    )
);

$allowed_tags = array_merge( $kses_defaults, $svg_args );

echo wp_kses( $rich_text_that_might_include_SVGs, $allowed_tags );

List all SVG elements at the same level regardless of how they are organized in the SVG code itself. Make sure for each SVG element, all attributes are represented. You do not need to indicate the attribute value in the $svg_args array.

Take for instance this SVG code:

<svg width="19px" height="17px" viewBox="0 0 19 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>View Page</title>
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="View Page" stroke="#1892FF" stroke-width="2">
            <line x1="0" y1="8" x2="17" y2="8" id="Path-3"></line>
            <polyline id="Path-4" points="9 0.5 17 8 9 15.5"></polyline>
        </g>
    </g>
</svg>

You may think your $svg_args need to be like this:

    // Passing this arg to wp_kses() will not display the svg.
    $svg_args = array( 
        'svg'   => array(
            'title' => true,
            'g'     => array(
                'id'             => true,
                'stroke'         => true,
                'stroke-width'   => true,
                'fill'           => true,
                'fill-rule'      => true,
                'g'    => array(
                    'line'     => array ( 
                        'id'        => true,
                        'x1'        => true,
                        'y1'        => true,
                        'x2'        => true,
                        'y2'        => true
                    ),
                    'polyline' => array ( 
                        'id'        => true,
                        'points'    => true
                    )
                )
            )
        )
    );

I want to re-clarify that the correct syntax (for this specific example) is:

    $svg_args = array(
        'svg'   => array(
            'class'           => true,
            'aria-hidden'     => true,
            'aria-labelledby' => true,
            'role'            => true,
            'xmlns'           => true,
            'width'           => true,
            'height'          => true,
            'viewbox'         => true // <= Must be lower case!
        ),
        'g'         => array( 'fill' => true ),
        'title'     => array( 'title' => true ),
        'line'      => array ( 
            'id'        => true,
            'x1'        => true,
            'y1'        => true,
            'x2'        => true,
            'y2'        => true
        ),
        'polyline' => array ( 
            'id'        => true,
            'points'    => true
        ),
    );

The correct syntax: You list every SVG element in your arguments at the the same level. Make sure to replace [] in these examples with the actual array of attributes that make up the element. You can find all the elements you need to allow and their attributes by observing the SVG code itself.

0
4

great solution @mrwweb

if you want to use this in functions.php

<?php
function get_kses_extended_ruleset() {
    $kses_defaults = wp_kses_allowed_html( 'post' );

    $svg_args = array(
        'svg'   => array(
            'class'           => true,
            'aria-hidden'     => true,
            'aria-labelledby' => true,
            'role'            => true,
            'xmlns'           => true,
            'width'           => true,
            'height'          => true,
            'viewbox'         => true, // <= Must be lower case!
        ),
        'g'     => array( 'fill' => true ),
        'title' => array( 'title' => true ),
        'path'  => array(
            'd'    => true,
            'fill' => true,
        ),
    );
    return array_merge( $kses_defaults, $svg_args );
}

template:

<?php

echo wp_kses( $svg_code, get_kses_extended_ruleset() );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.