0

I'm trying to write a simple permission admin page plugin. So far I made a page with every role where I can check a certain menu page to be disabled from menu. I simply get global $menu and save to option encoded to JSON array.

Example:

    array(2) {
  ["sub_administrator"]=>
  array(11) {
    [0]=>
    string(10) "menu-posts"
    [1]=>
    string(19) "toplevel_page_wpcf7"
    [2]=>
    string(15) "menu-appearance"
    [3]=>
    string(12) "menu-plugins"
    [4]=>
    string(10) "menu-tools"
    [5]=>
    string(13) "menu-settings"
    [6]=>
    string(32) "toplevel_page_edit?post_type=acf"
    [7]=>
    string(30) "toplevel_page_bwp_capt_general"
    [8]=>
    string(40) "toplevel_page_mr_permissions_admin_pages"
    [9]=>
    string(23) "toplevel_page_Wordfence"
    [10]=>
    string(28) "toplevel_page_wp-user-avatar"
  }
}

Later using admin_menu hook I remove from display a certain menu item

function mr_permissions_roles_admin_menu_restriction() {
        echo'<pre>';
        global $menu;
        $restricted=array();

        $current_user=wp_get_current_user();        
        $role_restriction=get_option('mr_permissions_roles');
        $role_restriction=(array)json_decode($role_restriction);
        $role=$current_user->roles[0];
        if(!empty($role_restriction[$role]))
        {
            $restricted=$role_restriction[$role];
        }


        foreach ( $menu as $item => $data ) {
            if ( ! isset( $data[5] ) ) {
                continue; // Move along if the current $item doesn't have a slug.
            } elseif ( in_array( $data[5], $restricted ) ) {
                unset( $menu[$item] ); // Remove the current $item from the $menu.
            }
        }
        echo'</pre>';
    }

    add_action( 'admin_menu', 'mr_permissions_roles_admin_menu_restriction',20);

That's the easy part here.

Now I want before every admin page to load check if user has plugin permission to go to page (people still can go to page by url).

I made something that works but not everywhere. I explain under code.

function mr_permissions_roles_admin_page_restriction($screen)
    {

        global $menu;
        $current_user=wp_get_current_user();
        $role_restriction=get_option('mr_permissions_roles');
        $role_restriction=(array)json_decode($role_restriction);
        $role=$current_user->roles[0];
        if(in_array($screen->base,$role_restriction[$role]))
            exit('<!DOCTYPE html> <!-- Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono --> <html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width"> <title>WordPress &rsaquo; Błąd</title> <style type="text/css"> html { background: #f1f1f1; } body { background: #fff; color: #444; font-family: "Open Sans", sans-serif; margin: 2em auto; padding: 1em 2em; max-width: 700px; -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13); box-shadow: 0 1px 3px rgba(0,0,0,0.13); } h1 { border-bottom: 1px solid #dadada; clear: both; color: #666; font: 24px "Open Sans", sans-serif; margin: 30px 0 0 0; padding: 0; padding-bottom: 7px; } #error-page { margin-top: 50px; } #error-page p { font-size: 14px; line-height: 1.5; margin: 25px 0 20px; } #error-page code { font-family: Consolas, Monaco, monospace; } ul li { margin-bottom: 10px; font-size: 14px; } a { color: #0073aa; } a:hover, a:active { color: #00a0d2; } a:focus { color: #124964; -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); outline: none; } .button { background: #f7f7f7; border: 1px solid #ccc; color: #555; display: inline-block; text-decoration: none; font-size: 13px; line-height: 26px; height: 28px; margin: 0; padding: 0 10px 1px; cursor: pointer; -webkit-border-radius: 3px; -webkit-appearance: none; border-radius: 3px; white-space: nowrap; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; -webkit-box-shadow: 0 1px 0 #ccc; box-shadow: 0 1px 0 #ccc; vertical-align: top; } .button.button-large { height: 30px; line-height: 28px; padding: 0 12px 2px; } .button:hover, .button:focus { background: #fafafa; border-color: #999; color: #23282d; } .button:focus { border-color: #5b9dd9; -webkit-box-shadow: 0 0 3px rgba( 0, 115, 170, .8 ); box-shadow: 0 0 3px rgba( 0, 115, 170, .8 ); outline: none; } .button:active { background: #eee; border-color: #999; -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 ); box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 ); -webkit-transform: translateY(1px); -ms-transform: translateY(1px); transform: translateY(1px); } </style> </head> <body id="error-page"> <p>Nie posiadasz wystarczających uprawnień, by wejść na tę stronę.</p></body> </html> ');
        if($current_user->ID!=38)
        {
            echo '<pre>';
            //var_dump($screen);
            echo '</pre>';
        }
    }
    add_action('current_screen','mr_permissions_roles_admin_page_restriction');

