I'm running a multisite network with 200+ themes installed and activated. Is there a way to manipulate the list of available themes in wp-admin so that certain theme does not appear in the list? I want to do it without editing core files.

I know WordPress gets the list of available themes from the function get_themes(). And that there is a function called get_allowed_themes() that might be the solution. But no idea about how to use it.


The following filter works in Multisite in the following screens:

  • /wp-admin/network/themes.php
  • /wp-admin/network/site-themes.php?id=1 (individual sites allowed themes)
add_filter( 'all_themes', 'wpse_55081_remove_themes_ms' );
function wpse_55081_remove_themes_ms($themes)
    unset($themes['Twenty Ten'], $themes['Twenty Eleven']);
    return $themes;

For the regular theme selector in a single site or sub-site of a network /wp-admin/themes.php (Appearance -> Themes), looks like there's no hook...

I found that $wp_themes global var holds the array with all themes, but couldn't manage to unset items in it...

The old jQuery trickery does the job, but pagination may become funny...

add_action( 'admin_head-themes.php', 'wpse_55081_remove_themes' );

function wpse_55081_remove_themes()
    <script type="text/javascript">
    jQuery(document).ready( function($) {


Looks like there's a new hook on the block: extra_theme_headers.
But there's something weird:

  • it is documented as a new filter in WP 3.4
  • but it appears in wp-includes/deprecated.php (?!)
 * The returning $arr is always empty, but we are able to unset items in the global $wp_themes
 * Works in all theme screens, Multisite or Single Site (and doesn't bugs pagination)
 * It is defined this way: apply_filters( 'extra_theme_headers', array() )
 * The array value is always empty but, if we return it, the filter doesn't works..
add_filter( 'extra_theme_headers', 'wpse_55081_remove_themes_everywhere', 10, 1 );

function wpse_55081_remove_themes_everywhere($arr)
    global $wp_themes;
    unset($wp_themes['Convertible/Convertible'], $wp_themes['grido-child'], $wp_themes['ilost'], $wp_themes['parallels'], $wp_themes['twentyeleven']);
    // return $arr;
  • The second looks better than the first one, since it uses $themes as a global var. I'm going to try out it. Thanks. – grosshat Jun 13 '12 at 17:14
  • The second code works only for the admin page devoted to manage themes, not for the theme editor select menu. – grosshat Jun 14 '12 at 8:03
  • @grosshat : I've updated my answer with an explicit differentiation of where each code applies. – brasofilo Jun 14 '12 at 15:31
  • @grosshat : please check the last update. Only one filter can handle everything, but there's something I don't get about it (see code comments). – brasofilo Jun 19 '12 at 20:39
  • Yep, I see. Weird, documented as a new filter and at the same time already deprecated. I'll try out it. Thanks. – grosshat Jun 20 '12 at 6:39
add_filter( 'wp_prepare_themes_for_js', 'hideThemes');
function hideThemes($arr){
    foreach($arr as $key => &$value){
        //unset what you want
    return $arr;

Or alternatively:

add_filter( 'wp_prepare_themes_for_js', 'hideThemes');
function hideThemes($arr){


    return $arr;
  • 1
    Please explain why this answer is helpful. – kaiser Mar 13 '14 at 16:44
  • This is helpful because it is the answer - I actually prefer this method to the accepted solution - as this doesn't rely on and functions/methods in deprecated - I modified the code slightly which makes even simpler (added to the answer above) – acSlater Oct 2 '14 at 13:13

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.