How To Add Inline SVG Menu Icons to WordPress Custom Post Types

Custom post types are a powerful feature in WordPress. When you create a new custom post type, the same thumbtack menu icon seen next to ‘Posts’ is inserted by default. This can be overridden with any Dashicon you like, but the selection of Dashicons is fairly limited. Let’s get fancy and add our own custom svg icon.

As always, when it comes to WordPress, there are multiple ways to achieve the same goal.

Method 1: register_post_type

First, let’s suppose you have registered a custom post type in your theme or plugin. If that is the case, you can simply update the menu_icon parameter in the register_post_type arguments.

Pass a base64-encoded SVG using a data URI, which will be colored to match the color scheme — this should begin with ‘data:image/svg+xml;base64,’.

WordPress Developer Resources

I’m using a free FontAwesome icon in this case, and you can copy the svg code directly from their website. That said, not all icons are created equal, and you may have to tweak them a bit to get it to display correctly. In the case of FontAwesome icons, I had to add a fill="currentColor" to the icon to make it work.

/**
 * Register custom post type
 *
 * @see https://developer.wordpress.org/reference/functions/register_post_type/
 *
 * @return void
 */
register_post_type( 'people', array(
    'labels' => array(
        'name' => 'People',
        'singular_name' => 'People',
        'all_items' => 'All People',
    ),
    'menu_icon' => 'data:image/svg+xml;base64,' . base64_encode('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" fill="currentColor"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M72 88a56 56 0 1 1 112 0A56 56 0 1 1 72 88zM64 245.7C54 256.9 48 271.8 48 288s6 31.1 16 42.3V245.7zm144.4-49.3C178.7 222.7 160 261.2 160 304c0 34.3 12 65.8 32 90.5V416c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V389.2C26.2 371.2 0 332.7 0 288c0-61.9 50.1-112 112-112h32c24 0 46.2 7.5 64.4 20.3zM448 416V394.5c20-24.7 32-56.2 32-90.5c0-42.8-18.7-81.3-48.4-107.7C449.8 183.5 472 176 496 176h32c61.9 0 112 50.1 112 112c0 44.7-26.2 83.2-64 101.2V416c0 17.7-14.3 32-32 32H480c-17.7 0-32-14.3-32-32zm8-328a56 56 0 1 1 112 0A56 56 0 1 1 456 88zM576 245.7v84.7c10-11.3 16-26.1 16-42.3s-6-31.1-16-42.3zM320 32a64 64 0 1 1 0 128 64 64 0 1 1 0-128zM240 304c0 16.2 6 31 16 42.3V261.7c-10 11.3-16 26.1-16 42.3zm144-42.3v84.7c10-11.3 16-26.1 16-42.3s-6-31.1-16-42.3zM448 304c0 44.7-26.2 83.2-64 101.2V448c0 17.7-14.3 32-32 32H288c-17.7 0-32-14.3-32-32V405.2c-37.8-18-64-56.5-64-101.2c0-61.9 50.1-112 112-112h32c61.9 0 112 50.1 112 112z"/></svg>'),
    'public' => true,
    'show_in_rest' => true,
    'supports' => array(
        0 => 'title',
        1 => 'editor',
        2 => 'thumbnail',
    ),
    'delete_with_user' => false,
));

Method 2: registered_post_type

In the case where your custom post type has been registered by a third-party plugin, and you don’t want to alter the code, you can use the registered_post_type hook to update the menu_icon parameter like so. Keep in mind, this method can also be used to replace any of the default registered post types as well (ie. Posts, Media, Pages, etc…)

/**
 * Add custom post type icon
 * 
 * @see https://developer.wordpress.org/reference/hooks/registered_post_type/
 * 
 * @param string $post_type
 * @param object $post_type_object
 * 
 * @return void
 */
add_action('registered_post_type', function ($post_type, $post_type_object) {
    if ($post_type === 'people') {
        $post_type_object->menu_icon = 'data:image/svg+xml;base64,' . base64_encode('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" fill="currentColor"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M72 88a56 56 0 1 1 112 0A56 56 0 1 1 72 88zM64 245.7C54 256.9 48 271.8 48 288s6 31.1 16 42.3V245.7zm144.4-49.3C178.7 222.7 160 261.2 160 304c0 34.3 12 65.8 32 90.5V416c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V389.2C26.2 371.2 0 332.7 0 288c0-61.9 50.1-112 112-112h32c24 0 46.2 7.5 64.4 20.3zM448 416V394.5c20-24.7 32-56.2 32-90.5c0-42.8-18.7-81.3-48.4-107.7C449.8 183.5 472 176 496 176h32c61.9 0 112 50.1 112 112c0 44.7-26.2 83.2-64 101.2V416c0 17.7-14.3 32-32 32H480c-17.7 0-32-14.3-32-32zm8-328a56 56 0 1 1 112 0A56 56 0 1 1 456 88zM576 245.7v84.7c10-11.3 16-26.1 16-42.3s-6-31.1-16-42.3zM320 32a64 64 0 1 1 0 128 64 64 0 1 1 0-128zM240 304c0 16.2 6 31 16 42.3V261.7c-10 11.3-16 26.1-16 42.3zm144-42.3v84.7c10-11.3 16-26.1 16-42.3s-6-31.1-16-42.3zM448 304c0 44.7-26.2 83.2-64 101.2V448c0 17.7-14.3 32-32 32H288c-17.7 0-32-14.3-32-32V405.2c-37.8-18-64-56.5-64-101.2c0-61.9 50.1-112 112-112h32c61.9 0 112 50.1 112 112z"/></svg>');
    }
}, 10, 2);

Method 3: Using CSS

Instead of adding an inline svg, we have a third option available to us. We can simply leave the menu_icon parameter empty, and then add our own with CSS. This method requires two steps.

  1. Make sure the menu_icon parameter is empty in the register_post_type or registered_post_type functions respectively.
  2. Add custom CSS to the WordPress admin with the following code.

We can either create our own stylesheet and enqueue it in the admin.

/**
 * Add stylesheet to admin
 * 
 * @see https://developer.wordpress.org/reference/hooks/admin_enqueue_scripts/
 * 
 * @return void
 */
add_action( 'admin_enqueue_scripts', function () {
    wp_enqueue_style( 'admin-custom', get_stylesheet_directory_uri() . '/admin-custom.css');
});

Or, we can add inline styles directly to the admin_head. Emojis are still 🔥, right?

/**
 * Add inline styles to admin
 * 
 * @see https://developer.wordpress.org/reference/hooks/admin_head/
 * 
 * @return void
 */
add_action( 'admin_head', function () {
    echo '
        <style>
            #adminmenu #menu-posts-people div.wp-menu-image:before {
                content: "👽";
        }
        </style>
    ';
});

Leave a Reply

Your email address will not be published. Required fields are marked *