For block collections, it’s useful to group your blocks into a category for organizational purposes. In this tutorial, I will. show you how to create a category for your blocks and how to add a custom SVG icon.
Adding the Category
Adding the category is pretty simple. It all starts with the block_categories
filter. Let’s dive into the code needed. For example, here’s how Paid Memberships Pro does it for their block category:
/**
* Add PMPro block category
*/
function pmpro_place_blocks_in_panel( $categories, $post ) {
return array_merge(
$categories,
array(
array(
'slug' => 'pmpro',
'title' => __( 'Paid Memberships Pro', 'paid-memberships-pro' ),
),
)
);
}
add_filter( 'block_categories', 'pmpro_place_blocks_in_panel', 10, 2 );
Code language: PHP (php)
There’s a third argument called icon
that you can use to assign a dashicon to the block category. For example, re-using the above code, you could do:
function pmpro_place_blocks_in_panel( $categories, $post ) {
return array_merge(
$categories,
array(
array(
'slug' => 'pmpro',
'title' => __( 'Paid Memberships Pro', 'paid-memberships-pro' ),
'icon' => 'editor-table',
),
)
);
}
add_filter( 'block_categories', 'pmpro_place_blocks_in_panel', 10, 2 );
Code language: PHP (php)
A more elegant example is on a post entitled Creating a Block Category if you wish to check that one out. Here’s the result of adding the above Dashicon to the block category.
It’s really that simple. But what if you want to add a custom icon that isn’t a dashicon?
Adding a Custom Icon
To add a custom icon, you need an SVG version of your icon. It should be lightweight so it doesn’t balloon your file size, and there are some caveats to look out for. In the example below, I’ll be using JSX to include the icon. You’d include it either as a component, or inline in your block initialization script, which is the approach I’ll be taking.
For example, here’s some raw SVG code that is JSX-friendly (I grabbed it from Google’s Material Library).
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M11.99 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm3.61 6.34c1.07 0 1.93.86 1.93 1.93 0 1.07-.86 1.93-1.93 1.93-1.07 0-1.93-.86-1.93-1.93-.01-1.07.86-1.93 1.93-1.93zm-6-1.58c1.3 0 2.36 1.06 2.36 2.36 0 1.3-1.06 2.36-2.36 2.36s-2.36-1.06-2.36-2.36c0-1.31 1.05-2.36 2.36-2.36zm0 9.13v3.75c-2.4-.75-4.3-2.6-5.14-4.96 1.05-1.12 3.67-1.69 5.14-1.69.53 0 1.2.08 1.9.22-1.64.87-1.9 2.02-1.9 2.68zM11.99 20c-.27 0-.53-.01-.79-.04v-4.07c0-1.42 2.94-2.13 4.4-2.13 1.07 0 2.92.39 3.84 1.15-1.17 2.97-4.06 5.09-7.45 5.09z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
Code language: HTML, XML (xml)
An example of a non-JSX friendly SVG is shown below:
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 400"><defs><clipPath id="clip-path" transform="translate(-106 -196)"><path d="M476.41,296.5a1.17,1.17,0,0,0,0-.26c0-.19-.05-.37-.08-.57a1.14,1.14,0,0,1-.06-.25c-.06-.25-.1-.48-.17-.72a1.89,1.89,0,0,0-.11-.25,2,2,0,0,0-.17-.47,2.36,2.36,0,0,0-.12-.28c-.07-.16-.16-.32-.23-.47s-.07-.14-.11-.22-.26-.43-.38-.62a2.43,2.43,0,0,0-.14-.2,3.64,3.64,0,0,0-.35-.45,2.09,2.09,0,0,1-.14-.17c-.14-.19-.32-.34-.46-.53,0,0,0,0-.07-.05-.17-.17-.37-.36-.56-.52l-.17-.13c-.14-.12-.3-.23-.44-.34l-.23-.14a3.74,3.74,0,0,0-.49-.3c-.05,0-.14-.07-.18-.11l-.59-.29-.14-.05s0,0,0,0L309.66,217.45a9.07,9.07,0,0,0-7.29,0L141.08,289.09s0,0,0,0l-.13.05-.58.29c-.06,0-.14.07-.19.11s-.34.2-.5.3l-.22.14c-.15.11-.3.24-.46.34a.91.91,0,0,1-.16.13c-.2.16-.39.35-.58.52l-.05.05a5.82,5.82,0,0,0-.46.53.76.76,0,0,0-.15.17c-.13.15-.23.31-.34.45l-.15.2a3.9,3.9,0,0,0-.37.62l-.11.22c-.07.17-.16.33-.23.48s-.09.2-.13.29-.13.33-.18.48a1.31,1.31,0,0,1-.09.26c-.07.23-.12.48-.17.72a1.83,1.83,0,0,0-.06.25,5.62,5.62,0,0,0-.09.57c0,.09,0,.16,0,.25,0,.27,0,.54,0,.81V494.55a9,9,0,0,0,5.32,8.2l161.46,71.71.06,0a4.41,4.41,0,0,0,.72.26.91.91,0,0,0,.14.07c.27.07.56.14.84.23,0,0,0,0,0,0a9.1,9.1,0,0,0,3.7,0s0,0,0,0c.29,0,.58-.16.84-.23,0,0,.09,0,.15-.07.25-.07.48-.17.72-.26l.05,0L471.1,502.75a9,9,0,0,0,5.33-8.2V297.34c0-.27,0-.54,0-.81l0,0ZM306,235.39,445.4,297.3,306,359.21,166.64,297.3,306,235.39Zm-152.49,75.7,143.52,63.76V552.44L153.53,488.69V311.09ZM315,552.44V374.85l143.52-63.76v177.6L315,552.44Z" fill="none"/></clipPath></defs><image width="400" height="400" xlink:href="data:image/png;base64 (code intentionally shortened)
Code language: HTML, XML (xml)
Some things to look out for when converting your SVG for use in JSX:
- Look for any style attributes. In JSX, style must be an object and not a string. If you don’t need the style attribute, simply remove it. If you do need it, it’ll have to be in
style={{backgroundColor: red}}
format. - Look for HTML/XML-specific attributes such as
xmlns:clink
. It’s better to remove those attributes. - Convert
xlink:href
to JSX-friendly attributes such asxlinkHref
.
I’m sure there are others. Please leave a comment below if you’re aware of other caveats.
Update: There is an Awesome SVG Converter for React
Now that we have our SVG, how do we add it in? The code is fairly simple (I’m picking on Paid Memberships Pro again):
( function() {
const PMProSVG = <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M11.99 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm3.61 6.34c1.07 0 1.93.86 1.93 1.93 0 1.07-.86 1.93-1.93 1.93-1.07 0-1.93-.86-1.93-1.93-.01-1.07.86-1.93 1.93-1.93zm-6-1.58c1.3 0 2.36 1.06 2.36 2.36 0 1.3-1.06 2.36-2.36 2.36s-2.36-1.06-2.36-2.36c0-1.31 1.05-2.36 2.36-2.36zm0 9.13v3.75c-2.4-.75-4.3-2.6-5.14-4.96 1.05-1.12 3.67-1.69 5.14-1.69.53 0 1.2.08 1.9.22-1.64.87-1.9 2.02-1.9 2.68zM11.99 20c-.27 0-.53-.01-.79-.04v-4.07c0-1.42 2.94-2.13 4.4-2.13 1.07 0 2.92.39 3.84 1.15-1.17 2.97-4.06 5.09-7.45 5.09z"/><path d="M0 0h24v24H0z" fill="none"/></svg>;
wp.blocks.updateCategory( 'pmpro', { icon: PMProSVG } );
} )();
Code language: JavaScript (javascript)
I placed the above code in my initialization JavaScript file for the block.
Now here’s what the icon looks like now.
That’s it!
Debate Over Category Icons
There’s some debate over if block categories should have icons. I’m of the position of, why not?
Others have mentioned that the icons should blend in with the existing Gutenberg scheme (black and white). Other block category icons are full on color mode such as JetPack and WooCommerce.
I’m unsure of what the best practices are, but in my opinion it’s your plugin, so do with it as you wish. Users will be the ones complaining, while others may look at the icon, sigh in frustration, and move on with their lives.
If you have your own perspective, please leave a comment below.
Conclusion
Within this article I showed you how to create a custom block category, add a block icon, and went over briefly a point of contention in regards to block categories having icons.
Hi! I’ve been trying to get an easy custom SVG icon going for my custom ACF Blocks categories. I have the categories setup fine, same way you noted, but haven’t been able to get an SVG icon in there. Using your sample code above in my base theme chucks this error due to the SVG’s opening angle bracket.
Uncaught SyntaxError: Unexpected token ‘<'
The only way I've been able to get SVG icons to work is to convert them like so, but that's very difficult for any kind of complex icon:
( function() {
var el = wp.element.createElement;
var SVG = wp.primitives.SVG;
var circle = el( 'circle', { cx: 10, cy: 10, r: 8, fill: '#106c9b', stroke: '#6bccf0', strokeWidth: '2' } );
var svgIcon = el( SVG, { width: 20, height: 20, viewBox: '0 0 20 20'}, circle );
wp.blocks.updateCategory( 'gdt-blocks', { icon: svgIcon } );
} )();
Am I missing something obvious with your solution? I hope so because it looks to be a much better way to go. Thanks!
Hi Trevor. I’m using JSX for the SVG. I’m unfamiliar with how ACF does their blocks, but when I have time, I can do a bit of research.
Do you have a public repo with the block?
Thanks.
Hey Ronald. Thanks for reply! I went deeper into this topic since writing and understand it better now so I think I’m good. In regards to ACF, it simply utilises core functionality for managing block categories. (https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#managing-block-categories)
So that’s why I have to deconstruct my SVG. I was incorrectly putting doing that, especially with path values. I wasn’t converting them to JSX first before putting in the values in. Doing it this way is not ideal, but since it’s not something one has to do that often at all I can live with it. Thanks so much though for the follow up and offer to assist, very cool and appreciated!