2

I would like specific users to only see the WooCommerce -> Settings -> Shipping menu. I've managed to remove other tabs e.g. Products, Payments, etc, but stuck on the following 2 things that I want to to accomplish:

  1. Remove the "GENERAL" Tab in WooCommerce Settings.
  2. Remove the "ORDER STATUSES" Tab from a plugin. (Note: this isn't a tab exactly, the slug is 'edit.php?post_type=wc_order_status')

enter image description here

When I try to remove the GENERAL tab, it eliminates the entire Settings menu. As for the 'Order Statuses', my code just doesn't work.

add_filter( 'woocommerce_settings_tabs_array', 'remove_woocommerce_setting_tabs', 200, 1 );
function remove_woocommerce_setting_tabs( $array ) {

    global $current_user;

    //Declare the tabs we want to hide
    $tabs_to_hide = array(
        'general'         => 'General', //this one removes the entire Settings menu
        'wc_order_status' => 'Order Statuses'// this doesn't work, maybe bc it's a post_type
        );

    // Remove tab if user role is shipping_manager
    if ( in_array("shipping_manager", $$current_user->roles) ) {
        $array = array_diff_key($array, $tabs_to_hide);
    }
}

I had also tried the below code to remove the ORDER STATUSES tab, but still no luck:

    add_action( 'admin_menu', 'remove_order_statuses_tab', 999);
    function remove_order_statuses_tab() 
    {
      global $current_user;

      if ( in_array("shipping_manager", $current_user->roles) ) {
            remove_menu_page( 'edit.php?post_type=wc_order_status' ); //not working either
         }

    }
5
  • So you want them to still have access to the Shipping Options? Because if you want them to not have access to any of it, that's an easier fix. Commented Apr 18, 2020 at 0:12
  • Correct. I just want them to have only the Shipping Options available to them. I don't want them to have access to the other settings options; this user role is to manage shipping options only.
    – Les
    Commented Apr 19, 2020 at 13:49
  • Is the Order Statuses tab input by a secondary plugin? I seem to remember that being the case on a site I once worked on. Commented Apr 19, 2020 at 16:49
  • Wow, this is infuriating... ...I've been testing a bunch of methods and everything works EXCEPT it always first loads the general settings screen. Just working on resolving that. Commented Apr 19, 2020 at 17:42
  • To the question on Order Statuses - yes, this is a 3rd party plugin and is accessed as follows: 'edit.php?post_type=wc_order_status'. Unlike the other tabs that are accessed as 'admin.php?page=wc-settings&tab=shipping' for example.
    – Les
    Commented Apr 19, 2020 at 18:07

2 Answers 2

1

So it turns out that because of the way the WC settings page is built, that you can't unset the general screen. The tab, sure, but clicking on the WooCommerce settings in the dashboard submenu will always load the General settings, even if the tab is missing. So I wrote two different functions to remove all of it and the second function just so happens to allow us to also remove the Order Status screen. (Not sure about the tab though, but you can hide that with CSS because we'll already be making sure users can't navigate to that panel if they're lowly shipping_managers.)

add_filter( 'woocommerce_settings_tabs_array', 'remove_woocommerce_setting_tabs', 200, 1 );
function remove_woocommerce_setting_tabs( $array ) {
    global $current_user;
    if( in_array( 'shipping_manager', $current_user->roles ) ) {
        unset( $array[ 'general' ] );
        unset( $array[ 'products' ] );
        unset( $array[ 'tax' ] );
        unset( $array[ 'checkout' ] );
        unset( $array[ 'account' ] );
        unset( $array[ 'email' ] );
        unset( $array[ 'integration' ] );
        unset( $array[ 'advanced' ] );
        echo '<script>jQuery( document ).ready( function($) { $( \'[href="' . admin_url() . '/edit.php?post_type= wc_order_status"]\' ).hide(); } );</script>';
    }
    return $array;
}
add_action( 'admin_init', 'redirect_from_settings_screen' );
function redirect_from_settings_screen() {
    global $pagenow;
    global $current_user;
    if( in_array( 'shipping_manager', $current_user->roles ) ) {
        if( $pagenow == 'admin.php' && isset( $_GET['page'] ) && $_GET['page'] == 'wc-settings' && !isset( $_GET['tab'] ) ) {
            wp_redirect( admin_url( '/admin.php?page=wc-settings&tab=shipping' ) );
            exit;
        }
        if( $pagenow == 'edit.php' && isset( $_GET['post_type'] ) && $_GET['post_type'] == 'wc_order_status' ) {
            wp_redirect( admin_url( '/admin.php?page=wc-settings&tab=shipping' ) );
            exit;
        }
    }
}

