10

When I was running WP 3.9.2 I was able to use the following code to remove the Customize menu item from Appearance in the admin menu.

function remove_customize() {
  remove_submenu_page('themes.php', 'customize.php');
}
add_action('admin_init', 'remove_customize', 999);

Once I updated to 4.0 this is no longer working.

isabisa
  • 649
  • 2
  • 10
  • 23

14 Answers14

18

This works with WordPress 4.1 and 4.0 and 3.x here:

Edit: Adjusted for WordPress 4.1 compatibility:

function remove_customize() {
    $customize_url_arr = array();
    $customize_url_arr[] = 'customize.php'; // 3.x
    $customize_url = add_query_arg( 'return', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), 'customize.php' );
    $customize_url_arr[] = $customize_url; // 4.0 & 4.1
    if ( current_theme_supports( 'custom-header' ) && current_user_can( 'customize') ) {
        $customize_url_arr[] = add_query_arg( 'autofocus[control]', 'header_image', $customize_url ); // 4.1
        $customize_url_arr[] = 'custom-header'; // 4.0
    }
    if ( current_theme_supports( 'custom-background' ) && current_user_can( 'customize') ) {
        $customize_url_arr[] = add_query_arg( 'autofocus[control]', 'background_image', $customize_url ); // 4.1
        $customize_url_arr[] = 'custom-background'; // 4.0
    }
    foreach ( $customize_url_arr as $customize_url ) {
        remove_submenu_page( 'themes.php', $customize_url );
    }
}
add_action( 'admin_menu', 'remove_customize', 999 );
Ov3rfly
  • 178
  • 1
  • 5
17

Answer should be:

add_action( 'admin_menu', function () {
global $submenu;
if ( isset( $submenu[ 'themes.php' ] ) ) {
    foreach ( $submenu[ 'themes.php' ] as $index => $menu_item ) {
        foreach ($menu_item as $value) {
            if (strpos($value,'customize') !== false) {
                unset( $submenu[ 'themes.php' ][ $index ] );
            }
        }
    }
}
});

The way rjb used an array as the needle in in_array() in the accepted answer doesn't work. Check out why in the docs. I replaced in_array with another foreach that loops through the $menu_item arrays and looks for 'customize' as part of the value.

Works for me with WordPress 4.9.6

bash88
  • 171
  • 1
  • 5
8

You can directly modify the $submenus global like so:

global $submenu;
unset($submenu['themes.php'][6]); // Customize link

I'm using this in the same function, hooked into admin_menu, as I use to unset other admin items and it seems to be working fine

