Remove submenu page "customize.php" in WordPress 4.0 - wordpress

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.

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 );

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

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');

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.

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!

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);

WordPress >= 4.9.8
add_action('admin_menu', function () {
$request = urlencode($_SERVER['REQUEST_URI']);
remove_submenu_page('themes.php', 'customize.php?return='. $request);
}, 999);

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 ] );
}
}
}
});

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 :)

For WordPress 5
add_action( 'admin_menu', function() {
remove_submenu_page( 'themes.php', 'customize.php?return=' . urlencode($_SERVER['SCRIPT_NAME']));
}, 999 )

Try changing 'admin_init' in 'admin_menu'

#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' );

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]);
}
}
}
}
}

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.

Related

Detect a screen option change in WordPress Admin

In WordPress code, how can I detect a screen option change? Ie, in the below image I want to hook when one of the column screen options changes. Is there a specific hook for this?
My usecase:
I need to add a screen option to the 'All Posts' page. If the user has unchecked my screen option then the All Posts table should not display posts that have a certain category. I have pretty much all my code for this usecase working (see below) apart from being able to hook/detect when 'My Custom Screen Option' is changed (ticked on or off). If I can do that I can then update the users meta with this decision.
function add_custom_columns( $columns ) {
$columns['display_xyz'] = __( 'XYZ Posts' );
return $columns;
}
add_filter( 'manage_posts_columns', 'add_custom_columns' );
function set_sortable_columns( $columns ) {
$columns['display_xyz'] = 'display_xyz';
return $columns;
}
add_filter( 'manage_edit-post_sortable_columns', 'set_sortable_columns' );
function sort_all_posts( $query ) {
global $current_screen;
// If on 'All Posts' page.
if ( isset( $current_screen ) && is_admin() && $current_screen->id === 'edit-post' && $query->query_vars['post_type'] === 'post' ) {
$show_xyz_posts = get_user_meta( get_current_user_id(), 'display_xyz' );
if ( ! $show_xyz_posts ) {
// Edit $query to not retrieve posts that have a specific category 'xyz'
}
}
}
add_filter( 'parse_query', 'sort_all_posts' );
// How to detect change of my custom screen option so I can hook the below option??
function on_change_screen_option($option, $value) {
if ( $option === 'display_xyz' ) {
update_user_meta( get_current_user_id(), 'display_xyz', $value );
}
}
add_action( '???', 'on_change_screen_option' );

How to add custom stylesheet to TinyMCE in WordPress via a plugin?

I am trying to add a custom stylesheet to the TinyMCE editor in a WordPress plugin I am developing. The WP codex tells me to use the mce_css filter, but it does not seam to work.
As soon, as I use the filter, all the theme's custom stylesheets disappears from the editor, but my custom stylesheet is still not there.
See the following two screenshots, the first without the filter, the second with the filter activated:
Here is my code:
class test_plugin {
function __construct($args = array()){
if ( is_admin() ){
add_action('admin_head', array( $this, 'admin_head') );
add_action( 'admin_enqueue_scripts', array($this , 'admin_enqueue_scripts' ) );
}
}
function admin_head() {
if ( !current_user_can( 'edit_posts' ) && !current_user_can( 'edit_pages' ) ) {
return;
}
if ( 'true' == get_user_option( 'rich_editing' ) ) {
add_filter( 'mce_css', 'plugin_mce_css' );
}
}
function admin_enqueue_scripts(){
// wp_enqueue_style('fa_icon_shortcode', plugins_url( 'css/mce-button.css' , __FILE__ ) );
}
function plugin_mce_css( $mce_css ) {
if ( ! empty( $mce_css ) )
$mce_css .= ',';
$mce_css .= plugins_url( 'editor.css', __FILE__ );
return $mce_css;
}
}
new test_plugin();
Any idea what goes wrong here?
It actually was a pretty simple solution. Since I am using OOP, I had to add the filter with
add_filter( 'mce_css', array( $this , 'plugin_mce_css' ) );
instead of
add_filter( 'mce_css', 'plugin_mce_css' );
Works like charm!

WordPress SEO plugin only visible to specific user

