Version Description
- Tested with WordPress 3.8.
- Fixed several minor UI/layout issues related to the new 3.8 admin style.
- Fixed a bug where moving an item to a plugin menu and then deactivating that plugin would cause the moved item to disappear.
- Fixed deleted submenus not being restored if their original parent menu is no longer available.
- Fixed a rare glitch where submenu separators added by certain other plugins would sometimes disappear.
- Fixed a conflict with Shopp 1.2.9.
- Made the plugin treat "users.php" and "profile.php" as the same parent menu. This fixes situations where it would be impossible to hide a "Users" submenu item from roles that don't have access to the "Users" menu and instead get a "Profile" menu.
- Added extra logging for situations where a menu item is hidden because a higher-priority item with the same URL is also hidden.
- Minor performance improvements.
Download this release
Release Info
| Developer | whiteshadow |
| Plugin | |
| Version | 1.3.1 |
| Comparing to | |
| See all releases | |
Code changes from version 1.3 to 1.3.1
- css/menu-editor.css +24 -58
- css/screen-meta-old-wp.css +57 -0
- css/screen-meta.css +43 -0
- includes/editor-page.php +45 -4
- includes/menu-editor-core.php +239 -20
- includes/menu-item.php +41 -12
- includes/menu.php +50 -10
- includes/settings-page.php +21 -6
- js/menu-editor.js +67 -3
- menu-editor.php +1 -1
- readme.txt +14 -3
css/menu-editor.css
CHANGED
|
@@ -102,7 +102,7 @@
|
|
| 102 |
clear: both;
|
| 103 |
display: block;
|
| 104 |
margin: 4px;
|
| 105 |
-
width:
|
| 106 |
}
|
| 107 |
|
| 108 |
#ws_menu_editor #ws_save_menu {
|
|
@@ -289,7 +289,7 @@
|
|
| 289 |
#ws_menu_access_editor .ws_dropdown_button
|
| 290 |
{
|
| 291 |
width: 20px;
|
| 292 |
-
height:
|
| 293 |
|
| 294 |
margin: 1px 1px 1px 0;
|
| 295 |
padding: 0;
|
|
@@ -561,6 +561,9 @@ select.ws_dropdown optgroup option {
|
|
| 561 |
margin: 0;
|
| 562 |
padding: 0;
|
| 563 |
position: relative;
|
|
|
|
|
|
|
|
|
|
| 564 |
}
|
| 565 |
|
| 566 |
/* Current icon node (CSS class version, for the built-in WP icon sprites) */
|
|
@@ -611,12 +614,19 @@ select.ws_dropdown optgroup option {
|
|
| 611 |
|
| 612 |
.ui-widget-overlay {
|
| 613 |
background-color: black;
|
| 614 |
-
position:
|
| 615 |
left: 0;
|
| 616 |
top: 0;
|
| 617 |
opacity: 0.70;
|
| 618 |
-moz-opacity: 0.70;
|
| 619 |
-
filter: alpha(opacity=70);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 620 |
}
|
| 621 |
|
| 622 |
.ui-dialog {
|
|
@@ -689,6 +699,8 @@ select.ws_dropdown optgroup option {
|
|
| 689 |
height: 23px;
|
| 690 |
text-align: right;
|
| 691 |
margin-top: 20px;
|
|
|
|
|
|
|
| 692 |
}
|
| 693 |
|
| 694 |
.ws_dialog_buttons .button-primary {
|
|
@@ -718,6 +730,11 @@ select.ws_dropdown optgroup option {
|
|
| 718 |
padding-top: 25px;
|
| 719 |
}
|
| 720 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 721 |
/************************************
|
| 722 |
Menu access editor
|
| 723 |
*************************************/
|
|
@@ -886,6 +903,8 @@ select.ws_dropdown optgroup option {
|
|
| 886 |
}
|
| 887 |
|
| 888 |
#ws_sidebar_pro_ad {
|
|
|
|
|
|
|
| 889 |
margin-top: 5px;
|
| 890 |
margin-left: 3px;
|
| 891 |
|
|
@@ -893,57 +912,4 @@ select.ws_dropdown optgroup option {
|
|
| 893 |
right: 20px;
|
| 894 |
bottom: 40px;
|
| 895 |
z-index: 100;
|
| 896 |
-
}
|
| 897 |
-
|
| 898 |
-
/************************************
|
| 899 |
-
Screen meta buttons
|
| 900 |
-
*************************************/
|
| 901 |
-
|
| 902 |
-
/* All buttons */
|
| 903 |
-
#ws-pro-version-notice {
|
| 904 |
-
float: right;
|
| 905 |
-
height: 22px;
|
| 906 |
-
padding: 0;
|
| 907 |
-
margin: 0 0 0 6px;
|
| 908 |
-
font-family: sans-serif;
|
| 909 |
-
|
| 910 |
-
-moz-border-radius-bottomleft: 3px;
|
| 911 |
-
-moz-border-radius-bottomright: 3px;
|
| 912 |
-
-webkit-border-bottom-left-radius: 3px;
|
| 913 |
-
-webkit-border-bottom-right-radius: 3px;
|
| 914 |
-
border-bottom-left-radius: 3px;
|
| 915 |
-
border-bottom-right-radius: 3px;
|
| 916 |
-
|
| 917 |
-
background: #e3e3e3;
|
| 918 |
-
|
| 919 |
-
border-right: 1px solid transparent;
|
| 920 |
-
border-left: 1px solid transparent;
|
| 921 |
-
border-bottom: 1px solid transparent;
|
| 922 |
-
background-image: -ms-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* IE10 */
|
| 923 |
-
background-image: -moz-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Firefox */
|
| 924 |
-
background-image: -o-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Opera */
|
| 925 |
-
background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#f1f1f1)); /* old Webkit */
|
| 926 |
-
background-image: -webkit-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* new Webkit */
|
| 927 |
-
background-image: linear-gradient(bottom, #dfdfdf, #f1f1f1); /* proposed W3C Markup */
|
| 928 |
-
}
|
| 929 |
-
|
| 930 |
-
#ws-pro-version-notice a.show-settings {
|
| 931 |
-
background-image: none;
|
| 932 |
-
padding:0 6px 0 6px;
|
| 933 |
-
}
|
| 934 |
-
|
| 935 |
-
/* "Upgrade to Pro" */
|
| 936 |
-
#ws-pro-version-notice {
|
| 937 |
-
background: #00C31F none;
|
| 938 |
-
}
|
| 939 |
-
|
| 940 |
-
|
| 941 |
-
#ws-pro-version-notice a.show-settings {
|
| 942 |
-
font-weight: bold;
|
| 943 |
-
color: #DEFFD8;
|
| 944 |
-
text-shadow: none;
|
| 945 |
-
}
|
| 946 |
-
|
| 947 |
-
#ws-pro-version-notice a.show-settings:hover {
|
| 948 |
-
color: white;
|
| 949 |
-
}
|
| 102 |
clear: both;
|
| 103 |
display: block;
|
| 104 |
margin: 4px;
|
| 105 |
+
width: 130px;
|
| 106 |
}
|
| 107 |
|
| 108 |
#ws_menu_editor #ws_save_menu {
|
| 289 |
#ws_menu_access_editor .ws_dropdown_button
|
| 290 |
{
|
| 291 |
width: 20px;
|
| 292 |
+
height: 23px;
|
| 293 |
|
| 294 |
margin: 1px 1px 1px 0;
|
| 295 |
padding: 0;
|
| 561 |
margin: 0;
|
| 562 |
padding: 0;
|
| 563 |
position: relative;
|
| 564 |
+
|
| 565 |
+
box-sizing: border-box;
|
| 566 |
+
height: 25px;
|
| 567 |
}
|
| 568 |
|
| 569 |
/* Current icon node (CSS class version, for the built-in WP icon sprites) */
|
| 614 |
|
| 615 |
.ui-widget-overlay {
|
| 616 |
background-color: black;
|
| 617 |
+
position: fixed;
|
| 618 |
left: 0;
|
| 619 |
top: 0;
|
| 620 |
opacity: 0.70;
|
| 621 |
-moz-opacity: 0.70;
|
| 622 |
+
filter: alpha(opacity=70);
|
| 623 |
+
|
| 624 |
+
width: 100%;
|
| 625 |
+
height: 100%;
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
.ui-front {
|
| 629 |
+
z-index: 100;
|
| 630 |
}
|
| 631 |
|
| 632 |
.ui-dialog {
|
| 699 |
height: 23px;
|
| 700 |
text-align: right;
|
| 701 |
margin-top: 20px;
|
| 702 |
+
margin-bottom: 1px;
|
| 703 |
+
clear: both;
|
| 704 |
}
|
| 705 |
|
| 706 |
.ws_dialog_buttons .button-primary {
|
| 730 |
padding-top: 25px;
|
| 731 |
}
|
| 732 |
|
| 733 |
+
.ws_dont_show_again {
|
| 734 |
+
display: inline-block;
|
| 735 |
+
margin-top: 1em;
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
/************************************
|
| 739 |
Menu access editor
|
| 740 |
*************************************/
|
| 903 |
}
|
| 904 |
|
| 905 |
#ws_sidebar_pro_ad {
|
| 906 |
+
min-width: 225px;
|
| 907 |
+
|
| 908 |
margin-top: 5px;
|
| 909 |
margin-left: 3px;
|
| 910 |
|
| 912 |
right: 20px;
|
| 913 |
bottom: 40px;
|
| 914 |
z-index: 100;
|
| 915 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
css/screen-meta-old-wp.css
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/************************************
|
| 2 |
+
Screen meta buttons
|
| 3 |
+
for WP 3.7 and below
|
| 4 |
+
*************************************/
|
| 5 |
+
|
| 6 |
+
/* All buttons */
|
| 7 |
+
.custom-screen-meta-link-wrap {
|
| 8 |
+
float: right;
|
| 9 |
+
height: 22px;
|
| 10 |
+
padding: 0;
|
| 11 |
+
margin: 0 0 0 6px;
|
| 12 |
+
font-family: sans-serif;
|
| 13 |
+
-moz-border-radius-bottomleft: 3px;
|
| 14 |
+
-moz-border-radius-bottomright: 3px;
|
| 15 |
+
-webkit-border-bottom-left-radius: 3px;
|
| 16 |
+
-webkit-border-bottom-right-radius: 3px;
|
| 17 |
+
border-bottom-left-radius: 3px;
|
| 18 |
+
border-bottom-right-radius: 3px;
|
| 19 |
+
|
| 20 |
+
background: #e3e3e3;
|
| 21 |
+
|
| 22 |
+
border-right: 1px solid transparent;
|
| 23 |
+
border-left: 1px solid transparent;
|
| 24 |
+
border-bottom: 1px solid transparent;
|
| 25 |
+
background-image: -ms-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* IE10 */
|
| 26 |
+
background-image: -moz-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Firefox */
|
| 27 |
+
background-image: -o-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Opera */
|
| 28 |
+
background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#f1f1f1)); /* old Webkit */
|
| 29 |
+
background-image: -webkit-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* new Webkit */
|
| 30 |
+
background-image: linear-gradient(bottom, #dfdfdf, #f1f1f1); /* proposed W3C Markup */
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
| 34 |
+
#screen-meta-links .custom-screen-meta-link-wrap a.custom-screen-meta-link
|
| 35 |
+
{
|
| 36 |
+
background-image: none;
|
| 37 |
+
padding: 0 6px 0 6px;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
#screen-meta-links a.custom-screen-meta-link::after {
|
| 41 |
+
display: none;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/* "Upgrade to Pro" */
|
| 45 |
+
#ws-pro-version-notice {
|
| 46 |
+
background: #00C31F none;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
#ws-pro-version-notice a.show-settings {
|
| 50 |
+
font-weight: bold;
|
| 51 |
+
color: #DEFFD8;
|
| 52 |
+
text-shadow: none;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
#ws-pro-version-notice a.show-settings:hover {
|
| 56 |
+
color: white;
|
| 57 |
+
}
|
css/screen-meta.css
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/************************************
|
| 2 |
+
Screen meta buttons
|
| 3 |
+
for WP 3.8+
|
| 4 |
+
*************************************/
|
| 5 |
+
|
| 6 |
+
/* All buttons */
|
| 7 |
+
.custom-screen-meta-link-wrap {
|
| 8 |
+
float: right;
|
| 9 |
+
height: 28px;
|
| 10 |
+
margin: 0 0 0 6px;
|
| 11 |
+
|
| 12 |
+
border: 1px solid #ddd;
|
| 13 |
+
border-top: none;
|
| 14 |
+
background: #fff;
|
| 15 |
+
-webkit-box-shadow: 0px 1px 1px -1px rgba(0,0,0,0.1);
|
| 16 |
+
box-shadow: 0px 1px 1px -1px rgba(0,0,0,0.1);
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
| 20 |
+
#screen-meta-links .custom-screen-meta-link-wrap a.custom-screen-meta-link
|
| 21 |
+
{
|
| 22 |
+
padding: 3px 16px 3px 16px;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
#screen-meta-links a.custom-screen-meta-link::after {
|
| 26 |
+
display: none;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* "Upgrade to Pro" */
|
| 30 |
+
#ws-pro-version-notice {
|
| 31 |
+
background-color: #00C31F;
|
| 32 |
+
border-color: #0a0;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
#ws-pro-version-notice a.show-settings {
|
| 36 |
+
font-weight: bold;
|
| 37 |
+
color: #DEFFD8;
|
| 38 |
+
text-shadow: none;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
#ws-pro-version-notice a.show-settings:hover {
|
| 42 |
+
color: white;
|
| 43 |
+
}
|
includes/editor-page.php
CHANGED
|
@@ -24,8 +24,8 @@ if ( !apply_filters('admin_menu_editor_is_pro', false) ){
|
|
| 24 |
<script type="text/javascript">
|
| 25 |
(function($){
|
| 26 |
$('#screen-meta-links').append(
|
| 27 |
-
'<div id="ws-pro-version-notice">' +
|
| 28 |
-
'<a href="http://adminmenueditor.com/upgrade-to-pro/?utm_source=Admin%2BMenu%2BEditor%2Bfree&utm_medium=text_link&utm_content=top_upgrade_link&utm_campaign=Plugins" id="ws-pro-version-notice-link" class="show-settings" target="_blank" title="View Pro version details">Upgrade to Pro</a>' +
|
| 29 |
'</div>'
|
| 30 |
);
|
| 31 |
})(jQuery);
|
|
@@ -104,7 +104,11 @@ endif;
|
|
| 104 |
<div class="ws_separator"> </div>
|
| 105 |
|
| 106 |
<a id='ws_new_menu' class='ws_button' href='javascript:void(0)' title='New menu'><img src='<?php echo $icons['new']; ?>' alt="New menu" /></a>
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
<a id='ws_delete_menu' class='ws_button' href='javascript:void(0)' title='Delete menu'><img src='<?php echo $icons['delete']; ?>' alt="Delete menu" /></a>
|
| 109 |
|
| 110 |
<div class="ws_separator"> </div>
|
|
@@ -136,7 +140,9 @@ endif;
|
|
| 136 |
<div class="ws_separator"> </div>
|
| 137 |
|
| 138 |
<a id='ws_new_item' class='ws_button' href='javascript:void(0)' title='New menu item'><img src='<?php echo $icons['new']; ?>' alt="New menu item" /></a>
|
| 139 |
-
|
|
|
|
|
|
|
| 140 |
<a id='ws_delete_item' class='ws_button' href='javascript:void(0)' title='Delete menu item'><img src='<?php echo $icons['delete']; ?>' alt="Delete menu item" /></a>
|
| 141 |
|
| 142 |
<div class="ws_separator"> </div>
|
|
@@ -316,6 +322,41 @@ endif;
|
|
| 316 |
</label>
|
| 317 |
</span>
|
| 318 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
<script type='text/javascript'>
|
| 320 |
var defaultMenu = <?php echo $editor_data['default_menu_js']; ?>;
|
| 321 |
var customMenu = <?php echo $editor_data['custom_menu_js']; ?>;
|
| 24 |
<script type="text/javascript">
|
| 25 |
(function($){
|
| 26 |
$('#screen-meta-links').append(
|
| 27 |
+
'<div id="ws-pro-version-notice" class="custom-screen-meta-link-wrap">' +
|
| 28 |
+
'<a href="http://adminmenueditor.com/upgrade-to-pro/?utm_source=Admin%2BMenu%2BEditor%2Bfree&utm_medium=text_link&utm_content=top_upgrade_link&utm_campaign=Plugins" id="ws-pro-version-notice-link" class="show-settings custom-screen-meta-link" target="_blank" title="View Pro version details">Upgrade to Pro</a>' +
|
| 29 |
'</div>'
|
| 30 |
);
|
| 31 |
})(jQuery);
|
| 104 |
<div class="ws_separator"> </div>
|
| 105 |
|
| 106 |
<a id='ws_new_menu' class='ws_button' href='javascript:void(0)' title='New menu'><img src='<?php echo $icons['new']; ?>' alt="New menu" /></a>
|
| 107 |
+
|
| 108 |
+
<?php if ( $editor_data['show_deprecated_hide_button'] ): ?>
|
| 109 |
+
<a id='ws_hide_menu' class='ws_button' href='javascript:void(0)' title='Show/Hide'><img src='<?php echo $icons['hide']; ?>' alt="Show/Hide" /></a>
|
| 110 |
+
<?php endif; ?>
|
| 111 |
+
|
| 112 |
<a id='ws_delete_menu' class='ws_button' href='javascript:void(0)' title='Delete menu'><img src='<?php echo $icons['delete']; ?>' alt="Delete menu" /></a>
|
| 113 |
|
| 114 |
<div class="ws_separator"> </div>
|
| 140 |
<div class="ws_separator"> </div>
|
| 141 |
|
| 142 |
<a id='ws_new_item' class='ws_button' href='javascript:void(0)' title='New menu item'><img src='<?php echo $icons['new']; ?>' alt="New menu item" /></a>
|
| 143 |
+
<?php if ( $editor_data['show_deprecated_hide_button'] ): ?>
|
| 144 |
+
<a id='ws_hide_item' class='ws_button' href='javascript:void(0)' title='Show/Hide'><img src='<?php echo $icons['hide']; ?>' alt="Show/Hide" /></a>
|
| 145 |
+
<?php endif; ?>
|
| 146 |
<a id='ws_delete_item' class='ws_button' href='javascript:void(0)' title='Delete menu item'><img src='<?php echo $icons['delete']; ?>' alt="Delete menu item" /></a>
|
| 147 |
|
| 148 |
<div class="ws_separator"> </div>
|
| 322 |
</label>
|
| 323 |
</span>
|
| 324 |
|
| 325 |
+
|
| 326 |
+
<!-- Confirmation dialog when hiding "Dashboard -> Home" -->
|
| 327 |
+
<div id="ws-ame-dashboard-hide-confirmation" style="display: none;">
|
| 328 |
+
<span>
|
| 329 |
+
Hiding <em>Dashboard -> Home</em> may prevent users with the selected role from logging in!
|
| 330 |
+
Are you sure you want to do it?
|
| 331 |
+
</span>
|
| 332 |
+
|
| 333 |
+
<h4>Explanation</h4>
|
| 334 |
+
<p>
|
| 335 |
+
WordPress automatically redirects users to the <em>Dashboard -> Home</em> page upon successful login.
|
| 336 |
+
If you hide this page, users will get an "insufficient permissions" error when they log in
|
| 337 |
+
due to being redirected to a hidden page. As a result, it will look like their login failed.
|
| 338 |
+
</p>
|
| 339 |
+
|
| 340 |
+
<h4>Recommendations</h4>
|
| 341 |
+
<p>
|
| 342 |
+
You can use a plugin like <a href="http://wordpress.org/plugins/peters-login-redirect/">Peter's Login Redirect</a>
|
| 343 |
+
to redirect specific roles to different pages.
|
| 344 |
+
</p>
|
| 345 |
+
|
| 346 |
+
<div class="ws_dialog_buttons">
|
| 347 |
+
<?php
|
| 348 |
+
submit_button('Hide the menu', 'primary', 'ws_confirm_menu_hiding', false);
|
| 349 |
+
submit_button('Leave it visible', 'secondary', 'ws_cancel_menu_hiding', false);
|
| 350 |
+
?>
|
| 351 |
+
</div>
|
| 352 |
+
|
| 353 |
+
<label class="ws_dont_show_again">
|
| 354 |
+
<input type="checkbox" id="ws-ame-disable-dashboard-hide-confirmation">
|
| 355 |
+
Don't show this message again
|
| 356 |
+
</label>
|
| 357 |
+
</div>
|
| 358 |
+
|
| 359 |
+
|
| 360 |
<script type='text/javascript'>
|
| 361 |
var defaultMenu = <?php echo $editor_data['default_menu_js']; ?>;
|
| 362 |
var customMenu = <?php echo $editor_data['custom_menu_js']; ?>;
|
includes/menu-editor-core.php
CHANGED
|
@@ -69,6 +69,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 69 |
private $cached_custom_menu = null; //Cached, non-merged version of the custom menu. Used by load_custom_menu().
|
| 70 |
private $cached_virtual_caps = null;//List of virtual caps. Used by get_virtual_caps().
|
| 71 |
|
|
|
|
|
|
|
|
|
|
| 72 |
//Our personal copy of the request vars, without any "magic quotes".
|
| 73 |
private $post = array();
|
| 74 |
private $get = array();
|
|
@@ -96,6 +99,12 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 96 |
'allowed_user_id' => null,
|
| 97 |
//The user who can see this plugin on the "Plugins" page. By default all admins can see it.
|
| 98 |
'plugins_page_allowed_user_id' => null,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
);
|
| 100 |
$this->serialize_with_json = false; //(Don't) store the options in JSON format
|
| 101 |
|
|
@@ -105,10 +114,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 105 |
$this->magic_hook_priority = 99999;
|
| 106 |
|
| 107 |
//AJAXify screen options
|
| 108 |
-
add_action('wp_ajax_ws_ame_save_screen_options', array(
|
| 109 |
|
| 110 |
-
//AJAXify hints
|
| 111 |
add_action('wp_ajax_ws_ame_hide_hint', array($this, 'ajax_hide_hint'));
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
//Make sure we have access to the original, un-mangled request data.
|
| 114 |
//This is necessary because WordPress will stupidly apply "magic quotes"
|
|
@@ -123,6 +136,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 123 |
|
| 124 |
//User survey
|
| 125 |
add_action('admin_notices', array($this, 'display_survey_notice'));
|
|
|
|
|
|
|
|
|
|
| 126 |
}
|
| 127 |
|
| 128 |
function init_finish() {
|
|
@@ -182,7 +198,20 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 182 |
function hook_admin_menu(){
|
| 183 |
global $menu, $submenu;
|
| 184 |
|
| 185 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
$reset_requested = isset($this->get['reset_admin_menu']) && $this->get['reset_admin_menu'];
|
| 187 |
if ( $reset_requested && $this->current_user_can_edit_menu() ){
|
| 188 |
$this->set_custom_menu(null);
|
|
@@ -235,7 +264,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 235 |
|
| 236 |
//Convert our custom menu to the $menu + $submenu structure used by WP.
|
| 237 |
//Note: This method sets up multiple internal fields and may cause side-effects.
|
|
|
|
| 238 |
$this->build_custom_wp_menu($this->merged_custom_menu['tree']);
|
|
|
|
| 239 |
|
| 240 |
if ( !$this->user_can_access_current_page() ) {
|
| 241 |
$this->log_security_note('DENY access.');
|
|
@@ -278,7 +309,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 278 |
|
| 279 |
$menu = $this->custom_wp_menu;
|
| 280 |
$submenu = $this->custom_wp_submenu;
|
|
|
|
|
|
|
| 281 |
list($menu, $submenu) = $this->filter_menu($menu, $submenu);
|
|
|
|
| 282 |
|
| 283 |
return $parent_file;
|
| 284 |
}
|
|
@@ -496,6 +530,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 496 |
'selectedActor' => isset($this->get['selected_actor']) ? strval($this->get['selected_actor']) : null,
|
| 497 |
|
| 498 |
'showHints' => $this->get_hint_visibility(),
|
|
|
|
|
|
|
| 499 |
|
| 500 |
'isDemoMode' => defined('IS_DEMO_MODE'),
|
| 501 |
'isMasterMode' => defined('IS_MASTER_MODE'),
|
|
@@ -559,6 +595,17 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 559 |
array('menu-editor-base-style')
|
| 560 |
);
|
| 561 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 562 |
wp_enqueue_style('menu-editor-colours-classic');
|
| 563 |
}
|
| 564 |
|
|
@@ -585,6 +632,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 585 |
|
| 586 |
$this->cached_custom_menu = null;
|
| 587 |
$this->cached_virtual_caps = null;
|
|
|
|
| 588 |
}
|
| 589 |
|
| 590 |
/**
|
|
@@ -746,6 +794,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 746 |
*/
|
| 747 |
function menu_merge($tree){
|
| 748 |
//Iterate over all menus and submenus and look up default values
|
|
|
|
|
|
|
| 749 |
foreach ($tree as &$topmenu){
|
| 750 |
|
| 751 |
if ( !ameMenuItem::get($topmenu, 'custom') ) {
|
|
@@ -779,6 +829,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 779 |
//Yes, load defaults from that item
|
| 780 |
$item['defaults'] = $this->item_templates[$template_id]['defaults'];
|
| 781 |
$this->item_templates[$template_id]['used'] = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 782 |
} else if ( empty($item['separator']) ) {
|
| 783 |
//Record as missing, unless it's a menu separator
|
| 784 |
$item['missing'] = true;
|
|
@@ -787,6 +841,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 787 |
$temp = $this->set_final_menu_capability($temp);
|
| 788 |
$this->add_access_lookup($temp, 'submenu', true);
|
| 789 |
}
|
|
|
|
|
|
|
|
|
|
| 790 |
}
|
| 791 |
}
|
| 792 |
}
|
|
@@ -838,13 +895,25 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 838 |
$tree[$template['defaults']['parent']]['items'][] = $entry;
|
| 839 |
} else {
|
| 840 |
//This can happen if the original parent menu has been moved to a submenu.
|
| 841 |
-
|
| 842 |
}
|
| 843 |
} else {
|
| 844 |
$tree[$template['defaults']['file']] = $entry;
|
| 845 |
}
|
| 846 |
}
|
| 847 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 848 |
//Resort the tree to ensure the found items are in the right spots
|
| 849 |
$tree = ameMenu::sort_menu_tree($tree);
|
| 850 |
|
|
@@ -976,9 +1045,19 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 976 |
//Convert the prepared tree to the internal WordPress format.
|
| 977 |
foreach($new_tree as $topmenu) {
|
| 978 |
$trueAccess = isset($this->page_access_lookup[$topmenu['url']]) ? $this->page_access_lookup[$topmenu['url']] : null;
|
| 979 |
-
if ( $trueAccess === 'do_not_allow' ) {
|
| 980 |
$topmenu['access_level'] = $trueAccess;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 981 |
}
|
|
|
|
| 982 |
if ( !isset($this->reverse_item_lookup[$topmenu['url']]) ) { //Prefer sub-menus.
|
| 983 |
$this->reverse_item_lookup[$topmenu['url']] = $topmenu;
|
| 984 |
}
|
|
@@ -987,9 +1066,19 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 987 |
|
| 988 |
foreach($topmenu['items'] as $item) {
|
| 989 |
$trueAccess = isset($this->page_access_lookup[$item['url']]) ? $this->page_access_lookup[$item['url']] : null;
|
| 990 |
-
if ( $trueAccess === 'do_not_allow' ) {
|
| 991 |
$item['access_level'] = $trueAccess;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 992 |
}
|
|
|
|
| 993 |
$this->reverse_item_lookup[$item['url']] = $item;
|
| 994 |
$new_submenu[$topmenu['file']][] = $this->convert_to_wp_format($item);
|
| 995 |
}
|
|
@@ -1083,7 +1172,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1083 |
}
|
| 1084 |
|
| 1085 |
//Used later to determine the current page based on URL.
|
| 1086 |
-
|
|
|
|
|
|
|
|
|
|
| 1087 |
|
| 1088 |
//Convert relative URls to fully qualified ones. This prevents problems with WordPress
|
| 1089 |
//incorrectly converting "index.php?page=xyz" to, say, "tools.php?page=index.php?page=xyz"
|
|
@@ -1136,15 +1228,30 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1136 |
$user_has_access = true;
|
| 1137 |
$cap_to_use = '';
|
| 1138 |
if ( !empty($item['access_level']) ) {
|
| 1139 |
-
$user_has_cap = $this->current_user_can($item['access_level']);
|
| 1140 |
-
$user_has_access = $user_has_access && $user_has_cap;
|
| 1141 |
$cap_to_use = $item['access_level'];
|
| 1142 |
|
| 1143 |
-
$item['
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
-
|
| 1147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1148 |
} else {
|
| 1149 |
$item['access_check_log'][] = '- No required capability set.';
|
| 1150 |
}
|
|
@@ -1191,6 +1298,18 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1191 |
$this->handle_form_submission($this->post, $action);
|
| 1192 |
}
|
| 1193 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1194 |
$sub_section = isset($this->get['sub_section']) ? $this->get['sub_section'] : null;
|
| 1195 |
if ( $sub_section === 'settings' ) {
|
| 1196 |
$this->display_plugin_settings_ui();
|
|
@@ -1281,6 +1400,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1281 |
//Hide some menu options by default.
|
| 1282 |
$this->options['hide_advanced_settings'] = !empty($this->post['hide_advanced_settings']);
|
| 1283 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1284 |
$this->save_options();
|
| 1285 |
wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url()));
|
| 1286 |
}
|
|
@@ -1293,6 +1417,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1293 |
'images_url' => plugins_url('images', $this->plugin_file),
|
| 1294 |
'hide_advanced_settings' => $this->options['hide_advanced_settings'],
|
| 1295 |
'settings_page_url' => $this->get_settings_page_url(),
|
|
|
|
| 1296 |
);
|
| 1297 |
|
| 1298 |
//Build a tree struct. for the default menu
|
|
@@ -1346,8 +1471,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1346 |
*/
|
| 1347 |
private function display_plugin_settings_ui() {
|
| 1348 |
//These variables are used by settings-page.php.
|
|
|
|
| 1349 |
$settings = $this->options;
|
|
|
|
| 1350 |
$settings_page_url = $this->get_settings_page_url();
|
|
|
|
| 1351 |
$editor_page_url = admin_url($this->settings_link);
|
| 1352 |
|
| 1353 |
require dirname(__FILE__) . '/settings-page.php';
|
|
@@ -1408,7 +1536,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1408 |
}
|
| 1409 |
|
| 1410 |
foreach($custom_menu['tree'] as $item) {
|
| 1411 |
-
$caps =
|
| 1412 |
}
|
| 1413 |
|
| 1414 |
$this->cached_virtual_caps = $caps;
|
|
@@ -1431,12 +1559,25 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1431 |
}
|
| 1432 |
|
| 1433 |
foreach($item['items'] as $sub_item) {
|
| 1434 |
-
$caps =
|
| 1435 |
}
|
| 1436 |
|
| 1437 |
return $caps;
|
| 1438 |
}
|
| 1439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1440 |
/**
|
| 1441 |
* Create a virtual 'super_admin' capability that only super admins have.
|
| 1442 |
* This function accomplishes that by by filtering 'user_has_cap' calls.
|
|
@@ -1508,6 +1649,17 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1508 |
update_user_meta($user->ID, 'ame_show_hints', $show_hints);
|
| 1509 |
}
|
| 1510 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1511 |
/**
|
| 1512 |
* Enqueue a script that fixes a bug where pages moved to a different menu
|
| 1513 |
* would not be highlighted properly when the user visits them.
|
|
@@ -1561,7 +1713,19 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1561 |
* @return bool
|
| 1562 |
*/
|
| 1563 |
private function current_user_can($capability) {
|
| 1564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1565 |
}
|
| 1566 |
|
| 1567 |
/**
|
|
@@ -1600,6 +1764,12 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1600 |
$base_site_url = $matches[1];
|
| 1601 |
}
|
| 1602 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1603 |
$current_url = $base_site_url . remove_query_arg('___ame_dummy_param___');
|
| 1604 |
$this->log_security_note(sprintf('Current URL: "%s"', htmlentities($current_url)));
|
| 1605 |
|
|
@@ -1612,7 +1782,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1612 |
if ( substr($item_url, 0, 1) == '/' ) {
|
| 1613 |
$item_url = $base_site_url . $item_url;
|
| 1614 |
} else {
|
| 1615 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1616 |
}
|
| 1617 |
}
|
| 1618 |
$item_url = $this->parse_url($item_url);
|
|
@@ -1735,7 +1909,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1735 |
|
| 1736 |
$display_notice = $this->options['display_survey_notice'] && $this->current_user_can_edit_menu();
|
| 1737 |
if ( isset($this->options['first_install_time']) ) {
|
| 1738 |
-
$minimum_usage_period =
|
| 1739 |
$display_notice = $display_notice && ((time() - $this->options['first_install_time']) > $minimum_usage_period);
|
| 1740 |
}
|
| 1741 |
|
|
@@ -1753,7 +1927,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1753 |
$free_survey_url = 'https://docs.google.com/spreadsheet/viewform?formkey=dERyeDk0OWhlbkxYcEY4QTNaMnlTQUE6MQ';
|
| 1754 |
$pro_survey_url = 'https://docs.google.com/spreadsheet/viewform?formkey=dHl4MnlHaVI3NE5JdVFDWG01SkRKTWc6MA';
|
| 1755 |
|
| 1756 |
-
if (
|
| 1757 |
$survey_url = $pro_survey_url;
|
| 1758 |
} else {
|
| 1759 |
$survey_url = $free_survey_url;
|
|
@@ -1952,4 +2126,49 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1952 |
return $name;
|
| 1953 |
}
|
| 1954 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1955 |
} //class
|
| 69 |
private $cached_custom_menu = null; //Cached, non-merged version of the custom menu. Used by load_custom_menu().
|
| 70 |
private $cached_virtual_caps = null;//List of virtual caps. Used by get_virtual_caps().
|
| 71 |
|
| 72 |
+
private $cached_user_caps = array(); //A cache of the current user's capabilities. Used only in very specific places.
|
| 73 |
+
private $user_cap_cache_enabled = false;
|
| 74 |
+
|
| 75 |
//Our personal copy of the request vars, without any "magic quotes".
|
| 76 |
private $post = array();
|
| 77 |
private $get = array();
|
| 99 |
'allowed_user_id' => null,
|
| 100 |
//The user who can see this plugin on the "Plugins" page. By default all admins can see it.
|
| 101 |
'plugins_page_allowed_user_id' => null,
|
| 102 |
+
|
| 103 |
+
'show_deprecated_hide_button' => null,
|
| 104 |
+
'dashboard_hiding_confirmation_enabled' => true,
|
| 105 |
+
|
| 106 |
+
//Enable/disable the admin notice that tells the user where the plugin settings menu is.
|
| 107 |
+
'show_plugin_menu_notice' => true,
|
| 108 |
);
|
| 109 |
$this->serialize_with_json = false; //(Don't) store the options in JSON format
|
| 110 |
|
| 114 |
$this->magic_hook_priority = 99999;
|
| 115 |
|
| 116 |
//AJAXify screen options
|
| 117 |
+
add_action('wp_ajax_ws_ame_save_screen_options', array($this,'ajax_save_screen_options'));
|
| 118 |
|
| 119 |
+
//AJAXify hints and warnings
|
| 120 |
add_action('wp_ajax_ws_ame_hide_hint', array($this, 'ajax_hide_hint'));
|
| 121 |
+
add_action(
|
| 122 |
+
'wp_ajax_ws_ame_disable_dashboard_hiding_confirmation',
|
| 123 |
+
array($this, 'ajax_disable_dashboard_hiding_confirmation')
|
| 124 |
+
);
|
| 125 |
|
| 126 |
//Make sure we have access to the original, un-mangled request data.
|
| 127 |
//This is necessary because WordPress will stupidly apply "magic quotes"
|
| 136 |
|
| 137 |
//User survey
|
| 138 |
add_action('admin_notices', array($this, 'display_survey_notice'));
|
| 139 |
+
|
| 140 |
+
//Tell first-time users where they can find the plugin settings page.
|
| 141 |
+
add_action('all_admin_notices', array($this, 'display_plugin_menu_notice'));
|
| 142 |
}
|
| 143 |
|
| 144 |
function init_finish() {
|
| 198 |
function hook_admin_menu(){
|
| 199 |
global $menu, $submenu;
|
| 200 |
|
| 201 |
+
//Compatibility fix for Shopp 1.2.9. This plugin has an "admin_menu" hook (Flow::menu) that adds another
|
| 202 |
+
//"admin_menu" hook (AdminFlow::taxonomies) when it runs. Basically, it indirectly modifies the global
|
| 203 |
+
//$wp_filters['admin_menu'] array while WordPress is iterating it (nasty!). Due to how PHP arrays are
|
| 204 |
+
//implemented and how do_action() works, this second hook is the very last one to run, even after hooks
|
| 205 |
+
//with a lower priority.
|
| 206 |
+
//The only way we can see the changes made by the second hook is to do the same thing.
|
| 207 |
+
static $firstRunSkipped = false;
|
| 208 |
+
if ( !$firstRunSkipped && class_exists('Flow') ) {
|
| 209 |
+
add_action('admin_menu', array($this, 'hook_admin_menu'), $this->magic_hook_priority + 1);
|
| 210 |
+
$firstRunSkipped = true;
|
| 211 |
+
return;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
//Menu reset (for emergencies). Executed by accessing http://example.com/wp-admin/?reset_admin_menu=1
|
| 215 |
$reset_requested = isset($this->get['reset_admin_menu']) && $this->get['reset_admin_menu'];
|
| 216 |
if ( $reset_requested && $this->current_user_can_edit_menu() ){
|
| 217 |
$this->set_custom_menu(null);
|
| 264 |
|
| 265 |
//Convert our custom menu to the $menu + $submenu structure used by WP.
|
| 266 |
//Note: This method sets up multiple internal fields and may cause side-effects.
|
| 267 |
+
$this->user_cap_cache_enabled = true;
|
| 268 |
$this->build_custom_wp_menu($this->merged_custom_menu['tree']);
|
| 269 |
+
$this->user_cap_cache_enabled = false;
|
| 270 |
|
| 271 |
if ( !$this->user_can_access_current_page() ) {
|
| 272 |
$this->log_security_note('DENY access.');
|
| 309 |
|
| 310 |
$menu = $this->custom_wp_menu;
|
| 311 |
$submenu = $this->custom_wp_submenu;
|
| 312 |
+
|
| 313 |
+
$this->user_cap_cache_enabled = true;
|
| 314 |
list($menu, $submenu) = $this->filter_menu($menu, $submenu);
|
| 315 |
+
$this->user_cap_cache_enabled = false;
|
| 316 |
|
| 317 |
return $parent_file;
|
| 318 |
}
|
| 530 |
'selectedActor' => isset($this->get['selected_actor']) ? strval($this->get['selected_actor']) : null,
|
| 531 |
|
| 532 |
'showHints' => $this->get_hint_visibility(),
|
| 533 |
+
'dashboardHidingConfirmationEnabled' => $this->options['dashboard_hiding_confirmation_enabled'],
|
| 534 |
+
'disableDashboardConfirmationNonce' => wp_create_nonce('ws_ame_disable_dashboard_hiding_confirmation'),
|
| 535 |
|
| 536 |
'isDemoMode' => defined('IS_DEMO_MODE'),
|
| 537 |
'isMasterMode' => defined('IS_MASTER_MODE'),
|
| 595 |
array('menu-editor-base-style')
|
| 596 |
);
|
| 597 |
|
| 598 |
+
//WordPress introduced a new screen meta button style in WP 3.8.
|
| 599 |
+
//We have two different stylesheets - one for 3.8+ and one for backwards compatibility.
|
| 600 |
+
wp_register_auto_versioned_style('menu-editor-screen-meta', plugins_url('css/screen-meta.css', $this->plugin_file));
|
| 601 |
+
wp_register_auto_versioned_style('menu-editor-screen-meta-old', plugins_url('css/screen-meta-old-wp.css', $this->plugin_file));
|
| 602 |
+
|
| 603 |
+
if ( isset($GLOBALS['wp_version']) && version_compare($GLOBALS['wp_version'], '3.8-RC1', '<') ) {
|
| 604 |
+
wp_enqueue_style('menu-editor-screen-meta-old');
|
| 605 |
+
} else {
|
| 606 |
+
wp_enqueue_style('menu-editor-screen-meta');
|
| 607 |
+
}
|
| 608 |
+
|
| 609 |
wp_enqueue_style('menu-editor-colours-classic');
|
| 610 |
}
|
| 611 |
|
| 632 |
|
| 633 |
$this->cached_custom_menu = null;
|
| 634 |
$this->cached_virtual_caps = null;
|
| 635 |
+
$this->cached_user_caps = array();
|
| 636 |
}
|
| 637 |
|
| 638 |
/**
|
| 794 |
*/
|
| 795 |
function menu_merge($tree){
|
| 796 |
//Iterate over all menus and submenus and look up default values
|
| 797 |
+
//Also flag used and missing items.
|
| 798 |
+
$orphans = array();
|
| 799 |
foreach ($tree as &$topmenu){
|
| 800 |
|
| 801 |
if ( !ameMenuItem::get($topmenu, 'custom') ) {
|
| 829 |
//Yes, load defaults from that item
|
| 830 |
$item['defaults'] = $this->item_templates[$template_id]['defaults'];
|
| 831 |
$this->item_templates[$template_id]['used'] = true;
|
| 832 |
+
//We must move orphaned items elsewhere. Use the default location if possible.
|
| 833 |
+
if ( isset($topmenu['missing']) && $topmenu['missing'] ) {
|
| 834 |
+
$orphans[] = $item;
|
| 835 |
+
}
|
| 836 |
} else if ( empty($item['separator']) ) {
|
| 837 |
//Record as missing, unless it's a menu separator
|
| 838 |
$item['missing'] = true;
|
| 841 |
$temp = $this->set_final_menu_capability($temp);
|
| 842 |
$this->add_access_lookup($temp, 'submenu', true);
|
| 843 |
}
|
| 844 |
+
} else {
|
| 845 |
+
//What if the parent of this custom item is missing?
|
| 846 |
+
//Right now the custom item will just disappear.
|
| 847 |
}
|
| 848 |
}
|
| 849 |
}
|
| 895 |
$tree[$template['defaults']['parent']]['items'][] = $entry;
|
| 896 |
} else {
|
| 897 |
//This can happen if the original parent menu has been moved to a submenu.
|
| 898 |
+
$tree[$template['defaults']['file']] = $entry;
|
| 899 |
}
|
| 900 |
} else {
|
| 901 |
$tree[$template['defaults']['file']] = $entry;
|
| 902 |
}
|
| 903 |
}
|
| 904 |
|
| 905 |
+
//Move orphaned items back to their original parents.
|
| 906 |
+
foreach($orphans as $item) {
|
| 907 |
+
$defaultParent = !empty($item['defaults']['parent']) ? $item['defaults']['parent'] : null;
|
| 908 |
+
if ( isset($defaultParent) && isset($tree[$defaultParent]) ) {
|
| 909 |
+
$tree[$defaultParent]['items'][] = $item;
|
| 910 |
+
} else {
|
| 911 |
+
//This can happen if the parent has been moved to a submenu.
|
| 912 |
+
//Just put the orphan at the bottom of the menu.
|
| 913 |
+
$tree[$item['defaults']['file']] = $item;
|
| 914 |
+
}
|
| 915 |
+
}
|
| 916 |
+
|
| 917 |
//Resort the tree to ensure the found items are in the right spots
|
| 918 |
$tree = ameMenu::sort_menu_tree($tree);
|
| 919 |
|
| 1045 |
//Convert the prepared tree to the internal WordPress format.
|
| 1046 |
foreach($new_tree as $topmenu) {
|
| 1047 |
$trueAccess = isset($this->page_access_lookup[$topmenu['url']]) ? $this->page_access_lookup[$topmenu['url']] : null;
|
| 1048 |
+
if ( ($trueAccess === 'do_not_allow') && ($topmenu['access_level'] !== $trueAccess) ) {
|
| 1049 |
$topmenu['access_level'] = $trueAccess;
|
| 1050 |
+
if ( isset($topmenu['access_check_log']) ) {
|
| 1051 |
+
$topmenu['access_check_log'][] = sprintf(
|
| 1052 |
+
'+ Override: There is a hidden menu item with the same URL (%1$s) but a higher priority.' .
|
| 1053 |
+
' Setting the capability to "%2$s".',
|
| 1054 |
+
$topmenu['url'],
|
| 1055 |
+
$trueAccess
|
| 1056 |
+
);
|
| 1057 |
+
$topmenu['access_check_log'][] = str_repeat('=', 79);
|
| 1058 |
+
}
|
| 1059 |
}
|
| 1060 |
+
|
| 1061 |
if ( !isset($this->reverse_item_lookup[$topmenu['url']]) ) { //Prefer sub-menus.
|
| 1062 |
$this->reverse_item_lookup[$topmenu['url']] = $topmenu;
|
| 1063 |
}
|
| 1066 |
|
| 1067 |
foreach($topmenu['items'] as $item) {
|
| 1068 |
$trueAccess = isset($this->page_access_lookup[$item['url']]) ? $this->page_access_lookup[$item['url']] : null;
|
| 1069 |
+
if ( ($trueAccess === 'do_not_allow') && ($item['access_level'] !== $trueAccess) ) {
|
| 1070 |
$item['access_level'] = $trueAccess;
|
| 1071 |
+
if ( isset($item['access_check_log']) ) {
|
| 1072 |
+
$item['access_check_log'][] = sprintf(
|
| 1073 |
+
'+ Override: There is a hidden menu item with the same URL (%1$s) but a higher priority.' .
|
| 1074 |
+
' Setting the capability to "%2$s".',
|
| 1075 |
+
$item['url'],
|
| 1076 |
+
$trueAccess
|
| 1077 |
+
);
|
| 1078 |
+
$item['access_check_log'][] = str_repeat('=', 79);
|
| 1079 |
+
}
|
| 1080 |
}
|
| 1081 |
+
|
| 1082 |
$this->reverse_item_lookup[$item['url']] = $item;
|
| 1083 |
$new_submenu[$topmenu['file']][] = $this->convert_to_wp_format($item);
|
| 1084 |
}
|
| 1172 |
}
|
| 1173 |
|
| 1174 |
//Used later to determine the current page based on URL.
|
| 1175 |
+
if ( empty($item['url']) ) {
|
| 1176 |
+
$original_parent = !empty($item['defaults']['parent']) ? $item['defaults']['parent'] : $parent;
|
| 1177 |
+
$item['url'] = ameMenuItem::generate_url($item['file'], $original_parent);
|
| 1178 |
+
}
|
| 1179 |
|
| 1180 |
//Convert relative URls to fully qualified ones. This prevents problems with WordPress
|
| 1181 |
//incorrectly converting "index.php?page=xyz" to, say, "tools.php?page=index.php?page=xyz"
|
| 1228 |
$user_has_access = true;
|
| 1229 |
$cap_to_use = '';
|
| 1230 |
if ( !empty($item['access_level']) ) {
|
|
|
|
|
|
|
| 1231 |
$cap_to_use = $item['access_level'];
|
| 1232 |
|
| 1233 |
+
if ( isset($item['user_has_access_level']) ) {
|
| 1234 |
+
//The "custom_admin_menu_capability" filter has already determined whether this user should
|
| 1235 |
+
//have the required capability, so checking it again would be redundant. This usually only
|
| 1236 |
+
//applies to the Pro version which uses that filter in extras.php.
|
| 1237 |
+
$user_has_cap = $item['user_has_access_level'];
|
| 1238 |
+
|
| 1239 |
+
$item['access_check_log'][] = sprintf(
|
| 1240 |
+
'Skipping a "%1$s" capability check because we\'ve already determined that the current user %2$s access.',
|
| 1241 |
+
htmlentities($cap_to_use),
|
| 1242 |
+
$user_has_cap ? 'should have' : 'should not have'
|
| 1243 |
+
);
|
| 1244 |
+
} else {
|
| 1245 |
+
$user_has_cap = $this->current_user_can($cap_to_use);
|
| 1246 |
+
$item['access_check_log'][] = sprintf(
|
| 1247 |
+
'Required capability: %1$s. User %2$s this capability.',
|
| 1248 |
+
htmlentities($cap_to_use),
|
| 1249 |
+
$user_has_cap ? 'HAS' : 'DOES NOT have'
|
| 1250 |
+
);
|
| 1251 |
+
}
|
| 1252 |
+
|
| 1253 |
+
$user_has_access = $user_has_access && $user_has_cap;
|
| 1254 |
+
|
| 1255 |
} else {
|
| 1256 |
$item['access_check_log'][] = '- No required capability set.';
|
| 1257 |
}
|
| 1298 |
$this->handle_form_submission($this->post, $action);
|
| 1299 |
}
|
| 1300 |
|
| 1301 |
+
//By default, show the "Hide" button only if the user has already hidden something with it,
|
| 1302 |
+
//or if they're using the free version. Pro users should use role permissions instead, but can
|
| 1303 |
+
//explicitly enable the button if they want.
|
| 1304 |
+
if ( !isset($this->options['show_deprecated_hide_button']) ) {
|
| 1305 |
+
if ( $this->is_pro_version() ) {
|
| 1306 |
+
$this->options['show_deprecated_hide_button'] = ameMenu::has_hidden_items($this->merged_custom_menu);
|
| 1307 |
+
$this->save_options();
|
| 1308 |
+
} else {
|
| 1309 |
+
$this->options['show_deprecated_hide_button'] = true;
|
| 1310 |
+
}
|
| 1311 |
+
}
|
| 1312 |
+
|
| 1313 |
$sub_section = isset($this->get['sub_section']) ? $this->get['sub_section'] : null;
|
| 1314 |
if ( $sub_section === 'settings' ) {
|
| 1315 |
$this->display_plugin_settings_ui();
|
| 1400 |
//Hide some menu options by default.
|
| 1401 |
$this->options['hide_advanced_settings'] = !empty($this->post['hide_advanced_settings']);
|
| 1402 |
|
| 1403 |
+
//Enable the now-obsolete "Hide" button.
|
| 1404 |
+
if ( $this->is_pro_version() ) {
|
| 1405 |
+
$this->options['show_deprecated_hide_button'] = !empty($this->post['show_deprecated_hide_button']);
|
| 1406 |
+
}
|
| 1407 |
+
|
| 1408 |
$this->save_options();
|
| 1409 |
wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url()));
|
| 1410 |
}
|
| 1417 |
'images_url' => plugins_url('images', $this->plugin_file),
|
| 1418 |
'hide_advanced_settings' => $this->options['hide_advanced_settings'],
|
| 1419 |
'settings_page_url' => $this->get_settings_page_url(),
|
| 1420 |
+
'show_deprecated_hide_button' => $this->options['show_deprecated_hide_button'],
|
| 1421 |
);
|
| 1422 |
|
| 1423 |
//Build a tree struct. for the default menu
|
| 1471 |
*/
|
| 1472 |
private function display_plugin_settings_ui() {
|
| 1473 |
//These variables are used by settings-page.php.
|
| 1474 |
+
/** @noinspection PhpUnusedLocalVariableInspection */
|
| 1475 |
$settings = $this->options;
|
| 1476 |
+
/** @noinspection PhpUnusedLocalVariableInspection */
|
| 1477 |
$settings_page_url = $this->get_settings_page_url();
|
| 1478 |
+
/** @noinspection PhpUnusedLocalVariableInspection */
|
| 1479 |
$editor_page_url = admin_url($this->settings_link);
|
| 1480 |
|
| 1481 |
require dirname(__FILE__) . '/settings-page.php';
|
| 1536 |
}
|
| 1537 |
|
| 1538 |
foreach($custom_menu['tree'] as $item) {
|
| 1539 |
+
$caps = self::array_replace_recursive($caps, $this->get_virtual_caps_for($item));
|
| 1540 |
}
|
| 1541 |
|
| 1542 |
$this->cached_virtual_caps = $caps;
|
| 1559 |
}
|
| 1560 |
|
| 1561 |
foreach($item['items'] as $sub_item) {
|
| 1562 |
+
$caps = self::array_replace_recursive($caps, $this->get_virtual_caps_for($sub_item));
|
| 1563 |
}
|
| 1564 |
|
| 1565 |
return $caps;
|
| 1566 |
}
|
| 1567 |
|
| 1568 |
+
private static function array_replace_recursive($array1, $array2) {
|
| 1569 |
+
if ( function_exists('array_replace_recursive') ) {
|
| 1570 |
+
return array_replace_recursive($array1, $array2);
|
| 1571 |
+
}
|
| 1572 |
+
foreach($array2 as $key => $value) {
|
| 1573 |
+
if ( is_array($value) && isset($array1[$key]) && is_array($array1[$key]) ) {
|
| 1574 |
+
$value = self::array_replace_recursive($array1[$key], $value);
|
| 1575 |
+
}
|
| 1576 |
+
$array1[$key] = $value;
|
| 1577 |
+
}
|
| 1578 |
+
return $array1;
|
| 1579 |
+
}
|
| 1580 |
+
|
| 1581 |
/**
|
| 1582 |
* Create a virtual 'super_admin' capability that only super admins have.
|
| 1583 |
* This function accomplishes that by by filtering 'user_has_cap' calls.
|
| 1649 |
update_user_meta($user->ID, 'ame_show_hints', $show_hints);
|
| 1650 |
}
|
| 1651 |
|
| 1652 |
+
/**
|
| 1653 |
+
* AJAX callback for permanently hiding the "are you sure you want to hide the Dashboard?" warning.
|
| 1654 |
+
*/
|
| 1655 |
+
public function ajax_disable_dashboard_hiding_confirmation() {
|
| 1656 |
+
if (!check_ajax_referer('ws_ame_disable_dashboard_hiding_confirmation', false, false) || !$this->current_user_can_edit_menu()){
|
| 1657 |
+
die("You don't have sufficient permissions to do that.");
|
| 1658 |
+
}
|
| 1659 |
+
$this->options['dashboard_hiding_confirmation_enabled'] = false;
|
| 1660 |
+
$this->save_options();
|
| 1661 |
+
}
|
| 1662 |
+
|
| 1663 |
/**
|
| 1664 |
* Enqueue a script that fixes a bug where pages moved to a different menu
|
| 1665 |
* would not be highlighted properly when the user visits them.
|
| 1713 |
* @return bool
|
| 1714 |
*/
|
| 1715 |
private function current_user_can($capability) {
|
| 1716 |
+
//WP core uses a special "do_not_allow" capability in a dozen or so places to explicitly deny access.
|
| 1717 |
+
//Even multisite super admins do not have this cap. We can return early here.
|
| 1718 |
+
if ( $capability === 'do_not_allow' ) {
|
| 1719 |
+
return false;
|
| 1720 |
+
}
|
| 1721 |
+
|
| 1722 |
+
if ( $this->user_cap_cache_enabled && isset($this->cached_user_caps[$capability]) ) {
|
| 1723 |
+
return $this->cached_user_caps[$capability];
|
| 1724 |
+
}
|
| 1725 |
+
|
| 1726 |
+
$user_can = apply_filters('admin_menu_editor-current_user_can', current_user_can($capability), $capability);
|
| 1727 |
+
$this->cached_user_caps[$capability] = $user_can;
|
| 1728 |
+
return $user_can;
|
| 1729 |
}
|
| 1730 |
|
| 1731 |
/**
|
| 1764 |
$base_site_url = $matches[1];
|
| 1765 |
}
|
| 1766 |
|
| 1767 |
+
//Calling admin_url() once and then manually appending each page's path is measurably faster than calling it
|
| 1768 |
+
//for each menu, but it means the "admin_url" filter is only called once. If there is a plugin that changes
|
| 1769 |
+
//the admin_url for some pages but not others, this could lead to bugs (no such plugins are known at this time).
|
| 1770 |
+
$base_admin_url = admin_url();
|
| 1771 |
+
$admin_url_is_filtered = has_filter('admin_url');
|
| 1772 |
+
|
| 1773 |
$current_url = $base_site_url . remove_query_arg('___ame_dummy_param___');
|
| 1774 |
$this->log_security_note(sprintf('Current URL: "%s"', htmlentities($current_url)));
|
| 1775 |
|
| 1782 |
if ( substr($item_url, 0, 1) == '/' ) {
|
| 1783 |
$item_url = $base_site_url . $item_url;
|
| 1784 |
} else {
|
| 1785 |
+
if ( $admin_url_is_filtered ) {
|
| 1786 |
+
$item_url = admin_url($item_url);
|
| 1787 |
+
} else {
|
| 1788 |
+
$item_url = $base_admin_url . ltrim( $item_url, '/' );
|
| 1789 |
+
}
|
| 1790 |
}
|
| 1791 |
}
|
| 1792 |
$item_url = $this->parse_url($item_url);
|
| 1909 |
|
| 1910 |
$display_notice = $this->options['display_survey_notice'] && $this->current_user_can_edit_menu();
|
| 1911 |
if ( isset($this->options['first_install_time']) ) {
|
| 1912 |
+
$minimum_usage_period = 7*24*3600;
|
| 1913 |
$display_notice = $display_notice && ((time() - $this->options['first_install_time']) > $minimum_usage_period);
|
| 1914 |
}
|
| 1915 |
|
| 1927 |
$free_survey_url = 'https://docs.google.com/spreadsheet/viewform?formkey=dERyeDk0OWhlbkxYcEY4QTNaMnlTQUE6MQ';
|
| 1928 |
$pro_survey_url = 'https://docs.google.com/spreadsheet/viewform?formkey=dHl4MnlHaVI3NE5JdVFDWG01SkRKTWc6MA';
|
| 1929 |
|
| 1930 |
+
if ( $this->is_pro_version() ) {
|
| 1931 |
$survey_url = $pro_survey_url;
|
| 1932 |
} else {
|
| 1933 |
$survey_url = $free_survey_url;
|
| 2126 |
return $name;
|
| 2127 |
}
|
| 2128 |
|
| 2129 |
+
/**
|
| 2130 |
+
* Tell new users how to access the plugin settings page.
|
| 2131 |
+
*/
|
| 2132 |
+
public function display_plugin_menu_notice() {
|
| 2133 |
+
//Display the notice only if it's enabled, the current user can access our settings page,
|
| 2134 |
+
//and there is no custom menu (if a custom menu already exists, chances are the user knows
|
| 2135 |
+
//where the settings page is).
|
| 2136 |
+
$showNotice = $this->options['show_plugin_menu_notice'] && ($this->load_custom_menu() === null);
|
| 2137 |
+
$showNotice = $showNotice && $this->current_user_can_edit_menu();
|
| 2138 |
+
if ( !$showNotice ) {
|
| 2139 |
+
return;
|
| 2140 |
+
}
|
| 2141 |
+
|
| 2142 |
+
//Disable the notice when the user hides it or visits any of our admin pages.
|
| 2143 |
+
$hideNoticeParameter = 'ame-plugin-menu-notice';
|
| 2144 |
+
if ( !empty($_GET[$hideNoticeParameter]) || $this->is_editor_page() || $this->is_settings_page() ) {
|
| 2145 |
+
$this->options['show_plugin_menu_notice'] = false;
|
| 2146 |
+
$this->save_options();
|
| 2147 |
+
return;
|
| 2148 |
+
}
|
| 2149 |
+
|
| 2150 |
+
$dismissUrl = add_query_arg($hideNoticeParameter, 'hide');
|
| 2151 |
+
$dismissUrl = remove_query_arg(array('message', 'activate'), $dismissUrl);
|
| 2152 |
+
|
| 2153 |
+
if ( is_multisite() && is_network_admin() ) {
|
| 2154 |
+
$message = 'Tip: Go to any subsite to access Admin Menu Editor. It will not show up in the network admin.';
|
| 2155 |
+
} else {
|
| 2156 |
+
$message = 'Tip: Go to <a href="%1$s">Settings -> %2$s</a> to start customizing the admin menu.';
|
| 2157 |
+
}
|
| 2158 |
+
printf(
|
| 2159 |
+
'<div class="updated" id="ame-plugin-menu-notice">
|
| 2160 |
+
<p>' . $message . '</p>
|
| 2161 |
+
<p><a href="%3$s" id="ame-hide-plugin-menu-notice">Hide this message</a></p>
|
| 2162 |
+
</div>',
|
| 2163 |
+
esc_attr(admin_url($this->settings_link)),
|
| 2164 |
+
apply_filters('admin_menu_editor-self_menu_title', 'Menu Editor'),
|
| 2165 |
+
esc_attr($dismissUrl)
|
| 2166 |
+
);
|
| 2167 |
+
|
| 2168 |
+
}
|
| 2169 |
+
|
| 2170 |
+
private function is_pro_version() {
|
| 2171 |
+
return apply_filters('admin_menu_editor_is_pro', false);
|
| 2172 |
+
}
|
| 2173 |
+
|
| 2174 |
} //class
|
includes/menu-item.php
CHANGED
|
@@ -8,6 +8,22 @@
|
|
| 8 |
* currently registered hooks and the presence of specific files in admin/plugin folders.
|
| 9 |
*/
|
| 10 |
abstract class ameMenuItem {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
/**
|
| 12 |
* Convert a WP menu structure to an associative array.
|
| 13 |
*
|
|
@@ -193,6 +209,10 @@ abstract class ameMenuItem {
|
|
| 193 |
}
|
| 194 |
}
|
| 195 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
return $parent_file . '>' . $item_file;
|
| 197 |
}
|
| 198 |
|
|
@@ -218,10 +238,7 @@ abstract class ameMenuItem {
|
|
| 218 |
/**
|
| 219 |
* Apply custom menu filters to an item of the custom menu.
|
| 220 |
*
|
| 221 |
-
* Calls
|
| 222 |
-
* 'custom_admin_$item_type' with the entire $item passed as the argument.
|
| 223 |
-
* 'custom_admin_$item_type-$field' with the value of a single field of $item as the argument.
|
| 224 |
-
*
|
| 225 |
* Used when converting the current custom menu to a WP-format menu.
|
| 226 |
*
|
| 227 |
* @param array $item Associative array representing one menu item (either top-level or submenu).
|
|
@@ -230,12 +247,7 @@ abstract class ameMenuItem {
|
|
| 230 |
* @return array Filtered menu item.
|
| 231 |
*/
|
| 232 |
public static function apply_filters($item, $item_type, $extra = null){
|
| 233 |
-
|
| 234 |
-
foreach($item as $field => $value){
|
| 235 |
-
$item[$field] = apply_filters("custom_admin_{$item_type}-$field", $value, $extra);
|
| 236 |
-
}
|
| 237 |
-
|
| 238 |
-
return $item;
|
| 239 |
}
|
| 240 |
|
| 241 |
/**
|
|
@@ -376,11 +388,28 @@ abstract class ameMenuItem {
|
|
| 376 |
}
|
| 377 |
$pageFile = self::remove_query_from($page_url);
|
| 378 |
|
| 379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
$adminFileExists = is_file(ABSPATH . '/wp-admin/' . $pageFile);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
$pluginFileExists = ($page_url != 'index.php') && is_file(WP_PLUGIN_DIR . '/' . $pageFile);
|
|
|
|
|
|
|
|
|
|
| 382 |
|
| 383 |
-
return
|
| 384 |
}
|
| 385 |
|
| 386 |
/**
|
| 8 |
* currently registered hooks and the presence of specific files in admin/plugin folders.
|
| 9 |
*/
|
| 10 |
abstract class ameMenuItem {
|
| 11 |
+
/**
|
| 12 |
+
* @var array A partial list of files in /wp-admin/. Correct as of WP 3.8-RC1, 2013.12.04.
|
| 13 |
+
* When trying to determine if a menu links to one of the default WP admin pages, it's faster
|
| 14 |
+
* to check this list than to hit the disk.
|
| 15 |
+
*/
|
| 16 |
+
private static $known_wp_admin_files = array(
|
| 17 |
+
'customize.php' => true, 'edit-comments.php' => true, 'edit-tags.php' => true, 'edit.php' => true,
|
| 18 |
+
'export.php' => true, 'import.php' => true, 'index.php' => true, 'link-add.php' => true,
|
| 19 |
+
'link-manager.php' => true, 'media-new.php' => true, 'nav-menus.php' => true, 'options-discussion.php' => true,
|
| 20 |
+
'options-general.php' => true, 'options-media.php' => true, 'options-permalink.php' => true,
|
| 21 |
+
'options-reading.php' => true, 'options-writing.php' => true, 'plugin-editor.php' => true,
|
| 22 |
+
'plugin-install.php' => true, 'plugins.php' => true, 'post-new.php' => true, 'profile.php' => true,
|
| 23 |
+
'theme-editor.php' => true, 'themes.php' => true, 'tools.php' => true, 'update-core.php' => true,
|
| 24 |
+
'upload.php' => true, 'user-new.php' => true, 'users.php' => true, 'widgets.php' => true,
|
| 25 |
+
);
|
| 26 |
+
|
| 27 |
/**
|
| 28 |
* Convert a WP menu structure to an associative array.
|
| 29 |
*
|
| 209 |
}
|
| 210 |
}
|
| 211 |
|
| 212 |
+
if ($parent_file === 'profile.php') {
|
| 213 |
+
$parent_file = 'users.php';
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
return $parent_file . '>' . $item_file;
|
| 217 |
}
|
| 218 |
|
| 238 |
/**
|
| 239 |
* Apply custom menu filters to an item of the custom menu.
|
| 240 |
*
|
| 241 |
+
* Calls a 'custom_admin_$item_type' filter with the entire $item passed as the argument.
|
|
|
|
|
|
|
|
|
|
| 242 |
* Used when converting the current custom menu to a WP-format menu.
|
| 243 |
*
|
| 244 |
* @param array $item Associative array representing one menu item (either top-level or submenu).
|
| 247 |
* @return array Filtered menu item.
|
| 248 |
*/
|
| 249 |
public static function apply_filters($item, $item_type, $extra = null){
|
| 250 |
+
return apply_filters("custom_admin_{$item_type}", $item, $extra);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
}
|
| 252 |
|
| 253 |
/**
|
| 388 |
}
|
| 389 |
$pageFile = self::remove_query_from($page_url);
|
| 390 |
|
| 391 |
+
//Check our hard-coded list of admin pages first. It's measurably faster than
|
| 392 |
+
//hitting the disk with is_file().
|
| 393 |
+
if ( isset(self::$known_wp_admin_files[$pageFile]) ) {
|
| 394 |
+
return false;
|
| 395 |
+
}
|
| 396 |
+
//Now actually check the filesystem.
|
| 397 |
$adminFileExists = is_file(ABSPATH . '/wp-admin/' . $pageFile);
|
| 398 |
+
if ( $adminFileExists ) {
|
| 399 |
+
return false;
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
$hasHook = (get_plugin_page_hook($page_url, $parent_page_url) !== null);
|
| 403 |
+
if ( $hasHook ) {
|
| 404 |
+
return true;
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
$pluginFileExists = ($page_url != 'index.php') && is_file(WP_PLUGIN_DIR . '/' . $pageFile);
|
| 408 |
+
if ( $pluginFileExists ) {
|
| 409 |
+
return true;
|
| 410 |
+
}
|
| 411 |
|
| 412 |
+
return false;
|
| 413 |
}
|
| 414 |
|
| 415 |
/**
|
includes/menu.php
CHANGED
|
@@ -1,42 +1,50 @@
|
|
| 1 |
<?php
|
| 2 |
abstract class ameMenu {
|
| 3 |
const format_name = 'Admin Menu Editor menu';
|
| 4 |
-
const format_version = '5.
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Load an admin menu from a JSON string.
|
| 8 |
*
|
| 9 |
* @static
|
| 10 |
-
* @throws InvalidMenuException when the supplied input is not a valid menu.
|
| 11 |
*
|
| 12 |
* @param string $json A JSON-encoded menu structure.
|
| 13 |
* @param bool $assume_correct_format Skip the format header check and assume everything is fine. Defaults to false.
|
|
|
|
|
|
|
| 14 |
* @return array
|
| 15 |
*/
|
| 16 |
-
public static function load_json($json, $assume_correct_format = false) {
|
| 17 |
$arr = json_decode($json, true);
|
| 18 |
if ( !is_array($arr) ) {
|
| 19 |
throw new InvalidMenuException('The input is not a valid JSON-encoded admin menu.');
|
| 20 |
}
|
| 21 |
-
return self::load_array($arr, $assume_correct_format);
|
| 22 |
}
|
| 23 |
|
| 24 |
/**
|
| 25 |
* Load an admin menu structure from an associative array.
|
| 26 |
*
|
| 27 |
* @static
|
| 28 |
-
* @throws InvalidMenuException when the supplied input is not a valid menu.
|
| 29 |
*
|
| 30 |
* @param array $arr
|
| 31 |
* @param bool $assume_correct_format
|
|
|
|
|
|
|
| 32 |
* @return array
|
| 33 |
*/
|
| 34 |
-
public static function load_array($arr, $assume_correct_format = false){
|
|
|
|
| 35 |
if ( !$assume_correct_format ) {
|
| 36 |
if ( isset($arr['format']) && ($arr['format']['name'] == self::format_name) ) {
|
| 37 |
-
|
|
|
|
| 38 |
throw new InvalidMenuException("Can't load a menu created by a newer version of the plugin.");
|
| 39 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
} else {
|
| 41 |
return self::load_menu_40($arr);
|
| 42 |
}
|
|
@@ -49,8 +57,13 @@ abstract class ameMenu {
|
|
| 49 |
$menu = array('tree' => array());
|
| 50 |
$menu = self::add_format_header($menu);
|
| 51 |
|
| 52 |
-
|
| 53 |
-
$menu['tree']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
}
|
| 55 |
|
| 56 |
return $menu;
|
|
@@ -135,7 +148,7 @@ abstract class ameMenu {
|
|
| 135 |
$parent = $tree_item['defaults']['file'];
|
| 136 |
if ( isset($submenu[$parent]) ){
|
| 137 |
foreach($submenu[$parent] as $position => $subitem){
|
| 138 |
-
$tree_item['items'][
|
| 139 |
ameMenuItem::blank_menu(),
|
| 140 |
array('defaults' => ameMenuItem::fromWpItem($subitem, $position, $parent))
|
| 141 |
);
|
|
@@ -149,6 +162,33 @@ abstract class ameMenu {
|
|
| 149 |
|
| 150 |
return $tree;
|
| 151 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
}
|
| 153 |
|
| 154 |
|
| 1 |
<?php
|
| 2 |
abstract class ameMenu {
|
| 3 |
const format_name = 'Admin Menu Editor menu';
|
| 4 |
+
const format_version = '5.1';
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Load an admin menu from a JSON string.
|
| 8 |
*
|
| 9 |
* @static
|
|
|
|
| 10 |
*
|
| 11 |
* @param string $json A JSON-encoded menu structure.
|
| 12 |
* @param bool $assume_correct_format Skip the format header check and assume everything is fine. Defaults to false.
|
| 13 |
+
* @param bool $always_normalize Always normalize the menu structure, even if format.is_normalized is true.
|
| 14 |
+
* @throws InvalidMenuException
|
| 15 |
* @return array
|
| 16 |
*/
|
| 17 |
+
public static function load_json($json, $assume_correct_format = false, $always_normalize = false) {
|
| 18 |
$arr = json_decode($json, true);
|
| 19 |
if ( !is_array($arr) ) {
|
| 20 |
throw new InvalidMenuException('The input is not a valid JSON-encoded admin menu.');
|
| 21 |
}
|
| 22 |
+
return self::load_array($arr, $assume_correct_format, $always_normalize);
|
| 23 |
}
|
| 24 |
|
| 25 |
/**
|
| 26 |
* Load an admin menu structure from an associative array.
|
| 27 |
*
|
| 28 |
* @static
|
|
|
|
| 29 |
*
|
| 30 |
* @param array $arr
|
| 31 |
* @param bool $assume_correct_format
|
| 32 |
+
* @param bool $always_normalize
|
| 33 |
+
* @throws InvalidMenuException
|
| 34 |
* @return array
|
| 35 |
*/
|
| 36 |
+
public static function load_array($arr, $assume_correct_format = false, $always_normalize = false){
|
| 37 |
+
$is_normalized = false;
|
| 38 |
if ( !$assume_correct_format ) {
|
| 39 |
if ( isset($arr['format']) && ($arr['format']['name'] == self::format_name) ) {
|
| 40 |
+
$compared = version_compare($arr['format']['version'], self::format_version);
|
| 41 |
+
if ( $compared > 0 ) {
|
| 42 |
throw new InvalidMenuException("Can't load a menu created by a newer version of the plugin.");
|
| 43 |
}
|
| 44 |
+
//We can skip normalization if the version number matches exactly and the menu is already normalized.
|
| 45 |
+
if ( ($compared === 0) && isset($arr['format']['is_normalized']) ) {
|
| 46 |
+
$is_normalized = $arr['format']['is_normalized'];
|
| 47 |
+
}
|
| 48 |
} else {
|
| 49 |
return self::load_menu_40($arr);
|
| 50 |
}
|
| 57 |
$menu = array('tree' => array());
|
| 58 |
$menu = self::add_format_header($menu);
|
| 59 |
|
| 60 |
+
if ( $is_normalized && !$always_normalize ) {
|
| 61 |
+
$menu['tree'] = $arr['tree'];
|
| 62 |
+
} else {
|
| 63 |
+
foreach($arr['tree'] as $file => $item) {
|
| 64 |
+
$menu['tree'][$file] = ameMenuItem::normalize($item);
|
| 65 |
+
}
|
| 66 |
+
$menu['format']['is_normalized'] = true;
|
| 67 |
}
|
| 68 |
|
| 69 |
return $menu;
|
| 148 |
$parent = $tree_item['defaults']['file'];
|
| 149 |
if ( isset($submenu[$parent]) ){
|
| 150 |
foreach($submenu[$parent] as $position => $subitem){
|
| 151 |
+
$tree_item['items'][] = array_merge(
|
| 152 |
ameMenuItem::blank_menu(),
|
| 153 |
array('defaults' => ameMenuItem::fromWpItem($subitem, $position, $parent))
|
| 154 |
);
|
| 162 |
|
| 163 |
return $tree;
|
| 164 |
}
|
| 165 |
+
|
| 166 |
+
/**
|
| 167 |
+
* Check if a menu contains any items with the "hidden" flag set to true.
|
| 168 |
+
*
|
| 169 |
+
* @param array $menu
|
| 170 |
+
* @return bool
|
| 171 |
+
*/
|
| 172 |
+
public static function has_hidden_items($menu) {
|
| 173 |
+
if ( !is_array($menu) || empty($menu) || empty($menu['tree']) ) {
|
| 174 |
+
return false;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
foreach($menu['tree'] as $item) {
|
| 178 |
+
if ( ameMenuItem::get($item, 'hidden') ) {
|
| 179 |
+
return true;
|
| 180 |
+
}
|
| 181 |
+
if ( !empty($item['items']) ) {
|
| 182 |
+
foreach($item['items'] as $child) {
|
| 183 |
+
if ( ameMenuItem::get($child, 'hidden') ) {
|
| 184 |
+
return true;
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
return false;
|
| 191 |
+
}
|
| 192 |
}
|
| 193 |
|
| 194 |
|
includes/settings-page.php
CHANGED
|
@@ -125,11 +125,26 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
| 125 |
<tr>
|
| 126 |
<th scope="row">Interface</th>
|
| 127 |
<td>
|
| 128 |
-
<
|
| 129 |
-
<
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
</td>
|
| 134 |
</tr>
|
| 135 |
|
|
@@ -138,7 +153,7 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
| 138 |
<td>
|
| 139 |
<label>
|
| 140 |
<input type="checkbox" name="security_logging_enabled"
|
| 141 |
-
<?php checked($
|
| 142 |
Show menu access checks performed by the plugin on every admin page
|
| 143 |
</label>
|
| 144 |
<br><span class="description">
|
| 125 |
<tr>
|
| 126 |
<th scope="row">Interface</th>
|
| 127 |
<td>
|
| 128 |
+
<p>
|
| 129 |
+
<label>
|
| 130 |
+
<input type="checkbox" name="hide_advanced_settings"
|
| 131 |
+
<?php checked($settings['hide_advanced_settings']); ?>>
|
| 132 |
+
Hide advanced menu options by default
|
| 133 |
+
</label>
|
| 134 |
+
</p>
|
| 135 |
+
|
| 136 |
+
<?php if ($isProVersion): ?>
|
| 137 |
+
<p>
|
| 138 |
+
<label>
|
| 139 |
+
<input type="checkbox" name="show_deprecated_hide_button"
|
| 140 |
+
<?php checked($settings['show_deprecated_hide_button']); ?>>
|
| 141 |
+
Enable the "Show/Hide" toolbar button (not recommended)
|
| 142 |
+
</label>
|
| 143 |
+
<br><span class="description">
|
| 144 |
+
This feature is deprecated and is only kept for backwards compatibility purposes.
|
| 145 |
+
</span>
|
| 146 |
+
</p>
|
| 147 |
+
<?php endif; ?>
|
| 148 |
</td>
|
| 149 |
</tr>
|
| 150 |
|
| 153 |
<td>
|
| 154 |
<label>
|
| 155 |
<input type="checkbox" name="security_logging_enabled"
|
| 156 |
+
<?php checked($settings['security_logging_enabled']); ?>>
|
| 157 |
Show menu access checks performed by the plugin on every admin page
|
| 158 |
</label>
|
| 159 |
<br><span class="description">
|
js/menu-editor.js
CHANGED
|
@@ -1358,7 +1358,18 @@ $(document).ready(function(){
|
|
| 1358 |
var checked = $(this).is(':checked');
|
| 1359 |
var containerNode = $(this).closest('.ws_container');
|
| 1360 |
|
| 1361 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1362 |
});
|
| 1363 |
|
| 1364 |
/**
|
|
@@ -1388,6 +1399,58 @@ $(document).ready(function(){
|
|
| 1388 |
updateParentAccessUi(containerNode);
|
| 1389 |
}
|
| 1390 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1391 |
/*************************************************************************
|
| 1392 |
Access editor dialog
|
| 1393 |
*************************************************************************/
|
|
@@ -1460,7 +1523,7 @@ $(document).ready(function(){
|
|
| 1460 |
accessEditorState.menuItem = menuItem;
|
| 1461 |
|
| 1462 |
//Show/hide the hint about sub menus overriding menu permissions.
|
| 1463 |
-
var itemHasSubmenus = containerNode.data('submenu_id') &&
|
| 1464 |
$('#' + containerNode.data('submenu_id')).find('.ws_item').length > 0;
|
| 1465 |
var hintIsEnabled = !wsEditorData.showHints.hasOwnProperty('ws_hint_menu_permissions') || wsEditorData.showHints['ws_hint_menu_permissions'];
|
| 1466 |
$('#ws_hint_menu_permissions').toggle(hintIsEnabled && itemHasSubmenus);
|
|
@@ -1479,7 +1542,8 @@ $(document).ready(function(){
|
|
| 1479 |
|
| 1480 |
$('#ws_save_access_settings').click(function() {
|
| 1481 |
//Save the new settings.
|
| 1482 |
-
|
|
|
|
| 1483 |
|
| 1484 |
var grantAccess = accessEditorState.menuItem.grant_access;
|
| 1485 |
if (!$.isPlainObject(grantAccess)) {
|
| 1358 |
var checked = $(this).is(':checked');
|
| 1359 |
var containerNode = $(this).closest('.ws_container');
|
| 1360 |
|
| 1361 |
+
var menu = containerNode.data('menu_item');
|
| 1362 |
+
//Ask for confirmation if the user tries to hide Dashboard -> Home.
|
| 1363 |
+
if ( !checked && ((menu.template_id == 'index.php>index.php') || (menu.template_id == '>index.php')) ) {
|
| 1364 |
+
updateItemEditor(containerNode); //Resets the checkbox back to the old value.
|
| 1365 |
+
confirmDashboardHiding(function(ok) {
|
| 1366 |
+
if (ok) {
|
| 1367 |
+
setActorAccessForTreeAndUpdateUi(containerNode, selectedActor, checked);
|
| 1368 |
+
}
|
| 1369 |
+
});
|
| 1370 |
+
} else {
|
| 1371 |
+
setActorAccessForTreeAndUpdateUi(containerNode, selectedActor, checked);
|
| 1372 |
+
}
|
| 1373 |
});
|
| 1374 |
|
| 1375 |
/**
|
| 1399 |
updateParentAccessUi(containerNode);
|
| 1400 |
}
|
| 1401 |
|
| 1402 |
+
/**
|
| 1403 |
+
* Confirm with the user that they want to hide "Dashboard -> Home".
|
| 1404 |
+
*
|
| 1405 |
+
* This particular menu is important because hiding it can cause an "insufficient permissions" error
|
| 1406 |
+
* to be displayed right when someone logs in, making it look like login failed.
|
| 1407 |
+
*/
|
| 1408 |
+
var permissionConfirmationDialog = $('#ws-ame-dashboard-hide-confirmation').dialog({
|
| 1409 |
+
autoOpen: false,
|
| 1410 |
+
modal: true,
|
| 1411 |
+
closeText: ' ',
|
| 1412 |
+
width: 380,
|
| 1413 |
+
title: 'Warning'
|
| 1414 |
+
});
|
| 1415 |
+
var currentConfirmationCallback = function(ok) {};
|
| 1416 |
+
|
| 1417 |
+
/**
|
| 1418 |
+
* Confirm hiding "Dashboard -> Home".
|
| 1419 |
+
*
|
| 1420 |
+
* @param callback Called when the user selects an option. True = confirmed.
|
| 1421 |
+
*/
|
| 1422 |
+
function confirmDashboardHiding(callback) {
|
| 1423 |
+
//The user can disable the confirmation dialog.
|
| 1424 |
+
if (!wsEditorData.dashboardHidingConfirmationEnabled) {
|
| 1425 |
+
callback(true);
|
| 1426 |
+
return;
|
| 1427 |
+
}
|
| 1428 |
+
|
| 1429 |
+
currentConfirmationCallback = callback;
|
| 1430 |
+
permissionConfirmationDialog.dialog('open');
|
| 1431 |
+
}
|
| 1432 |
+
|
| 1433 |
+
$('#ws_confirm_menu_hiding, #ws_cancel_menu_hiding').click(function() {
|
| 1434 |
+
var confirmed = $(this).is('#ws_confirm_menu_hiding');
|
| 1435 |
+
var dontShowAgain = permissionConfirmationDialog.find('.ws_dont_show_again input[type="checkbox"]').is(':checked');
|
| 1436 |
+
|
| 1437 |
+
currentConfirmationCallback(confirmed);
|
| 1438 |
+
permissionConfirmationDialog.dialog('close');
|
| 1439 |
+
|
| 1440 |
+
if (dontShowAgain) {
|
| 1441 |
+
wsEditorData.dashboardHidingConfirmationEnabled = false;
|
| 1442 |
+
//Run an AJAX request to disable the dialog for this user.
|
| 1443 |
+
$.post(
|
| 1444 |
+
wsEditorData.adminAjaxUrl,
|
| 1445 |
+
{
|
| 1446 |
+
'action' : 'ws_ame_disable_dashboard_hiding_confirmation',
|
| 1447 |
+
'_ajax_nonce' : wsEditorData.disableDashboardConfirmationNonce
|
| 1448 |
+
}
|
| 1449 |
+
);
|
| 1450 |
+
}
|
| 1451 |
+
});
|
| 1452 |
+
|
| 1453 |
+
|
| 1454 |
/*************************************************************************
|
| 1455 |
Access editor dialog
|
| 1456 |
*************************************************************************/
|
| 1523 |
accessEditorState.menuItem = menuItem;
|
| 1524 |
|
| 1525 |
//Show/hide the hint about sub menus overriding menu permissions.
|
| 1526 |
+
var itemHasSubmenus = !!(containerNode.data('submenu_id')) &&
|
| 1527 |
$('#' + containerNode.data('submenu_id')).find('.ws_item').length > 0;
|
| 1528 |
var hintIsEnabled = !wsEditorData.showHints.hasOwnProperty('ws_hint_menu_permissions') || wsEditorData.showHints['ws_hint_menu_permissions'];
|
| 1529 |
$('#ws_hint_menu_permissions').toggle(hintIsEnabled && itemHasSubmenus);
|
| 1542 |
|
| 1543 |
$('#ws_save_access_settings').click(function() {
|
| 1544 |
//Save the new settings.
|
| 1545 |
+
var extraCapability = jsTrim($('#ws_extra_capability').val());
|
| 1546 |
+
accessEditorState.menuItem.extra_capability = (extraCapability === '') ? null : extraCapability;
|
| 1547 |
|
| 1548 |
var grantAccess = accessEditorState.menuItem.grant_access;
|
| 1549 |
if (!$.isPlainObject(grantAccess)) {
|
menu-editor.php
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
Plugin Name: Admin Menu Editor
|
| 4 |
Plugin URI: http://w-shadow.com/blog/2008/12/20/admin-menu-editor-for-wordpress/
|
| 5 |
Description: Lets you directly edit the WordPress admin menu. You can re-order, hide or rename existing menus, add custom menus and more.
|
| 6 |
-
Version: 1.3
|
| 7 |
Author: Janis Elsts
|
| 8 |
Author URI: http://w-shadow.com/blog/
|
| 9 |
*/
|
| 3 |
Plugin Name: Admin Menu Editor
|
| 4 |
Plugin URI: http://w-shadow.com/blog/2008/12/20/admin-menu-editor-for-wordpress/
|
| 5 |
Description: Lets you directly edit the WordPress admin menu. You can re-order, hide or rename existing menus, add custom menus and more.
|
| 6 |
+
Version: 1.3.1
|
| 7 |
Author: Janis Elsts
|
| 8 |
Author URI: http://w-shadow.com/blog/
|
| 9 |
*/
|
readme.txt
CHANGED
|
@@ -2,9 +2,9 @@
|
|
| 2 |
Contributors: whiteshadow
|
| 3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A6P9S6CE3SRSW
|
| 4 |
Tags: admin, dashboard, menu, security, wpmu
|
| 5 |
-
Requires at least: 3.
|
| 6 |
-
Tested up to: 3.
|
| 7 |
-
Stable tag: 1.3
|
| 8 |
|
| 9 |
Lets you edit the WordPress admin menu. You can re-order, hide or rename menus, add custom menus and more.
|
| 10 |
|
|
@@ -63,6 +63,17 @@ Plugins installed in the `mu-plugins` directory are treated as "always on", so y
|
|
| 63 |
|
| 64 |
== Changelog ==
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
= 1.3 =
|
| 67 |
* Added a new settings page that lets you choose whether admin menu settings are per-site or network-wide, as well as specify who can access the plugin. To access this page, go to "Settings -> Menu Editor Pro" and click the small "Settings" link next to the page title.
|
| 68 |
* Added a way to show/hide advanced menu options through the settings page in addition to the "Screen Options" panel.
|
| 2 |
Contributors: whiteshadow
|
| 3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A6P9S6CE3SRSW
|
| 4 |
Tags: admin, dashboard, menu, security, wpmu
|
| 5 |
+
Requires at least: 3.3
|
| 6 |
+
Tested up to: 3.8
|
| 7 |
+
Stable tag: 1.3.1
|
| 8 |
|
| 9 |
Lets you edit the WordPress admin menu. You can re-order, hide or rename menus, add custom menus and more.
|
| 10 |
|
| 63 |
|
| 64 |
== Changelog ==
|
| 65 |
|
| 66 |
+
= 1.3.1 =
|
| 67 |
+
* Tested with WordPress 3.8.
|
| 68 |
+
* Fixed several minor UI/layout issues related to the new 3.8 admin style.
|
| 69 |
+
* Fixed a bug where moving an item to a plugin menu and then deactivating that plugin would cause the moved item to disappear.
|
| 70 |
+
* Fixed deleted submenus not being restored if their original parent menu is no longer available.
|
| 71 |
+
* Fixed a rare glitch where submenu separators added by certain other plugins would sometimes disappear.
|
| 72 |
+
* Fixed a conflict with Shopp 1.2.9.
|
| 73 |
+
* Made the plugin treat "users.php" and "profile.php" as the same parent menu. This fixes situations where it would be impossible to hide a "Users" submenu item from roles that don't have access to the "Users" menu and instead get a "Profile" menu.
|
| 74 |
+
* Added extra logging for situations where a menu item is hidden because a higher-priority item with the same URL is also hidden.
|
| 75 |
+
* Minor performance improvements.
|
| 76 |
+
|
| 77 |
= 1.3 =
|
| 78 |
* Added a new settings page that lets you choose whether admin menu settings are per-site or network-wide, as well as specify who can access the plugin. To access this page, go to "Settings -> Menu Editor Pro" and click the small "Settings" link next to the page title.
|
| 79 |
* Added a way to show/hide advanced menu options through the settings page in addition to the "Screen Options" panel.
|