function as_remove_menus () {
       remove_menu_page('upload.php'); //hide Media
       remove_menu_page('link-manager.php'); //hide links
       remove_submenu_page( 'edit.php', 'edit-tags.php' ); //hide tags
       global $submenu;
        // Appearance Menu
        unset($submenu['themes.php'][6]); // Customize
}
add_action('admin_menu', 'as_remove_menus');
Andrew Cafourek
  • 431
  • 4
  • 11
  • Is there any worry about the index of the Appearance menu in that array changing in future releases? – isabisa Sep 17 '14 at 12:12
  • @isabisa Initially I thought you cold just use `array_search` but since it is a multidimensional array, you could use an approach like described in [this thread](http://stackoverflow.com/questions/6661530/php-multi-dimensional-array-search). – Andrew Cafourek Sep 17 '14 at 17:46
6

You can in fact use remove_submenu_page to remove the theme submenu option from the admin screen. The trick is that the url must match what is being exactly linked in the admin for that function to work.

function remove_admin_menus() {

    remove_submenu_page( 
        'themes.php', 
        'customize.php?return=' . 
            urlencode( str_replace( get_bloginfo('url'), "", get_admin_url() ) ) . 
            'themes.php' );

}

add_action( 'admin_init', 'remove_admin_menus' );

I have programmatically determined the admin url in the case that you aren't simply using '/wp-admin'. @isabisa This will also avoid breaking in the future if the index of the menu item ever changes.

I'm using this in WP 4.0 and it works great!

chrisphilton
  • 459
  • 3
  • 7
  • A nice succinct answer, that doesn't need to call a global! This is especially useful when you have a function being used to remove other menu/submenu items. – Phill Healey Jan 16 '17 at 13:12
6

Edit: Updated for WordPress 4.9+ and increased compatibility with PHP <= 5.4

WordPress core doesn't offer a hook to natively disable the theme customizer, but there is a clever and elegant way to remove the “Customize” link from the Appearance menu by altering the global $submenu variable:

/**
 * Remove Admin Menu Link to Theme Customizer
 */
add_action( 'admin_menu', function () {
    global $submenu;

    if ( isset( $submenu[ 'themes.php' ] ) ) {
        foreach ( $submenu[ 'themes.php' ] as $index => $menu_item ) {
            if ( in_array( array( 'Customize', 'Customizer', 'customize' ), $menu_item ) ) {
                unset( $submenu[ 'themes.php' ][ $index ] );
            }
        }
    }
});

While other code samples here and elsewhere irresponsibly rely on specific numeric indexes of the global $submenu variable (e.g. $submenu['themes.php'][6][0], ...), this method intelligently traverses through the hierarchy so it should be compatible with older (3.x) and newer versions of WordPress (4.x) alike.

rjb
  • 9,036
  • 2
  • 44
  • 49
  • I'm working with WP 8.4. The check on 'Customize' does dot work here, i had to change it into 'Customizer'. – jivanrij Oct 11 '17 at 13:25
  • Does not work for me in WP 4.8 (also not if 'Customize' is changed to 'Customizer'. @Ov3rfly's answer below worked. – nachtigall Dec 05 '17 at 20:47
  • 1
    @nachtigall I updated the answer to reflect current usage with WordPress 4.8+ and PHP 5.x+. – rjb Dec 19 '17 at 17:26
  • 1
    Using `in_array` with an array for the "needle" isn't working for me. When I changed the "needle" to a string, it worked i.e. `in_array( 'customize', $menu_item )`. – Josh Jan 31 '19 at 10:36
  • 3
    For some reason, the array for the "needle" isn't working for me. You can keep the same functionality by adjusting the if statement like so `if ( in_array( 'Customize', $menu_item, true ) || in_array( 'Customizer', $menu_item, true ) || in_array( 'customize', $menu_item, true )) { }`. – Borduhh Aug 03 '19 at 22:59
5

Removing the menu is only a halfway solution, since it doesn't completely disable the customizer. In order to fully and securely disable the customizer (and also remove the menu), you need to remove the customizer permission from all users. Something like this would do it:

add_filter('map_meta_cap', function($caps, $cap, $user_id, $args) {
    if ('customize' == $cap) return ['do_not_allow'];
    return $caps;
}, 10, 4);
Andrej Pavlovic
  • 364
  • 4
  • 12
  • This solution completely removed the Customizer link from the admin bar and the admin panel Appearance menu using v5.1.8. Thanks! – Nekomajin42 Dec 21 '20 at 21:10
3

WordPress >= 4.9.8

add_action('admin_menu', function () {
  $request = urlencode($_SERVER['REQUEST_URI']);
  remove_submenu_page('themes.php', 'customize.php?return='. $request);
}, 999);
Kuba Paczyński
  • 129
  • 1
  • 4
1

The accepted answer by @rjb didn't work for my spanish wordpress, but just changing the Customize to customize did the trick.

/**
 * Remove Admin Menu Link to Theme Customizer
 */
add_action( 'admin_menu', function () {
    global $submenu;

    if ( isset( $submenu[ 'themes.php' ] ) ) {
        foreach ( $submenu[ 'themes.php' ] as $index => $menu_item ) {
            if ( in_array( 'customize', $menu_item ) ) {
                unset( $submenu[ 'themes.php' ][ $index ] );
            }
        }
    }
});
Emanuel A.
  • 112
  • 1
  • 8
1

Works in wordpres 5.*

Removing Customize from Wordpress Admin you need to remove from the sidebar and from the top bar in front end as well

From the Sidebar Menu

add_action( 'admin_menu', 'remove_customize' );

function remove_customize() {
    global $submenu;
    if ( isset( $submenu[ 'themes.php' ] ) ) {
        foreach ( $submenu[ 'themes.php' ] as $index => $menu_item ) {
            if(in_array('Customize', $menu_item) || in_array('Customizer', $menu_item) || in_array('customize', $menu_item))
            {
                unset( $submenu[ 'themes.php' ][ $index ] );
            }
        }
    }
}

From Admin bar in top (In The front End)

add_action( 'admin_bar_menu', 'remove_customize_menu_bar', 999 );

function remove_customize_menu_bar( $wp_admin_bar ) {
    $wp_admin_bar->remove_node( 'customize' );
}

This will completely disable the customize option :)

  • This worked perfectly for me. Little sidenote: it does not remove the customizer completely as there are still buttons directing to it from Theme's. – Web Tailor May 05 '20 at 16:14
1

For WordPress 5

add_action( 'admin_menu', function() {
    remove_submenu_page( 'themes.php', 'customize.php?return=' . urlencode($_SERVER['SCRIPT_NAME']));
}, 999 )
FooBar
  • 5,752
  • 10
  • 44
  • 93
0

Try changing 'admin_init' in 'admin_menu'

Sjors
  • 1,205
  • 1
  • 8
  • 24
0

@bash88 answer and @Emanuel A. answer works but if you want also remove buttons (blue customize buttons) from themes page answer should be:

Tested WordPress 5.0.3

/**
 * Remove customize links from admin panel.
 */
function admin_remove_customize_links() {
    echo '<style>.hide-if-no-customize { display: none !important; }</style>';
}
add_action( 'admin_head', 'admin_remove_customize_links' );
Enes Sahin
  • 11
  • 1
0

Update of the approved response (Wordpress 5)

add_action( 'admin_menu', 'rompiot_remove_customize' );

/**
 * Remove Admin Menu Link to Theme Customizer
 */
public function rompiot_remove_customize()
{
    global $submenu;

    if (isset($submenu['themes.php'])) {
        
        foreach ($submenu['themes.php'] as $index => $array_menu_item) {

            foreach ($array_menu_item as $key => $menu_item) {
                if (in_array($menu_item, ['Customize', 'Customizer', 'customize'])) {
                    unset($submenu['themes.php'][$index]);
                }
            }                

        }
    }
}
Rompiot
  • 1
  • 1
0

FUNCTIONING CODE AS OF WORDPRESS 5.7+, AUGUST 2021

I needed to customize the WP admin bar for a large WP site we are working on (text was running off the admin bar when resizing). I tried literally every snippet of code from all the previous answers to this question; unfortunately none worked for me. This code I found off Google did, so I wanted to share with others (goes in your functions.php):

/**
 * This function removes items from the WP admin bar. If it gets too cluttered,
 * things will run off the screen and look bad.
 * @param object $wp_admin_bar representing the WP admin bar.
 */
function remove_from_admin_bar($wp_admin_bar) {
    // WordPress Core Items (uncomment to remove)
    $wp_admin_bar->remove_node('updates');
    $wp_admin_bar->remove_node('comments');
    //wp_admin_bar->remove_node('new-content');
    $wp_admin_bar->remove_node('wp-logo');
    //$wp_admin_bar->remove_node('site-name');
    //$wp_admin_bar->remove_node('my-account');
    //$wp_admin_bar->remove_node('search');
    $wp_admin_bar->remove_node('customize');
}

add_action('admin_bar_menu', 'remove_from_admin_bar', 999);

I think a great start is to remove the comments, updates, and WP icon. Custom plugins can be disabled here, too. The 999 indicates when the hook will fire off later. You can wrap elements in the is_admin() function if you want to hide or show different links on the front end vs. the WP admin.

Edward B.
  • 437
  • 3
  • 10