A new version of MainWP was released today (5th August 2025) and with it came a couple of brilliant new filters to fix some issues I’ve had as a plugin creator and a user of MainWP the changelog of this release is below
Change Log
5.4.0.18 – Maintenance Release – 8-5-2025
- Fixed: Issues with sorting and filtering data by PHP version in cases where version numbers contain text strings. (#815)
- Added: Support for custom plugin and theme icons that may be set by third-party developers.
- Added: Element ID for the “Log Out” menu item in the user settings menu to improve accessibility and targeting.
- Updated: Element ID for the “Add New” and “Import Sites” menu items to prevent duplicate ID conflicts.
- Dev: Refined REST API responses to properly support the
selected_sites
field when creating or updating clients. - Dev: Updated
selected_sites
parameter behavior to allow assignment of multiple sites to a single client. - Dev: Added
mainwp_before_save_cached_icons
filter hook to allow developers to manipulate cached plugin and theme icons.
I’ve highlighted the items that I am specifically talking about and will deal with them one in a time
Custom Icons for third-party developers
This brilliant new improvement allows me to now pass my plugin icons to MainWP so it begins to use them in update notifications and also when you view installed plugins etc. It is achieved by using the mainwp_child_stats_get_plugin_info
filter and passing your icon along with the rest of the data.
So this means all my plugins will now show up there icons within the dashboard in the next couple of release cycles
For information the code i’ve used to do this is below in this example its from my bubble-intergrator-block plugin
// MainWP Icon Filter
add_filter('mainwp_child_stats_get_plugin_info', function($info, $slug) {
if ('bubble-intergrator-block/bubble-intergrator-block.php' === $slug) {
$info['icon'] = 'https://raw.githubusercontent.com/stingray82/bubble-intergrator/main/uupd/icon-128.png'; // Supported types: jpeg, jpg, gif, ico, png
}
return $info;
}, 10, 2);
PHPThis will now tell your dashboards where to load this particular plugins logo from.
Bulk Icon Updates from Dashboard – mainwp_before_save_cached_icons
The above is great if you’ve got an active developer but it could be years before this is common place, so the brilliant development team at MainWP have added a filter that allows you to bulk add icons to your dashboard using the new mainwp_before_save_cached_icons
filter.
Now I have developed a little snippet and icon repository designed to allow all dashboard owners to contribute to the open source repository and have begun populating it with working icons using the following snippet
add_filter('mainwp_before_save_cached_icons', function ($cached_icons, $icon, $slug, $type, $custom_icon, $noexp) {
// Determine correct JSON source based on type
$json_url = '';
if ($type === 'plugin') {
$json_url = 'https://raw.githubusercontent.com/stingray82/mainwp-plugin-icons/main/icons-map.json';
} elseif ($type === 'theme') {
$json_url = 'https://raw.githubusercontent.com/stingray82/mainwp-plugin-icons/main/themes-icons-map.json';
} else {
return $cached_icons;
}
// Fetch JSON data
$response = wp_remote_get($json_url);
if (is_wp_error($response)) {
error_log("[MainWP ICONS] Failed to fetch {$type} icon map: " . $response->get_error_message());
return $cached_icons;
}
$icons_map = json_decode(wp_remote_retrieve_body($response), true);
if (!is_array($icons_map)) {
error_log("[MainWP ICONS] Invalid JSON for {$type} icons.");
return $cached_icons;
}
// Inject custom icons if not already cached
foreach ($icons_map as $custom_slug => $custom_icon_url) {
if (!isset($cached_icons[$custom_slug])) {
$cached_icons[$custom_slug] = [
'lasttime_cached' => time(),
'path_custom' => '',
'path' => urlencode($custom_icon_url),
];
error_log("[MainWP ICONS] Injected {$type} icon for: {$custom_slug}");
}
}
return $cached_icons;
}, 10, 6);
PHPThis reads the JSON file at https://raw.githubusercontent.com/stingray82/mainwp-plugin-icons/main/icons-map.json
and will add the icons from there to your dashboard now its really early days and this has been designed to be a public updated repo we should all contribute and add to the intergrations
Current Icons at launch by slug:
admin-site-enhancements-pro
advanced-custom-fields-pro
advanced-database-cleaner-pro
automaticcss-plugin
bricksextras
complianz-gdpr-premium
frames-plugin
happyfiles-pro
ninja-updater
presto-player-pro
simply-static-pro
sleek-ai
slim-seo-pro
updraftplus
wp-armour-extended
wpcodebox2
I have left this as a snippet as I assume most dashboard owners have snippets running already or like me a settings plugin for mainwp if this isn’t the case I will happily turn it into a little plugin to update automatically too but thought this was the easiest way
Cache Issues:
Now while developing and testing this I had issues with the icon cache and had to delete it a few times, to do this i used the following snippet
Warning this works on your database directly please use snippets with care and backup before use
This snippet will delete the options and allow them to be repopulated with fresh cache (once run and pulled, don’t forget to refresh your browser too)
// Add "Clear Icon Cache" link to admin bar
add_action('admin_bar_menu', function ($admin_bar) {
if (!current_user_can('manage_options')) {
return;
}
$url = add_query_arg('mainwp_clear_icon_cache', '1', admin_url());
$url = wp_nonce_url($url, 'mainwp_clear_icon_cache');
$admin_bar->add_menu(array(
'id' => 'mainwp-clear-icon-cache',
'title' => 'Clear Icon Cache',
'href' => $url,
'meta' => array(
'title' => 'Clear MainWP plugin & theme icon cache',
),
));
}, 100);
add_action('admin_init', function () {
if (
isset($_GET['mainwp_clear_icon_cache']) &&
current_user_can('manage_options') &&
check_admin_referer('mainwp_clear_icon_cache')
) {
global $wpdb;
$table = $wpdb->prefix . 'mainwp_wp_options';
$result = $wpdb->query("
DELETE FROM {$table}
WHERE name IN ('plugins_icons', 'themes_icons') AND wpid = 0
");
// Debug info
//error_log("[MainWP ICON CLEAR] Deleted rows: " . $result);
//error_log("[MainWP ICON CLEAR] Last query: " . $wpdb->last_query);
add_action('admin_notices', function () use ($result) {
echo '<div class="notice notice-success is-dismissible"><p><strong>MainWP Icon Cache Cleared.</strong> Deleted rows: ' . intval($result) . '</p></div>';
});
}
});
PHPIt adds a new option to the admin menu bar to clear the cache for you

This to me is a real improvement to the look and feel of my dashboard and has been a pain point for me for a while so I am really pleased with what’s achievable with these two filters.
Article Changes:
Snippet was updated 07th August 2025 to include themes from the same repo