[wp-trac] [WordPress Trac] #22895: user_can_admin_menu() is Type-Insensitive for Users who Can't Create Pages

WordPress Trac noreply at wordpress.org
Fri Jul 18 13:49:41 UTC 2014


#22895: user_can_admin_menu() is Type-Insensitive for Users who Can't Create Pages
-----------------------------------------------+---------------------------
 Reporter:  kevinB                             |       Owner:
     Type:  defect (bug)                       |      Status:  new
 Priority:  normal                             |   Milestone:  Future
Component:  Role/Capability                    |  Release
 Severity:  normal                             |     Version:  3.5
 Keywords:  has-patch needs-testing 3.7-early  |  Resolution:
                                               |     Focuses:
-----------------------------------------------+---------------------------

Comment (by Solinx):

 Replying to [comment:13 nacin]:
 > Replying to [comment:12 johnbillion]:
 > > I've just run into this problem. A user who doesn't have the
 `create_posts` capability for a custom post type can't see the edit menu
 for that post type unless they also have the general `edit_posts`
 capability. This is caused by `$parent` in `user_can_access_admin_page()`
 being empty when it shouldn't.
 >
 > So [attachment:22895.diff] would be the wrong fix? Patch welcome for
 sure.

 I've also run into this exact issue as described by johnbillion.

 To be honest I found the code dealing with menu rights to be quite a mess.
 A rewrite or at least some documentation wouldn’t hurt, but obviously both
 take quite a bit of time. In the meantime there are several possible
 solutions to this problem.

 1. Address `$parent` being empty - quick fix
 2. Add `$typenow` to `$pagenow` - quick fix
 3. Consider changes that are (potentially) more impactful and time
 consuming


 ----

 1. Address `$parent` being empty

 To address the problem by setting a $parent value the following code could
 be added to `get_admin_page_parent()` at line 1525:
 {{{
         if ( !empty($typenow) ) {
                 foreach ( $menu as $menuitem ) {
                         if ( $menuitem[2] ===
 "$pagenow?post_type=$typenow" ) {
                                 return $parent_file =
 "$pagenow?post_type=$typenow";
                         }
                 }
         }
 }}}
 Besides in `user_can_access_admin_page()`, `get_admin_page_parent()` is
 also used to determine page title and page hook.

 The above code does not influence the former. I have not tested whether it
 influences the latter, but if it does, it would be for the better. Plugin
 and theme authors would not expect the hook of the post_type edit page to
 change (which I think it does upon becoming a parent menu item after
 removing the create_posts capability).

 The con to this solution is that the page being visited in reality has no
 parent page. There is essentially nothing wrong with `$parent` being empty
 in `user_can_access_admin_page()`, because there is no parent. For this
 reason I prefer solution 2 and did not look into the above points any
 further.


 ----
 2. Add `$typenow` to `$pagenow`

 The initial solution I came up with closely resembles what you did and is
 also located at the same place in `user_can_access_admin_page()`:
 {{{
 if ($pagenow === 'edit.php' && isset($_REQUEST['post_type']))
                 $curpage .= '?post_type=' . $_REQUEST['post_type'];
         else
                 $curpage = $pagenow;
 }}}
 Our solutions effectively differ at only one point. I also check whether
 the current page is an 'edit.php' page. My reason for adding this check
 was to limit any possible side effects - this issue is limited to edit.php
 pages.

 The con to this solution is that it feels like a hack and does not help
 improve the quality of the code structure. That said, I strongly recommend
 implementing this solution as a short term fix to this particular issue.


 ----

 3. Consider changes that are (potentially) more impactful and time
 consuming

 As noted, the `$parent` value being empty in
 `user_can_access_admin_page()` is actually as it should be. If you
 consider that, there are a few problems with
 `user_can_access_admin_page()`, where the second solution is a fix
 targeted to this specific case.

 a.) Admin pages with an empty `$parent` value are passed by blacklists
 targeted at submenu items.

 Unless submenu items can be created without a parent menu item there is no
 sense to this. The specific issue of this ticket is resolved if the checks
 for submenu items are removed. It is the Posts submenu item that causes
 the permission denied message, because that is the only ‘edit.php’ submenu
 without GET strings attached in the keys.

 I do not know what the full impact of removing the submenu blacklists will
 be. This will have to be studied.


 b.) The permission blacklists used in case `$parent` is empty include GET
 strings in the array keys, while the checks are made without GET strings

 Fixing this inconsistency for this specific case is what solution 2 is
 aimed at. The code is not quite future proof, but that may not be a
 concern if a rewrite is planned anyhow.


 c.) A blacklist system is used to check whether a user has access to a
 certain page.

 Blacklisting is generally a bad idea. Any rewrite attempt should use
 whitelists instead.

 The use of blacklists is not limited to the situation where `$parent` is
 empty. The `user_can_access_admin_page()` function defaults to `true` if
 no matches can be found - which effectively means the whole function is
 designed as a blacklist system.


 Each of these options need further attention if they are to be pursued,
 and could then just as well be the start of a rewrite.

 ----


 In sum, I would for now recommend implementing solution 2, or your earlier
 code, in the upcoming update. It may not be perfect, but it does solve a
 production issue and can be implemented now without any apparent negative
 effects.

 I hope there is still time to make this part of 4.0.

 Cheers,
 W. van Dam

--
Ticket URL: <https://core.trac.wordpress.org/ticket/22895#comment:17>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list