0

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 :-)

6
  • You could also insert the HTML in PHP or via JS, saving it in the DB and letting those parts of the SVG through the filters isn't the only solution ( or the easiest )
    – Tom J Nowell
    Apr 15 at 16:18
  • Hmmm yeah - feels like a deprecated block is probably incoming - version already in production.... Thanks @TomJNowell
    – Bysander
    Apr 16 at 10:33
  • Although - is it even possible to add the PHP callback as a migration? Once the callback has been added then all blocks regardless of whether they've been deprecated and migrated would include the php callback.... therefore doubling up the SVG
    – Bysander
    Apr 16 at 13:05
  • as a general rule, the React components in @wordpress/components are intended for GUI use, and were never intended to be in a blocks save function or have their HTML rendered to a string and stored. It might be easier to instead save a HTML tag and use CSS to add the icon on the frontend
    – Tom J Nowell
    Apr 16 at 15:16
  • Yep. I feel like I have just learnt this the hard way... Given the fast nature of the block editor development and lack of clear examples and documentation online I’m sure I’m not alone in working out how to use these tools through pure trial and error.
    – Bysander
    Apr 16 at 22:05
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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