So here's a breakdown, the first function allow us to remove all of the WC Settings Tabs, including General. Works like a treat except for the fact that navigating to the WC Settings screen will, by default, load the General settings fields. So that's no good. But, everything else is gone and the shipping tab is visible and works perfectly.

Next we have a function to redirect access to the General Settings screen admin.php?page=wc-settings to route people to admin.php?page=wc-settings&tab=shipping.

Then I add on a second check to see if $pagenow is on the Order Status screen, check for the post_type and if it's wc_order_status and if it is, redirect it to Shipping again.

Now, the first function removes the tabs for all those different settings panels, but a user could technically still access the URLs if they know them. So you could repeat the set-up of the General -> Shipping redirect, or do it as an array of tabs and make sure that even manual attempts to access the other tabs reroute to Shipping.

NOTE

I don't have a shipping_manager user role to test with so hopefully that won't pose any problems.

12
  • The first part for eliminating the General tab works great, thanks! The second part doesn't quite work as the Order Status tab is still displaying. Also the way to access the Order statuses is on the edit.php not admin.php i.e. wp-admin/edit.php?post_type=wc_order_status. I tried to change the if $pagenow == 'edit.php', but that didn't do it.
    – Les
    Commented Apr 19, 2020 at 19:25
  • You'll have to hide the tab via CSS. I can't assist with that because I don't have the plugin so I can't figure out which id or class to target. But it should be straight forward. For the Order Status redirect you'll need to match the full .php & parameter path - I may have gotten it wrong because I can't actually see the full path myself. Commented Apr 19, 2020 at 19:42
  • What would I be looking for in the plugin in terms of the id and class, and then how would I hide it? Here's what I get when I inspect the element just on the browser. <nav class="nav-tab-wrapper woo-nav-tab-wrapper"> <a href="example.com/wp-admin/…" class="nav-tab nav-tab-active">Shipping</a> <a href="example.com/wp-admin/edit.php?post_type=wc_order_status" class="nav-tab ">Order Statuses</a> </nav>
    – Les
    Commented Apr 19, 2020 at 19:57
  • Wow, the plugin developer didn't provide any differentiation for their own custom tab. Not cool. So now I guess we have to consider using jQuery to .hide() that one tab. I'll amend my answer. Commented Apr 19, 2020 at 20:16
  • I've updated the solution with a bit of jQuery (similar to a part of @mujuonly's answer) that will hide the tab. I personally wouldn't put it there but would add it to your plugin's main xxx.js file. Commented Apr 19, 2020 at 20:29
1

Here is the simple answer

add_filter( 'woocommerce_settings_tabs_array', 'remove_woocommerce_setting_tabs', 200, 1 );

function remove_woocommerce_setting_tabs( $array ) {

        global $current_user;

        // Remove tab if user role is shipping_manager

        if ( in_array( "shipping_manager", $current_user->roles ) ) {
            unset( $array[ 'general' ] );
            ?>
                <script>
            document.querySelector("[href='<?php echo esc_url( admin_url( 'edit.php?post_type=wc_order_status' ) ); ?>']").style.display = 'none';

            </script>
        <?php
    }
    return $array;
}
6
  • That just hides the tab but still allows users to navigate to it. Commented Apr 19, 2020 at 19:38
  • Can you help me understand how the querySelector() works. Also, I don't want to hard-code the domain - any way around this?
    – Les
    Commented Apr 19, 2020 at 19:53
  • @Les Check the updated answer
    – mujuonly
    Commented Apr 20, 2020 at 4:03
  • Still not working. Not sure what's the issue.
    – Les
    Commented Apr 20, 2020 at 6:49
  • @Les - Checking as administrator or shop_manager?
    – mujuonly
    Commented Apr 20, 2020 at 7:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.