I found that current_screen hook. Well hook which I wanted but not exactly. For example to post menu item slug is menu-posts. In $screen variable and $menu variable there no single thing I can compare. For custom admin menu pages it works well. $menu slug is in $screen->base so I can compare it. But when it comes to built-in pages it doesn't work. So here are a few questions which may solve my problem.

  1. How to get admin menu item. Then I can save it in a different way and compare differently.

  2. Is there any way I can get more data from current_screen.

  3. Any other ideas?

  4. (bonus) How can I get submenu pages for example for posts. global $menu doesn't have it. I would like to add to my plugin possibility to disable access to submenu pages (a few of them not all for example)

I even tried to look into database for any information but couldn't find anything.

I also made a custom page to edit every user to let them add posts to one or few of my custom_posts. So for default Editor have no right to custom_posts. When I want to make someone who will for example add companies (custom_post) I go to users and I check checkbox and save. From now on this user with role editor can edit companies but others editors can't.

2 Answers 2

0

WordPress has a fairly good roles and capabilities system already and, IMHO, you'd find it easier working with that.

When the admin menu is constructed, every item on the admin menu is subject to a check on a relevant capability. Similarly every attempt to use an admin screen is checked.

It's possible to use map_meta_cap to rework some of these permissions. For example, I like to make my clients Editors of their websites but also allow them to manage widgets and menus without being able to make other theme changes. I use this snippet:

add_filter( 'map_meta_cap', 'tbdn_map_meta_cap', 10, 4 );

function tbdn_map_meta_cap( $caps, $cap, $user_id, $args ) {

    if ( 'edit_theme_options' == $cap ) {

        $screen = get_current_screen();

        $caps = array( 'edit_theme_options' );

        switch ( $screen->id ) {
            case 'widgets':
                $caps[] = 'manage_widgets';
                break;
            case 'nav-menus':
                $caps[] = 'manage_nav_menus';
                break;

        }

    }
    return $caps;
}

This traps the check for the default capability of edit_theme_options and if you are trying to access the widgets screen it adds a manage_widgets capability to the list of sufficient capabilities for using this screen. Similarly the nav-menus screen is given its own capability.

Then you can use an existing role management plugin to turn off edit_theme_options for a role or user, removing access to all the theme option screens. Then give the role/user manage_widgets and manage_nav_menus capabilities and they can get to those screens without having further access to theme options.

Combine this with your editing of the admin menu and you should be good to go.

1
  • Please check my EDIT. Anyway i read about your idea and will try figure something out with this.
    – Mr 660
    May 18, 2016 at 12:57
0

Well guys i post answet for anybody interested! I edited mr_permissions_roles_admin_page_restriction function because i noticed one thing: the restrictions i save are URL!

so well here it is:

function mr_permissions_roles_admin_page_restriction($screen)
{
    $block=FALSE;
    $url=str_replace('/wp-admin/','',$_SERVER['REQUEST_URI']);
    global $menu;
    $current_user=wp_get_current_user();        
    $role_restriction=get_option('mr_permissions_roles');
    $role_restriction=(array)json_decode($role_restriction);
    $role=$current_user->roles[0];

    if(in_array($screen->base,$role_restriction[$role]))
        $block=TRUE;
    else if(in_array($url,$role_restriction[$role]))
        $block=TRUE;
    else if(in_array($_GET['page'],$role_restriction[$role]))
        $block=TRUE;
    if($block)
        wp_die('Nie posiadasz wystarczających uprawnień, by wejść na tę stronę.');          
}
add_action('current_screen','mr_permissions_roles_admin_page_restriction');

Your Answer

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

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