I am using the Yoast SEO plugin in WordPress and wanted to know if there was a way to make it only visible to one specific user in the db or in the functions.php file? Not a role, an actual user.
I tried an universal solution to simply add "plugin-name" and disable it, but failed.
But, to show WPSEO only to a specific user (ID equals 2), the following works:
add_action( 'plugins_loaded', 'seo_so_25654837' );
function seo_so_25654837()
{
if ( '2' == get_current_user_id() )
return;
remove_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
}
Don't add the code to functions.php, use it as a normal plugin.
The following is also needed to remove the SEO menu from the admin bar:
add_action( 'wp_before_admin_bar_render', 'bar_so_25654837' );
function bar_so_25654837()
{
if ( '2' == get_current_user_id() )
return;
global $wp_admin_bar;
$nodes = $wp_admin_bar->get_nodes();
foreach( $nodes as $node )
{
if( !$node->parent )
{
if( 'wpseo-menu' === $node->id )
$wp_admin_bar->remove_menu( $node->id );
}
}
}
You can hook to pre_current_active_plugins to remove elements from the table before it is displayed. Using get_current_user_id() within the function will let you selectively hide a plugin.
function hide_plugins_by_user( $all_plugins=false ) {
global $wp_list_table;
// if the current user ID is not 1, hide it.
if ( 1 != get_current_user_id() ){
// the active plugins from the table
$plugins = $wp_list_table->items;
// loop through them
foreach ( $plugins as $key => $val ) {
// use the dir + filename of the plugin to hide
if ( $key == 'plugindir/plugin.php' ) {
unset( $wp_list_table->items[$key] );
}
}
}
}
add_action( 'pre_current_active_plugins', 'hide_plugins_by_user' );
This code is working fine (Credits goes to Hislop):
// Returns true if user has specific role
function check_user_role( $role, $user_id = null ) {
if ( is_numeric( $user_id ) )
$user = get_userdata( $user_id );
else
$user = wp_get_current_user();
if ( empty( $user ) )
return false;
return in_array( $role, (array) $user->roles );
}
// Disable WordPress SEO meta box for all roles other than administrator and seo
function wpse_init(){
if( !(check_user_role('seo') || check_user_role('administrator')) ){
// Remove page analysis columns from post lists, also SEO status on post editor
add_filter('wpseo_use_page_analysis', '__return_false');
// Remove Yoast meta boxes
add_action('add_meta_boxes', 'disable_seo_metabox', 100000);
}
}
add_action('init', 'wpse_init');
function disable_seo_metabox(){
remove_meta_box('wpseo_meta', 'post', 'normal');
remove_meta_box('wpseo_meta', 'page', 'normal');
}
Just place it in the functions.php file.
To disable the Yoast for all the users and enable it for just for few or specific, just add the following piece of code to your function.php file.
function remove_wpseo(){
/* if you want to keep it enabled for user with id 2 */
if ( '2' == get_current_user_id() ) {
return;
}
global $wpseo_front;
if(defined($wpseo_front)){
remove_action('wp_head',array($wpseo_front,'head'),1);
}
else {
$wp_thing = WPSEO_Frontend::get_instance();
remove_action('wp_head',array($wp_thing,'head'),1);
}
}
add_action('template_redirect','remove_wpseo');
Reference: https://makersbyte.com/disable-yoast-seo-plugin-specific-page/

Redirect from edit.php to different page in wordpress backend

Trying to setup a redirect for Wordpress backend. I have used this code:
function redirected_admin_pages(){
global $pagenow;
if($pagenow == 'edit.php'){
wp_redirect('edit.php?post_status=publish&post_type=post');
exit;
}
}
add_action('admin_init', array($this, 'redirected_admin_pages'));
I based it on the answer here https://wordpress.stackexchange.com/questions/52114/admin-page-redirect
For some reason I cant get it work. What am I doing wrong?
Well I got there in the end with a login redirect, see function below:
add_action( 'admin_menu', 'name_changing_thing' );
function name_changing_thing() {
global $submenu;
foreach( $submenu['edit.php'] as $key => $value )
{
if( in_array( 'edit.php', $value ) )
{
$submenu['edit.php'][ $key ][2] = 'edit.php?post_status=publish&post_type=post';
}
}
}
Thank you to anyone who looked.

remove columns from woocommerce product page

Hi I am trying to limit the options certain users have when viewing the products list within woocommerce for wordpress admin pages.
if( current_user_can('vendor') ) {
function my_columns_filter( $columns ) {
unset($columns['tags']);
unset($columns['featured']);
unset($columns['type']);
return $columns;
}
}
add_filter( 'manage_edit-product_columns', 'my_columns_filter', 10, 1 );
Any help or guidance would be much appreciated.
You're doing it wrong.
Place if/else inside the function instead of wrapping the function.
function my_columns_filter( $columns ) {
if( current_user_can('vendor') ) {
unset($columns['tags']);
unset($columns['featured']);
unset($columns['type']);
return $columns;
}
}
add_filter( 'manage_edit-product_columns', 'my_columns_filter', 10, 1 );
You are not using the correct column names, or perhaps WC has changed them since you posted your question. It also better to check if a column still exists before removing it in case WC does change their column names.
Here is a future proof solution you can past into your theme's functions.php:
function my_product_columns_filter( $columns ) {
if ( current_user_can( 'vendor' ) ) {
foreach ( array( 'product_tag', 'featured', 'product_type' ) as $name ) {
if ( isset( $columns[ $name ] ) ) {
unset( $columns[ $name ] );
}
}
}
return $columns;
}
add_filter( 'manage_edit-product_columns', 'my_product_columns_filter' );
no coding solution
If you're just looking for a quick solution without the need for coding, you could use the free admin columns plugin from wordpress.org, which allows you to add and remove columns with a few clicks.

Resources