Version Description
- Split the "required capability" field into two parts - a read-only field that shows the actual required capability, and an editable "extra capability" that you can use to restrict access to the menu.
- Added more detailed permission error messages. You can turn them off in the "Settings" tab by changing "Error verbosity level" to "Low".
- Tested up to WP 4.6.
Download this release
Release Info
Developer | whiteshadow |
Plugin | Admin Menu Editor |
Version | 1.7.1 |
Comparing to | |
See all releases |
Code changes from version 1.7 to 1.7.1
- css/menu-editor.css +77 -14
- css/menu-editor.scss +119 -17
- includes/editor-page.php +30 -32
- includes/menu-editor-core.php +119 -20
- includes/module.php +20 -0
- includes/settings-page.php +45 -0
- js/actor-manager.js +12 -2
- js/actor-manager.ts +34 -9
- js/jquery.biscuit.d.ts +5 -0
- js/menu-editor.js +123 -51
- menu-editor.php +1 -1
- modules/plugin-visibility/plugin-visibility.php +0 -5
- readme.txt +7 -2
css/menu-editor.css
CHANGED
@@ -1,8 +1,6 @@
|
|
1 |
/* Admin Menu Editor CSS file */
|
2 |
#ws_menu_editor {
|
3 |
min-width: 780px; }
|
4 |
-
#ws_menu_editor #ws_actor_selector {
|
5 |
-
margin-top: 6px; }
|
6 |
|
7 |
.ame-is-free-version #ws_menu_editor {
|
8 |
margin-top: 9px; }
|
@@ -65,7 +63,7 @@
|
|
65 |
margin-bottom: -1px; }
|
66 |
|
67 |
#ws_actor_selector {
|
68 |
-
margin-top:
|
69 |
|
70 |
/**
|
71 |
* The checkbox that lets the user show/hide a menu for the currently selected actor.
|
@@ -513,6 +511,36 @@ select.ws_dropdown option {
|
|
513 |
select.ws_dropdown optgroup option {
|
514 |
padding-left: 10px; }
|
515 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
516 |
/************************************
|
517 |
Icon selector
|
518 |
*************************************/
|
@@ -521,11 +549,11 @@ select.ws_dropdown optgroup option {
|
|
521 |
border-radius: 3px;
|
522 |
background-color: white;
|
523 |
width: 216px;
|
524 |
-
padding:
|
525 |
position: absolute; }
|
526 |
|
527 |
#ws_icon_selector.ws_with_more_icons {
|
528 |
-
width:
|
529 |
|
530 |
#ws_icon_selector .ws_icon_extra {
|
531 |
display: none; }
|
@@ -613,6 +641,17 @@ select.ws_dropdown optgroup option {
|
|
613 |
width: 16px;
|
614 |
height: 16px; }
|
615 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
616 |
/* MP6 admin style compatibility */
|
617 |
#ws_icon_selector .ws_icon_option .icon16::before {
|
618 |
margin: 0;
|
@@ -625,11 +664,6 @@ select.ws_dropdown optgroup option {
|
|
625 |
#ws_choose_icon_from_media {
|
626 |
margin: 2px; }
|
627 |
|
628 |
-
#ws_show_more_icons {
|
629 |
-
margin: 2px;
|
630 |
-
height: 30px;
|
631 |
-
width: 68px; }
|
632 |
-
|
633 |
/************************************
|
634 |
Embedded page selector
|
635 |
*************************************/
|
@@ -976,8 +1010,7 @@ a#ws-ame-delete-color-preset:hover {
|
|
976 |
background: white;
|
977 |
filter: alpha(opacity=60);
|
978 |
opacity: 0.6;
|
979 |
-
-moz-opacity: 0.6;
|
980 |
-
-khtml-opacity: 0.6; }
|
981 |
|
982 |
#ws_role_access_overlay_content {
|
983 |
position: absolute;
|
@@ -1181,7 +1214,7 @@ a#ws-ame-delete-color-preset:hover {
|
|
1181 |
padding-left: 6px; }
|
1182 |
#ws_user_selection_panels #ws_selected_users .ws_user_display_name_column {
|
1183 |
display: none; }
|
1184 |
-
#ws_user_selection_panels #ws_selected_users tr.
|
1185 |
display: none; }
|
1186 |
#ws_user_selection_panels #ws_selected_users_caption {
|
1187 |
font-size: 14px;
|
@@ -1212,7 +1245,7 @@ a#ws-ame-delete-color-preset:hover {
|
|
1212 |
/************************************
|
1213 |
Tooltips and hints
|
1214 |
*************************************/
|
1215 |
-
.ws_tooltip_trigger {
|
1216 |
cursor: pointer; }
|
1217 |
|
1218 |
.ws_tooltip_content_list {
|
@@ -1226,6 +1259,14 @@ a#ws-ame-delete-color-preset:hover {
|
|
1226 |
border-radius: 3px;
|
1227 |
max-width: 300px; }
|
1228 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1229 |
#ws_plugin_settings_form .ws_tooltip_trigger .dashicons {
|
1230 |
font-size: 18px; }
|
1231 |
|
@@ -1267,6 +1308,28 @@ a#ws-ame-delete-color-preset:hover {
|
|
1267 |
list-style-position: inside;
|
1268 |
margin-left: 0.5em; }
|
1269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1270 |
/************************************
|
1271 |
Copy Permissions dialog
|
1272 |
*************************************/
|
1 |
/* Admin Menu Editor CSS file */
|
2 |
#ws_menu_editor {
|
3 |
min-width: 780px; }
|
|
|
|
|
4 |
|
5 |
.ame-is-free-version #ws_menu_editor {
|
6 |
margin-top: 9px; }
|
63 |
margin-bottom: -1px; }
|
64 |
|
65 |
#ws_actor_selector {
|
66 |
+
margin-top: 6px; }
|
67 |
|
68 |
/**
|
69 |
* The checkbox that lets the user show/hide a menu for the currently selected actor.
|
511 |
select.ws_dropdown optgroup option {
|
512 |
padding-left: 10px; }
|
513 |
|
514 |
+
/************************************
|
515 |
+
Tabs (small)
|
516 |
+
************************************
|
517 |
+
Tabbed navigation for dropdowns and small dialogs.
|
518 |
+
*/
|
519 |
+
.ws_tool_tab_nav {
|
520 |
+
list-style: outside none none;
|
521 |
+
padding: 0;
|
522 |
+
margin: 0 0 0 6px; }
|
523 |
+
.ws_tool_tab_nav li {
|
524 |
+
display: inline-block;
|
525 |
+
border: 1px solid transparent;
|
526 |
+
border-bottom-width: 0;
|
527 |
+
padding: 3px 5px 5px;
|
528 |
+
line-height: 1.35em;
|
529 |
+
margin-bottom: 0; }
|
530 |
+
.ws_tool_tab_nav li.ui-tabs-active {
|
531 |
+
border-color: #dfdfdf;
|
532 |
+
background-color: #FDFDFD;
|
533 |
+
border-bottom-color: #FDFDFD; }
|
534 |
+
.ws_tool_tab_nav a {
|
535 |
+
text-decoration: none; }
|
536 |
+
.ws_tool_tab_nav li.ui-tabs-active a {
|
537 |
+
color: #32373C; }
|
538 |
+
|
539 |
+
.ws_tool_tab {
|
540 |
+
border-top: 1px solid #DFDFDF;
|
541 |
+
margin-top: -1px;
|
542 |
+
background-color: #FDFDFD; }
|
543 |
+
|
544 |
/************************************
|
545 |
Icon selector
|
546 |
*************************************/
|
549 |
border-radius: 3px;
|
550 |
background-color: white;
|
551 |
width: 216px;
|
552 |
+
padding: 4px 0 0 0;
|
553 |
position: absolute; }
|
554 |
|
555 |
#ws_icon_selector.ws_with_more_icons {
|
556 |
+
width: 570px; }
|
557 |
|
558 |
#ws_icon_selector .ws_icon_extra {
|
559 |
display: none; }
|
641 |
width: 16px;
|
642 |
height: 16px; }
|
643 |
|
644 |
+
#ws_icon_selector .ws_tool_tab_nav {
|
645 |
+
display: inline-block;
|
646 |
+
margin-top: 2px;
|
647 |
+
position: relative; }
|
648 |
+
#ws_icon_selector .ws_tool_tab_nav li {
|
649 |
+
padding: 4px 10px 11px; }
|
650 |
+
#ws_icon_selector .ws_tool_tab {
|
651 |
+
padding: 4px 4px 2px;
|
652 |
+
max-height: 324px;
|
653 |
+
overflow-y: auto; }
|
654 |
+
|
655 |
/* MP6 admin style compatibility */
|
656 |
#ws_icon_selector .ws_icon_option .icon16::before {
|
657 |
margin: 0;
|
664 |
#ws_choose_icon_from_media {
|
665 |
margin: 2px; }
|
666 |
|
|
|
|
|
|
|
|
|
|
|
667 |
/************************************
|
668 |
Embedded page selector
|
669 |
*************************************/
|
1010 |
background: white;
|
1011 |
filter: alpha(opacity=60);
|
1012 |
opacity: 0.6;
|
1013 |
+
-moz-opacity: 0.6; }
|
|
|
1014 |
|
1015 |
#ws_role_access_overlay_content {
|
1016 |
position: absolute;
|
1214 |
padding-left: 6px; }
|
1215 |
#ws_user_selection_panels #ws_selected_users .ws_user_display_name_column {
|
1216 |
display: none; }
|
1217 |
+
#ws_user_selection_panels #ws_selected_users tr.ws_user_must_be_selected .ws_user_action_button {
|
1218 |
display: none; }
|
1219 |
#ws_user_selection_panels #ws_selected_users_caption {
|
1220 |
font-size: 14px;
|
1245 |
/************************************
|
1246 |
Tooltips and hints
|
1247 |
*************************************/
|
1248 |
+
.ws_tooltip_trigger, .ws_field_tooltip_trigger {
|
1249 |
cursor: pointer; }
|
1250 |
|
1251 |
.ws_tooltip_content_list {
|
1259 |
border-radius: 3px;
|
1260 |
max-width: 300px; }
|
1261 |
|
1262 |
+
.ws_field_tooltip_trigger .dashicons {
|
1263 |
+
font-size: 16px;
|
1264 |
+
height: 16px;
|
1265 |
+
vertical-align: bottom; }
|
1266 |
+
|
1267 |
+
.ws_field_tooltip_trigger {
|
1268 |
+
color: #a1a1a1; }
|
1269 |
+
|
1270 |
#ws_plugin_settings_form .ws_tooltip_trigger .dashicons {
|
1271 |
font-size: 18px; }
|
1272 |
|
1308 |
list-style-position: inside;
|
1309 |
margin-left: 0.5em; }
|
1310 |
|
1311 |
+
.ws_ame_doc_box .hndle {
|
1312 |
+
cursor: default !important; }
|
1313 |
+
.ws_ame_doc_box ul {
|
1314 |
+
list-style: disc outside;
|
1315 |
+
margin-left: 1em; }
|
1316 |
+
.ws_ame_doc_box li > ul {
|
1317 |
+
margin-top: 6px; }
|
1318 |
+
.ws_ame_doc_box .button-link .toggle-indicator::before {
|
1319 |
+
margin-top: 4px;
|
1320 |
+
width: 20px;
|
1321 |
+
-webkit-border-radius: 50%;
|
1322 |
+
border-radius: 50%;
|
1323 |
+
text-indent: -1px;
|
1324 |
+
content: "\f142";
|
1325 |
+
display: inline-block;
|
1326 |
+
font: normal 20px/1 dashicons;
|
1327 |
+
-webkit-font-smoothing: antialiased;
|
1328 |
+
-moz-osx-font-smoothing: grayscale;
|
1329 |
+
text-decoration: none !important; }
|
1330 |
+
.ws_ame_doc_box.closed .button-link .toggle-indicator::before {
|
1331 |
+
content: "\f140"; }
|
1332 |
+
|
1333 |
/************************************
|
1334 |
Copy Permissions dialog
|
1335 |
*************************************/
|
css/menu-editor.scss
CHANGED
@@ -2,10 +2,6 @@
|
|
2 |
|
3 |
#ws_menu_editor {
|
4 |
min-width: 780px;
|
5 |
-
|
6 |
-
#ws_actor_selector {
|
7 |
-
margin-top: 6px;
|
8 |
-
}
|
9 |
}
|
10 |
|
11 |
.ame-is-free-version #ws_menu_editor {
|
@@ -97,7 +93,7 @@ $mainContainerBorderWidth: 1px;
|
|
97 |
}
|
98 |
|
99 |
#ws_actor_selector {
|
100 |
-
margin-top:
|
101 |
}
|
102 |
|
103 |
/**
|
@@ -706,6 +702,53 @@ select.ws_dropdown optgroup option {
|
|
706 |
padding-left: 10px;
|
707 |
}
|
708 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
709 |
/************************************
|
710 |
Icon selector
|
711 |
*************************************/
|
@@ -716,12 +759,12 @@ select.ws_dropdown optgroup option {
|
|
716 |
background-color: white;
|
717 |
|
718 |
width: 216px;
|
719 |
-
padding:
|
720 |
position: absolute;
|
721 |
}
|
722 |
|
723 |
#ws_icon_selector.ws_with_more_icons {
|
724 |
-
width:
|
725 |
}
|
726 |
|
727 |
#ws_icon_selector .ws_icon_extra {
|
@@ -828,6 +871,28 @@ select.ws_dropdown optgroup option {
|
|
828 |
height: 16px;
|
829 |
}
|
830 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
831 |
/* MP6 admin style compatibility */
|
832 |
#ws_icon_selector .ws_icon_option .icon16::before {
|
833 |
margin: 0;
|
@@ -842,12 +907,6 @@ select.ws_dropdown optgroup option {
|
|
842 |
margin: 2px;
|
843 |
}
|
844 |
|
845 |
-
#ws_show_more_icons {
|
846 |
-
margin: 2px;
|
847 |
-
height: 30px;
|
848 |
-
width: 68px;
|
849 |
-
}
|
850 |
-
|
851 |
/************************************
|
852 |
Embedded page selector
|
853 |
*************************************/
|
@@ -1294,7 +1353,6 @@ a#ws-ame-delete-color-preset:hover {
|
|
1294 |
filter: alpha(opacity=60);
|
1295 |
opacity: 0.6;
|
1296 |
-moz-opacity:0.6;
|
1297 |
-
-khtml-opacity: 0.6;
|
1298 |
}
|
1299 |
|
1300 |
#ws_role_access_overlay_content {
|
@@ -1639,8 +1697,8 @@ $userSelectionPanelPadding: 10px;
|
|
1639 |
display: none;
|
1640 |
}
|
1641 |
|
1642 |
-
//You can't deselect the current user. It always stays in the actor list.
|
1643 |
-
tr.
|
1644 |
.ws_user_action_button {
|
1645 |
display: none;
|
1646 |
}
|
@@ -1699,7 +1757,7 @@ $userSelectionPanelPadding: 10px;
|
|
1699 |
Tooltips and hints
|
1700 |
*************************************/
|
1701 |
|
1702 |
-
.ws_tooltip_trigger {
|
1703 |
cursor: pointer;
|
1704 |
}
|
1705 |
|
@@ -1716,6 +1774,16 @@ $userSelectionPanelPadding: 10px;
|
|
1716 |
max-width: 300px;
|
1717 |
}
|
1718 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1719 |
//Tooltips on the settings page.
|
1720 |
#ws_plugin_settings_form .ws_tooltip_trigger .dashicons {
|
1721 |
font-size: 18px;
|
@@ -1768,6 +1836,40 @@ $userSelectionPanelPadding: 10px;
|
|
1768 |
margin-left: 0.5em;
|
1769 |
}
|
1770 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1771 |
|
1772 |
/************************************
|
1773 |
Copy Permissions dialog
|
2 |
|
3 |
#ws_menu_editor {
|
4 |
min-width: 780px;
|
|
|
|
|
|
|
|
|
5 |
}
|
6 |
|
7 |
.ame-is-free-version #ws_menu_editor {
|
93 |
}
|
94 |
|
95 |
#ws_actor_selector {
|
96 |
+
margin-top: 6px;
|
97 |
}
|
98 |
|
99 |
/**
|
702 |
padding-left: 10px;
|
703 |
}
|
704 |
|
705 |
+
/************************************
|
706 |
+
Tabs (small)
|
707 |
+
************************************
|
708 |
+
Tabbed navigation for dropdowns and small dialogs.
|
709 |
+
*/
|
710 |
+
|
711 |
+
$activeToolTabBackground: #FDFDFD;
|
712 |
+
|
713 |
+
.ws_tool_tab_nav {
|
714 |
+
list-style: outside none none;
|
715 |
+
padding: 0;
|
716 |
+
margin: 0 0 0 6px;
|
717 |
+
|
718 |
+
li {
|
719 |
+
display: inline-block;
|
720 |
+
|
721 |
+
border: 1px solid transparent;
|
722 |
+
border-bottom-width: 0;
|
723 |
+
padding: 3px 5px 5px;
|
724 |
+
line-height: 1.35em;
|
725 |
+
|
726 |
+
margin-bottom: 0;
|
727 |
+
}
|
728 |
+
|
729 |
+
li.ui-tabs-active {
|
730 |
+
border-color: #dfdfdf;
|
731 |
+
background-color: #FDFDFD;
|
732 |
+
border-bottom-color: $activeToolTabBackground;
|
733 |
+
}
|
734 |
+
|
735 |
+
a {
|
736 |
+
text-decoration: none;
|
737 |
+
}
|
738 |
+
|
739 |
+
li.ui-tabs-active a {
|
740 |
+
color: #32373C;
|
741 |
+
}
|
742 |
+
}
|
743 |
+
|
744 |
+
.ws_tool_tab {
|
745 |
+
border-top: 1px solid #DFDFDF;
|
746 |
+
margin-top: -1px;
|
747 |
+
background-color: $activeToolTabBackground;
|
748 |
+
|
749 |
+
//Suggestion: Use 12px inner padding like in post editor boxes.
|
750 |
+
}
|
751 |
+
|
752 |
/************************************
|
753 |
Icon selector
|
754 |
*************************************/
|
759 |
background-color: white;
|
760 |
|
761 |
width: 216px;
|
762 |
+
padding: 4px 0 0 0;
|
763 |
position: absolute;
|
764 |
}
|
765 |
|
766 |
#ws_icon_selector.ws_with_more_icons {
|
767 |
+
width: 570px;
|
768 |
}
|
769 |
|
770 |
#ws_icon_selector .ws_icon_extra {
|
871 |
height: 16px;
|
872 |
}
|
873 |
|
874 |
+
#ws_icon_selector {
|
875 |
+
$tabTopPadding: 4px;
|
876 |
+
$tabHorizontalPadding: 4px;
|
877 |
+
|
878 |
+
.ws_tool_tab_nav {
|
879 |
+
display: inline-block;
|
880 |
+
margin-top: 2px;
|
881 |
+
|
882 |
+
li {
|
883 |
+
padding: 4px 10px 11px;
|
884 |
+
}
|
885 |
+
|
886 |
+
position: relative;
|
887 |
+
}
|
888 |
+
|
889 |
+
.ws_tool_tab {
|
890 |
+
padding: $tabTopPadding $tabHorizontalPadding 2px;
|
891 |
+
max-height: 324px;
|
892 |
+
overflow-y: auto;
|
893 |
+
}
|
894 |
+
}
|
895 |
+
|
896 |
/* MP6 admin style compatibility */
|
897 |
#ws_icon_selector .ws_icon_option .icon16::before {
|
898 |
margin: 0;
|
907 |
margin: 2px;
|
908 |
}
|
909 |
|
|
|
|
|
|
|
|
|
|
|
|
|
910 |
/************************************
|
911 |
Embedded page selector
|
912 |
*************************************/
|
1353 |
filter: alpha(opacity=60);
|
1354 |
opacity: 0.6;
|
1355 |
-moz-opacity:0.6;
|
|
|
1356 |
}
|
1357 |
|
1358 |
#ws_role_access_overlay_content {
|
1697 |
display: none;
|
1698 |
}
|
1699 |
|
1700 |
+
//You can't deselect the current user. It always stays in the visible actor list.
|
1701 |
+
tr.ws_user_must_be_selected {
|
1702 |
.ws_user_action_button {
|
1703 |
display: none;
|
1704 |
}
|
1757 |
Tooltips and hints
|
1758 |
*************************************/
|
1759 |
|
1760 |
+
.ws_tooltip_trigger, .ws_field_tooltip_trigger {
|
1761 |
cursor: pointer;
|
1762 |
}
|
1763 |
|
1774 |
max-width: 300px;
|
1775 |
}
|
1776 |
|
1777 |
+
.ws_field_tooltip_trigger .dashicons {
|
1778 |
+
font-size: 16px;
|
1779 |
+
height: 16px;
|
1780 |
+
vertical-align: bottom;
|
1781 |
+
}
|
1782 |
+
|
1783 |
+
.ws_field_tooltip_trigger {
|
1784 |
+
color: #a1a1a1;
|
1785 |
+
}
|
1786 |
+
|
1787 |
//Tooltips on the settings page.
|
1788 |
#ws_plugin_settings_form .ws_tooltip_trigger .dashicons {
|
1789 |
font-size: 18px;
|
1836 |
margin-left: 0.5em;
|
1837 |
}
|
1838 |
|
1839 |
+
.ws_ame_doc_box {
|
1840 |
+
.hndle {
|
1841 |
+
cursor: default !important;
|
1842 |
+
}
|
1843 |
+
|
1844 |
+
ul {
|
1845 |
+
list-style: disc outside;
|
1846 |
+
margin-left: 1em;
|
1847 |
+
}
|
1848 |
+
|
1849 |
+
li > ul {
|
1850 |
+
margin-top: 6px;
|
1851 |
+
}
|
1852 |
+
|
1853 |
+
.button-link .toggle-indicator::before {
|
1854 |
+
margin-top: 4px;
|
1855 |
+
width: 20px;
|
1856 |
+
-webkit-border-radius: 50%;
|
1857 |
+
border-radius: 50%;
|
1858 |
+
text-indent: -1px;
|
1859 |
+
|
1860 |
+
content: "\f142";
|
1861 |
+
display: inline-block;
|
1862 |
+
font: normal 20px/1 dashicons;
|
1863 |
+
|
1864 |
+
-webkit-font-smoothing: antialiased;
|
1865 |
+
-moz-osx-font-smoothing: grayscale;
|
1866 |
+
text-decoration: none !important;
|
1867 |
+
}
|
1868 |
+
|
1869 |
+
&.closed .button-link .toggle-indicator::before {
|
1870 |
+
content: "\f140";
|
1871 |
+
}
|
1872 |
+
}
|
1873 |
|
1874 |
/************************************
|
1875 |
Copy Permissions dialog
|
includes/editor-page.php
CHANGED
@@ -9,13 +9,6 @@ $is_second_toolbar_visible = isset($_COOKIE['ame-show-second-toolbar']) && (intv
|
|
9 |
$is_compact_layout_enabled = isset($_COOKIE['ame-compact-layout']) && (intval($_COOKIE['ame-compact-layout']) === 1);
|
10 |
$is_multisite = is_multisite();
|
11 |
|
12 |
-
$wrap_classes = array('wrap');
|
13 |
-
if ( $is_pro_version ) {
|
14 |
-
$wrap_classes[] = 'ame-is-pro-version';
|
15 |
-
} else {
|
16 |
-
$wrap_classes[] = 'ame-is-free-version';
|
17 |
-
}
|
18 |
-
|
19 |
$icons = array(
|
20 |
'cut' => '/gnome-icon-theme/edit-cut-blue.png',
|
21 |
'copy' => '/gion/edit-copy.png',
|
@@ -68,7 +61,7 @@ if ( !empty($_GET['message']) ){
|
|
68 |
|
69 |
include dirname(__FILE__) . '/../modules/access-editor/access-editor-template.php';
|
70 |
$extrasDirectory = dirname(__FILE__) . '/../extras';
|
71 |
-
if (
|
72 |
include $extrasDirectory . '/menu-color-dialog.php';
|
73 |
include $extrasDirectory . '/copy-permissions-dialog.php';
|
74 |
}
|
@@ -342,22 +335,37 @@ function ame_output_sort_buttons($icons) {
|
|
342 |
?>
|
343 |
|
344 |
<!-- Menu icon selector widget -->
|
345 |
-
|
346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
<?php
|
348 |
//Let the user select a custom icon via the media uploader.
|
349 |
//We only support the new WP 3.5+ media API. Hence the function_exists() check.
|
350 |
if ( function_exists('wp_enqueue_media') ):
|
351 |
-
|
352 |
<input type="button" class="button"
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
<div class="clear"></div>
|
357 |
-
|
358 |
endif;
|
359 |
?>
|
360 |
|
|
|
|
|
361 |
<?php
|
362 |
//The old "menu-icon-something" icons are only available in WP 3.8.x and below. Newer versions use Dashicons.
|
363 |
//Plugins can change $wp_version to something useless for security, so lets check if Dashicons are available
|
@@ -462,16 +470,13 @@ function ame_output_sort_buttons($icons) {
|
|
462 |
<img src="<?php echo esc_attr(admin_url('images/loading.gif')); ?>">
|
463 |
</div>
|
464 |
|
|
|
|
|
465 |
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
id="ws_show_more_icons"
|
470 |
-
title="Toggle additional icons"
|
471 |
-
value="<?php echo esc_attr($editor_data['show_extra_icons'] ? 'Less ▲' : 'More ▼'); ?>">
|
472 |
-
<?php endif; ?>
|
473 |
|
474 |
-
<div class="clear"></div>
|
475 |
</div>
|
476 |
|
477 |
<span id="ws-ame-screen-meta-contents" style="display:none;">
|
@@ -482,14 +487,6 @@ function ame_output_sort_buttons($icons) {
|
|
482 |
}
|
483 |
?> /> Hide advanced options
|
484 |
</label><br>
|
485 |
-
|
486 |
-
<label for="ws-show-extra-icons">
|
487 |
-
<input type="checkbox" id="ws-show-extra-icons"<?php
|
488 |
-
if ( $this->options['show_extra_icons'] ){
|
489 |
-
echo ' checked="checked"';
|
490 |
-
}
|
491 |
-
?> /> Show extra menu icons
|
492 |
-
</label>
|
493 |
</span>
|
494 |
|
495 |
|
@@ -555,12 +552,13 @@ function ame_output_sort_buttons($icons) {
|
|
555 |
</div>
|
556 |
|
557 |
<?php
|
558 |
-
if (
|
559 |
include $extrasDirectory . '/page-dropdown.php';
|
560 |
}
|
561 |
?>
|
562 |
|
563 |
|
|
|
564 |
<script type='text/javascript'>
|
565 |
var defaultMenu = <?php echo $editor_data['default_menu_js']; ?>;
|
566 |
var customMenu = <?php echo $editor_data['custom_menu_js']; ?>;
|
9 |
$is_compact_layout_enabled = isset($_COOKIE['ame-compact-layout']) && (intval($_COOKIE['ame-compact-layout']) === 1);
|
10 |
$is_multisite = is_multisite();
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
$icons = array(
|
13 |
'cut' => '/gnome-icon-theme/edit-cut-blue.png',
|
14 |
'copy' => '/gion/edit-copy.png',
|
61 |
|
62 |
include dirname(__FILE__) . '/../modules/access-editor/access-editor-template.php';
|
63 |
$extrasDirectory = dirname(__FILE__) . '/../extras';
|
64 |
+
if ( $is_pro_version ) {
|
65 |
include $extrasDirectory . '/menu-color-dialog.php';
|
66 |
include $extrasDirectory . '/copy-permissions-dialog.php';
|
67 |
}
|
335 |
?>
|
336 |
|
337 |
<!-- Menu icon selector widget -->
|
338 |
+
<div id="ws_icon_selector" class="ws_with_more_icons" style="display: none;">
|
339 |
+
|
340 |
+
<div id="ws_icon_source_tabs">
|
341 |
+
<ul class="ws_tool_tab_nav">
|
342 |
+
<?php
|
343 |
+
$iconSelectorTabs = apply_filters(
|
344 |
+
'admin_menu_editor-icon_selector_tabs',
|
345 |
+
array('ws_core_icons_tab' => 'Dashicons')
|
346 |
+
);
|
347 |
+
foreach($iconSelectorTabs as $id => $caption) {
|
348 |
+
printf('<li><a href="#%s">%s</a></li>', esc_attr($id), $caption);
|
349 |
+
}
|
350 |
+
?>
|
351 |
+
</ul>
|
352 |
+
|
353 |
<?php
|
354 |
//Let the user select a custom icon via the media uploader.
|
355 |
//We only support the new WP 3.5+ media API. Hence the function_exists() check.
|
356 |
if ( function_exists('wp_enqueue_media') ):
|
357 |
+
?>
|
358 |
<input type="button" class="button"
|
359 |
+
id="ws_choose_icon_from_media"
|
360 |
+
title="Upload an image or choose one from your media library"
|
361 |
+
value="Media Library">
|
362 |
<div class="clear"></div>
|
363 |
+
<?php
|
364 |
endif;
|
365 |
?>
|
366 |
|
367 |
+
<div class="ws_tool_tab" id="ws_core_icons_tab">
|
368 |
+
|
369 |
<?php
|
370 |
//The old "menu-icon-something" icons are only available in WP 3.8.x and below. Newer versions use Dashicons.
|
371 |
//Plugins can change $wp_version to something useless for security, so lets check if Dashicons are available
|
470 |
<img src="<?php echo esc_attr(admin_url('images/loading.gif')); ?>">
|
471 |
</div>
|
472 |
|
473 |
+
<div class="clear"></div>
|
474 |
+
</div>
|
475 |
|
476 |
+
<?php do_action('admin_menu_editor-icon_selector'); ?>
|
477 |
+
|
478 |
+
</div><!-- tab container -->
|
|
|
|
|
|
|
|
|
479 |
|
|
|
480 |
</div>
|
481 |
|
482 |
<span id="ws-ame-screen-meta-contents" style="display:none;">
|
487 |
}
|
488 |
?> /> Hide advanced options
|
489 |
</label><br>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
490 |
</span>
|
491 |
|
492 |
|
552 |
</div>
|
553 |
|
554 |
<?php
|
555 |
+
if ( $is_pro_version ) {
|
556 |
include $extrasDirectory . '/page-dropdown.php';
|
557 |
}
|
558 |
?>
|
559 |
|
560 |
|
561 |
+
<!--suppress JSUnusedLocalSymbols These variables are actually used by menu-editor.js -->
|
562 |
<script type='text/javascript'>
|
563 |
var defaultMenu = <?php echo $editor_data['default_menu_js']; ?>;
|
564 |
var customMenu = <?php echo $editor_data['custom_menu_js']; ?>;
|
includes/menu-editor-core.php
CHANGED
@@ -20,6 +20,11 @@ require $thisDirectory . '/module.php';
|
|
20 |
|
21 |
class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
22 |
const WPML_CONTEXT = 'admin-menu-editor menu texts';
|
|
|
|
|
|
|
|
|
|
|
23 |
/**
|
24 |
* @var string The heading tag to use for admin pages.
|
25 |
*/
|
@@ -149,6 +154,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
149 |
//This usually applies to new items added by other plugins and, in Multisite, items that exist on
|
150 |
//the current site but did not exist on the site where the user last edited the menu configuration.
|
151 |
'unused_item_position' => 'relative', //"relative" or "bottom".
|
|
|
|
|
|
|
152 |
);
|
153 |
$this->serialize_with_json = false; //(Don't) store the options in JSON format
|
154 |
|
@@ -447,7 +455,20 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
447 |
if ( !$this->user_can_access_current_page() ) {
|
448 |
$this->log_security_note('DENY access.');
|
449 |
$message = 'You do not have sufficient permissions to access this admin page.';
|
450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
$message .= '<p><strong>Admin Menu Editor security log</strong></p>';
|
452 |
$message .= $this->get_formatted_security_log();
|
453 |
}
|
@@ -642,6 +663,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
642 |
|
643 |
//Lodash library
|
644 |
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
|
|
|
|
|
645 |
|
646 |
//Move admin notices (e.g. "Settings saved") below editor tabs.
|
647 |
//This is a separate script because it has to run after common.js which is loaded in the page footer.
|
@@ -715,14 +738,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
715 |
foreach($logins_to_include as $login) {
|
716 |
$user = get_user_by('login', $login);
|
717 |
if ( !empty($user) ) {
|
718 |
-
$users[$login] =
|
719 |
-
'user_login' => $user->get('user_login'),
|
720 |
-
'id' => $user->ID,
|
721 |
-
'roles' => !empty($user->roles) ? (array)($user->roles) : array(),
|
722 |
-
'capabilities' => $this->castValuesToBool($user->caps),
|
723 |
-
'display_name' => $user->display_name,
|
724 |
-
'is_super_admin' => is_multisite() && is_super_admin($user->ID),
|
725 |
-
);
|
726 |
}
|
727 |
}
|
728 |
|
@@ -763,17 +779,12 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
763 |
//Remove the default jQuery Form plugin to prevent conflicts with our custom version.
|
764 |
wp_dequeue_script('jquery-form');
|
765 |
|
766 |
-
$showExtraIcons = (boolean)$this->options['show_extra_icons'];
|
767 |
-
if ( isset($_COOKIE['ame-show-extra-icons']) && is_numeric($_COOKIE['ame-show-extra-icons']) ) {
|
768 |
-
$showExtraIcons = intval($_COOKIE['ame-show-extra-icons']) > 0;
|
769 |
-
}
|
770 |
-
|
771 |
//The editor will need access to some of the plugin data and WP data.
|
772 |
$script_data = array(
|
773 |
'imagesUrl' => plugins_url('images', $this->plugin_file),
|
774 |
'adminAjaxUrl' => admin_url('admin-ajax.php'),
|
775 |
'hideAdvancedSettings' => (boolean)$this->options['hide_advanced_settings'],
|
776 |
-
'showExtraIcons' =>
|
777 |
'submenuIconsEnabled' => $this->options['submenu_icons_enabled'],
|
778 |
|
779 |
'hideAdvancedSettingsNonce' => wp_create_nonce('ws_ame_save_screen_options'),
|
@@ -817,6 +828,24 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
817 |
wp_localize_script('menu-editor', 'wsEditorData', $script_data);
|
818 |
}
|
819 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
820 |
/**
|
821 |
* Move editor scripts closer to the top of the script queue.
|
822 |
*
|
@@ -1588,8 +1617,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1588 |
$item = ameMenuItem::apply_defaults($item);
|
1589 |
$item = ameMenuItem::apply_filters($item, $item_type, $parent_file); //may cause side-effects
|
1590 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1591 |
$item = $this->set_final_menu_capability($item, $parent);
|
1592 |
-
if ( !$this->
|
1593 |
unset($item['access_check_log']); //Throw away the log to conserve memory.
|
1594 |
}
|
1595 |
$this->add_access_lookup($item, $item_type);
|
@@ -1668,6 +1703,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1668 |
str_repeat('=', 79),
|
1669 |
'Figuring out what capability the user will need to access this item...'
|
1670 |
);
|
|
|
1671 |
|
1672 |
//The user can configure the plugin to automatically hide all submenu items if the parent menu is hidden.
|
1673 |
//This is the opposite of how WordPress usually handles submenu permissions, so it's optional.
|
@@ -1699,6 +1735,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1699 |
//Check if the current user can access this menu.
|
1700 |
$user_has_access = true;
|
1701 |
$cap_to_use = '';
|
|
|
|
|
|
|
|
|
1702 |
if ( !empty($item['access_level']) ) {
|
1703 |
$cap_to_use = $item['access_level'];
|
1704 |
|
@@ -1720,6 +1760,16 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1720 |
htmlentities($cap_to_use),
|
1721 |
$user_has_cap ? 'HAS' : 'DOES NOT have'
|
1722 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1723 |
}
|
1724 |
|
1725 |
$user_has_access = $user_has_access && $user_has_cap;
|
@@ -1729,6 +1779,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1729 |
}
|
1730 |
|
1731 |
if ( !empty($item['extra_capability']) ) {
|
|
|
|
|
1732 |
$user_has_cap = $this->current_user_can($item['extra_capability']);
|
1733 |
$user_has_access = $user_has_access && $user_has_cap;
|
1734 |
$cap_to_use = $item['extra_capability'];
|
@@ -1738,10 +1790,35 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1738 |
htmlentities($cap_to_use),
|
1739 |
$user_has_cap ? 'HAS' : 'DOES NOT have'
|
1740 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1741 |
} else {
|
1742 |
$item['access_check_log'][] = 'No "extra capability" set.';
|
1743 |
}
|
1744 |
|
|
|
|
|
|
|
|
|
1745 |
$capability = $user_has_access ? $cap_to_use : 'do_not_allow';
|
1746 |
$item['access_check_log'][] = 'Final capability setting: ' . $capability;
|
1747 |
$item['access_check_log'][] = str_repeat('=', 79);
|
@@ -1935,6 +2012,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1935 |
}
|
1936 |
}
|
1937 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1938 |
|
1939 |
$this->save_options();
|
1940 |
wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url()));
|
@@ -2008,7 +2093,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2008 |
* This includes the page heading and tab list.
|
2009 |
*/
|
2010 |
public function display_settings_page_header() {
|
2011 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012 |
printf(
|
2013 |
'<%1$s id="ws_ame_editor_heading">%2$s</%1$s>',
|
2014 |
self::$admin_heading_tag,
|
@@ -2669,7 +2761,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2669 |
return substr($string, -$len) === $suffix;
|
2670 |
}
|
2671 |
|
2672 |
-
|
2673 |
if ( !is_array($capabilities) ) {
|
2674 |
if ( empty($capabilities) ) {
|
2675 |
$capabilities = array();
|
@@ -2802,7 +2894,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2802 |
* Get one of the plugin configuration values.
|
2803 |
*
|
2804 |
* @param string $name Option name.
|
2805 |
-
* @return mixed
|
2806 |
*/
|
2807 |
public function get_plugin_option($name) {
|
2808 |
if ( array_key_exists($name, $this->options) ) {
|
@@ -2828,7 +2920,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2828 |
* @param string|array $message The message to add tot he log, or an array of messages.
|
2829 |
*/
|
2830 |
private function log_security_note($message) {
|
2831 |
-
if ( !$this->
|
2832 |
return;
|
2833 |
}
|
2834 |
if ( is_array($message) ) {
|
@@ -2838,6 +2930,13 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2838 |
}
|
2839 |
}
|
2840 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2841 |
/**
|
2842 |
* Callback for "admin_notices".
|
2843 |
*/
|
20 |
|
21 |
class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
22 |
const WPML_CONTEXT = 'admin-menu-editor menu texts';
|
23 |
+
|
24 |
+
const VERBOSITY_LOW = 1;
|
25 |
+
const VERBOSITY_NORMAL = 2;
|
26 |
+
const VERBOSITY_VERBOSE = 5;
|
27 |
+
|
28 |
/**
|
29 |
* @var string The heading tag to use for admin pages.
|
30 |
*/
|
154 |
//This usually applies to new items added by other plugins and, in Multisite, items that exist on
|
155 |
//the current site but did not exist on the site where the user last edited the menu configuration.
|
156 |
'unused_item_position' => 'relative', //"relative" or "bottom".
|
157 |
+
|
158 |
+
//Verbosity level of menu permission errors.
|
159 |
+
'error_verbosity' => self::VERBOSITY_NORMAL,
|
160 |
);
|
161 |
$this->serialize_with_json = false; //(Don't) store the options in JSON format
|
162 |
|
455 |
if ( !$this->user_can_access_current_page() ) {
|
456 |
$this->log_security_note('DENY access.');
|
457 |
$message = 'You do not have sufficient permissions to access this admin page.';
|
458 |
+
|
459 |
+
if ( ($this->options['error_verbosity'] >= self::VERBOSITY_NORMAL) ) {
|
460 |
+
$current_item = $this->get_current_menu_item();
|
461 |
+
if ( isset($current_item, $current_item['access_decision_reason']) ) {
|
462 |
+
$message .= sprintf(
|
463 |
+
'<p>Reason: %s</p>',
|
464 |
+
htmlentities($current_item['access_decision_reason'])
|
465 |
+
);
|
466 |
+
}
|
467 |
+
}
|
468 |
+
|
469 |
+
if ($this->options['security_logging_enabled']
|
470 |
+
|| ($this->options['error_verbosity'] >= self::VERBOSITY_VERBOSE)
|
471 |
+
) {
|
472 |
$message .= '<p><strong>Admin Menu Editor security log</strong></p>';
|
473 |
$message .= $this->get_formatted_security_log();
|
474 |
}
|
663 |
|
664 |
//Lodash library
|
665 |
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
|
666 |
+
//Knockout
|
667 |
+
wp_register_auto_versioned_script('knockout', plugins_url('js/knockout.js', $this->plugin_file));
|
668 |
|
669 |
//Move admin notices (e.g. "Settings saved") below editor tabs.
|
670 |
//This is a separate script because it has to run after common.js which is loaded in the page footer.
|
738 |
foreach($logins_to_include as $login) {
|
739 |
$user = get_user_by('login', $login);
|
740 |
if ( !empty($user) ) {
|
741 |
+
$users[$login] = $this->user_to_property_map($user);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
742 |
}
|
743 |
}
|
744 |
|
779 |
//Remove the default jQuery Form plugin to prevent conflicts with our custom version.
|
780 |
wp_dequeue_script('jquery-form');
|
781 |
|
|
|
|
|
|
|
|
|
|
|
782 |
//The editor will need access to some of the plugin data and WP data.
|
783 |
$script_data = array(
|
784 |
'imagesUrl' => plugins_url('images', $this->plugin_file),
|
785 |
'adminAjaxUrl' => admin_url('admin-ajax.php'),
|
786 |
'hideAdvancedSettings' => (boolean)$this->options['hide_advanced_settings'],
|
787 |
+
'showExtraIcons' => true, //No longer used.
|
788 |
'submenuIconsEnabled' => $this->options['submenu_icons_enabled'],
|
789 |
|
790 |
'hideAdvancedSettingsNonce' => wp_create_nonce('ws_ame_save_screen_options'),
|
828 |
wp_localize_script('menu-editor', 'wsEditorData', $script_data);
|
829 |
}
|
830 |
|
831 |
+
/**
|
832 |
+
* Convert a WP_User instance to an associative array with the keys defined
|
833 |
+
* in the AmeUserPropertyMap interface in actor-manager.ts.
|
834 |
+
*
|
835 |
+
* @param WP_User $user
|
836 |
+
* @return array
|
837 |
+
*/
|
838 |
+
public function user_to_property_map($user) {
|
839 |
+
return array(
|
840 |
+
'user_login' => $user->get('user_login'),
|
841 |
+
'id' => $user->ID,
|
842 |
+
'roles' => !empty($user->roles) ? (array)($user->roles) : array(),
|
843 |
+
'capabilities' => $this->castValuesToBool($user->caps),
|
844 |
+
'display_name' => $user->display_name,
|
845 |
+
'is_super_admin' => is_multisite() && is_super_admin($user->ID),
|
846 |
+
);
|
847 |
+
}
|
848 |
+
|
849 |
/**
|
850 |
* Move editor scripts closer to the top of the script queue.
|
851 |
*
|
1617 |
$item = ameMenuItem::apply_defaults($item);
|
1618 |
$item = ameMenuItem::apply_filters($item, $item_type, $parent_file); //may cause side-effects
|
1619 |
|
1620 |
+
//Store the hierarchical menu title for errors and debugging messages.
|
1621 |
+
$item['full_title'] = $item['menu_title'];
|
1622 |
+
if ( isset($parent, $parent['menu_title']) ) {
|
1623 |
+
$item['full_title'] = $parent['menu_title'] . ' → ' . $item['full_title'];
|
1624 |
+
}
|
1625 |
+
|
1626 |
$item = $this->set_final_menu_capability($item, $parent);
|
1627 |
+
if ( !$this->should_store_security_log() ) {
|
1628 |
unset($item['access_check_log']); //Throw away the log to conserve memory.
|
1629 |
}
|
1630 |
$this->add_access_lookup($item, $item_type);
|
1703 |
str_repeat('=', 79),
|
1704 |
'Figuring out what capability the user will need to access this item...'
|
1705 |
);
|
1706 |
+
$debug_title = ameMenuItem::get($item, 'full_title', ameMenuItem::get($item, 'menu_title', '[untitled menu]'));
|
1707 |
|
1708 |
//The user can configure the plugin to automatically hide all submenu items if the parent menu is hidden.
|
1709 |
//This is the opposite of how WordPress usually handles submenu permissions, so it's optional.
|
1735 |
//Check if the current user can access this menu.
|
1736 |
$user_has_access = true;
|
1737 |
$cap_to_use = '';
|
1738 |
+
|
1739 |
+
$user_has_default_cap = null;
|
1740 |
+
$reason = isset($item['access_decision_reason']) ? $item['access_decision_reason'] : null;
|
1741 |
+
|
1742 |
if ( !empty($item['access_level']) ) {
|
1743 |
$cap_to_use = $item['access_level'];
|
1744 |
|
1760 |
htmlentities($cap_to_use),
|
1761 |
$user_has_cap ? 'HAS' : 'DOES NOT have'
|
1762 |
);
|
1763 |
+
|
1764 |
+
$user_has_default_cap = $user_has_cap;
|
1765 |
+
if ( is_null($reason) ) {
|
1766 |
+
$reason = sprintf(
|
1767 |
+
'The current user %1$s the "%2$s" capability that is required to access the "%3$s" menu item.',
|
1768 |
+
$user_has_cap ? 'has' : 'doesn\'t have',
|
1769 |
+
$cap_to_use,
|
1770 |
+
$debug_title
|
1771 |
+
);
|
1772 |
+
}
|
1773 |
}
|
1774 |
|
1775 |
$user_has_access = $user_has_access && $user_has_cap;
|
1779 |
}
|
1780 |
|
1781 |
if ( !empty($item['extra_capability']) ) {
|
1782 |
+
$had_access_before_extra_cap = $user_has_access;
|
1783 |
+
|
1784 |
$user_has_cap = $this->current_user_can($item['extra_capability']);
|
1785 |
$user_has_access = $user_has_access && $user_has_cap;
|
1786 |
$cap_to_use = $item['extra_capability'];
|
1790 |
htmlentities($cap_to_use),
|
1791 |
$user_has_cap ? 'HAS' : 'DOES NOT have'
|
1792 |
);
|
1793 |
+
|
1794 |
+
//Provide a more detailed reason for situations where the extra cap disagrees.
|
1795 |
+
if ( !$user_has_access ) {
|
1796 |
+
if ( $had_access_before_extra_cap && !$user_has_cap ) {
|
1797 |
+
$reason = sprintf(
|
1798 |
+
'The current user doesn\'t have the extra capability "%1$s" that is required to access the "%2$s" menu item.',
|
1799 |
+
$item['extra_capability'],
|
1800 |
+
$debug_title
|
1801 |
+
);
|
1802 |
+
} else if ( $user_has_cap && !$user_has_default_cap && !is_null($user_has_default_cap) ) {
|
1803 |
+
//Note: Will this ever show up? If the user doesn't have the required cap,
|
1804 |
+
//WordPress won't even register the menu. AME won't be able to identify the menu for that user.
|
1805 |
+
$reason = sprintf(
|
1806 |
+
'The current user has the extra capability "%1$s". However, they don\'t ' .
|
1807 |
+
'have the "%2$s" capability that is also required to access "%3$s".',
|
1808 |
+
$item['extra_capability'],
|
1809 |
+
$item['access_level'],
|
1810 |
+
$debug_title
|
1811 |
+
);
|
1812 |
+
}
|
1813 |
+
}
|
1814 |
} else {
|
1815 |
$item['access_check_log'][] = 'No "extra capability" set.';
|
1816 |
}
|
1817 |
|
1818 |
+
if ( !is_null($reason) ) {
|
1819 |
+
$item['access_decision_reason'] = $reason;
|
1820 |
+
}
|
1821 |
+
|
1822 |
$capability = $user_has_access ? $cap_to_use : 'do_not_allow';
|
1823 |
$item['access_check_log'][] = 'Final capability setting: ' . $capability;
|
1824 |
$item['access_check_log'][] = str_repeat('=', 79);
|
2012 |
}
|
2013 |
}
|
2014 |
|
2015 |
+
//How verbose "access denied" errors should be.
|
2016 |
+
if ( !empty($this->post['error_verbosity']) ) {
|
2017 |
+
$error_verbosity = intval($this->post['error_verbosity']);
|
2018 |
+
$valid_verbosity_levels = array(self::VERBOSITY_LOW, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE);
|
2019 |
+
if ( in_array($error_verbosity, $valid_verbosity_levels) ) {
|
2020 |
+
$this->options['error_verbosity'] = $error_verbosity;
|
2021 |
+
}
|
2022 |
+
}
|
2023 |
|
2024 |
$this->save_options();
|
2025 |
wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url()));
|
2093 |
* This includes the page heading and tab list.
|
2094 |
*/
|
2095 |
public function display_settings_page_header() {
|
2096 |
+
$wrap_classes = array('wrap');
|
2097 |
+
if ( $this->is_pro_version() ) {
|
2098 |
+
$wrap_classes[] = 'ame-is-pro-version';
|
2099 |
+
} else {
|
2100 |
+
$wrap_classes[] = 'ame-is-free-version';
|
2101 |
+
}
|
2102 |
+
|
2103 |
+
echo '<div class="', implode(' ', $wrap_classes), '">';
|
2104 |
printf(
|
2105 |
'<%1$s id="ws_ame_editor_heading">%2$s</%1$s>',
|
2106 |
self::$admin_heading_tag,
|
2761 |
return substr($string, -$len) === $suffix;
|
2762 |
}
|
2763 |
|
2764 |
+
public function castValuesToBool($capabilities) {
|
2765 |
if ( !is_array($capabilities) ) {
|
2766 |
if ( empty($capabilities) ) {
|
2767 |
$capabilities = array();
|
2894 |
* Get one of the plugin configuration values.
|
2895 |
*
|
2896 |
* @param string $name Option name.
|
2897 |
+
* @return mixed|null
|
2898 |
*/
|
2899 |
public function get_plugin_option($name) {
|
2900 |
if ( array_key_exists($name, $this->options) ) {
|
2920 |
* @param string|array $message The message to add tot he log, or an array of messages.
|
2921 |
*/
|
2922 |
private function log_security_note($message) {
|
2923 |
+
if ( !$this->should_store_security_log() ) {
|
2924 |
return;
|
2925 |
}
|
2926 |
if ( is_array($message) ) {
|
2930 |
}
|
2931 |
}
|
2932 |
|
2933 |
+
private function should_store_security_log() {
|
2934 |
+
return (
|
2935 |
+
$this->options['security_logging_enabled']
|
2936 |
+
|| ($this->options['error_verbosity'] >= self::VERBOSITY_VERBOSE)
|
2937 |
+
);
|
2938 |
+
}
|
2939 |
+
|
2940 |
/**
|
2941 |
* Callback for "admin_notices".
|
2942 |
*/
|
includes/module.php
CHANGED
@@ -21,10 +21,15 @@ abstract class ameModule {
|
|
21 |
$this->moduleId = basename($this->moduleDir);
|
22 |
}
|
23 |
|
|
|
|
|
24 |
//Register the module tab.
|
25 |
if ( ($this->tabSlug !== '') && is_string($this->tabSlug) ) {
|
26 |
add_action('admin_menu_editor-tabs', array($this, 'addTab'), $this->tabOrder);
|
27 |
add_action('admin_menu_editor-section-' . $this->tabSlug, array($this, 'displaySettingsPage'));
|
|
|
|
|
|
|
28 |
}
|
29 |
}
|
30 |
|
@@ -61,10 +66,25 @@ abstract class ameModule {
|
|
61 |
protected function outputTemplate($name) {
|
62 |
$templateFile = $this->moduleDir . '/' . $name . '-template.php';
|
63 |
if ( file_exists($templateFile) ) {
|
|
|
|
|
|
|
64 |
/** @noinspection PhpIncludeInspection */
|
65 |
require $templateFile;
|
66 |
return true;
|
67 |
}
|
68 |
return false;
|
69 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
}
|
21 |
$this->moduleId = basename($this->moduleDir);
|
22 |
}
|
23 |
|
24 |
+
add_action('admin_menu_editor-register_scripts', array($this, 'registerScripts'));
|
25 |
+
|
26 |
//Register the module tab.
|
27 |
if ( ($this->tabSlug !== '') && is_string($this->tabSlug) ) {
|
28 |
add_action('admin_menu_editor-tabs', array($this, 'addTab'), $this->tabOrder);
|
29 |
add_action('admin_menu_editor-section-' . $this->tabSlug, array($this, 'displaySettingsPage'));
|
30 |
+
|
31 |
+
add_action('admin_menu_editor-enqueue_scripts-' . $this->tabSlug, array($this, 'enqueueTabScripts'));
|
32 |
+
add_action('admin_menu_editor-enqueue_styles-' . $this->tabSlug, array($this, 'enqueueTabStyles'));
|
33 |
}
|
34 |
}
|
35 |
|
66 |
protected function outputTemplate($name) {
|
67 |
$templateFile = $this->moduleDir . '/' . $name . '-template.php';
|
68 |
if ( file_exists($templateFile) ) {
|
69 |
+
/** @noinspection PhpUnusedLocalVariableInspection Used in some templates. */
|
70 |
+
$moduleTabUrl = $this->getTabUrl();
|
71 |
+
|
72 |
/** @noinspection PhpIncludeInspection */
|
73 |
require $templateFile;
|
74 |
return true;
|
75 |
}
|
76 |
return false;
|
77 |
}
|
78 |
+
|
79 |
+
public function registerScripts() {
|
80 |
+
//Override this method to register scripts.
|
81 |
+
}
|
82 |
+
|
83 |
+
public function enqueueTabScripts() {
|
84 |
+
//Override this method to add scripts to the $this->tabSlug tab.
|
85 |
+
}
|
86 |
+
|
87 |
+
public function enqueueTabStyles() {
|
88 |
+
//Override this method to add stylesheets to the $this->tabSlug tab.
|
89 |
+
}
|
90 |
}
|
includes/settings-page.php
CHANGED
@@ -250,6 +250,51 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
250 |
</td>
|
251 |
</tr>
|
252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
<tr>
|
254 |
<th scope="row">Debugging</th>
|
255 |
<td>
|
250 |
</td>
|
251 |
</tr>
|
252 |
|
253 |
+
<tr>
|
254 |
+
<th scope="row">Error verbosity level</th>
|
255 |
+
<td>
|
256 |
+
<fieldset id="ame-submenu-icons-settings">
|
257 |
+
<p>
|
258 |
+
<label>
|
259 |
+
<input type="radio" name="error_verbosity" value="<?php echo WPMenuEditor::VERBOSITY_LOW ?>>"
|
260 |
+
<?php checked(WPMenuEditor::VERBOSITY_LOW, $settings['error_verbosity']); ?>>
|
261 |
+
Low
|
262 |
+
|
263 |
+
<br><span class="description">
|
264 |
+
Shows a generic error message without any details.
|
265 |
+
</span>
|
266 |
+
</label>
|
267 |
+
</p>
|
268 |
+
|
269 |
+
<p>
|
270 |
+
<label>
|
271 |
+
<input type="radio" name="error_verbosity" value="<?php echo WPMenuEditor::VERBOSITY_NORMAL; ?>>"
|
272 |
+
<?php checked(WPMenuEditor::VERBOSITY_NORMAL, $settings['error_verbosity']); ?>>
|
273 |
+
Normal
|
274 |
+
|
275 |
+
<br><span class="description">
|
276 |
+
Shows a one or two sentence explanation. For example: "The current user doesn't have
|
277 |
+
the "manage_options" capability that is required to access the "Settings" menu item."
|
278 |
+
</span>
|
279 |
+
</label>
|
280 |
+
</p>
|
281 |
+
|
282 |
+
<p>
|
283 |
+
<label>
|
284 |
+
<input type="radio" name="error_verbosity" value="<?php echo WPMenuEditor::VERBOSITY_VERBOSE; ?>>"
|
285 |
+
<?php checked(WPMenuEditor::VERBOSITY_VERBOSE, $settings['error_verbosity']); ?>>
|
286 |
+
Verbose
|
287 |
+
|
288 |
+
<br><span class="description">
|
289 |
+
Like "normal", but also includes a log of menu settings and permissions that
|
290 |
+
caused the current menu to be hidden. Useful for debugging.
|
291 |
+
</span>
|
292 |
+
</label>
|
293 |
+
</p>
|
294 |
+
</fieldset>
|
295 |
+
</td>
|
296 |
+
</tr>
|
297 |
+
|
298 |
<tr>
|
299 |
<th scope="row">Debugging</th>
|
300 |
<td>
|
js/actor-manager.js
CHANGED
@@ -68,14 +68,17 @@ var AmeRole = (function (_super) {
|
|
68 |
}(AmeBaseActor));
|
69 |
var AmeUser = (function (_super) {
|
70 |
__extends(AmeUser, _super);
|
71 |
-
function AmeUser(userLogin, displayName, capabilities, roles, isSuperAdmin) {
|
72 |
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
73 |
_super.call(this, 'user:' + userLogin, displayName, capabilities);
|
|
|
74 |
this.isSuperAdmin = false;
|
|
|
75 |
this.actorTypeSpecificity = 10;
|
76 |
this.userLogin = userLogin;
|
77 |
this.roles = roles;
|
78 |
this.isSuperAdmin = isSuperAdmin;
|
|
|
79 |
if (this.isSuperAdmin) {
|
80 |
this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
81 |
}
|
@@ -83,6 +86,13 @@ var AmeUser = (function (_super) {
|
|
83 |
this.groupActors.push('role:' + this.roles[i]);
|
84 |
}
|
85 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
return AmeUser;
|
87 |
}(AmeBaseActor));
|
88 |
var AmeSuperAdmin = (function (_super) {
|
@@ -112,7 +122,7 @@ var AmeActorManager = (function () {
|
|
112 |
_this.roles[role.name] = role;
|
113 |
});
|
114 |
AmeActorManager._.forEach(users, function (userDetails) {
|
115 |
-
var user =
|
116 |
_this.users[user.userLogin] = user;
|
117 |
});
|
118 |
if (this.isMultisite) {
|
68 |
}(AmeBaseActor));
|
69 |
var AmeUser = (function (_super) {
|
70 |
__extends(AmeUser, _super);
|
71 |
+
function AmeUser(userLogin, displayName, capabilities, roles, isSuperAdmin, userId) {
|
72 |
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
73 |
_super.call(this, 'user:' + userLogin, displayName, capabilities);
|
74 |
+
this.userId = 0;
|
75 |
this.isSuperAdmin = false;
|
76 |
+
this.avatarHTML = '';
|
77 |
this.actorTypeSpecificity = 10;
|
78 |
this.userLogin = userLogin;
|
79 |
this.roles = roles;
|
80 |
this.isSuperAdmin = isSuperAdmin;
|
81 |
+
this.userId = userId || 0;
|
82 |
if (this.isSuperAdmin) {
|
83 |
this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
84 |
}
|
86 |
this.groupActors.push('role:' + this.roles[i]);
|
87 |
}
|
88 |
}
|
89 |
+
AmeUser.createFromProperties = function (properties) {
|
90 |
+
var user = new AmeUser(properties.user_login, properties.display_name, properties.capabilities, properties.roles, properties.is_super_admin, properties.hasOwnProperty('id') ? properties.id : null);
|
91 |
+
if (properties.avatar_html) {
|
92 |
+
user.avatarHTML = properties.avatar_html;
|
93 |
+
}
|
94 |
+
return user;
|
95 |
+
};
|
96 |
return AmeUser;
|
97 |
}(AmeBaseActor));
|
98 |
var AmeSuperAdmin = (function (_super) {
|
122 |
_this.roles[role.name] = role;
|
123 |
});
|
124 |
AmeActorManager._.forEach(users, function (userDetails) {
|
125 |
+
var user = AmeUser.createFromProperties(userDetails);
|
126 |
_this.users[user.userLogin] = user;
|
127 |
});
|
128 |
if (this.isMultisite) {
|
js/actor-manager.ts
CHANGED
@@ -81,11 +81,23 @@ class AmeRole extends AmeBaseActor {
|
|
81 |
}
|
82 |
}
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
class AmeUser extends AmeBaseActor {
|
85 |
userLogin: string;
|
|
|
86 |
roles: string[];
|
87 |
isSuperAdmin: boolean = false;
|
88 |
groupActors: string[];
|
|
|
89 |
|
90 |
protected actorTypeSpecificity = 10;
|
91 |
|
@@ -94,13 +106,15 @@ class AmeUser extends AmeBaseActor {
|
|
94 |
displayName: string,
|
95 |
capabilities: CapabilityMap,
|
96 |
roles: string[],
|
97 |
-
isSuperAdmin: boolean = false
|
|
|
98 |
) {
|
99 |
super('user:' + userLogin, displayName, capabilities);
|
100 |
|
101 |
this.userLogin = userLogin;
|
102 |
this.roles = roles;
|
103 |
this.isSuperAdmin = isSuperAdmin;
|
|
|
104 |
|
105 |
if (this.isSuperAdmin) {
|
106 |
this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
@@ -109,6 +123,23 @@ class AmeUser extends AmeBaseActor {
|
|
109 |
this.groupActors.push('role:' + this.roles[i]);
|
110 |
}
|
111 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
}
|
113 |
|
114 |
class AmeSuperAdmin extends AmeBaseActor {
|
@@ -149,14 +180,8 @@ class AmeActorManager {
|
|
149 |
this.roles[role.name] = role;
|
150 |
});
|
151 |
|
152 |
-
AmeActorManager._.forEach(users, (userDetails) => {
|
153 |
-
var user =
|
154 |
-
userDetails.user_login,
|
155 |
-
userDetails.display_name,
|
156 |
-
userDetails.capabilities,
|
157 |
-
userDetails.roles,
|
158 |
-
userDetails.is_super_admin
|
159 |
-
);
|
160 |
this.users[user.userLogin] = user;
|
161 |
});
|
162 |
|
81 |
}
|
82 |
}
|
83 |
|
84 |
+
interface AmeUserPropertyMap {
|
85 |
+
user_login: string;
|
86 |
+
display_name: string;
|
87 |
+
capabilities: CapabilityMap;
|
88 |
+
roles : string[];
|
89 |
+
is_super_admin: boolean;
|
90 |
+
id?: number;
|
91 |
+
avatar_html?: string;
|
92 |
+
}
|
93 |
+
|
94 |
class AmeUser extends AmeBaseActor {
|
95 |
userLogin: string;
|
96 |
+
userId: number = 0;
|
97 |
roles: string[];
|
98 |
isSuperAdmin: boolean = false;
|
99 |
groupActors: string[];
|
100 |
+
avatarHTML: string = '';
|
101 |
|
102 |
protected actorTypeSpecificity = 10;
|
103 |
|
106 |
displayName: string,
|
107 |
capabilities: CapabilityMap,
|
108 |
roles: string[],
|
109 |
+
isSuperAdmin: boolean = false,
|
110 |
+
userId?: number
|
111 |
) {
|
112 |
super('user:' + userLogin, displayName, capabilities);
|
113 |
|
114 |
this.userLogin = userLogin;
|
115 |
this.roles = roles;
|
116 |
this.isSuperAdmin = isSuperAdmin;
|
117 |
+
this.userId = userId || 0;
|
118 |
|
119 |
if (this.isSuperAdmin) {
|
120 |
this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
123 |
this.groupActors.push('role:' + this.roles[i]);
|
124 |
}
|
125 |
}
|
126 |
+
|
127 |
+
static createFromProperties(properties: AmeUserPropertyMap): AmeUser {
|
128 |
+
let user = new AmeUser(
|
129 |
+
properties.user_login,
|
130 |
+
properties.display_name,
|
131 |
+
properties.capabilities,
|
132 |
+
properties.roles,
|
133 |
+
properties.is_super_admin,
|
134 |
+
properties.hasOwnProperty('id') ? properties.id : null
|
135 |
+
);
|
136 |
+
|
137 |
+
if (properties.avatar_html) {
|
138 |
+
user.avatarHTML = properties.avatar_html;
|
139 |
+
}
|
140 |
+
|
141 |
+
return user;
|
142 |
+
}
|
143 |
}
|
144 |
|
145 |
class AmeSuperAdmin extends AmeBaseActor {
|
180 |
this.roles[role.name] = role;
|
181 |
});
|
182 |
|
183 |
+
AmeActorManager._.forEach(users, (userDetails: AmeUserPropertyMap) => {
|
184 |
+
var user = AmeUser.createFromProperties(userDetails);
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
this.users[user.userLogin] = user;
|
186 |
});
|
187 |
|
js/jquery.biscuit.d.ts
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
interface JQueryStatic {
|
2 |
+
//These methods are added by the jquery-cookie plugin.
|
3 |
+
cookie: (name: string, value?: string, options?: {}) => string;
|
4 |
+
removeCookie: (name: string, options?: {}) => boolean;
|
5 |
+
}
|
js/menu-editor.js
CHANGED
@@ -471,7 +471,9 @@ var baseField = {
|
|
471 |
visible: true,
|
472 |
|
473 |
write: null,
|
474 |
-
display: null
|
|
|
|
|
475 |
};
|
476 |
|
477 |
/*
|
@@ -672,19 +674,49 @@ var knownMenuFields = {
|
|
672 |
}
|
673 |
}),
|
674 |
|
675 |
-
'
|
676 |
caption: 'Required capability',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
677 |
defaultValue: 'read',
|
678 |
type: 'text',
|
679 |
addDropdown: 'ws_cap_selector',
|
|
|
|
|
|
|
|
|
|
|
|
|
680 |
|
681 |
display: function(menuItem) {
|
682 |
-
//Permissions display is a little complicated and could use improvement.
|
683 |
var requiredCap = getFieldValue(menuItem, 'access_level', '');
|
684 |
var extraCap = getFieldValue(menuItem, 'extra_capability', '');
|
685 |
|
|
|
|
|
686 |
var displayValue = extraCap;
|
687 |
-
if ((
|
688 |
displayValue = requiredCap;
|
689 |
}
|
690 |
|
@@ -700,13 +732,6 @@ var knownMenuFields = {
|
|
700 |
return;
|
701 |
}
|
702 |
|
703 |
-
//It would be redundant to set an extra_capability that it matches access_level.
|
704 |
-
var requiredCap = getFieldValue(menuItem, 'access_level', '');
|
705 |
-
var extraCap = getFieldValue(menuItem, 'extra_capability', '');
|
706 |
-
if (extraCap === '' && value === requiredCap) {
|
707 |
-
return;
|
708 |
-
}
|
709 |
-
|
710 |
menuItem.extra_capability = value;
|
711 |
}
|
712 |
}),
|
@@ -797,17 +822,24 @@ var knownMenuFields = {
|
|
797 |
var imageIcon = selectButton.find('img');
|
798 |
|
799 |
var matches = cssClass.match(/\b(ame-)?menu-icon-([^\s]+)\b/);
|
800 |
-
var
|
801 |
|
802 |
//Icon URL takes precedence over icon class.
|
803 |
-
if ( iconUrl && iconUrl !== 'none' && iconUrl !== 'div' && !
|
804 |
//Regular image icon.
|
805 |
cssIcon.hide();
|
806 |
imageIcon.prop('src', iconUrl).show();
|
807 |
-
} else if (
|
808 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
809 |
imageIcon.hide();
|
810 |
-
cssIcon.
|
811 |
} else if ( matches ) {
|
812 |
//Other CSS-based icon.
|
813 |
imageIcon.hide();
|
@@ -1001,7 +1033,11 @@ function buildEditboxField(entry, field_name, field_settings){
|
|
1001 |
|
1002 |
var caption = '';
|
1003 |
if (field_settings.standardCaption) {
|
1004 |
-
|
|
|
|
|
|
|
|
|
1005 |
}
|
1006 |
var editField = $('<div>' + caption + '</div>')
|
1007 |
.attr('class', className)
|
@@ -1216,6 +1252,9 @@ function updateItemEditor(containerNode) {
|
|
1216 |
isDefault = (getFieldValue(menuItem, 'extra_capability', '') === '')
|
1217 |
&& isEmptyObject(menuItem.grant_access)
|
1218 |
&& (!getFieldValue(menuItem, 'restrict_access_to_items', false));
|
|
|
|
|
|
|
1219 |
}
|
1220 |
|
1221 |
field.toggleClass('ws_has_no_default', !hasADefaultValue);
|
@@ -2372,6 +2411,9 @@ function ameOnDomReady() {
|
|
2372 |
var iconSelector = $('#ws_icon_selector');
|
2373 |
var currentIconButton = null; //Keep track of the last clicked icon button.
|
2374 |
|
|
|
|
|
|
|
2375 |
//When the user clicks one of the available icons, update the menu item.
|
2376 |
iconSelector.on('click', '.ws_icon_option', function() {
|
2377 |
var selectedIcon = $(this).addClass('ws_selected_icon');
|
@@ -2425,33 +2467,33 @@ function ameOnDomReady() {
|
|
2425 |
//Highlight the currently selected icon.
|
2426 |
iconSelector.find('.ws_selected_icon').removeClass('ws_selected_icon');
|
2427 |
|
2428 |
-
var
|
2429 |
var classMatches = cssClass.match(/\b(ame-)?menu-icon-([^\s]+)\b/);
|
2430 |
-
//Dashicons are set via the icon URL field, but they are actually CSS-based.
|
2431 |
-
var
|
2432 |
|
2433 |
-
if ( iconUrl && iconUrl !== 'none' && iconUrl !== 'div' && !
|
2434 |
var currentIcon = iconSelector.find('.ws_icon_option img[src="' + iconUrl + '"]').first().closest('.ws_icon_option');
|
2435 |
if ( currentIcon.length > 0 ) {
|
2436 |
-
currentIcon.addClass('ws_selected_icon').show();
|
2437 |
} else {
|
2438 |
//Display and highlight the custom image.
|
2439 |
customImageOption.find('img').prop('src', iconUrl);
|
2440 |
customImageOption.addClass('ws_selected_icon').show().data('icon-url', iconUrl);
|
|
|
2441 |
}
|
2442 |
-
} else if ( classMatches ||
|
2443 |
-
//Highlight the icon that corresponds to the current CSS class or Dashicon
|
2444 |
-
var iconClass =
|
2445 |
-
|
2446 |
-
//If the icon is one of those hidden by default, automatically expand the selector so it becomes visible.
|
2447 |
-
if (selectedIcon.hasClass('ws_icon_extra')) {
|
2448 |
-
expandSelector = true;
|
2449 |
-
}
|
2450 |
}
|
2451 |
|
2452 |
-
|
2453 |
-
|
2454 |
-
|
|
|
|
|
|
|
2455 |
|
2456 |
iconSelector.show();
|
2457 |
iconSelector.position({ //Requires jQuery UI.
|
@@ -2529,16 +2571,6 @@ function ameOnDomReady() {
|
|
2529 |
iconSelector.hide();
|
2530 |
});
|
2531 |
|
2532 |
-
//Show/hide additional icons.
|
2533 |
-
$('#ws_show_more_icons').click(function() {
|
2534 |
-
iconSelector.toggleClass('ws_with_more_icons');
|
2535 |
-
wsEditorData.showExtraIcons = iconSelector.hasClass('ws_with_more_icons');
|
2536 |
-
$(this).val(wsEditorData.showExtraIcons ? 'Less \u25B2' : 'More \u25BC');
|
2537 |
-
|
2538 |
-
//Remember the user's choice.
|
2539 |
-
$.cookie('ame-show-extra-icons', wsEditorData.showExtraIcons ? '1' : '0', {expires: 90});
|
2540 |
-
});
|
2541 |
-
|
2542 |
//Hide the icon selector if the user clicks outside of it.
|
2543 |
//Exception: Clicks on "Select icon" buttons are handled above.
|
2544 |
$(document).on('mouseup', function(event) {
|
@@ -4137,6 +4169,10 @@ function ameOnDomReady() {
|
|
4137 |
});
|
4138 |
}
|
4139 |
|
|
|
|
|
|
|
|
|
4140 |
|
4141 |
//Set up tooltips
|
4142 |
$('.ws_tooltip_trigger').qtip({
|
@@ -4149,6 +4185,49 @@ function ameOnDomReady() {
|
|
4149 |
}
|
4150 |
});
|
4151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4152 |
//Set up the "additional permissions are available" tooltips.
|
4153 |
menuEditorNode.on('mouseenter click', '.ws_ext_permissions_indicator', function() {
|
4154 |
var $indicator = $(this);
|
@@ -4264,15 +4343,11 @@ jQuery(function($){
|
|
4264 |
|
4265 |
var screenOptions = $('#ws-ame-screen-meta-contents');
|
4266 |
var hideSettingsCheckbox = screenOptions.find('#ws-hide-advanced-settings');
|
4267 |
-
var extraIconsCheckbox = screenOptions.find('#ws-show-extra-icons');
|
4268 |
-
|
4269 |
hideSettingsCheckbox.prop('checked', wsEditorData.hideAdvancedSettings);
|
4270 |
-
extraIconsCheckbox.prop('checked', wsEditorData.showExtraIcons);
|
4271 |
|
4272 |
//Update editor state when settings change
|
4273 |
-
$('#ws-hide-advanced-settings
|
4274 |
wsEditorData.hideAdvancedSettings = hideSettingsCheckbox.prop('checked');
|
4275 |
-
wsEditorData.showExtraIcons = extraIconsCheckbox.prop('checked');
|
4276 |
|
4277 |
//Show/hide advanced settings dynamically as the user changes the setting.
|
4278 |
if ($(this).is(hideSettingsCheckbox)) {
|
@@ -4295,9 +4370,6 @@ jQuery(function($){
|
|
4295 |
'_ajax_nonce' : wsEditorData.hideAdvancedSettingsNonce
|
4296 |
}
|
4297 |
);
|
4298 |
-
|
4299 |
-
//We also have a cookie for the current user.
|
4300 |
-
$.cookie('ame-show-extra-icons', wsEditorData.showExtraIcons ? '1' : '0', {expires: 90});
|
4301 |
});
|
4302 |
|
4303 |
//Move our options into the screen meta panel
|
471 |
visible: true,
|
472 |
|
473 |
write: null,
|
474 |
+
display: null,
|
475 |
+
|
476 |
+
tooltip: null
|
477 |
};
|
478 |
|
479 |
/*
|
674 |
}
|
675 |
}),
|
676 |
|
677 |
+
'required_capability_read_only' : $.extend({}, baseField, {
|
678 |
caption: 'Required capability',
|
679 |
+
defaultValue: 'none',
|
680 |
+
type: 'text',
|
681 |
+
tooltip: "Only users who have this capability can see the menu. "+
|
682 |
+
"The capability can't be changed because it's usually hard-coded in WordPress or the plugin that created the menu."+
|
683 |
+
"<br><br>Use the \"Extra capability\" field to restrict access to this menu.",
|
684 |
+
|
685 |
+
visible: function(menuItem) {
|
686 |
+
//Show only in the free version, on non-custom menus.
|
687 |
+
return !wsEditorData.wsMenuEditorPro && (menuItem.template_id !== '');
|
688 |
+
},
|
689 |
+
|
690 |
+
display: function(menuItem, displayValue, input) {
|
691 |
+
input.prop('readonly', true);
|
692 |
+
return getFieldValue(menuItem, 'access_level', '');
|
693 |
+
},
|
694 |
+
|
695 |
+
write: function(menuItem, value) {
|
696 |
+
//The required capability is read-only. Ignore writes.
|
697 |
+
}
|
698 |
+
}),
|
699 |
+
|
700 |
+
'extra_capability' : $.extend({}, baseField, {
|
701 |
+
caption: 'Extra capability',
|
702 |
defaultValue: 'read',
|
703 |
type: 'text',
|
704 |
addDropdown: 'ws_cap_selector',
|
705 |
+
tooltip: function(menuItem) {
|
706 |
+
if (menuItem.template_id === '') {
|
707 |
+
return 'Only users who have this capability can see the menu.';
|
708 |
+
}
|
709 |
+
return 'An additional capability check that is applied on top of the required capability.';
|
710 |
+
},
|
711 |
|
712 |
display: function(menuItem) {
|
|
|
713 |
var requiredCap = getFieldValue(menuItem, 'access_level', '');
|
714 |
var extraCap = getFieldValue(menuItem, 'extra_capability', '');
|
715 |
|
716 |
+
//On custom menus, show the default required cap when no extra cap is selected.
|
717 |
+
//Otherwise there would be no visible capability requirements at all.
|
718 |
var displayValue = extraCap;
|
719 |
+
if ((menuItem.template_id === '') && (extraCap === '')) {
|
720 |
displayValue = requiredCap;
|
721 |
}
|
722 |
|
732 |
return;
|
733 |
}
|
734 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
735 |
menuItem.extra_capability = value;
|
736 |
}
|
737 |
}),
|
822 |
var imageIcon = selectButton.find('img');
|
823 |
|
824 |
var matches = cssClass.match(/\b(ame-)?menu-icon-([^\s]+)\b/);
|
825 |
+
var iconFontMatches = iconUrl && iconUrl.match(/^\s*((dashicons|ame-fa)-[a-z0-9\-]+)/);
|
826 |
|
827 |
//Icon URL takes precedence over icon class.
|
828 |
+
if ( iconUrl && iconUrl !== 'none' && iconUrl !== 'div' && !iconFontMatches ) {
|
829 |
//Regular image icon.
|
830 |
cssIcon.hide();
|
831 |
imageIcon.prop('src', iconUrl).show();
|
832 |
+
} else if ( iconFontMatches ) {
|
833 |
+
cssIcon.removeClass().addClass('icon16');
|
834 |
+
if ( iconFontMatches[2] === 'dashicons' ) {
|
835 |
+
//Dashicon.
|
836 |
+
cssIcon.addClass('dashicons ' + iconFontMatches[1]);
|
837 |
+
} else if ( iconFontMatches[2] === 'ame-fa' ) {
|
838 |
+
//FontAwesome icon.
|
839 |
+
cssIcon.addClass('ame-fa ' + iconFontMatches[1]);
|
840 |
+
}
|
841 |
imageIcon.hide();
|
842 |
+
cssIcon.show();
|
843 |
} else if ( matches ) {
|
844 |
//Other CSS-based icon.
|
845 |
imageIcon.hide();
|
1033 |
|
1034 |
var caption = '';
|
1035 |
if (field_settings.standardCaption) {
|
1036 |
+
var tooltip = '';
|
1037 |
+
if (field_settings.tooltip !== null) {
|
1038 |
+
tooltip = ' <a class="ws_field_tooltip_trigger"><div class="dashicons dashicons-info"></div></a>';
|
1039 |
+
}
|
1040 |
+
caption = '<span class="ws_field_label_text">' + field_settings.caption + tooltip + '</span><br>';
|
1041 |
}
|
1042 |
var editField = $('<div>' + caption + '</div>')
|
1043 |
.attr('class', className)
|
1252 |
isDefault = (getFieldValue(menuItem, 'extra_capability', '') === '')
|
1253 |
&& isEmptyObject(menuItem.grant_access)
|
1254 |
&& (!getFieldValue(menuItem, 'restrict_access_to_items', false));
|
1255 |
+
} else if (fieldName === 'required_capability_read_only') {
|
1256 |
+
isDefault = true;
|
1257 |
+
hasADefaultValue = true;
|
1258 |
}
|
1259 |
|
1260 |
field.toggleClass('ws_has_no_default', !hasADefaultValue);
|
2411 |
var iconSelector = $('#ws_icon_selector');
|
2412 |
var currentIconButton = null; //Keep track of the last clicked icon button.
|
2413 |
|
2414 |
+
var iconSelectorTabs = iconSelector.find('#ws_icon_source_tabs');
|
2415 |
+
iconSelectorTabs.tabs();
|
2416 |
+
|
2417 |
//When the user clicks one of the available icons, update the menu item.
|
2418 |
iconSelector.on('click', '.ws_icon_option', function() {
|
2419 |
var selectedIcon = $(this).addClass('ws_selected_icon');
|
2467 |
//Highlight the currently selected icon.
|
2468 |
iconSelector.find('.ws_selected_icon').removeClass('ws_selected_icon');
|
2469 |
|
2470 |
+
var selectedIcon = null;
|
2471 |
var classMatches = cssClass.match(/\b(ame-)?menu-icon-([^\s]+)\b/);
|
2472 |
+
//Dashicons and FontAwesome icons are set via the icon URL field, but they are actually CSS-based.
|
2473 |
+
var iconFontMatches = iconUrl && iconUrl.match('^\s*((?:dashicons|ame-fa)-[a-z0-9\-]+)\s*$');
|
2474 |
|
2475 |
+
if ( iconUrl && iconUrl !== 'none' && iconUrl !== 'div' && !iconFontMatches ) {
|
2476 |
var currentIcon = iconSelector.find('.ws_icon_option img[src="' + iconUrl + '"]').first().closest('.ws_icon_option');
|
2477 |
if ( currentIcon.length > 0 ) {
|
2478 |
+
selectedIcon = currentIcon.addClass('ws_selected_icon').show();
|
2479 |
} else {
|
2480 |
//Display and highlight the custom image.
|
2481 |
customImageOption.find('img').prop('src', iconUrl);
|
2482 |
customImageOption.addClass('ws_selected_icon').show().data('icon-url', iconUrl);
|
2483 |
+
selectedIcon = customImageOption;
|
2484 |
}
|
2485 |
+
} else if ( classMatches || iconFontMatches ) {
|
2486 |
+
//Highlight the icon that corresponds to the current CSS class or Dashicon/FontAwesome icon.
|
2487 |
+
var iconClass = iconFontMatches ? iconFontMatches[1] : ((classMatches[1] ? classMatches[1] : '') + 'icon-' + classMatches[2]);
|
2488 |
+
selectedIcon = iconSelector.find('.' + iconClass).closest('.ws_icon_option').addClass('ws_selected_icon');
|
|
|
|
|
|
|
|
|
2489 |
}
|
2490 |
|
2491 |
+
//Activate the tab that contains the icon.
|
2492 |
+
var activeTabId = selectedIcon.closest('.ws_tool_tab').prop('id'),
|
2493 |
+
activeTabItem = iconSelectorTabs.find('a[href="#' + activeTabId + '"]').closest('li');
|
2494 |
+
if (activeTabItem.length > 0) {
|
2495 |
+
iconSelectorTabs.tabs('option', 'active', activeTabItem.index());
|
2496 |
+
}
|
2497 |
|
2498 |
iconSelector.show();
|
2499 |
iconSelector.position({ //Requires jQuery UI.
|
2571 |
iconSelector.hide();
|
2572 |
});
|
2573 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2574 |
//Hide the icon selector if the user clicks outside of it.
|
2575 |
//Exception: Clicks on "Select icon" buttons are handled above.
|
2576 |
$(document).on('mouseup', function(event) {
|
4169 |
});
|
4170 |
}
|
4171 |
|
4172 |
+
/******************************************************************
|
4173 |
+
Tooltips and hints
|
4174 |
+
******************************************************************/
|
4175 |
+
|
4176 |
|
4177 |
//Set up tooltips
|
4178 |
$('.ws_tooltip_trigger').qtip({
|
4185 |
}
|
4186 |
});
|
4187 |
|
4188 |
+
//Set up menu field toltips.
|
4189 |
+
menuEditorNode.on('mouseenter click', '.ws_edit_field .ws_field_tooltip_trigger', function(event) {
|
4190 |
+
var $trigger = $(this),
|
4191 |
+
fieldName = $trigger.closest('.ws_edit_field').data('field_name');
|
4192 |
+
|
4193 |
+
if (knownMenuFields[fieldName].tooltip === null) {
|
4194 |
+
return;
|
4195 |
+
}
|
4196 |
+
|
4197 |
+
var tooltipText = 'Invalid tooltip';
|
4198 |
+
if (typeof knownMenuFields[fieldName].tooltip === 'string') {
|
4199 |
+
tooltipText = knownMenuFields[fieldName].tooltip;
|
4200 |
+
} else if (typeof knownMenuFields[fieldName].tooltip === 'function') {
|
4201 |
+
tooltipText = function() {
|
4202 |
+
var $theTrigger = $(this),
|
4203 |
+
menuItem = $theTrigger.closest('.ws_container').data('menu_item');
|
4204 |
+
return knownMenuFields[fieldName].tooltip(menuItem);
|
4205 |
+
}
|
4206 |
+
}
|
4207 |
+
|
4208 |
+
$trigger.qtip({
|
4209 |
+
overwrite: false,
|
4210 |
+
content: {
|
4211 |
+
text: tooltipText
|
4212 |
+
},
|
4213 |
+
show: {
|
4214 |
+
event: event.type,
|
4215 |
+
ready: true //Show immediately.
|
4216 |
+
},
|
4217 |
+
style: {
|
4218 |
+
classes: 'qtip qtip-rounded ws_tooltip_node'
|
4219 |
+
},
|
4220 |
+
hide: {
|
4221 |
+
fixed: true,
|
4222 |
+
delay: 300
|
4223 |
+
},
|
4224 |
+
position: {
|
4225 |
+
my: 'bottom center',
|
4226 |
+
at: 'top center'
|
4227 |
+
}
|
4228 |
+
}, event);
|
4229 |
+
});
|
4230 |
+
|
4231 |
//Set up the "additional permissions are available" tooltips.
|
4232 |
menuEditorNode.on('mouseenter click', '.ws_ext_permissions_indicator', function() {
|
4233 |
var $indicator = $(this);
|
4343 |
|
4344 |
var screenOptions = $('#ws-ame-screen-meta-contents');
|
4345 |
var hideSettingsCheckbox = screenOptions.find('#ws-hide-advanced-settings');
|
|
|
|
|
4346 |
hideSettingsCheckbox.prop('checked', wsEditorData.hideAdvancedSettings);
|
|
|
4347 |
|
4348 |
//Update editor state when settings change
|
4349 |
+
$('#ws-hide-advanced-settings').click(function(){
|
4350 |
wsEditorData.hideAdvancedSettings = hideSettingsCheckbox.prop('checked');
|
|
|
4351 |
|
4352 |
//Show/hide advanced settings dynamically as the user changes the setting.
|
4353 |
if ($(this).is(hideSettingsCheckbox)) {
|
4370 |
'_ajax_nonce' : wsEditorData.hideAdvancedSettingsNonce
|
4371 |
}
|
4372 |
);
|
|
|
|
|
|
|
4373 |
});
|
4374 |
|
4375 |
//Move our options into the screen meta panel
|
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.7
|
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.7.1
|
7 |
Author: Janis Elsts
|
8 |
Author URI: http://w-shadow.com/blog/
|
9 |
*/
|
modules/plugin-visibility/plugin-visibility.php
CHANGED
@@ -308,11 +308,6 @@ class amePluginVisibility {
|
|
308 |
}
|
309 |
|
310 |
public function enqueueScripts() {
|
311 |
-
wp_register_auto_versioned_script(
|
312 |
-
'knockout',
|
313 |
-
plugins_url('js/knockout.js', $this->menuEditor->plugin_file)
|
314 |
-
);
|
315 |
-
|
316 |
wp_register_auto_versioned_script(
|
317 |
'ame-plugin-visibility',
|
318 |
plugins_url('plugin-visibility.js', __FILE__),
|
308 |
}
|
309 |
|
310 |
public function enqueueScripts() {
|
|
|
|
|
|
|
|
|
|
|
311 |
wp_register_auto_versioned_script(
|
312 |
'ame-plugin-visibility',
|
313 |
plugins_url('plugin-visibility.js', __FILE__),
|
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.6
|
7 |
-
Stable tag: 1.7
|
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,11 @@ Plugins installed in the `mu-plugins` directory are treated as "always on", so y
|
|
63 |
|
64 |
== Changelog ==
|
65 |
|
|
|
|
|
|
|
|
|
|
|
66 |
= 1.7 =
|
67 |
* Added a "Plugins" tab. It lets you hide specific plugins from other users. Note that this only affects the list on the "Plugins" page and tasks like editing plugin files, but it doesn't affect the admin menu.
|
68 |
* Tested up to WordPress 4.6-beta3.
|
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.6
|
7 |
+
Stable tag: 1.7.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.7.1 =
|
67 |
+
* Split the "required capability" field into two parts - a read-only field that shows the actual required capability, and an editable "extra capability" that you can use to restrict access to the menu.
|
68 |
+
* Added more detailed permission error messages. You can turn them off in the "Settings" tab by changing "Error verbosity level" to "Low".
|
69 |
+
* Tested up to WP 4.6.
|
70 |
+
|
71 |
= 1.7 =
|
72 |
* Added a "Plugins" tab. It lets you hide specific plugins from other users. Note that this only affects the list on the "Plugins" page and tasks like editing plugin files, but it doesn't affect the admin menu.
|
73 |
* Tested up to WordPress 4.6-beta3.
|