Whitelist a single SVG for use in post_content

I have a block built in Gutenberg - in it I use an Icon element from '@wordpress/components'

I use a single arrow to create a dropdown which renders as an SVG. Of course when anyone who is not a super admin or admin saves this block - then the SVG is stripped and the block breaks as no SVG is found matching the save() function.

I don't want to whitelist all SVGs on a site for security reasons - so ideally I'd just like to white-list this one. I had thought that WP KSES can pass acceptable values too but I'm wrong.

function allow_arrow_svg( $tags ) {

$tags['svg'] = array(
    'aria-hidden' = array( 'true', 'false' ),
    'role'        = array( 'img' ),
    'xmlns'       = array( 'http://www.w3.org/2000/svg' ),
    'width'       = array( '20' ),
    'height'      = array( '20' ),
    'viewbox'     = array( '0 0 20 20' ),
    'style'       = array( 'color', 'fill' ),
    'class'       = array(),
);

$tags['path'] = array(
    'd' = array( 'M5 6l5 5 5-5 2 1-7 7-7-7z' ),
);
return $tags;
}

add_filter( 'wp_kses_allowed_html', 'allow_arrow_svg', 10, 2 );

Would be perfect - but doesn't work as I can still pass anything in the various attributes.

Any suggestions out there folks? Thanks for your time :-)

Topic block-editor svg wp-kses Wordpress

Category Web


The question changed somewhat to what was asked - however thought this might be useful if some other mug gets carried away with react in their save functions.

So - this was solved as @Tom J Nowell suggested and a PHP callback was made instead to allow the save instead. I deprecated the block and removed the SVG from the save function so that the save function inside the deprecation included the SVG and the new one didn't.

So old blocks would not show the SVG twice, but new blocks could get migrated I ended up forcing an attribute set in the migration of the block - under the block deprecation function remembering to declare the new blockVersion attribute in the new version of the block registration - I set the default value as null for both PHP and JS side of block registration.

migrate( attributes ) {
    attributes.blockVersion = '2.0.0';
return { ...attributes }

Under the render_callback function I only rendered the SVG server side if a version attribute of '2.0.0' was picked up. Like below:

/**
 * Callback function to render the block on the front end
 *
 * @since 2.0.0
 * @param Array  $attributes  Array of block attributes
 * @param String $content     Block content
 *
 * @return String HTML
 */
function render_block( $attributes, $content ) {
    if ( ! empty( $attributes['blockVersion'] ) && version_compare( $attributes['blockVersion'], '2.0.0', '>=' ) ) {
        $arrow_colour = esc_attr( $attributes['svgColor'] );
        $position     = esc_attr( $attributes['position'] );
    
        $svg = "<svg aria-hidden='true' role='img' xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' style='color:$arrow_colour;fill:$arrow_colour' class='dashicon dashicons-arrow-down-alt2 arrow-side-$position'><path d='M5 6l5 5 5-5 2 1-7 7-7-7z'></path></svg>";
    
        return "
        <div class='wp-block-namespace-blockname'>
            $svg
            $content
        </div>";

    } else {
        return $content;
    }
}

Finally in the edit function of the block - I used setAttribute() to set the attribute to '2.0.0' so new blocks would always have a non-default value of the block version in the content. This allows PHP to pick up the different version.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.