Version Description
- Fixed the PHP warning "count(): Parameter must be an array or an object that implements Countable in menu-editor-core.php".
- Fixed a bug that could cause some network admin menus to be highlighted in green as if they were new.
- Fixed a conflict with WP Courseware 4.1.2 where activating AME would cause many extra menu items to show up unexpectedly.
- Fixed a conflict with Ultra WordPress Admin 7.4 that made it impossible to hide plugins.
- Replaced the "this is a new item" icon with a different one.
- Tested with WP 4.9.4.
Download this release
Release Info
| Developer | whiteshadow |
| Plugin | |
| Version | 1.8.2 |
| Comparing to | |
| See all releases | |
Code changes from version 1.8.1 to 1.8.2
- css/menu-editor.css +28 -2
- css/menu-editor.scss +41 -2
- images/new-menu-badge.png +0 -0
- includes/editor-page.php +60 -3
- includes/menu-editor-core.php +154 -14
- includes/module.php +33 -0
- includes/role-utils.php +7 -1
- js/actor-manager.js +41 -28
- js/actor-manager.ts +47 -26
- js/menu-editor.js +46 -12
- menu-editor.php +1 -1
- modules/actor-selector/actor-selector.js +9 -1
- modules/actor-selector/actor-selector.ts +7 -0
- modules/highlight-new-menus/wsNewMenuHighlighter.php +8 -2
- modules/plugin-visibility/plugin-visibility.js +2 -2
- modules/plugin-visibility/plugin-visibility.php +1 -1
- readme.txt +10 -2
css/menu-editor.css
CHANGED
|
@@ -422,7 +422,8 @@ to accommodate the drop-down button.
|
|
| 422 |
|
| 423 |
/* unused items - those that are in the default menu but not in the custom one */
|
| 424 |
.ws_unused_flag {
|
| 425 |
-
background-image: url("../images/
|
|
|
|
| 426 |
|
| 427 |
/* hidden items */
|
| 428 |
.ws_hidden_flag {
|
|
@@ -446,6 +447,15 @@ to accommodate the drop-down button.
|
|
| 446 |
.ws_hidden_from_others_flag {
|
| 447 |
background-image: url("../images/font-awesome/eye-slash.png"); }
|
| 448 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 449 |
/* These classes could be used to apply different styles to items depending on their flags */
|
| 450 |
/************************************
|
| 451 |
Toolbars
|
|
@@ -802,7 +812,8 @@ a#ws-ame-delete-color-preset:hover {
|
|
| 802 |
font-size: 12px;
|
| 803 |
border: 1px solid #ddd;
|
| 804 |
background: white;
|
| 805 |
-
cursor: pointer;
|
|
|
|
| 806 |
|
| 807 |
.ws_color_display_item {
|
| 808 |
display: inline-block;
|
|
@@ -1320,6 +1331,8 @@ a#ws-ame-delete-color-preset:hover {
|
|
| 1320 |
|
| 1321 |
.ws_ame_doc_box .hndle, .ws_ame_custom_postbox .hndle {
|
| 1322 |
cursor: default !important; }
|
|
|
|
|
|
|
| 1323 |
.ws_ame_doc_box ul, .ws_ame_custom_postbox ul {
|
| 1324 |
list-style: disc outside;
|
| 1325 |
margin-left: 1em; }
|
|
@@ -1344,6 +1357,19 @@ a#ws-ame-delete-color-preset:hover {
|
|
| 1344 |
margin-left: 2px;
|
| 1345 |
margin-right: 2px; }
|
| 1346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1347 |
/************************************
|
| 1348 |
Copy Permissions dialog
|
| 1349 |
*************************************/
|
| 422 |
|
| 423 |
/* unused items - those that are in the default menu but not in the custom one */
|
| 424 |
.ws_unused_flag {
|
| 425 |
+
background-image: url("../images/new-menu-badge.png");
|
| 426 |
+
width: 31px; }
|
| 427 |
|
| 428 |
/* hidden items */
|
| 429 |
.ws_hidden_flag {
|
| 447 |
.ws_hidden_from_others_flag {
|
| 448 |
background-image: url("../images/font-awesome/eye-slash.png"); }
|
| 449 |
|
| 450 |
+
/* Item visibility can't be determined because it depends on a meta capability. */
|
| 451 |
+
.ws_uncertain_meta_cap_flag::before {
|
| 452 |
+
font: 16px/1 'dashicons';
|
| 453 |
+
content: "\f348";
|
| 454 |
+
color: black;
|
| 455 |
+
filter: alpha(opacity=25);
|
| 456 |
+
/*IE 5-7*/
|
| 457 |
+
opacity: 0.25; }
|
| 458 |
+
|
| 459 |
/* These classes could be used to apply different styles to items depending on their flags */
|
| 460 |
/************************************
|
| 461 |
Toolbars
|
| 812 |
font-size: 12px;
|
| 813 |
border: 1px solid #ddd;
|
| 814 |
background: white;
|
| 815 |
+
cursor: pointer;
|
| 816 |
+
line-height: 20px; }
|
| 817 |
|
| 818 |
.ws_color_display_item {
|
| 819 |
display: inline-block;
|
| 1331 |
|
| 1332 |
.ws_ame_doc_box .hndle, .ws_ame_custom_postbox .hndle {
|
| 1333 |
cursor: default !important; }
|
| 1334 |
+
.ws_ame_doc_box .inside, .ws_ame_custom_postbox .inside {
|
| 1335 |
+
margin-bottom: 0; }
|
| 1336 |
.ws_ame_doc_box ul, .ws_ame_custom_postbox ul {
|
| 1337 |
list-style: disc outside;
|
| 1338 |
margin-left: 1em; }
|
| 1357 |
margin-left: 2px;
|
| 1358 |
margin-right: 2px; }
|
| 1359 |
|
| 1360 |
+
.ws_ame_custom_postbox .ame-tutorial-list {
|
| 1361 |
+
margin: 0; }
|
| 1362 |
+
.ws_ame_custom_postbox .ame-tutorial-list a {
|
| 1363 |
+
text-decoration: none;
|
| 1364 |
+
display: block;
|
| 1365 |
+
padding: 4px; }
|
| 1366 |
+
.ws_ame_custom_postbox .ame-tutorial-list ul {
|
| 1367 |
+
margin-left: 1em; }
|
| 1368 |
+
.ws_ame_custom_postbox .ame-tutorial-list li {
|
| 1369 |
+
display: block;
|
| 1370 |
+
margin: 0;
|
| 1371 |
+
list-style: none; }
|
| 1372 |
+
|
| 1373 |
/************************************
|
| 1374 |
Copy Permissions dialog
|
| 1375 |
*************************************/
|
css/menu-editor.scss
CHANGED
|
@@ -582,7 +582,8 @@ to accommodate the drop-down button.
|
|
| 582 |
|
| 583 |
/* unused items - those that are in the default menu but not in the custom one */
|
| 584 |
.ws_unused_flag {
|
| 585 |
-
background-image: url('../images/
|
|
|
|
| 586 |
}
|
| 587 |
|
| 588 |
/* hidden items */
|
|
@@ -608,6 +609,16 @@ to accommodate the drop-down button.
|
|
| 608 |
background-image: url('../images/font-awesome/eye-slash.png');
|
| 609 |
}
|
| 610 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 611 |
/* These classes could be used to apply different styles to items depending on their flags */
|
| 612 |
.ws_custom { }
|
| 613 |
.ws_hidden { }
|
|
@@ -1078,8 +1089,10 @@ a#ws-ame-delete-color-preset:hover {
|
|
| 1078 |
/* Color scheme display in the editor widget. */
|
| 1079 |
|
| 1080 |
.ws_color_scheme_display {
|
|
|
|
|
|
|
| 1081 |
display: inline-block;
|
| 1082 |
-
height:
|
| 1083 |
width: 186px;
|
| 1084 |
|
| 1085 |
margin-right: 5px;
|
|
@@ -1089,6 +1102,8 @@ a#ws-ame-delete-color-preset:hover {
|
|
| 1089 |
border: 1px solid #ddd;
|
| 1090 |
background: white;
|
| 1091 |
cursor: pointer;
|
|
|
|
|
|
|
| 1092 |
}
|
| 1093 |
|
| 1094 |
.ws_color_display_item {
|
|
@@ -1860,6 +1875,10 @@ $userSelectionPanelPadding: 10px;
|
|
| 1860 |
cursor: default !important;
|
| 1861 |
}
|
| 1862 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1863 |
ul {
|
| 1864 |
list-style: disc outside;
|
| 1865 |
margin-left: 1em;
|
|
@@ -1896,6 +1915,26 @@ $userSelectionPanelPadding: 10px;
|
|
| 1896 |
margin-right: 2px;
|
| 1897 |
}
|
| 1898 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1899 |
/************************************
|
| 1900 |
Copy Permissions dialog
|
| 1901 |
*************************************/
|
| 582 |
|
| 583 |
/* unused items - those that are in the default menu but not in the custom one */
|
| 584 |
.ws_unused_flag {
|
| 585 |
+
background-image: url('../images/new-menu-badge.png');
|
| 586 |
+
width: 31px;
|
| 587 |
}
|
| 588 |
|
| 589 |
/* hidden items */
|
| 609 |
background-image: url('../images/font-awesome/eye-slash.png');
|
| 610 |
}
|
| 611 |
|
| 612 |
+
/* Item visibility can't be determined because it depends on a meta capability. */
|
| 613 |
+
.ws_uncertain_meta_cap_flag::before {
|
| 614 |
+
font: 16px/1 'dashicons';
|
| 615 |
+
content: "\f348";
|
| 616 |
+
color: black;
|
| 617 |
+
|
| 618 |
+
filter: alpha(opacity=25); /*IE 5-7*/
|
| 619 |
+
opacity: 0.25;
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
/* These classes could be used to apply different styles to items depending on their flags */
|
| 623 |
.ws_custom { }
|
| 624 |
.ws_hidden { }
|
| 1089 |
/* Color scheme display in the editor widget. */
|
| 1090 |
|
| 1091 |
.ws_color_scheme_display {
|
| 1092 |
+
$colorFieldHeight: 20px;
|
| 1093 |
+
|
| 1094 |
display: inline-block;
|
| 1095 |
+
height: $colorFieldHeight;
|
| 1096 |
width: 186px;
|
| 1097 |
|
| 1098 |
margin-right: 5px;
|
| 1102 |
border: 1px solid #ddd;
|
| 1103 |
background: white;
|
| 1104 |
cursor: pointer;
|
| 1105 |
+
|
| 1106 |
+
line-height: $colorFieldHeight;
|
| 1107 |
}
|
| 1108 |
|
| 1109 |
.ws_color_display_item {
|
| 1875 |
cursor: default !important;
|
| 1876 |
}
|
| 1877 |
|
| 1878 |
+
.inside {
|
| 1879 |
+
margin-bottom: 0;
|
| 1880 |
+
}
|
| 1881 |
+
|
| 1882 |
ul {
|
| 1883 |
list-style: disc outside;
|
| 1884 |
margin-left: 1em;
|
| 1915 |
margin-right: 2px;
|
| 1916 |
}
|
| 1917 |
|
| 1918 |
+
.ws_ame_custom_postbox .ame-tutorial-list {
|
| 1919 |
+
margin: 0;
|
| 1920 |
+
|
| 1921 |
+
a {
|
| 1922 |
+
text-decoration: none;
|
| 1923 |
+
display: block;
|
| 1924 |
+
padding: 4px;
|
| 1925 |
+
}
|
| 1926 |
+
|
| 1927 |
+
ul {
|
| 1928 |
+
margin-left: 1em;
|
| 1929 |
+
}
|
| 1930 |
+
|
| 1931 |
+
li {
|
| 1932 |
+
display: block;
|
| 1933 |
+
margin: 0;
|
| 1934 |
+
list-style: none;
|
| 1935 |
+
}
|
| 1936 |
+
}
|
| 1937 |
+
|
| 1938 |
/************************************
|
| 1939 |
Copy Permissions dialog
|
| 1940 |
*************************************/
|
images/new-menu-badge.png
ADDED
|
Binary file
|
includes/editor-page.php
CHANGED
|
@@ -286,6 +286,8 @@ function ame_output_sort_buttons($icons) {
|
|
| 286 |
?>
|
| 287 |
</div>
|
| 288 |
|
|
|
|
|
|
|
| 289 |
<?php
|
| 290 |
if ( apply_filters('admin_menu_editor-show_general_box', false) ) :
|
| 291 |
$is_general_box_open = true;
|
|
@@ -295,8 +297,6 @@ function ame_output_sort_buttons($icons) {
|
|
| 295 |
$box_class = $is_general_box_open ? '' : 'closed';
|
| 296 |
|
| 297 |
?>
|
| 298 |
-
<div class="clear"></div>
|
| 299 |
-
<div class="metabox-holder">
|
| 300 |
<div class="postbox ws_ame_custom_postbox <?php echo $box_class; ?>" id="ws_ame_general_vis_box">
|
| 301 |
<button type="button" class="handlediv button-link">
|
| 302 |
<span class="toggle-indicator"></span>
|
|
@@ -306,16 +306,73 @@ function ame_output_sort_buttons($icons) {
|
|
| 306 |
<?php do_action('admin_menu_editor-general_box'); ?>
|
| 307 |
</div>
|
| 308 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
</div>
|
| 310 |
<?php
|
| 311 |
endif;
|
|
|
|
|
|
|
| 312 |
|
|
|
|
| 313 |
$hint_id = 'ws_sidebar_pro_ad';
|
| 314 |
$show_pro_benefits = !apply_filters('admin_menu_editor_is_pro', false) && (!isset($editor_data['show_hints'][$hint_id]) || $editor_data['show_hints'][$hint_id]);
|
| 315 |
|
| 316 |
if ( $show_pro_benefits ):
|
| 317 |
$benefit_variations = array(
|
| 318 |
-
'
|
| 319 |
'More menu icons.',
|
| 320 |
'Make menus open in a new tab or an iframe.',
|
| 321 |
'Prevent users from deleting a specific user.',
|
| 286 |
?>
|
| 287 |
</div>
|
| 288 |
|
| 289 |
+
<div class="clear"></div>
|
| 290 |
+
<div class="metabox-holder">
|
| 291 |
<?php
|
| 292 |
if ( apply_filters('admin_menu_editor-show_general_box', false) ) :
|
| 293 |
$is_general_box_open = true;
|
| 297 |
$box_class = $is_general_box_open ? '' : 'closed';
|
| 298 |
|
| 299 |
?>
|
|
|
|
|
|
|
| 300 |
<div class="postbox ws_ame_custom_postbox <?php echo $box_class; ?>" id="ws_ame_general_vis_box">
|
| 301 |
<button type="button" class="handlediv button-link">
|
| 302 |
<span class="toggle-indicator"></span>
|
| 306 |
<?php do_action('admin_menu_editor-general_box'); ?>
|
| 307 |
</div>
|
| 308 |
</div>
|
| 309 |
+
<?php
|
| 310 |
+
endif;
|
| 311 |
+
|
| 312 |
+
if ( $is_pro_version ) :
|
| 313 |
+
$is_how_to_box_open = true;
|
| 314 |
+
if ( isset($_COOKIE['ame_how_to_box_open']) ) {
|
| 315 |
+
$is_how_to_box_open = ($_COOKIE['ame_how_to_box_open'] === '1');
|
| 316 |
+
}
|
| 317 |
+
$box_class = $is_how_to_box_open ? '' : 'closed';
|
| 318 |
+
|
| 319 |
+
$how_to_link_template = '<a href="https://adminmenueditor.com/documentation/%1$s" target="_blank" title="Opens in a new tab">%2$s</a>';
|
| 320 |
+
$how_to_item_template = '<li>' . $how_to_link_template . '</li>';
|
| 321 |
+
|
| 322 |
+
?>
|
| 323 |
+
<div class="postbox ws_ame_custom_postbox <?php echo $box_class; ?>" id="ws_ame_how_to_box">
|
| 324 |
+
<button type="button" class="handlediv button-link">
|
| 325 |
+
<span class="toggle-indicator"></span>
|
| 326 |
+
</button>
|
| 327 |
+
<h2 class="hndle">How To</h2>
|
| 328 |
+
<div class="inside">
|
| 329 |
+
<ul class="ame-tutorial-list">
|
| 330 |
+
<li><?php
|
| 331 |
+
printf($how_to_link_template, 'how-to-hide-a-menu-item/', 'Hide a Menu...');
|
| 332 |
+
?>
|
| 333 |
+
<ul class="ame-tutorial-list">
|
| 334 |
+
<?php
|
| 335 |
+
foreach (
|
| 336 |
+
array(
|
| 337 |
+
'how-to-hide-a-menu-item/#how-to-hide-a-menu-from-a-role' => 'From a Role',
|
| 338 |
+
'how-to-hide-a-menu-item/#how-to-hide-a-menu-from-a-user' => 'From a User',
|
| 339 |
+
'how-to-hide-a-menu-item/#how-to-hide-a-menu-from-everyone-except-yourself' => 'From Everyone Except You',
|
| 340 |
+
'how-to-hide-menu-without-preventing-access/' => 'Without Preventing Access',
|
| 341 |
+
)
|
| 342 |
+
as $how_to_url => $how_to_title
|
| 343 |
+
) {
|
| 344 |
+
printf($how_to_item_template, esc_attr($how_to_url), $how_to_title);
|
| 345 |
+
}
|
| 346 |
+
?>
|
| 347 |
+
</ul>
|
| 348 |
+
</li>
|
| 349 |
+
<?php
|
| 350 |
+
foreach (
|
| 351 |
+
array(
|
| 352 |
+
'how-to-give-access-to-menu/' => 'Show a Menu',
|
| 353 |
+
'how-to-move-and-sort-menus/' => 'Move and Sort Menus',
|
| 354 |
+
'how-to-add-a-new-menu-item/' => 'Add a New Menu',
|
| 355 |
+
)
|
| 356 |
+
as $how_to_url => $how_to_title
|
| 357 |
+
) {
|
| 358 |
+
printf($how_to_item_template, esc_attr($how_to_url), $how_to_title);
|
| 359 |
+
}
|
| 360 |
+
?>
|
| 361 |
+
</ul>
|
| 362 |
+
</div>
|
| 363 |
</div>
|
| 364 |
<?php
|
| 365 |
endif;
|
| 366 |
+
?>
|
| 367 |
+
</div> <!-- / .metabox-holder -->
|
| 368 |
|
| 369 |
+
<?php
|
| 370 |
$hint_id = 'ws_sidebar_pro_ad';
|
| 371 |
$show_pro_benefits = !apply_filters('admin_menu_editor_is_pro', false) && (!isset($editor_data['show_hints'][$hint_id]) || $editor_data['show_hints'][$hint_id]);
|
| 372 |
|
| 373 |
if ( $show_pro_benefits ):
|
| 374 |
$benefit_variations = array(
|
| 375 |
+
'Hide dashboard widgets.',
|
| 376 |
'More menu icons.',
|
| 377 |
'Make menus open in a new tab or an iframe.',
|
| 378 |
'Prevent users from deleting a specific user.',
|
includes/menu-editor-core.php
CHANGED
|
@@ -114,6 +114,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 114 |
*/
|
| 115 |
private $current_tab = '';
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
function init(){
|
| 118 |
$this->sitewide_options = true;
|
| 119 |
|
|
@@ -221,6 +226,22 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 221 |
'index.php?page=nf-credits' => true,
|
| 222 |
//All in One SEO Pack 2.3.9.2
|
| 223 |
'index.php?page=aioseop-about' => true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
);
|
| 225 |
|
| 226 |
//AJAXify screen options
|
|
@@ -320,6 +341,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 320 |
add_action('admin_notices', array($this, 'display_security_log'));
|
| 321 |
}
|
| 322 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
//Modules
|
| 324 |
foreach($this->get_active_modules() as $module) {
|
| 325 |
/** @noinspection PhpIncludeInspection */
|
|
@@ -329,7 +358,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 329 |
}
|
| 330 |
}
|
| 331 |
|
| 332 |
-
//Set up the tabs for the menu editor page.
|
| 333 |
$firstTabs = array('editor' => 'Admin Menu');
|
| 334 |
if ( is_network_admin() ) {
|
| 335 |
//TODO: This could be in extras.php
|
|
@@ -676,20 +705,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 676 |
}
|
| 677 |
$done = true;
|
| 678 |
|
|
|
|
|
|
|
| 679 |
//Lodash library
|
| 680 |
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
|
| 681 |
|
| 682 |
-
//jQuery JSON plugin
|
| 683 |
-
wp_register_auto_versioned_script('jquery-json', plugins_url('js/jquery.json.js', $this->plugin_file), array('jquery'));
|
| 684 |
-
//jQuery sort plugin
|
| 685 |
-
wp_register_auto_versioned_script('jquery-sort', plugins_url('js/jquery.sort.js', $this->plugin_file), array('jquery'));
|
| 686 |
-
//qTip2 - jQuery tooltip plugin
|
| 687 |
-
wp_register_auto_versioned_script('jquery-qtip', plugins_url('js/jquery.qtip.min.js', $this->plugin_file), array('jquery'));
|
| 688 |
-
//jQuery Form plugin. This is a more recent version than the one included with WP.
|
| 689 |
-
wp_register_auto_versioned_script('ame-jquery-form', plugins_url('js/jquery.form.js', $this->plugin_file), array('jquery'));
|
| 690 |
-
//jQuery cookie plugin
|
| 691 |
-
wp_register_auto_versioned_script('jquery-cookie', plugins_url('js/jquery.biscuit.js', $this->plugin_file), array('jquery'));
|
| 692 |
-
|
| 693 |
//Knockout
|
| 694 |
wp_register_auto_versioned_script('knockout', plugins_url('js/knockout.js', $this->plugin_file));
|
| 695 |
|
|
@@ -728,12 +748,19 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 728 |
//Compatibility workaround: Get the real roles of the current user even if other plugins corrupt the list.
|
| 729 |
$users[$current_user->get('user_login')]['roles'] = array_values($this->get_user_roles($current_user));
|
| 730 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 731 |
//TODO: Include currentUserLogin
|
| 732 |
$actor_data = array(
|
| 733 |
'roles' => $roles,
|
| 734 |
'users' => $users,
|
| 735 |
'isMultisite' => is_multisite(),
|
| 736 |
'capPower' => $this->load_cap_power(),
|
|
|
|
| 737 |
);
|
| 738 |
wp_localize_script('ame-actor-manager', 'wsAmeActorData', $actor_data);
|
| 739 |
|
|
@@ -748,6 +775,115 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 748 |
do_action('admin_menu_editor-register_scripts');
|
| 749 |
}
|
| 750 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 751 |
|
| 752 |
/**
|
| 753 |
* Add the JS required by the editor to the page header
|
|
@@ -898,6 +1034,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 898 |
'id' => $user->ID,
|
| 899 |
'roles' => !empty($user->roles) ? (array)($user->roles) : array(),
|
| 900 |
'capabilities' => $this->castValuesToBool($user->caps),
|
|
|
|
| 901 |
'display_name' => $user->display_name,
|
| 902 |
'is_super_admin' => is_multisite() && is_super_admin($user->ID),
|
| 903 |
);
|
|
@@ -1185,7 +1322,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 1185 |
* @param string $login
|
| 1186 |
* @param WP_User $current_user
|
| 1187 |
*/
|
| 1188 |
-
public function maybe_reset_plugin_access(/** @noinspection PhpUnusedParameterInspection */ $login, $current_user) {
|
| 1189 |
if ( ($this->options['plugin_access'] !== 'specific_user') || !$current_user || !$current_user->exists() ) {
|
| 1190 |
return;
|
| 1191 |
}
|
|
@@ -3849,7 +3986,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 3849 |
continue;
|
| 3850 |
}
|
| 3851 |
|
| 3852 |
-
if ( count($line) >= 2 ) {
|
| 3853 |
$cap_power[strval($line[0])] = floatval(str_replace(',', '.', $line[1]));
|
| 3854 |
}
|
| 3855 |
}
|
|
@@ -3938,6 +4075,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
| 3938 |
}
|
| 3939 |
unset($module);
|
| 3940 |
|
|
|
|
|
|
|
| 3941 |
$modules = array_filter($modules, array($this, 'module_path_exists'));
|
| 3942 |
|
| 3943 |
return $modules;
|
|
@@ -4037,6 +4176,7 @@ class ameMenuTemplateBuilder {
|
|
| 4037 |
}
|
| 4038 |
|
| 4039 |
//Skip blacklisted menus.
|
|
|
|
| 4040 |
if ( isset($item['url'], $this->blacklist[$item['url']]) ) {
|
| 4041 |
return;
|
| 4042 |
}
|
| 114 |
*/
|
| 115 |
private $current_tab = '';
|
| 116 |
|
| 117 |
+
/**
|
| 118 |
+
* @var array List of capabilities that are used in the default admin menu. Used to detect meta capabilities.
|
| 119 |
+
*/
|
| 120 |
+
private $caps_used_in_menu = array();
|
| 121 |
+
|
| 122 |
function init(){
|
| 123 |
$this->sitewide_options = true;
|
| 124 |
|
| 226 |
'index.php?page=nf-credits' => true,
|
| 227 |
//All in One SEO Pack 2.3.9.2
|
| 228 |
'index.php?page=aioseop-about' => true,
|
| 229 |
+
//WP Courseware 4.1.2
|
| 230 |
+
//'wpcw' => true, //This is commented out due to a bug. The Courseware top level menu and its first submenu
|
| 231 |
+
//both have the URL "wpcw", but the top level menu also has some visible, non-blacklisted items. AME would
|
| 232 |
+
//still hide the entire menu because the template builder doesn't check if a menu has submenu items.
|
| 233 |
+
'admin.php?page=wpcw-course-classroom' => true,
|
| 234 |
+
'admin.php?page=wpcw-student' => true,
|
| 235 |
+
'admin.php?page=WPCW_showPage_ConvertPage' => true,
|
| 236 |
+
'admin.php?page=WPCW_showPage_CourseOrdering' => true,
|
| 237 |
+
'admin.php?page=WPCW_showPage_GradeBook' => true,
|
| 238 |
+
'admin.php?page=WPCW_showPage_ModifyCourse' => true,
|
| 239 |
+
'admin.php?page=WPCW_showPage_ModifyModule' => true,
|
| 240 |
+
'admin.php?page=WPCW_showPage_ModifyQuestion' => true,
|
| 241 |
+
'admin.php?page=WPCW_showPage_ModifyQuiz' => true,
|
| 242 |
+
'admin.php?page=WPCW_showPage_UserCourseAccess' => true,
|
| 243 |
+
'admin.php?page=WPCW_showPage_UserProgess' => true,
|
| 244 |
+
'admin.php?page=WPCW_showPage_UserProgess_quizAnswers' => true,
|
| 245 |
);
|
| 246 |
|
| 247 |
//AJAXify screen options
|
| 341 |
add_action('admin_notices', array($this, 'display_security_log'));
|
| 342 |
}
|
| 343 |
|
| 344 |
+
if ( did_action('plugins_loaded') ) {
|
| 345 |
+
$this->load_modules();
|
| 346 |
+
} else {
|
| 347 |
+
add_action('plugins_loaded', array($this, 'load_modules'), 11);
|
| 348 |
+
}
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
public function load_modules() {
|
| 352 |
//Modules
|
| 353 |
foreach($this->get_active_modules() as $module) {
|
| 354 |
/** @noinspection PhpIncludeInspection */
|
| 358 |
}
|
| 359 |
}
|
| 360 |
|
| 361 |
+
//Set up the tabs for the menu editor page. Many tabs are provided by modules.
|
| 362 |
$firstTabs = array('editor' => 'Admin Menu');
|
| 363 |
if ( is_network_admin() ) {
|
| 364 |
//TODO: This could be in extras.php
|
| 705 |
}
|
| 706 |
$done = true;
|
| 707 |
|
| 708 |
+
$this->register_jquery_plugins();
|
| 709 |
+
|
| 710 |
//Lodash library
|
| 711 |
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
|
| 712 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
//Knockout
|
| 714 |
wp_register_auto_versioned_script('knockout', plugins_url('js/knockout.js', $this->plugin_file));
|
| 715 |
|
| 748 |
//Compatibility workaround: Get the real roles of the current user even if other plugins corrupt the list.
|
| 749 |
$users[$current_user->get('user_login')]['roles'] = array_values($this->get_user_roles($current_user));
|
| 750 |
|
| 751 |
+
$suspected_meta_caps = $this->detect_meta_caps($roles, $users);
|
| 752 |
+
|
| 753 |
+
//The current user has all of the meta caps. That's how we know they're meta caps and not just regular
|
| 754 |
+
//capabilities that simply haven't been granted to anyone.
|
| 755 |
+
$users[$current_user->get('user_login')]['meta_capabilities'] = $suspected_meta_caps;
|
| 756 |
+
|
| 757 |
//TODO: Include currentUserLogin
|
| 758 |
$actor_data = array(
|
| 759 |
'roles' => $roles,
|
| 760 |
'users' => $users,
|
| 761 |
'isMultisite' => is_multisite(),
|
| 762 |
'capPower' => $this->load_cap_power(),
|
| 763 |
+
'suspectedMetaCaps' => $suspected_meta_caps,
|
| 764 |
);
|
| 765 |
wp_localize_script('ame-actor-manager', 'wsAmeActorData', $actor_data);
|
| 766 |
|
| 775 |
do_action('admin_menu_editor-register_scripts');
|
| 776 |
}
|
| 777 |
|
| 778 |
+
/**
|
| 779 |
+
* @access private
|
| 780 |
+
*/
|
| 781 |
+
public function register_jquery_plugins() {
|
| 782 |
+
//jQuery JSON plugin
|
| 783 |
+
wp_register_auto_versioned_script('jquery-json', plugins_url('js/jquery.json.js', $this->plugin_file), array('jquery'));
|
| 784 |
+
//jQuery sort plugin
|
| 785 |
+
wp_register_auto_versioned_script('jquery-sort', plugins_url('js/jquery.sort.js', $this->plugin_file), array('jquery'));
|
| 786 |
+
//qTip2 - jQuery tooltip plugin
|
| 787 |
+
wp_register_auto_versioned_script('jquery-qtip', plugins_url('js/jquery.qtip.min.js', $this->plugin_file), array('jquery'));
|
| 788 |
+
//jQuery Form plugin. This is a more recent version than the one included with WP.
|
| 789 |
+
wp_register_auto_versioned_script('ame-jquery-form', plugins_url('js/jquery.form.js', $this->plugin_file), array('jquery'));
|
| 790 |
+
//jQuery cookie plugin
|
| 791 |
+
wp_register_auto_versioned_script('jquery-cookie', plugins_url('js/jquery.biscuit.js', $this->plugin_file), array('jquery'));
|
| 792 |
+
}
|
| 793 |
+
|
| 794 |
+
/**
|
| 795 |
+
* Detect meta capabilities.
|
| 796 |
+
* This only works if the current user is an admin. In Multisite, they must be a Super Admin.
|
| 797 |
+
*
|
| 798 |
+
* @param array $roles
|
| 799 |
+
* @param array $users
|
| 800 |
+
* @return array [capability => true]
|
| 801 |
+
*/
|
| 802 |
+
private function detect_meta_caps($roles, $users) {
|
| 803 |
+
if ( !$this->current_user_can_edit_menu() || !is_super_admin() ) {
|
| 804 |
+
return array();
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
//Any capability that's assigned to a role probably isn't a meta capability.
|
| 808 |
+
$allRealCaps = ameRoleUtils::get_all_capabilities();
|
| 809 |
+
//Similarly, capabilities that are directly assigned to users are probably real.
|
| 810 |
+
foreach($users as $user) {
|
| 811 |
+
$allRealCaps = array_merge($allRealCaps, $user['capabilities']);
|
| 812 |
+
}
|
| 813 |
+
//Role IDs can also be used as capabilities.
|
| 814 |
+
foreach($roles as $roleId => $role) {
|
| 815 |
+
$allRealCaps[$roleId] = true;
|
| 816 |
+
}
|
| 817 |
+
|
| 818 |
+
//Collect all of the required capabilities from the admin menu.
|
| 819 |
+
$menu = $this->get_default_menu();
|
| 820 |
+
ameMenu::for_each($menu['tree'], array($this, 'collect_menu_cap'));
|
| 821 |
+
|
| 822 |
+
//Any capability that's part of the admin menu but not assigned to any role or user
|
| 823 |
+
//is probably a meta capability.
|
| 824 |
+
$suspectedMetaCaps = array_diff_key($this->caps_used_in_menu, $allRealCaps);
|
| 825 |
+
|
| 826 |
+
//The current user is an admin and should have access to everything. If they don't have a cap,
|
| 827 |
+
//that's probably a non-meta cap that isn't enabled for *anyone*.
|
| 828 |
+
$suspectedMetaCaps = array_filter(array_keys($suspectedMetaCaps), 'current_user_can');
|
| 829 |
+
|
| 830 |
+
return array_fill_keys($suspectedMetaCaps, true);
|
| 831 |
+
}
|
| 832 |
+
|
| 833 |
+
/**
|
| 834 |
+
* @access private
|
| 835 |
+
* @param array $item
|
| 836 |
+
*/
|
| 837 |
+
public function collect_menu_cap($item) {
|
| 838 |
+
if ( isset($item['defaults'], $item['defaults']['access_level']) ) {
|
| 839 |
+
$this->caps_used_in_menu[$item['defaults']['access_level']] = true;
|
| 840 |
+
}
|
| 841 |
+
}
|
| 842 |
+
|
| 843 |
+
/** @noinspection PhpUnusedPrivateMethodInspection */
|
| 844 |
+
/**
|
| 845 |
+
* Unfinished feature: Detect which roles have which meta capabilities.
|
| 846 |
+
*
|
| 847 |
+
* Create a temp. user for each role, test which meta caps they have, then cache the results in a site option.
|
| 848 |
+
* Put this part in an AJAX request to avoid a massive slowdown (takes several seconds even on a fast PC).
|
| 849 |
+
*
|
| 850 |
+
* @param array $suspected_meta_caps
|
| 851 |
+
* @param string[] $roleIds
|
| 852 |
+
* @return array
|
| 853 |
+
*/
|
| 854 |
+
private function analyse_role_meta_caps($suspected_meta_caps, $roleIds) {
|
| 855 |
+
//$start = microtime(true);
|
| 856 |
+
$results = array();
|
| 857 |
+
$real_current_user = wp_get_current_user();
|
| 858 |
+
|
| 859 |
+
foreach($roleIds as $role_id) {
|
| 860 |
+
$id = wp_insert_user(array(
|
| 861 |
+
'role' => $role_id,
|
| 862 |
+
'user_login' => wp_slash('ametemp_' . wp_generate_password(14)),
|
| 863 |
+
'user_pass' => wp_generate_password(20),
|
| 864 |
+
'display_name' => 'Temporary user created by AME',
|
| 865 |
+
));
|
| 866 |
+
$user = new WP_User($id);
|
| 867 |
+
|
| 868 |
+
//Some plugins only check the current user and ignore the user ID passed to the "user_has_cap" filter.
|
| 869 |
+
//To account for cases like that, we need to also change the current user.
|
| 870 |
+
wp_set_current_user($user->ID);
|
| 871 |
+
|
| 872 |
+
$results[$role_id] = array();
|
| 873 |
+
foreach($suspected_meta_caps as $meta_cap => $ignored) {
|
| 874 |
+
$results[$role_id][$meta_cap] = $user->has_cap($meta_cap);
|
| 875 |
+
}
|
| 876 |
+
|
| 877 |
+
wp_delete_user($id);
|
| 878 |
+
}
|
| 879 |
+
|
| 880 |
+
//Restore the original user.
|
| 881 |
+
wp_set_current_user($real_current_user->ID);
|
| 882 |
+
|
| 883 |
+
/*$elapsed = microtime(true) - $start;
|
| 884 |
+
printf('Meta cap analysis: %.2f ms<br>', $elapsed * 1000);*/
|
| 885 |
+
return $results;
|
| 886 |
+
}
|
| 887 |
|
| 888 |
/**
|
| 889 |
* Add the JS required by the editor to the page header
|
| 1034 |
'id' => $user->ID,
|
| 1035 |
'roles' => !empty($user->roles) ? (array)($user->roles) : array(),
|
| 1036 |
'capabilities' => $this->castValuesToBool($user->caps),
|
| 1037 |
+
'meta_capabilities' => array(),
|
| 1038 |
'display_name' => $user->display_name,
|
| 1039 |
'is_super_admin' => is_multisite() && is_super_admin($user->ID),
|
| 1040 |
);
|
| 1322 |
* @param string $login
|
| 1323 |
* @param WP_User $current_user
|
| 1324 |
*/
|
| 1325 |
+
public function maybe_reset_plugin_access(/** @noinspection PhpUnusedParameterInspection */ $login = null, $current_user = null) {
|
| 1326 |
if ( ($this->options['plugin_access'] !== 'specific_user') || !$current_user || !$current_user->exists() ) {
|
| 1327 |
return;
|
| 1328 |
}
|
| 3986 |
continue;
|
| 3987 |
}
|
| 3988 |
|
| 3989 |
+
if ( is_array($line) && (count($line) >= 2) ) {
|
| 3990 |
$cap_power[strval($line[0])] = floatval(str_replace(',', '.', $line[1]));
|
| 3991 |
}
|
| 3992 |
}
|
| 4075 |
}
|
| 4076 |
unset($module);
|
| 4077 |
|
| 4078 |
+
$modules = apply_filters('admin_menu_editor-available_modules', $modules);
|
| 4079 |
+
|
| 4080 |
$modules = array_filter($modules, array($this, 'module_path_exists'));
|
| 4081 |
|
| 4082 |
return $modules;
|
| 4176 |
}
|
| 4177 |
|
| 4178 |
//Skip blacklisted menus.
|
| 4179 |
+
//BUG: We shouldn't skip top level menus that have non-blacklisted submenu items.
|
| 4180 |
if ( isset($item['url'], $this->blacklist[$item['url']]) ) {
|
| 4181 |
return;
|
| 4182 |
}
|
includes/module.php
CHANGED
|
@@ -7,6 +7,8 @@ abstract class ameModule {
|
|
| 7 |
protected $moduleId = '';
|
| 8 |
protected $moduleDir = '';
|
| 9 |
|
|
|
|
|
|
|
| 10 |
/**
|
| 11 |
* @var WPMenuEditor
|
| 12 |
*/
|
|
@@ -34,6 +36,11 @@ abstract class ameModule {
|
|
| 34 |
|
| 35 |
add_action('admin_menu_editor-enqueue_scripts-' . $this->tabSlug, array($this, 'enqueueTabScripts'));
|
| 36 |
add_action('admin_menu_editor-enqueue_styles-' . $this->tabSlug, array($this, 'enqueueTabStyles'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
}
|
| 38 |
}
|
| 39 |
|
|
@@ -80,6 +87,11 @@ abstract class ameModule {
|
|
| 80 |
/** @noinspection PhpUnusedLocalVariableInspection Used in some templates. */
|
| 81 |
$moduleTabUrl = $this->getTabUrl();
|
| 82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
/** @noinspection PhpIncludeInspection */
|
| 84 |
require $templateFile;
|
| 85 |
return true;
|
|
@@ -87,6 +99,11 @@ abstract class ameModule {
|
|
| 87 |
return false;
|
| 88 |
}
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
public function registerScripts() {
|
| 91 |
//Override this method to register scripts.
|
| 92 |
}
|
|
@@ -98,4 +115,20 @@ abstract class ameModule {
|
|
| 98 |
public function enqueueTabStyles() {
|
| 99 |
//Override this method to add stylesheets to the $this->tabSlug tab.
|
| 100 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
}
|
| 7 |
protected $moduleId = '';
|
| 8 |
protected $moduleDir = '';
|
| 9 |
|
| 10 |
+
protected $settingsFormAction = '';
|
| 11 |
+
|
| 12 |
/**
|
| 13 |
* @var WPMenuEditor
|
| 14 |
*/
|
| 36 |
|
| 37 |
add_action('admin_menu_editor-enqueue_scripts-' . $this->tabSlug, array($this, 'enqueueTabScripts'));
|
| 38 |
add_action('admin_menu_editor-enqueue_styles-' . $this->tabSlug, array($this, 'enqueueTabStyles'));
|
| 39 |
+
|
| 40 |
+
//Optionally, handle settings form submission.
|
| 41 |
+
if ( $this->settingsFormAction !== '' ) {
|
| 42 |
+
add_action('admin_menu_editor-header', array($this, '_processAction'), 10, 2);
|
| 43 |
+
}
|
| 44 |
}
|
| 45 |
}
|
| 46 |
|
| 87 |
/** @noinspection PhpUnusedLocalVariableInspection Used in some templates. */
|
| 88 |
$moduleTabUrl = $this->getTabUrl();
|
| 89 |
|
| 90 |
+
$templateVariables = $this->getTemplateVariables($name);
|
| 91 |
+
if ( !empty($templateVariables) ) {
|
| 92 |
+
extract($templateVariables, EXTR_SKIP);
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
/** @noinspection PhpIncludeInspection */
|
| 96 |
require $templateFile;
|
| 97 |
return true;
|
| 99 |
return false;
|
| 100 |
}
|
| 101 |
|
| 102 |
+
protected function getTemplateVariables(/** @noinspection PhpUnusedParameterInspection */ $templateName) {
|
| 103 |
+
//Override this method to pass variables to a template.
|
| 104 |
+
return array();
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
public function registerScripts() {
|
| 108 |
//Override this method to register scripts.
|
| 109 |
}
|
| 115 |
public function enqueueTabStyles() {
|
| 116 |
//Override this method to add stylesheets to the $this->tabSlug tab.
|
| 117 |
}
|
| 118 |
+
|
| 119 |
+
/**
|
| 120 |
+
* @access private
|
| 121 |
+
* @param string $action
|
| 122 |
+
* @param array $post
|
| 123 |
+
*/
|
| 124 |
+
public function _processAction($action, $post = array()) {
|
| 125 |
+
if ( $action === $this->settingsFormAction ) {
|
| 126 |
+
check_admin_referer($action);
|
| 127 |
+
$this->handleSettingsForm($post);
|
| 128 |
+
}
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
public function handleSettingsForm($post = array()) {
|
| 132 |
+
//Override this method to process a form submitted from the module's tab.
|
| 133 |
+
}
|
| 134 |
}
|
includes/role-utils.php
CHANGED
|
@@ -1,11 +1,17 @@
|
|
| 1 |
<?php
|
| 2 |
class ameRoleUtils {
|
| 3 |
/**
|
| 4 |
-
* Retrieve a list of all known capabilities of all roles
|
| 5 |
*
|
| 6 |
* @return array Associative array with capability names as keys
|
| 7 |
*/
|
| 8 |
public static function get_all_capabilities(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
$wp_roles = self::get_roles();
|
| 10 |
$capabilities = array();
|
| 11 |
|
| 1 |
<?php
|
| 2 |
class ameRoleUtils {
|
| 3 |
/**
|
| 4 |
+
* Retrieve a list of all known, non-meta capabilities of all roles.
|
| 5 |
*
|
| 6 |
* @return array Associative array with capability names as keys
|
| 7 |
*/
|
| 8 |
public static function get_all_capabilities(){
|
| 9 |
+
//Cache the results.
|
| 10 |
+
static $capabilities = null;
|
| 11 |
+
if ( isset($capabilities) ) {
|
| 12 |
+
return $capabilities;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
$wp_roles = self::get_roles();
|
| 16 |
$capabilities = array();
|
| 17 |
|
js/actor-manager.js
CHANGED
|
@@ -10,14 +10,15 @@ var __extends = (this && this.__extends) || (function () {
|
|
| 10 |
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
| 11 |
};
|
| 12 |
})();
|
| 13 |
-
var AmeBaseActor = (function () {
|
| 14 |
-
function AmeBaseActor(id, displayName, capabilities) {
|
|
|
|
| 15 |
this.displayName = '[Error: No displayName set]';
|
| 16 |
this.groupActors = [];
|
| 17 |
-
this.actorTypeSpecificity = 0;
|
| 18 |
this.id = id;
|
| 19 |
this.displayName = displayName;
|
| 20 |
this.capabilities = capabilities;
|
|
|
|
| 21 |
}
|
| 22 |
/**
|
| 23 |
* Get the capability setting directly from this actor, ignoring capabilities
|
|
@@ -32,6 +33,9 @@ var AmeBaseActor = (function () {
|
|
| 32 |
if (this.capabilities.hasOwnProperty(capability)) {
|
| 33 |
return this.capabilities[capability];
|
| 34 |
}
|
|
|
|
|
|
|
|
|
|
| 35 |
return null;
|
| 36 |
};
|
| 37 |
AmeBaseActor.getActorSpecificity = function (actorId) {
|
|
@@ -56,11 +60,11 @@ var AmeBaseActor = (function () {
|
|
| 56 |
};
|
| 57 |
return AmeBaseActor;
|
| 58 |
}());
|
| 59 |
-
var AmeRole = (function (_super) {
|
| 60 |
__extends(AmeRole, _super);
|
| 61 |
-
function AmeRole(roleId, displayName, capabilities) {
|
| 62 |
-
|
| 63 |
-
_this
|
| 64 |
_this.name = roleId;
|
| 65 |
return _this;
|
| 66 |
}
|
|
@@ -75,15 +79,15 @@ var AmeRole = (function (_super) {
|
|
| 75 |
};
|
| 76 |
return AmeRole;
|
| 77 |
}(AmeBaseActor));
|
| 78 |
-
var AmeUser = (function (_super) {
|
| 79 |
__extends(AmeUser, _super);
|
| 80 |
-
function AmeUser(userLogin, displayName, capabilities, roles, isSuperAdmin, userId) {
|
| 81 |
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
| 82 |
-
|
|
|
|
| 83 |
_this.userId = 0;
|
| 84 |
_this.isSuperAdmin = false;
|
| 85 |
_this.avatarHTML = '';
|
| 86 |
-
_this.actorTypeSpecificity = 10;
|
| 87 |
_this.userLogin = userLogin;
|
| 88 |
_this.roles = roles;
|
| 89 |
_this.isSuperAdmin = isSuperAdmin;
|
|
@@ -97,7 +101,7 @@ var AmeUser = (function (_super) {
|
|
| 97 |
return _this;
|
| 98 |
}
|
| 99 |
AmeUser.createFromProperties = function (properties) {
|
| 100 |
-
var user = new AmeUser(properties.user_login, properties.display_name, properties.capabilities, properties.roles, properties.is_super_admin, properties.hasOwnProperty('id') ? properties.id : null);
|
| 101 |
if (properties.avatar_html) {
|
| 102 |
user.avatarHTML = properties.avatar_html;
|
| 103 |
}
|
|
@@ -105,12 +109,10 @@ var AmeUser = (function (_super) {
|
|
| 105 |
};
|
| 106 |
return AmeUser;
|
| 107 |
}(AmeBaseActor));
|
| 108 |
-
var AmeSuperAdmin = (function (_super) {
|
| 109 |
__extends(AmeSuperAdmin, _super);
|
| 110 |
function AmeSuperAdmin() {
|
| 111 |
-
|
| 112 |
-
_this.actorTypeSpecificity = 2;
|
| 113 |
-
return _this;
|
| 114 |
}
|
| 115 |
AmeSuperAdmin.prototype.hasOwnCap = function (capability) {
|
| 116 |
//The Super Admin has all possible capabilities except the special "do_not_allow" flag.
|
|
@@ -119,9 +121,10 @@ var AmeSuperAdmin = (function (_super) {
|
|
| 119 |
AmeSuperAdmin.permanentActorId = 'special:super_admin';
|
| 120 |
return AmeSuperAdmin;
|
| 121 |
}(AmeBaseActor));
|
| 122 |
-
var AmeActorManager = (function () {
|
| 123 |
-
function AmeActorManager(roles, users, isMultisite) {
|
| 124 |
if (isMultisite === void 0) { isMultisite = false; }
|
|
|
|
| 125 |
var _this = this;
|
| 126 |
this.roles = {};
|
| 127 |
this.users = {};
|
|
@@ -132,7 +135,7 @@ var AmeActorManager = (function () {
|
|
| 132 |
this.suggestedCapabilities = [];
|
| 133 |
this.isMultisite = !!isMultisite;
|
| 134 |
AmeActorManager._.forEach(roles, function (roleDetails, id) {
|
| 135 |
-
var role = new AmeRole(id, roleDetails.name, roleDetails.capabilities);
|
| 136 |
_this.roles[role.name] = role;
|
| 137 |
});
|
| 138 |
AmeActorManager._.forEach(users, function (userDetails) {
|
|
@@ -142,6 +145,7 @@ var AmeActorManager = (function () {
|
|
| 142 |
if (this.isMultisite) {
|
| 143 |
this.superAdmin = new AmeSuperAdmin();
|
| 144 |
}
|
|
|
|
| 145 |
var exclusiveCaps = [
|
| 146 |
'update_core', 'update_plugins', 'delete_plugins', 'install_plugins', 'upload_plugins', 'update_themes',
|
| 147 |
'delete_themes', 'install_themes', 'upload_themes', 'update_core', 'edit_css', 'unfiltered_html',
|
|
@@ -235,7 +239,11 @@ var AmeActorManager = (function () {
|
|
| 235 |
}
|
| 236 |
}
|
| 237 |
//Step #3: Check owned/default capabilities. Always checked.
|
| 238 |
-
var actor = this.getActor(actorId)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
if (hasOwnCap !== null) {
|
| 240 |
return hasOwnCap;
|
| 241 |
}
|
|
@@ -247,11 +255,19 @@ var AmeActorManager = (function () {
|
|
| 247 |
return this.actorHasCap('special:super_admin', capability, contextList);
|
| 248 |
}
|
| 249 |
//Check if any of the user's roles have the capability.
|
| 250 |
-
result =
|
| 251 |
for (var index = 0; index < actor.roles.length; index++) {
|
| 252 |
-
|
|
|
|
|
|
|
|
|
|
| 253 |
}
|
| 254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
}
|
| 256 |
return false;
|
| 257 |
};
|
|
@@ -325,9 +341,6 @@ var AmeActorManager = (function () {
|
|
| 325 |
var grant = sourceType ? [hasCap, sourceType, sourceName || null] : hasCap;
|
| 326 |
AmeActorManager._.set(context, [actor, capability], grant);
|
| 327 |
};
|
| 328 |
-
AmeActorManager.prototype.resetCap = function (actor, capability) {
|
| 329 |
-
this.resetCapInContext(this.grantedCapabilities, actor, capability);
|
| 330 |
-
};
|
| 331 |
AmeActorManager.prototype.resetCapInContext = function (context, actor, capability) {
|
| 332 |
capability = this.mapMetaCap(capability);
|
| 333 |
if (AmeActorManager._.has(context, [actor, capability])) {
|
|
@@ -355,7 +368,7 @@ var AmeActorManager = (function () {
|
|
| 355 |
_.forEach(_.keys(pruned[actor]), function (capability) {
|
| 356 |
var grant = pruned[actor][capability];
|
| 357 |
delete pruned[actor][capability];
|
| 358 |
-
var hasCap = _.isArray(grant) ? grant[0] : grant, hasCapWhenPruned = _this.actorHasCap(actor, capability, context);
|
| 359 |
if (hasCap !== hasCapWhenPruned) {
|
| 360 |
pruned[actor][capability] = grant; //Restore.
|
| 361 |
}
|
|
@@ -471,7 +484,7 @@ var AmeActorManager = (function () {
|
|
| 471 |
return AmeActorManager;
|
| 472 |
}());
|
| 473 |
if (typeof wsAmeActorData !== 'undefined') {
|
| 474 |
-
AmeActors = new AmeActorManager(wsAmeActorData.roles, wsAmeActorData.users, wsAmeActorData.isMultisite);
|
| 475 |
if (typeof wsAmeActorData['capPower'] !== 'undefined') {
|
| 476 |
AmeActors.generateCapabilitySuggestions(wsAmeActorData['capPower']);
|
| 477 |
}
|
| 10 |
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
| 11 |
};
|
| 12 |
})();
|
| 13 |
+
var AmeBaseActor = /** @class */ (function () {
|
| 14 |
+
function AmeBaseActor(id, displayName, capabilities, metaCapabilities) {
|
| 15 |
+
if (metaCapabilities === void 0) { metaCapabilities = {}; }
|
| 16 |
this.displayName = '[Error: No displayName set]';
|
| 17 |
this.groupActors = [];
|
|
|
|
| 18 |
this.id = id;
|
| 19 |
this.displayName = displayName;
|
| 20 |
this.capabilities = capabilities;
|
| 21 |
+
this.metaCapabilities = metaCapabilities;
|
| 22 |
}
|
| 23 |
/**
|
| 24 |
* Get the capability setting directly from this actor, ignoring capabilities
|
| 33 |
if (this.capabilities.hasOwnProperty(capability)) {
|
| 34 |
return this.capabilities[capability];
|
| 35 |
}
|
| 36 |
+
if (this.metaCapabilities.hasOwnProperty(capability)) {
|
| 37 |
+
return this.metaCapabilities[capability];
|
| 38 |
+
}
|
| 39 |
return null;
|
| 40 |
};
|
| 41 |
AmeBaseActor.getActorSpecificity = function (actorId) {
|
| 60 |
};
|
| 61 |
return AmeBaseActor;
|
| 62 |
}());
|
| 63 |
+
var AmeRole = /** @class */ (function (_super) {
|
| 64 |
__extends(AmeRole, _super);
|
| 65 |
+
function AmeRole(roleId, displayName, capabilities, metaCapabilities) {
|
| 66 |
+
if (metaCapabilities === void 0) { metaCapabilities = {}; }
|
| 67 |
+
var _this = _super.call(this, 'role:' + roleId, displayName, capabilities, metaCapabilities) || this;
|
| 68 |
_this.name = roleId;
|
| 69 |
return _this;
|
| 70 |
}
|
| 79 |
};
|
| 80 |
return AmeRole;
|
| 81 |
}(AmeBaseActor));
|
| 82 |
+
var AmeUser = /** @class */ (function (_super) {
|
| 83 |
__extends(AmeUser, _super);
|
| 84 |
+
function AmeUser(userLogin, displayName, capabilities, roles, isSuperAdmin, userId, metaCapabilities) {
|
| 85 |
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
| 86 |
+
if (metaCapabilities === void 0) { metaCapabilities = {}; }
|
| 87 |
+
var _this = _super.call(this, 'user:' + userLogin, displayName, capabilities, metaCapabilities) || this;
|
| 88 |
_this.userId = 0;
|
| 89 |
_this.isSuperAdmin = false;
|
| 90 |
_this.avatarHTML = '';
|
|
|
|
| 91 |
_this.userLogin = userLogin;
|
| 92 |
_this.roles = roles;
|
| 93 |
_this.isSuperAdmin = isSuperAdmin;
|
| 101 |
return _this;
|
| 102 |
}
|
| 103 |
AmeUser.createFromProperties = function (properties) {
|
| 104 |
+
var user = new AmeUser(properties.user_login, properties.display_name, properties.capabilities, properties.roles, properties.is_super_admin, properties.hasOwnProperty('id') ? properties.id : null, properties.meta_capabilities);
|
| 105 |
if (properties.avatar_html) {
|
| 106 |
user.avatarHTML = properties.avatar_html;
|
| 107 |
}
|
| 109 |
};
|
| 110 |
return AmeUser;
|
| 111 |
}(AmeBaseActor));
|
| 112 |
+
var AmeSuperAdmin = /** @class */ (function (_super) {
|
| 113 |
__extends(AmeSuperAdmin, _super);
|
| 114 |
function AmeSuperAdmin() {
|
| 115 |
+
return _super.call(this, AmeSuperAdmin.permanentActorId, 'Super Admin', {}) || this;
|
|
|
|
|
|
|
| 116 |
}
|
| 117 |
AmeSuperAdmin.prototype.hasOwnCap = function (capability) {
|
| 118 |
//The Super Admin has all possible capabilities except the special "do_not_allow" flag.
|
| 121 |
AmeSuperAdmin.permanentActorId = 'special:super_admin';
|
| 122 |
return AmeSuperAdmin;
|
| 123 |
}(AmeBaseActor));
|
| 124 |
+
var AmeActorManager = /** @class */ (function () {
|
| 125 |
+
function AmeActorManager(roles, users, isMultisite, suspectedMetaCaps) {
|
| 126 |
if (isMultisite === void 0) { isMultisite = false; }
|
| 127 |
+
if (suspectedMetaCaps === void 0) { suspectedMetaCaps = {}; }
|
| 128 |
var _this = this;
|
| 129 |
this.roles = {};
|
| 130 |
this.users = {};
|
| 135 |
this.suggestedCapabilities = [];
|
| 136 |
this.isMultisite = !!isMultisite;
|
| 137 |
AmeActorManager._.forEach(roles, function (roleDetails, id) {
|
| 138 |
+
var role = new AmeRole(id, roleDetails.name, roleDetails.capabilities, AmeActorManager._.get(roleDetails, 'meta_capabilities', {}));
|
| 139 |
_this.roles[role.name] = role;
|
| 140 |
});
|
| 141 |
AmeActorManager._.forEach(users, function (userDetails) {
|
| 145 |
if (this.isMultisite) {
|
| 146 |
this.superAdmin = new AmeSuperAdmin();
|
| 147 |
}
|
| 148 |
+
this.suspectedMetaCaps = suspectedMetaCaps;
|
| 149 |
var exclusiveCaps = [
|
| 150 |
'update_core', 'update_plugins', 'delete_plugins', 'install_plugins', 'upload_plugins', 'update_themes',
|
| 151 |
'delete_themes', 'install_themes', 'upload_themes', 'update_core', 'edit_css', 'unfiltered_html',
|
| 239 |
}
|
| 240 |
}
|
| 241 |
//Step #3: Check owned/default capabilities. Always checked.
|
| 242 |
+
var actor = this.getActor(actorId);
|
| 243 |
+
if (actor === null) {
|
| 244 |
+
return false;
|
| 245 |
+
}
|
| 246 |
+
var hasOwnCap = actor.hasOwnCap(capability);
|
| 247 |
if (hasOwnCap !== null) {
|
| 248 |
return hasOwnCap;
|
| 249 |
}
|
| 255 |
return this.actorHasCap('special:super_admin', capability, contextList);
|
| 256 |
}
|
| 257 |
//Check if any of the user's roles have the capability.
|
| 258 |
+
result = null;
|
| 259 |
for (var index = 0; index < actor.roles.length; index++) {
|
| 260 |
+
var roleHasCap = this.actorHasCap('role:' + actor.roles[index], capability, contextList);
|
| 261 |
+
if (roleHasCap !== null) {
|
| 262 |
+
result = result || roleHasCap;
|
| 263 |
+
}
|
| 264 |
}
|
| 265 |
+
if (result !== null) {
|
| 266 |
+
return result;
|
| 267 |
+
}
|
| 268 |
+
}
|
| 269 |
+
if (this.suspectedMetaCaps.hasOwnProperty(capability)) {
|
| 270 |
+
return null;
|
| 271 |
}
|
| 272 |
return false;
|
| 273 |
};
|
| 341 |
var grant = sourceType ? [hasCap, sourceType, sourceName || null] : hasCap;
|
| 342 |
AmeActorManager._.set(context, [actor, capability], grant);
|
| 343 |
};
|
|
|
|
|
|
|
|
|
|
| 344 |
AmeActorManager.prototype.resetCapInContext = function (context, actor, capability) {
|
| 345 |
capability = this.mapMetaCap(capability);
|
| 346 |
if (AmeActorManager._.has(context, [actor, capability])) {
|
| 368 |
_.forEach(_.keys(pruned[actor]), function (capability) {
|
| 369 |
var grant = pruned[actor][capability];
|
| 370 |
delete pruned[actor][capability];
|
| 371 |
+
var hasCap = _.isArray(grant) ? grant[0] : grant, hasCapWhenPruned = !!_this.actorHasCap(actor, capability, context);
|
| 372 |
if (hasCap !== hasCapWhenPruned) {
|
| 373 |
pruned[actor][capability] = grant; //Restore.
|
| 374 |
}
|
| 484 |
return AmeActorManager;
|
| 485 |
}());
|
| 486 |
if (typeof wsAmeActorData !== 'undefined') {
|
| 487 |
+
AmeActors = new AmeActorManager(wsAmeActorData.roles, wsAmeActorData.users, wsAmeActorData.isMultisite, wsAmeActorData.suspectedMetaCaps);
|
| 488 |
if (typeof wsAmeActorData['capPower'] !== 'undefined') {
|
| 489 |
AmeActors.generateCapabilitySuggestions(wsAmeActorData['capPower']);
|
| 490 |
}
|
js/actor-manager.ts
CHANGED
|
@@ -5,6 +5,9 @@ declare let wsAmeActorData: any;
|
|
| 5 |
declare var wsAmeLodash: _.LoDashStatic;
|
| 6 |
declare let AmeActors: AmeActorManager;
|
| 7 |
|
|
|
|
|
|
|
|
|
|
| 8 |
interface CapabilityMap {
|
| 9 |
[capabilityName: string] : boolean;
|
| 10 |
}
|
|
@@ -13,15 +16,15 @@ abstract class AmeBaseActor {
|
|
| 13 |
public id: string;
|
| 14 |
public displayName: string = '[Error: No displayName set]';
|
| 15 |
public capabilities: CapabilityMap;
|
|
|
|
| 16 |
|
| 17 |
groupActors: string[] = [];
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
constructor(id: string, displayName: string, capabilities: CapabilityMap) {
|
| 22 |
this.id = id;
|
| 23 |
this.displayName = displayName;
|
| 24 |
this.capabilities = capabilities;
|
|
|
|
| 25 |
}
|
| 26 |
|
| 27 |
/**
|
|
@@ -37,6 +40,9 @@ abstract class AmeBaseActor {
|
|
| 37 |
if (this.capabilities.hasOwnProperty(capability)) {
|
| 38 |
return this.capabilities[capability];
|
| 39 |
}
|
|
|
|
|
|
|
|
|
|
| 40 |
return null;
|
| 41 |
}
|
| 42 |
|
|
@@ -66,10 +72,9 @@ abstract class AmeBaseActor {
|
|
| 66 |
|
| 67 |
class AmeRole extends AmeBaseActor {
|
| 68 |
name: string;
|
| 69 |
-
protected actorTypeSpecificity = 1;
|
| 70 |
|
| 71 |
-
constructor(roleId: string, displayName: string, capabilities: CapabilityMap) {
|
| 72 |
-
super('role:' + roleId, displayName, capabilities);
|
| 73 |
this.name = roleId;
|
| 74 |
}
|
| 75 |
|
|
@@ -88,6 +93,7 @@ interface AmeUserPropertyMap {
|
|
| 88 |
user_login: string;
|
| 89 |
display_name: string;
|
| 90 |
capabilities: CapabilityMap;
|
|
|
|
| 91 |
roles : string[];
|
| 92 |
is_super_admin: boolean;
|
| 93 |
id?: number;
|
|
@@ -102,17 +108,16 @@ class AmeUser extends AmeBaseActor {
|
|
| 102 |
groupActors: string[];
|
| 103 |
avatarHTML: string = '';
|
| 104 |
|
| 105 |
-
protected actorTypeSpecificity = 10;
|
| 106 |
-
|
| 107 |
constructor(
|
| 108 |
userLogin: string,
|
| 109 |
displayName: string,
|
| 110 |
capabilities: CapabilityMap,
|
| 111 |
roles: string[],
|
| 112 |
isSuperAdmin: boolean = false,
|
| 113 |
-
userId?: number
|
|
|
|
| 114 |
) {
|
| 115 |
-
super('user:' + userLogin, displayName, capabilities);
|
| 116 |
|
| 117 |
this.userLogin = userLogin;
|
| 118 |
this.roles = roles;
|
|
@@ -134,7 +139,8 @@ class AmeUser extends AmeBaseActor {
|
|
| 134 |
properties.capabilities,
|
| 135 |
properties.roles,
|
| 136 |
properties.is_super_admin,
|
| 137 |
-
properties.hasOwnProperty('id') ? properties.id : null
|
|
|
|
| 138 |
);
|
| 139 |
|
| 140 |
if (properties.avatar_html) {
|
|
@@ -147,7 +153,6 @@ class AmeUser extends AmeBaseActor {
|
|
| 147 |
|
| 148 |
class AmeSuperAdmin extends AmeBaseActor {
|
| 149 |
static permanentActorId = 'special:super_admin';
|
| 150 |
-
protected actorTypeSpecificity = 2;
|
| 151 |
|
| 152 |
constructor() {
|
| 153 |
super(AmeSuperAdmin.permanentActorId, 'Super Admin', {});
|
|
@@ -182,14 +187,20 @@ class AmeActorManager {
|
|
| 182 |
private exclusiveSuperAdminCapabilities = {};
|
| 183 |
|
| 184 |
private tagMetaCaps = {};
|
|
|
|
| 185 |
|
| 186 |
private suggestedCapabilities: AmeCapabilitySuggestion[] = [];
|
| 187 |
|
| 188 |
-
constructor(roles, users, isMultisite:
|
| 189 |
this.isMultisite = !!isMultisite;
|
| 190 |
|
| 191 |
AmeActorManager._.forEach(roles, (roleDetails, id) => {
|
| 192 |
-
const role = new AmeRole(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
this.roles[role.name] = role;
|
| 194 |
});
|
| 195 |
|
|
@@ -202,6 +213,8 @@ class AmeActorManager {
|
|
| 202 |
this.superAdmin = new AmeSuperAdmin();
|
| 203 |
}
|
| 204 |
|
|
|
|
|
|
|
| 205 |
const exclusiveCaps: string[] = [
|
| 206 |
'update_core', 'update_plugins', 'delete_plugins', 'install_plugins', 'upload_plugins', 'update_themes',
|
| 207 |
'delete_themes', 'install_themes', 'upload_themes', 'update_core', 'edit_css', 'unfiltered_html',
|
|
@@ -277,7 +290,7 @@ class AmeActorManager {
|
|
| 277 |
return this.actorHasCap(actorId, capability);
|
| 278 |
}
|
| 279 |
|
| 280 |
-
private actorHasCap(actorId: string, capability: string, contextList?: Array<Object>): boolean {
|
| 281 |
//It's like the chain-of-responsibility pattern.
|
| 282 |
|
| 283 |
//Everybody has the "exist" cap and it can't be removed or overridden by plugins.
|
|
@@ -310,8 +323,11 @@ class AmeActorManager {
|
|
| 310 |
}
|
| 311 |
|
| 312 |
//Step #3: Check owned/default capabilities. Always checked.
|
| 313 |
-
let actor = this.getActor(actorId)
|
| 314 |
-
|
|
|
|
|
|
|
|
|
|
| 315 |
if (hasOwnCap !== null) {
|
| 316 |
return hasOwnCap;
|
| 317 |
}
|
|
@@ -325,13 +341,21 @@ class AmeActorManager {
|
|
| 325 |
}
|
| 326 |
|
| 327 |
//Check if any of the user's roles have the capability.
|
| 328 |
-
result =
|
| 329 |
for (let index = 0; index < actor.roles.length; index++) {
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
}
|
| 332 |
-
return result;
|
| 333 |
}
|
| 334 |
|
|
|
|
|
|
|
|
|
|
| 335 |
return false;
|
| 336 |
}
|
| 337 |
|
|
@@ -425,10 +449,6 @@ class AmeActorManager {
|
|
| 425 |
AmeActorManager._.set(context, [actor, capability], grant);
|
| 426 |
}
|
| 427 |
|
| 428 |
-
resetCap(actor: string, capability: string) {
|
| 429 |
-
this.resetCapInContext(this.grantedCapabilities, actor, capability);
|
| 430 |
-
}
|
| 431 |
-
|
| 432 |
public resetCapInContext(context: AmeGrantedCapabilityMap, actor: string, capability: string) {
|
| 433 |
capability = this.mapMetaCap(capability);
|
| 434 |
|
|
@@ -463,7 +483,7 @@ class AmeActorManager {
|
|
| 463 |
delete pruned[actor][capability];
|
| 464 |
|
| 465 |
const hasCap = _.isArray(grant) ? grant[0] : grant,
|
| 466 |
-
hasCapWhenPruned = this.actorHasCap(actor, capability, context);
|
| 467 |
|
| 468 |
if (hasCap !== hasCapWhenPruned) {
|
| 469 |
pruned[actor][capability] = grant; //Restore.
|
|
@@ -605,7 +625,8 @@ if (typeof wsAmeActorData !== 'undefined') {
|
|
| 605 |
AmeActors = new AmeActorManager(
|
| 606 |
wsAmeActorData.roles,
|
| 607 |
wsAmeActorData.users,
|
| 608 |
-
wsAmeActorData.isMultisite
|
|
|
|
| 609 |
);
|
| 610 |
|
| 611 |
if (typeof wsAmeActorData['capPower'] !== 'undefined') {
|
| 5 |
declare var wsAmeLodash: _.LoDashStatic;
|
| 6 |
declare let AmeActors: AmeActorManager;
|
| 7 |
|
| 8 |
+
type Falsy = false | null | '' | undefined | 0;
|
| 9 |
+
type Truthy = true | string | 1;
|
| 10 |
+
|
| 11 |
interface CapabilityMap {
|
| 12 |
[capabilityName: string] : boolean;
|
| 13 |
}
|
| 16 |
public id: string;
|
| 17 |
public displayName: string = '[Error: No displayName set]';
|
| 18 |
public capabilities: CapabilityMap;
|
| 19 |
+
public metaCapabilities: CapabilityMap;
|
| 20 |
|
| 21 |
groupActors: string[] = [];
|
| 22 |
|
| 23 |
+
constructor(id: string, displayName: string, capabilities: CapabilityMap, metaCapabilities: CapabilityMap = {}) {
|
|
|
|
|
|
|
| 24 |
this.id = id;
|
| 25 |
this.displayName = displayName;
|
| 26 |
this.capabilities = capabilities;
|
| 27 |
+
this.metaCapabilities = metaCapabilities;
|
| 28 |
}
|
| 29 |
|
| 30 |
/**
|
| 40 |
if (this.capabilities.hasOwnProperty(capability)) {
|
| 41 |
return this.capabilities[capability];
|
| 42 |
}
|
| 43 |
+
if (this.metaCapabilities.hasOwnProperty(capability)) {
|
| 44 |
+
return this.metaCapabilities[capability];
|
| 45 |
+
}
|
| 46 |
return null;
|
| 47 |
}
|
| 48 |
|
| 72 |
|
| 73 |
class AmeRole extends AmeBaseActor {
|
| 74 |
name: string;
|
|
|
|
| 75 |
|
| 76 |
+
constructor(roleId: string, displayName: string, capabilities: CapabilityMap, metaCapabilities: CapabilityMap = {}) {
|
| 77 |
+
super('role:' + roleId, displayName, capabilities, metaCapabilities);
|
| 78 |
this.name = roleId;
|
| 79 |
}
|
| 80 |
|
| 93 |
user_login: string;
|
| 94 |
display_name: string;
|
| 95 |
capabilities: CapabilityMap;
|
| 96 |
+
meta_capabilities: CapabilityMap;
|
| 97 |
roles : string[];
|
| 98 |
is_super_admin: boolean;
|
| 99 |
id?: number;
|
| 108 |
groupActors: string[];
|
| 109 |
avatarHTML: string = '';
|
| 110 |
|
|
|
|
|
|
|
| 111 |
constructor(
|
| 112 |
userLogin: string,
|
| 113 |
displayName: string,
|
| 114 |
capabilities: CapabilityMap,
|
| 115 |
roles: string[],
|
| 116 |
isSuperAdmin: boolean = false,
|
| 117 |
+
userId?: number,
|
| 118 |
+
metaCapabilities: CapabilityMap = {}
|
| 119 |
) {
|
| 120 |
+
super('user:' + userLogin, displayName, capabilities, metaCapabilities);
|
| 121 |
|
| 122 |
this.userLogin = userLogin;
|
| 123 |
this.roles = roles;
|
| 139 |
properties.capabilities,
|
| 140 |
properties.roles,
|
| 141 |
properties.is_super_admin,
|
| 142 |
+
properties.hasOwnProperty('id') ? properties.id : null,
|
| 143 |
+
properties.meta_capabilities
|
| 144 |
);
|
| 145 |
|
| 146 |
if (properties.avatar_html) {
|
| 153 |
|
| 154 |
class AmeSuperAdmin extends AmeBaseActor {
|
| 155 |
static permanentActorId = 'special:super_admin';
|
|
|
|
| 156 |
|
| 157 |
constructor() {
|
| 158 |
super(AmeSuperAdmin.permanentActorId, 'Super Admin', {});
|
| 187 |
private exclusiveSuperAdminCapabilities = {};
|
| 188 |
|
| 189 |
private tagMetaCaps = {};
|
| 190 |
+
private suspectedMetaCaps: CapabilityMap;
|
| 191 |
|
| 192 |
private suggestedCapabilities: AmeCapabilitySuggestion[] = [];
|
| 193 |
|
| 194 |
+
constructor(roles, users, isMultisite: Truthy | Falsy = false, suspectedMetaCaps: CapabilityMap = {}) {
|
| 195 |
this.isMultisite = !!isMultisite;
|
| 196 |
|
| 197 |
AmeActorManager._.forEach(roles, (roleDetails, id) => {
|
| 198 |
+
const role = new AmeRole(
|
| 199 |
+
id,
|
| 200 |
+
roleDetails.name,
|
| 201 |
+
roleDetails.capabilities,
|
| 202 |
+
AmeActorManager._.get(roleDetails, 'meta_capabilities', {})
|
| 203 |
+
);
|
| 204 |
this.roles[role.name] = role;
|
| 205 |
});
|
| 206 |
|
| 213 |
this.superAdmin = new AmeSuperAdmin();
|
| 214 |
}
|
| 215 |
|
| 216 |
+
this.suspectedMetaCaps = suspectedMetaCaps;
|
| 217 |
+
|
| 218 |
const exclusiveCaps: string[] = [
|
| 219 |
'update_core', 'update_plugins', 'delete_plugins', 'install_plugins', 'upload_plugins', 'update_themes',
|
| 220 |
'delete_themes', 'install_themes', 'upload_themes', 'update_core', 'edit_css', 'unfiltered_html',
|
| 290 |
return this.actorHasCap(actorId, capability);
|
| 291 |
}
|
| 292 |
|
| 293 |
+
private actorHasCap(actorId: string, capability: string, contextList?: Array<Object>): (boolean | null) {
|
| 294 |
//It's like the chain-of-responsibility pattern.
|
| 295 |
|
| 296 |
//Everybody has the "exist" cap and it can't be removed or overridden by plugins.
|
| 323 |
}
|
| 324 |
|
| 325 |
//Step #3: Check owned/default capabilities. Always checked.
|
| 326 |
+
let actor = this.getActor(actorId);
|
| 327 |
+
if (actor === null) {
|
| 328 |
+
return false;
|
| 329 |
+
}
|
| 330 |
+
let hasOwnCap = actor.hasOwnCap(capability);
|
| 331 |
if (hasOwnCap !== null) {
|
| 332 |
return hasOwnCap;
|
| 333 |
}
|
| 341 |
}
|
| 342 |
|
| 343 |
//Check if any of the user's roles have the capability.
|
| 344 |
+
result = null;
|
| 345 |
for (let index = 0; index < actor.roles.length; index++) {
|
| 346 |
+
let roleHasCap = this.actorHasCap('role:' + actor.roles[index], capability, contextList);
|
| 347 |
+
if (roleHasCap !== null) {
|
| 348 |
+
result = result || roleHasCap;
|
| 349 |
+
}
|
| 350 |
+
}
|
| 351 |
+
if (result !== null) {
|
| 352 |
+
return result;
|
| 353 |
}
|
|
|
|
| 354 |
}
|
| 355 |
|
| 356 |
+
if (this.suspectedMetaCaps.hasOwnProperty(capability)) {
|
| 357 |
+
return null;
|
| 358 |
+
}
|
| 359 |
return false;
|
| 360 |
}
|
| 361 |
|
| 449 |
AmeActorManager._.set(context, [actor, capability], grant);
|
| 450 |
}
|
| 451 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 452 |
public resetCapInContext(context: AmeGrantedCapabilityMap, actor: string, capability: string) {
|
| 453 |
capability = this.mapMetaCap(capability);
|
| 454 |
|
| 483 |
delete pruned[actor][capability];
|
| 484 |
|
| 485 |
const hasCap = _.isArray(grant) ? grant[0] : grant,
|
| 486 |
+
hasCapWhenPruned = !!this.actorHasCap(actor, capability, context);
|
| 487 |
|
| 488 |
if (hasCap !== hasCapWhenPruned) {
|
| 489 |
pruned[actor][capability] = grant; //Restore.
|
| 625 |
AmeActors = new AmeActorManager(
|
| 626 |
wsAmeActorData.roles,
|
| 627 |
wsAmeActorData.users,
|
| 628 |
+
wsAmeActorData.isMultisite,
|
| 629 |
+
wsAmeActorData.suspectedMetaCaps
|
| 630 |
);
|
| 631 |
|
| 632 |
if (typeof wsAmeActorData['capPower'] !== 'undefined') {
|
js/menu-editor.js
CHANGED
|
@@ -1191,13 +1191,13 @@ function updateActorAccessUi(containerNode) {
|
|
| 1191 |
var checkbox = containerNode.find('.ws_actor_access_checkbox');
|
| 1192 |
checkbox.prop('checked', hasAccess);
|
| 1193 |
|
| 1194 |
-
//Display the checkbox
|
|
|
|
|
|
|
|
|
|
| 1195 |
//or if their permissions don't match this menu's permissions.
|
| 1196 |
var submenuItems = getSubmenuItemNodes(containerNode);
|
| 1197 |
-
if ((submenuItems.length
|
| 1198 |
-
//Either this menu doesn't contain any items, or their permissions don't matter because they're overridden.
|
| 1199 |
-
checkbox.prop('indeterminate', false);
|
| 1200 |
-
} else {
|
| 1201 |
var differentPermissions = false;
|
| 1202 |
submenuItems.each(function() {
|
| 1203 |
var item = $(this).data('menu_item');
|
|
@@ -1212,7 +1212,24 @@ function updateActorAccessUi(containerNode) {
|
|
| 1212 |
return true;
|
| 1213 |
});
|
| 1214 |
|
| 1215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1216 |
}
|
| 1217 |
|
| 1218 |
containerNode.toggleClass('ws_is_hidden_for_actor', !hasAccess);
|
|
@@ -1222,12 +1239,17 @@ function updateActorAccessUi(containerNode) {
|
|
| 1222 |
} else {
|
| 1223 |
containerNode.removeClass('ws_is_hidden_for_actor ws_has_custom_permissions_for_actor');
|
| 1224 |
setMenuFlag(containerNode, 'custom_actor_permissions', false);
|
|
|
|
| 1225 |
|
| 1226 |
var currentUserActor = 'user:' + wsEditorData.currentUserLogin;
|
| 1227 |
var otherActors = _(wsEditorData.actors).keys().without(currentUserActor, 'special:super_admin').value(),
|
| 1228 |
hiddenFromCurrentUser = ! actorCanAccessMenu(menuItem, currentUserActor),
|
| 1229 |
-
|
|
|
|
|
|
|
|
|
|
| 1230 |
visibleForSuperAdmin = AmeActors.isMultisite && actorCanAccessMenu(menuItem, 'special:super_admin');
|
|
|
|
| 1231 |
setMenuFlag(
|
| 1232 |
containerNode,
|
| 1233 |
'hidden_from_others',
|
|
@@ -1729,11 +1751,12 @@ function readAllFields(container){
|
|
| 1729 |
***************************************************************************/
|
| 1730 |
|
| 1731 |
var item_flags = {
|
| 1732 |
-
'custom':'This is a custom menu item',
|
| 1733 |
-
'unused':'This item was
|
| 1734 |
-
'hidden':'Cosmetically hidden',
|
| 1735 |
-
'custom_actor_permissions'
|
| 1736 |
-
'hidden_from_others'
|
|
|
|
| 1737 |
};
|
| 1738 |
|
| 1739 |
function setMenuFlag(item, flag, state, title) {
|
|
@@ -4729,6 +4752,17 @@ function ameOnDomReady() {
|
|
| 4729 |
);
|
| 4730 |
});
|
| 4731 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4732 |
|
| 4733 |
/******************************************************************
|
| 4734 |
Actor views
|
| 1191 |
var checkbox = containerNode.find('.ws_actor_access_checkbox');
|
| 1192 |
checkbox.prop('checked', hasAccess);
|
| 1193 |
|
| 1194 |
+
//Display the checkbox in an indeterminate state if the actual menu permissions are unknown
|
| 1195 |
+
//because it uses meta capabilities.
|
| 1196 |
+
var isIndeterminate = (hasAccess === null);
|
| 1197 |
+
//Also show it as indeterminate if some items of this menu are hidden and some are visible,
|
| 1198 |
//or if their permissions don't match this menu's permissions.
|
| 1199 |
var submenuItems = getSubmenuItemNodes(containerNode);
|
| 1200 |
+
if ((submenuItems.length > 0) && !isOverrideActive) {
|
|
|
|
|
|
|
|
|
|
| 1201 |
var differentPermissions = false;
|
| 1202 |
submenuItems.each(function() {
|
| 1203 |
var item = $(this).data('menu_item');
|
| 1212 |
return true;
|
| 1213 |
});
|
| 1214 |
|
| 1215 |
+
if (differentPermissions) {
|
| 1216 |
+
isIndeterminate = true;
|
| 1217 |
+
}
|
| 1218 |
+
}
|
| 1219 |
+
checkbox.prop('indeterminate', isIndeterminate);
|
| 1220 |
+
|
| 1221 |
+
if (isIndeterminate && (hasAccess === null)) {
|
| 1222 |
+
setMenuFlag(
|
| 1223 |
+
containerNode,
|
| 1224 |
+
'uncertain_meta_cap',
|
| 1225 |
+
true,
|
| 1226 |
+
"This item might be visible.\n"
|
| 1227 |
+
+ "The plugin cannot reliably detect if \"" + actorSelectorWidget.selectedDisplayName
|
| 1228 |
+
+ "\" has the \"" + getFieldValue(menuItem, 'access_level', '[No capability]')
|
| 1229 |
+
+ "\" capability. If you need to hide the item, try checking and then unchecking it."
|
| 1230 |
+
);
|
| 1231 |
+
} else {
|
| 1232 |
+
setMenuFlag(containerNode, 'uncertain_meta_cap', false);
|
| 1233 |
}
|
| 1234 |
|
| 1235 |
containerNode.toggleClass('ws_is_hidden_for_actor', !hasAccess);
|
| 1239 |
} else {
|
| 1240 |
containerNode.removeClass('ws_is_hidden_for_actor ws_has_custom_permissions_for_actor');
|
| 1241 |
setMenuFlag(containerNode, 'custom_actor_permissions', false);
|
| 1242 |
+
setMenuFlag(containerNode, 'uncertain_meta_cap', false);
|
| 1243 |
|
| 1244 |
var currentUserActor = 'user:' + wsEditorData.currentUserLogin;
|
| 1245 |
var otherActors = _(wsEditorData.actors).keys().without(currentUserActor, 'special:super_admin').value(),
|
| 1246 |
hiddenFromCurrentUser = ! actorCanAccessMenu(menuItem, currentUserActor),
|
| 1247 |
+
hasAccessToThisItem = _.curry(actorCanAccessMenu, 2)(menuItem),
|
| 1248 |
+
hiddenFromOthers = _.every(otherActors, function(actorId) {
|
| 1249 |
+
return (hasAccessToThisItem(actorId) === false);
|
| 1250 |
+
}),
|
| 1251 |
visibleForSuperAdmin = AmeActors.isMultisite && actorCanAccessMenu(menuItem, 'special:super_admin');
|
| 1252 |
+
|
| 1253 |
setMenuFlag(
|
| 1254 |
containerNode,
|
| 1255 |
'hidden_from_others',
|
| 1751 |
***************************************************************************/
|
| 1752 |
|
| 1753 |
var item_flags = {
|
| 1754 |
+
'custom': 'This is a custom menu item',
|
| 1755 |
+
'unused': 'This item was added since the last time you saved menu settings.',
|
| 1756 |
+
'hidden': 'Cosmetically hidden',
|
| 1757 |
+
'custom_actor_permissions': "The selected role has custom permissions for this item.",
|
| 1758 |
+
'hidden_from_others': 'Hidden from everyone except you.',
|
| 1759 |
+
'uncertain_meta_cap': 'The plugin cannot detect if this item is visible by default.'
|
| 1760 |
};
|
| 1761 |
|
| 1762 |
function setMenuFlag(item, flag, state, title) {
|
| 4752 |
);
|
| 4753 |
});
|
| 4754 |
|
| 4755 |
+
//Expand/collapse the "How To" box.
|
| 4756 |
+
var $howToBox = $("#ws_ame_how_to_box");
|
| 4757 |
+
$howToBox.find(".handlediv").click(function() {
|
| 4758 |
+
$howToBox.toggleClass('closed');
|
| 4759 |
+
$.cookie(
|
| 4760 |
+
'ame_how_to_box_open',
|
| 4761 |
+
($howToBox.hasClass('closed') ? '0' : '1'),
|
| 4762 |
+
{ expires: 180 }
|
| 4763 |
+
);
|
| 4764 |
+
});
|
| 4765 |
+
|
| 4766 |
|
| 4767 |
/******************************************************************
|
| 4768 |
Actor views
|
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.8.
|
| 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.8.2
|
| 7 |
Author: Janis Elsts
|
| 8 |
Author URI: http://w-shadow.com/blog/
|
| 9 |
*/
|
modules/actor-selector/actor-selector.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
| 1 |
/// <reference path="../../js/jquery.d.ts" />
|
| 2 |
/// <reference path="../../js/jquery-json.d.ts" />
|
| 3 |
/// <reference path="../../js/actor-manager.ts" />
|
| 4 |
-
var AmeActorSelector = (function () {
|
| 5 |
function AmeActorSelector(actorManager, isProVersion, currentUserLogin, visibleUsers, ajaxParams) {
|
| 6 |
var _this = this;
|
| 7 |
this.selectedActor = null;
|
|
|
|
| 8 |
this.visibleUsers = [];
|
| 9 |
this.subscribers = [];
|
| 10 |
this.isProVersion = false;
|
|
@@ -88,6 +89,12 @@ var AmeActorSelector = (function () {
|
|
| 88 |
var previousSelection = this.selectedActor;
|
| 89 |
this.selectedActor = actorId;
|
| 90 |
this.highlightSelectedActor();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
//Notify subscribers that the selection has changed.
|
| 92 |
if (this.selectedActor !== previousSelection) {
|
| 93 |
for (var i = 0; i < this.subscribers.length; i++) {
|
|
@@ -199,3 +206,4 @@ var AmeActorSelector = (function () {
|
|
| 199 |
AmeActorSelector._ = wsAmeLodash;
|
| 200 |
return AmeActorSelector;
|
| 201 |
}());
|
|
|
| 1 |
/// <reference path="../../js/jquery.d.ts" />
|
| 2 |
/// <reference path="../../js/jquery-json.d.ts" />
|
| 3 |
/// <reference path="../../js/actor-manager.ts" />
|
| 4 |
+
var AmeActorSelector = /** @class */ (function () {
|
| 5 |
function AmeActorSelector(actorManager, isProVersion, currentUserLogin, visibleUsers, ajaxParams) {
|
| 6 |
var _this = this;
|
| 7 |
this.selectedActor = null;
|
| 8 |
+
this.selectedDisplayName = 'All';
|
| 9 |
this.visibleUsers = [];
|
| 10 |
this.subscribers = [];
|
| 11 |
this.isProVersion = false;
|
| 89 |
var previousSelection = this.selectedActor;
|
| 90 |
this.selectedActor = actorId;
|
| 91 |
this.highlightSelectedActor();
|
| 92 |
+
if (actorId !== null) {
|
| 93 |
+
this.selectedDisplayName = this.actorManager.getActor(actorId).displayName;
|
| 94 |
+
}
|
| 95 |
+
else {
|
| 96 |
+
this.selectedDisplayName = 'All';
|
| 97 |
+
}
|
| 98 |
//Notify subscribers that the selection has changed.
|
| 99 |
if (this.selectedActor !== previousSelection) {
|
| 100 |
for (var i = 0; i < this.subscribers.length; i++) {
|
| 206 |
AmeActorSelector._ = wsAmeLodash;
|
| 207 |
return AmeActorSelector;
|
| 208 |
}());
|
| 209 |
+
//# sourceMappingURL=actor-selector.js.map
|
modules/actor-selector/actor-selector.ts
CHANGED
|
@@ -27,6 +27,7 @@ class AmeActorSelector {
|
|
| 27 |
private static _ = wsAmeLodash;
|
| 28 |
|
| 29 |
public selectedActor: string = null;
|
|
|
|
| 30 |
|
| 31 |
private visibleUsers: string[] = [];
|
| 32 |
private subscribers: SelectedActorChangedCallback[] = [];
|
|
@@ -128,6 +129,12 @@ class AmeActorSelector {
|
|
| 128 |
this.selectedActor = actorId;
|
| 129 |
this.highlightSelectedActor();
|
| 130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
//Notify subscribers that the selection has changed.
|
| 132 |
if (this.selectedActor !== previousSelection) {
|
| 133 |
for (let i = 0; i < this.subscribers.length; i++) {
|
| 27 |
private static _ = wsAmeLodash;
|
| 28 |
|
| 29 |
public selectedActor: string = null;
|
| 30 |
+
public selectedDisplayName: string = 'All';
|
| 31 |
|
| 32 |
private visibleUsers: string[] = [];
|
| 33 |
private subscribers: SelectedActorChangedCallback[] = [];
|
| 129 |
this.selectedActor = actorId;
|
| 130 |
this.highlightSelectedActor();
|
| 131 |
|
| 132 |
+
if (actorId !== null) {
|
| 133 |
+
this.selectedDisplayName = this.actorManager.getActor(actorId).displayName;
|
| 134 |
+
} else {
|
| 135 |
+
this.selectedDisplayName = 'All';
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
//Notify subscribers that the selection has changed.
|
| 139 |
if (this.selectedActor !== previousSelection) {
|
| 140 |
for (let i = 0; i < this.subscribers.length; i++) {
|
modules/highlight-new-menus/wsNewMenuHighlighter.php
CHANGED
|
@@ -44,6 +44,12 @@ class wsNewMenuHighlighter {
|
|
| 44 |
'user-new.php' => true,
|
| 45 |
'users.php' => true,
|
| 46 |
'widgets.php' => true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
);
|
| 48 |
|
| 49 |
private $menusWithNewSubmenus = array();
|
|
@@ -180,10 +186,10 @@ class wsNewMenuHighlighter {
|
|
| 180 |
|
| 181 |
if ( isset($GLOBALS['wp_menu_editor']) && is_callable(array(
|
| 182 |
$GLOBALS['wp_menu_editor'],
|
| 183 |
-
'
|
| 184 |
))
|
| 185 |
) {
|
| 186 |
-
$GLOBALS['wp_menu_editor']->
|
| 187 |
$dependencies[] = 'jquery-cookie';
|
| 188 |
}
|
| 189 |
|
| 44 |
'user-new.php' => true,
|
| 45 |
'users.php' => true,
|
| 46 |
'widgets.php' => true,
|
| 47 |
+
//Network admin items.
|
| 48 |
+
'settings.php' => true,
|
| 49 |
+
'site-new.php' => true,
|
| 50 |
+
'sites.php' => true,
|
| 51 |
+
'theme-install.php' => true,
|
| 52 |
+
'upgrade.php' => true,
|
| 53 |
);
|
| 54 |
|
| 55 |
private $menusWithNewSubmenus = array();
|
| 186 |
|
| 187 |
if ( isset($GLOBALS['wp_menu_editor']) && is_callable(array(
|
| 188 |
$GLOBALS['wp_menu_editor'],
|
| 189 |
+
'register_jquery_plugins',
|
| 190 |
))
|
| 191 |
) {
|
| 192 |
+
$GLOBALS['wp_menu_editor']->register_jquery_plugins();
|
| 193 |
$dependencies[] = 'jquery-cookie';
|
| 194 |
}
|
| 195 |
|
modules/plugin-visibility/plugin-visibility.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
/// <reference path="../../js/lodash-3.10.d.ts" />
|
| 5 |
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
|
| 6 |
/// <reference path="../../ajax-wrapper/ajax-action-wrapper.d.ts" />
|
| 7 |
-
var AmePluginVisibilityModule = (function () {
|
| 8 |
function AmePluginVisibilityModule(scriptData) {
|
| 9 |
var _this = this;
|
| 10 |
var _ = AmePluginVisibilityModule._;
|
|
@@ -159,7 +159,7 @@ var AmePluginVisibilityModule = (function () {
|
|
| 159 |
AmePluginVisibilityModule._ = wsAmeLodash;
|
| 160 |
return AmePluginVisibilityModule;
|
| 161 |
}());
|
| 162 |
-
var AmePlugin = (function () {
|
| 163 |
function AmePlugin(details, settings, module) {
|
| 164 |
var _this = this;
|
| 165 |
var _ = AmePluginVisibilityModule._;
|
| 4 |
/// <reference path="../../js/lodash-3.10.d.ts" />
|
| 5 |
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
|
| 6 |
/// <reference path="../../ajax-wrapper/ajax-action-wrapper.d.ts" />
|
| 7 |
+
var AmePluginVisibilityModule = /** @class */ (function () {
|
| 8 |
function AmePluginVisibilityModule(scriptData) {
|
| 9 |
var _this = this;
|
| 10 |
var _ = AmePluginVisibilityModule._;
|
| 159 |
AmePluginVisibilityModule._ = wsAmeLodash;
|
| 160 |
return AmePluginVisibilityModule;
|
| 161 |
}());
|
| 162 |
+
var AmePlugin = /** @class */ (function () {
|
| 163 |
function AmePlugin(details, settings, module) {
|
| 164 |
var _this = this;
|
| 165 |
var _ = AmePluginVisibilityModule._;
|
modules/plugin-visibility/plugin-visibility.php
CHANGED
|
@@ -20,7 +20,7 @@ class amePluginVisibility {
|
|
| 20 |
self::$lastInstance = $this;
|
| 21 |
|
| 22 |
//Remove "hidden" plugins from the list on the "Plugins -> Installed Plugins" page.
|
| 23 |
-
add_filter('all_plugins', array($this, 'filterPluginList'));
|
| 24 |
|
| 25 |
//It's not possible to completely prevent a user from (de)activating "hidden" plugins because plugin API
|
| 26 |
//functions like activate_plugin() and deactivate_plugins() don't provide a way to abort (de)activation.
|
| 20 |
self::$lastInstance = $this;
|
| 21 |
|
| 22 |
//Remove "hidden" plugins from the list on the "Plugins -> Installed Plugins" page.
|
| 23 |
+
add_filter('all_plugins', array($this, 'filterPluginList'), 15);
|
| 24 |
|
| 25 |
//It's not possible to completely prevent a user from (de)activating "hidden" plugins because plugin API
|
| 26 |
//functions like activate_plugin() and deactivate_plugins() don't provide a way to abort (de)activation.
|
readme.txt
CHANGED
|
@@ -3,8 +3,8 @@ 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: 4.1
|
| 6 |
-
Tested up to: 4.9
|
| 7 |
-
Stable tag: 1.8.
|
| 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,14 @@ Plugins installed in the `mu-plugins` directory are treated as "always on", so y
|
|
| 63 |
|
| 64 |
== Changelog ==
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
= 1.8.1 =
|
| 67 |
* Added a workaround for a buggy "defer_parsing_of_js" code snippet that some users have added to their functions.php. This snippet produces invalid HTML code, which used to break the menu editor.
|
| 68 |
* Fixed a PHP warning that appeared when using this plugin together with WooCommerce or YITH WooCommerce Gift Cards and running PHP 7.1.
|
| 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: 4.1
|
| 6 |
+
Tested up to: 4.9.4
|
| 7 |
+
Stable tag: 1.8.2
|
| 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.8.2 =
|
| 67 |
+
* Fixed the PHP warning "count(): Parameter must be an array or an object that implements Countable in menu-editor-core.php".
|
| 68 |
+
* Fixed a bug that could cause some network admin menus to be highlighted in green as if they were new.
|
| 69 |
+
* Fixed a conflict with WP Courseware 4.1.2 where activating AME would cause many extra menu items to show up unexpectedly.
|
| 70 |
+
* Fixed a conflict with Ultra WordPress Admin 7.4 that made it impossible to hide plugins.
|
| 71 |
+
* Replaced the "this is a new item" icon with a different one.
|
| 72 |
+
* Tested with WP 4.9.4.
|
| 73 |
+
|
| 74 |
= 1.8.1 =
|
| 75 |
* Added a workaround for a buggy "defer_parsing_of_js" code snippet that some users have added to their functions.php. This snippet produces invalid HTML code, which used to break the menu editor.
|
| 76 |
* Fixed a PHP warning that appeared when using this plugin together with WooCommerce or YITH WooCommerce Gift Cards and running PHP 7.1.
|
