Version Description
- Added a couple of tutorial links to the settings page.
- Fixed a potential crash that was caused by a bug in the "WP Editor" plugin version 1.2.6.3.
- Fixed some obsolete callback syntax that was still using "&$this".
- Changed the order of some menu settings and added separators between groups of settings.
- Removed the "Screen Options" panel from AME tabs that didn't need it like "Plugins".
- Tested with WP 4.9.5.
Download this release
Release Info
Developer | whiteshadow |
Plugin | Admin Menu Editor |
Version | 1.8.3 |
Comparing to | |
See all releases |
Code changes from version 1.8.2 to 1.8.3
- css/_test-access-screen.scss +131 -0
- css/menu-editor.css +140 -4
- css/menu-editor.scss +66 -9
- includes/access-test-runner.php +268 -0
- includes/editor-page.php +67 -40
- includes/menu-editor-core.php +86 -2
- includes/module.php +16 -0
- includes/persistent-module.php +62 -0
- includes/settings-page.php +47 -0
- includes/shadow_plugin_framework.php +7 -6
- includes/test-access-screen.php +67 -0
- js/menu-editor.js +262 -47
- menu-editor.php +1 -1
- modules/tweaks/default-tweaks.php +21 -0
- modules/tweaks/tweaks-template.php +13 -0
- modules/tweaks/tweaks.php +158 -0
- readme.txt +10 -2
css/_test-access-screen.scss
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*********************************************
|
2 |
+
"Test access" dialog
|
3 |
+
**********************************************/
|
4 |
+
|
5 |
+
#ws_ame_test_access_screen {
|
6 |
+
display: none;
|
7 |
+
background: #fcfcfc;
|
8 |
+
}
|
9 |
+
|
10 |
+
#ws_ame_test_inputs {
|
11 |
+
//border-bottom: 1px solid #ddd;
|
12 |
+
padding-bottom: 16px;
|
13 |
+
}
|
14 |
+
|
15 |
+
.ws_ame_test_input {
|
16 |
+
display: block;
|
17 |
+
float: left;
|
18 |
+
|
19 |
+
width: 100%;
|
20 |
+
margin: 2px 0;
|
21 |
+
box-sizing: content-box;
|
22 |
+
}
|
23 |
+
|
24 |
+
.ws_ame_test_input_name {
|
25 |
+
display: block;
|
26 |
+
float: left;
|
27 |
+
width: 35%;
|
28 |
+
margin-right: 4%;
|
29 |
+
|
30 |
+
text-align: right;
|
31 |
+
padding-top: 6px;
|
32 |
+
line-height: 16px;
|
33 |
+
}
|
34 |
+
|
35 |
+
.ws_ame_test_input_value {
|
36 |
+
display: block;
|
37 |
+
float: right;
|
38 |
+
width: 60%;
|
39 |
+
|
40 |
+
-webkit-box-sizing: border-box;
|
41 |
+
-moz-box-sizing: border-box;
|
42 |
+
box-sizing: border-box;
|
43 |
+
}
|
44 |
+
|
45 |
+
#ws_ame_test_actions {
|
46 |
+
float: left;
|
47 |
+
width: 100%;
|
48 |
+
margin-top: 1em;
|
49 |
+
}
|
50 |
+
|
51 |
+
#ws_ame_test_button_container {
|
52 |
+
width: 35%;
|
53 |
+
margin-right: 4%;
|
54 |
+
float: left;
|
55 |
+
text-align: right;
|
56 |
+
}
|
57 |
+
|
58 |
+
#ws_ame_test_progress {
|
59 |
+
display: none;
|
60 |
+
width: 60%;
|
61 |
+
float: right;
|
62 |
+
|
63 |
+
.spinner {
|
64 |
+
float: none;
|
65 |
+
vertical-align: bottom;
|
66 |
+
margin-left: 0;
|
67 |
+
margin-right: 4px;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
#ws_ame_test_access_body {
|
72 |
+
width: 100%;
|
73 |
+
position: relative;
|
74 |
+
|
75 |
+
border: 1px solid #ddd;
|
76 |
+
-webkit-border-radius: 3px;
|
77 |
+
-moz-border-radius: 3px;
|
78 |
+
border-radius: 3px;
|
79 |
+
}
|
80 |
+
|
81 |
+
#ws_ame_test_frame_container {
|
82 |
+
margin-right: 250px;
|
83 |
+
background: white;
|
84 |
+
|
85 |
+
min-height: 500px;
|
86 |
+
position: relative;
|
87 |
+
}
|
88 |
+
|
89 |
+
#ws_ame_test_access_frame {
|
90 |
+
-webkit-box-sizing: border-box;
|
91 |
+
-moz-box-sizing: border-box;
|
92 |
+
box-sizing: border-box;
|
93 |
+
|
94 |
+
width: 100%;
|
95 |
+
height: 100%;
|
96 |
+
min-height: 500px;
|
97 |
+
|
98 |
+
border: none;
|
99 |
+
margin: 0;
|
100 |
+
padding: 0;
|
101 |
+
}
|
102 |
+
|
103 |
+
#ws_ame_test_access_sidebar {
|
104 |
+
-webkit-box-sizing: border-box;
|
105 |
+
-moz-box-sizing: border-box;
|
106 |
+
box-sizing: border-box;
|
107 |
+
|
108 |
+
position: absolute;
|
109 |
+
top: 0;
|
110 |
+
right: 0;
|
111 |
+
bottom: 0;
|
112 |
+
|
113 |
+
width: 250px;
|
114 |
+
padding: 16px 24px;
|
115 |
+
|
116 |
+
background-color: #f3f3f3;
|
117 |
+
border-left: 1px solid #ddd;
|
118 |
+
|
119 |
+
h4:first-of-type {
|
120 |
+
margin-top: 0;
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
#ws_ame_test_frame_placeholder {
|
125 |
+
display: block;
|
126 |
+
padding: 16px 24px;
|
127 |
+
}
|
128 |
+
|
129 |
+
#ws_ame_test_output {
|
130 |
+
display: none;
|
131 |
+
}
|
css/menu-editor.css
CHANGED
@@ -272,6 +272,19 @@
|
|
272 |
height: 25px;
|
273 |
min-height: 25px; }
|
274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
/* The reset-to-default button */
|
276 |
.ws_reset_button {
|
277 |
display: block;
|
@@ -805,16 +818,20 @@ a#ws-ame-delete-color-preset:hover {
|
|
805 |
/* Color scheme display in the editor widget. */
|
806 |
.ws_color_scheme_display {
|
807 |
display: inline-block;
|
808 |
-
|
809 |
-
|
|
|
810 |
margin-right: 5px;
|
811 |
-
padding: 2px
|
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;
|
820 |
width: 18px;
|
@@ -956,7 +973,8 @@ a#ws-ame-delete-color-preset:hover {
|
|
956 |
margin-right: 5px; }
|
957 |
|
958 |
.ws_launch_access_editor {
|
959 |
-
min-width: 40px;
|
|
|
960 |
|
961 |
#ws_menu_access_editor {
|
962 |
width: 400px;
|
@@ -1408,6 +1426,22 @@ a#ws-ame-delete-color-preset:hover {
|
|
1408 |
margin-top: 0;
|
1409 |
margin-bottom: 1em; }
|
1410 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1411 |
/*********************************************
|
1412 |
Miscellaneous
|
1413 |
**********************************************/
|
@@ -1441,4 +1475,106 @@ a#ws-ame-delete-color-preset:hover {
|
|
1441 |
.test-content {
|
1442 |
padding: 8px; }
|
1443 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1444 |
/*# sourceMappingURL=menu-editor.css.map */
|
272 |
height: 25px;
|
273 |
min-height: 25px; }
|
274 |
|
275 |
+
/*
|
276 |
+
* Group headings
|
277 |
+
*/
|
278 |
+
.ws_edit_field.ws_field_group_heading {
|
279 |
+
height: 1px;
|
280 |
+
min-height: 0;
|
281 |
+
padding-top: 0;
|
282 |
+
background: #ccc;
|
283 |
+
margin: 8px -4px 5px; }
|
284 |
+
.ws_edit_field.ws_field_group_heading span {
|
285 |
+
display: none;
|
286 |
+
font-weight: bold; }
|
287 |
+
|
288 |
/* The reset-to-default button */
|
289 |
.ws_reset_button {
|
290 |
display: block;
|
818 |
/* Color scheme display in the editor widget. */
|
819 |
.ws_color_scheme_display {
|
820 |
display: inline-block;
|
821 |
+
box-sizing: border-box;
|
822 |
+
height: 26px;
|
823 |
+
width: 190px;
|
824 |
margin-right: 5px;
|
825 |
+
padding: 2px 4px;
|
826 |
font-size: 12px;
|
827 |
border: 1px solid #ddd;
|
828 |
background: white;
|
829 |
cursor: pointer;
|
830 |
line-height: 20px; }
|
831 |
|
832 |
+
.ws_open_color_editor {
|
833 |
+
width: 58px; }
|
834 |
+
|
835 |
.ws_color_display_item {
|
836 |
display: inline-block;
|
837 |
width: 18px;
|
973 |
margin-right: 5px; }
|
974 |
|
975 |
.ws_launch_access_editor {
|
976 |
+
min-width: 40px;
|
977 |
+
width: 58px; }
|
978 |
|
979 |
#ws_menu_access_editor {
|
980 |
width: 400px;
|
1426 |
margin-top: 0;
|
1427 |
margin-bottom: 1em; }
|
1428 |
|
1429 |
+
.ame-available-add-ons tr:first-of-type td {
|
1430 |
+
margin-top: 0;
|
1431 |
+
padding-top: 0; }
|
1432 |
+
.ame-available-add-ons td {
|
1433 |
+
padding-top: 10px;
|
1434 |
+
padding-bottom: 10px; }
|
1435 |
+
.ame-available-add-ons .ame-add-on-heading {
|
1436 |
+
padding-left: 0; }
|
1437 |
+
|
1438 |
+
.ame-add-on-name {
|
1439 |
+
font-weight: 600; }
|
1440 |
+
|
1441 |
+
.ame-add-on-details-link::after {
|
1442 |
+
/*content: " \f504";
|
1443 |
+
font-family: dashicons, sans-serif;*/ }
|
1444 |
+
|
1445 |
/*********************************************
|
1446 |
Miscellaneous
|
1447 |
**********************************************/
|
1475 |
.test-content {
|
1476 |
padding: 8px; }
|
1477 |
|
1478 |
+
/*********************************************
|
1479 |
+
"Test access" dialog
|
1480 |
+
**********************************************/
|
1481 |
+
#ws_ame_test_access_screen {
|
1482 |
+
display: none;
|
1483 |
+
background: #fcfcfc; }
|
1484 |
+
|
1485 |
+
#ws_ame_test_inputs {
|
1486 |
+
padding-bottom: 16px; }
|
1487 |
+
|
1488 |
+
.ws_ame_test_input {
|
1489 |
+
display: block;
|
1490 |
+
float: left;
|
1491 |
+
width: 100%;
|
1492 |
+
margin: 2px 0;
|
1493 |
+
box-sizing: content-box; }
|
1494 |
+
|
1495 |
+
.ws_ame_test_input_name {
|
1496 |
+
display: block;
|
1497 |
+
float: left;
|
1498 |
+
width: 35%;
|
1499 |
+
margin-right: 4%;
|
1500 |
+
text-align: right;
|
1501 |
+
padding-top: 6px;
|
1502 |
+
line-height: 16px; }
|
1503 |
+
|
1504 |
+
.ws_ame_test_input_value {
|
1505 |
+
display: block;
|
1506 |
+
float: right;
|
1507 |
+
width: 60%;
|
1508 |
+
-webkit-box-sizing: border-box;
|
1509 |
+
-moz-box-sizing: border-box;
|
1510 |
+
box-sizing: border-box; }
|
1511 |
+
|
1512 |
+
#ws_ame_test_actions {
|
1513 |
+
float: left;
|
1514 |
+
width: 100%;
|
1515 |
+
margin-top: 1em; }
|
1516 |
+
|
1517 |
+
#ws_ame_test_button_container {
|
1518 |
+
width: 35%;
|
1519 |
+
margin-right: 4%;
|
1520 |
+
float: left;
|
1521 |
+
text-align: right; }
|
1522 |
+
|
1523 |
+
#ws_ame_test_progress {
|
1524 |
+
display: none;
|
1525 |
+
width: 60%;
|
1526 |
+
float: right; }
|
1527 |
+
#ws_ame_test_progress .spinner {
|
1528 |
+
float: none;
|
1529 |
+
vertical-align: bottom;
|
1530 |
+
margin-left: 0;
|
1531 |
+
margin-right: 4px; }
|
1532 |
+
|
1533 |
+
#ws_ame_test_access_body {
|
1534 |
+
width: 100%;
|
1535 |
+
position: relative;
|
1536 |
+
border: 1px solid #ddd;
|
1537 |
+
-webkit-border-radius: 3px;
|
1538 |
+
-moz-border-radius: 3px;
|
1539 |
+
border-radius: 3px; }
|
1540 |
+
|
1541 |
+
#ws_ame_test_frame_container {
|
1542 |
+
margin-right: 250px;
|
1543 |
+
background: white;
|
1544 |
+
min-height: 500px;
|
1545 |
+
position: relative; }
|
1546 |
+
|
1547 |
+
#ws_ame_test_access_frame {
|
1548 |
+
-webkit-box-sizing: border-box;
|
1549 |
+
-moz-box-sizing: border-box;
|
1550 |
+
box-sizing: border-box;
|
1551 |
+
width: 100%;
|
1552 |
+
height: 100%;
|
1553 |
+
min-height: 500px;
|
1554 |
+
border: none;
|
1555 |
+
margin: 0;
|
1556 |
+
padding: 0; }
|
1557 |
+
|
1558 |
+
#ws_ame_test_access_sidebar {
|
1559 |
+
-webkit-box-sizing: border-box;
|
1560 |
+
-moz-box-sizing: border-box;
|
1561 |
+
box-sizing: border-box;
|
1562 |
+
position: absolute;
|
1563 |
+
top: 0;
|
1564 |
+
right: 0;
|
1565 |
+
bottom: 0;
|
1566 |
+
width: 250px;
|
1567 |
+
padding: 16px 24px;
|
1568 |
+
background-color: #f3f3f3;
|
1569 |
+
border-left: 1px solid #ddd; }
|
1570 |
+
#ws_ame_test_access_sidebar h4:first-of-type {
|
1571 |
+
margin-top: 0; }
|
1572 |
+
|
1573 |
+
#ws_ame_test_frame_placeholder {
|
1574 |
+
display: block;
|
1575 |
+
padding: 16px 24px; }
|
1576 |
+
|
1577 |
+
#ws_ame_test_output {
|
1578 |
+
display: none; }
|
1579 |
+
|
1580 |
/*# sourceMappingURL=menu-editor.css.map */
|
css/menu-editor.scss
CHANGED
@@ -393,6 +393,24 @@ $mainContainerBorderRadius: 0px;
|
|
393 |
min-height: 25px;
|
394 |
}
|
395 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 |
/* The reset-to-default button */
|
397 |
.ws_reset_button {
|
398 |
display: block;
|
@@ -427,11 +445,12 @@ $mainContainerBorderRadius: 0px;
|
|
427 |
}
|
428 |
|
429 |
/* The input box in each field editor */
|
|
|
430 |
#ws_menu_editor .ws_editbox input[type="text"],
|
431 |
#ws_menu_editor .ws_editbox select {
|
432 |
display: block;
|
433 |
float: left;
|
434 |
-
width:
|
435 |
height: 25px;
|
436 |
|
437 |
font-size: 12px;
|
@@ -1088,22 +1107,30 @@ a#ws-ame-delete-color-preset:hover {
|
|
1088 |
|
1089 |
/* Color scheme display in the editor widget. */
|
1090 |
|
|
|
|
|
|
|
1091 |
.ws_color_scheme_display {
|
1092 |
-
$colorFieldHeight:
|
1093 |
|
1094 |
display: inline-block;
|
|
|
1095 |
height: $colorFieldHeight;
|
1096 |
-
width:
|
1097 |
|
1098 |
-
margin-right:
|
1099 |
-
padding: 2px
|
1100 |
|
1101 |
font-size: 12px;
|
1102 |
border: 1px solid #ddd;
|
1103 |
background: white;
|
1104 |
cursor: pointer;
|
1105 |
|
1106 |
-
line-height: $colorFieldHeight;
|
|
|
|
|
|
|
|
|
1107 |
}
|
1108 |
|
1109 |
.ws_color_display_item {
|
@@ -1285,14 +1312,17 @@ a#ws-ame-delete-color-preset:hover {
|
|
1285 |
*************************************/
|
1286 |
|
1287 |
/* The launch button */
|
|
|
|
|
1288 |
#ws_menu_editor .ws_edit_field-access_level input.ws_field_value
|
1289 |
{
|
1290 |
-
width:
|
1291 |
-
margin-right:
|
1292 |
}
|
1293 |
|
1294 |
.ws_launch_access_editor {
|
1295 |
min-width: 40px;
|
|
|
1296 |
}
|
1297 |
|
1298 |
#ws_menu_access_editor {
|
@@ -1991,6 +2021,31 @@ $userSelectionPanelPadding: 10px;
|
|
1991 |
margin-bottom: 1em;
|
1992 |
}
|
1993 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1994 |
/*********************************************
|
1995 |
Miscellaneous
|
1996 |
**********************************************/
|
@@ -2034,4 +2089,6 @@ $userSelectionPanelPadding: 10px;
|
|
2034 |
|
2035 |
.test-content {
|
2036 |
padding: 8px;
|
2037 |
-
}
|
|
|
|
393 |
min-height: 25px;
|
394 |
}
|
395 |
|
396 |
+
/*
|
397 |
+
* Group headings
|
398 |
+
*/
|
399 |
+
.ws_edit_field.ws_field_group_heading {
|
400 |
+
//display: none;
|
401 |
+
height: 1px;
|
402 |
+
min-height: 0;
|
403 |
+
padding-top: 0;
|
404 |
+
|
405 |
+
background: #ccc;
|
406 |
+
margin: 8px -4px 5px;
|
407 |
+
|
408 |
+
& span {
|
409 |
+
display: none;
|
410 |
+
font-weight: bold;
|
411 |
+
}
|
412 |
+
}
|
413 |
+
|
414 |
/* The reset-to-default button */
|
415 |
.ws_reset_button {
|
416 |
display: block;
|
445 |
}
|
446 |
|
447 |
/* The input box in each field editor */
|
448 |
+
$basicInputWidth: 254px;
|
449 |
#ws_menu_editor .ws_editbox input[type="text"],
|
450 |
#ws_menu_editor .ws_editbox select {
|
451 |
display: block;
|
452 |
float: left;
|
453 |
+
width: $basicInputWidth;
|
454 |
height: 25px;
|
455 |
|
456 |
font-size: 12px;
|
1107 |
|
1108 |
/* Color scheme display in the editor widget. */
|
1109 |
|
1110 |
+
$colorFieldWidth: 190px;
|
1111 |
+
$colorFieldRightMargin: 5px;
|
1112 |
+
|
1113 |
.ws_color_scheme_display {
|
1114 |
+
$colorFieldHeight: 26px;
|
1115 |
|
1116 |
display: inline-block;
|
1117 |
+
box-sizing: border-box;
|
1118 |
height: $colorFieldHeight;
|
1119 |
+
width: $colorFieldWidth;
|
1120 |
|
1121 |
+
margin-right: $colorFieldRightMargin;
|
1122 |
+
padding: 2px 4px;
|
1123 |
|
1124 |
font-size: 12px;
|
1125 |
border: 1px solid #ddd;
|
1126 |
background: white;
|
1127 |
cursor: pointer;
|
1128 |
|
1129 |
+
line-height: $colorFieldHeight - 6px;
|
1130 |
+
}
|
1131 |
+
|
1132 |
+
.ws_open_color_editor {
|
1133 |
+
width: $basicInputWidth - $colorFieldWidth - $colorFieldRightMargin - 1px;
|
1134 |
}
|
1135 |
|
1136 |
.ws_color_display_item {
|
1312 |
*************************************/
|
1313 |
|
1314 |
/* The launch button */
|
1315 |
+
$accessLevelInputWidth: 190px;
|
1316 |
+
$accessLevelRightMargin: 5px;
|
1317 |
#ws_menu_editor .ws_edit_field-access_level input.ws_field_value
|
1318 |
{
|
1319 |
+
width: $accessLevelInputWidth;
|
1320 |
+
margin-right: $accessLevelRightMargin;
|
1321 |
}
|
1322 |
|
1323 |
.ws_launch_access_editor {
|
1324 |
min-width: 40px;
|
1325 |
+
width: $basicInputWidth - $accessLevelRightMargin - $accessLevelInputWidth - 1px;
|
1326 |
}
|
1327 |
|
1328 |
#ws_menu_access_editor {
|
2021 |
margin-bottom: 1em;
|
2022 |
}
|
2023 |
|
2024 |
+
.ame-available-add-ons {
|
2025 |
+
tr:first-of-type td {
|
2026 |
+
margin-top: 0;
|
2027 |
+
padding-top: 0;
|
2028 |
+
}
|
2029 |
+
|
2030 |
+
td {
|
2031 |
+
padding-top: 10px;
|
2032 |
+
padding-bottom: 10px;
|
2033 |
+
}
|
2034 |
+
|
2035 |
+
.ame-add-on-heading {
|
2036 |
+
padding-left: 0;
|
2037 |
+
}
|
2038 |
+
}
|
2039 |
+
|
2040 |
+
.ame-add-on-name {
|
2041 |
+
font-weight: 600;
|
2042 |
+
}
|
2043 |
+
|
2044 |
+
.ame-add-on-details-link::after {
|
2045 |
+
/*content: " \f504";
|
2046 |
+
font-family: dashicons, sans-serif;*/
|
2047 |
+
}
|
2048 |
+
|
2049 |
/*********************************************
|
2050 |
Miscellaneous
|
2051 |
**********************************************/
|
2089 |
|
2090 |
.test-content {
|
2091 |
padding: 8px;
|
2092 |
+
}
|
2093 |
+
|
2094 |
+
@import "test-access-screen";
|
includes/access-test-runner.php
ADDED
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ameAccessTestRunner implements ArrayAccess {
|
4 |
+
const TEST_DATA_META_KEY = 'ws_ame_access_test_data';
|
5 |
+
|
6 |
+
/**
|
7 |
+
* @var WPMenuEditor
|
8 |
+
*/
|
9 |
+
private $menuEditor;
|
10 |
+
|
11 |
+
private $get = array();
|
12 |
+
|
13 |
+
private $test_menu = null;
|
14 |
+
private $test_target_item = null;
|
15 |
+
private $test_target_parent = null;
|
16 |
+
private $test_relevant_role = null;
|
17 |
+
|
18 |
+
private $original_wp_die_handler = null;
|
19 |
+
private $access_test_results = array();
|
20 |
+
|
21 |
+
public function __construct($menuEditor, $queryParameters) {
|
22 |
+
$this->menuEditor = $menuEditor;
|
23 |
+
$this->get = $queryParameters;
|
24 |
+
|
25 |
+
add_filter('admin_menu_editor-script_data', array($this, 'addEditorScriptData'));
|
26 |
+
|
27 |
+
add_action('wp_ajax_ws_ame_set_test_configuration', array($this, 'ajax_set_test_configuration'));
|
28 |
+
add_action('set_current_user', array($this, 'init_access_test'));
|
29 |
+
}
|
30 |
+
|
31 |
+
public function addEditorScriptData($scriptData) {
|
32 |
+
$scriptData = array_merge(
|
33 |
+
$scriptData,
|
34 |
+
array(
|
35 |
+
'setTestConfigurationNonce' => wp_create_nonce('ws_ame_set_test_configuration'),
|
36 |
+
'testAccessNonce' => wp_create_nonce('ws_ame_test_access'),
|
37 |
+
)
|
38 |
+
);
|
39 |
+
return $scriptData;
|
40 |
+
}
|
41 |
+
|
42 |
+
public function ajax_set_test_configuration() {
|
43 |
+
check_ajax_referer('ws_ame_set_test_configuration');
|
44 |
+
if ( !$this->menuEditor->current_user_can_edit_menu() ) {
|
45 |
+
exit($this->menuEditor->json_encode(array(
|
46 |
+
'error' => 'You don\'t have permission to test menu settings.',
|
47 |
+
)));
|
48 |
+
}
|
49 |
+
|
50 |
+
$post = $this->menuEditor->get_post_params();
|
51 |
+
$menuData = strval($post['data']);
|
52 |
+
|
53 |
+
$metaId = add_user_meta(get_current_user_id(), self::TEST_DATA_META_KEY, wp_slash($menuData), false);
|
54 |
+
if ( $metaId === false ) {
|
55 |
+
exit($this->menuEditor->json_encode(array(
|
56 |
+
'error' => 'Failed to store test data. add_user_meta() returned FALSE.',
|
57 |
+
)));
|
58 |
+
}
|
59 |
+
|
60 |
+
exit($this->menuEditor->json_encode(array(
|
61 |
+
'success' => true,
|
62 |
+
'meta_id' => $metaId,
|
63 |
+
)));
|
64 |
+
}
|
65 |
+
|
66 |
+
public function init_access_test() {
|
67 |
+
//We want to do this only once per page load: specifically, when WP authenticates
|
68 |
+
//the user at the start of the request.
|
69 |
+
static $is_user_already_set = false;
|
70 |
+
if ( $is_user_already_set || $this->menuEditor->is_access_test || did_action('init') ) {
|
71 |
+
return;
|
72 |
+
}
|
73 |
+
$is_user_already_set = true;
|
74 |
+
|
75 |
+
if (
|
76 |
+
!isset(
|
77 |
+
$this->get['ame-test-menu-access-as'],
|
78 |
+
$this->get['ame-test-target-item']
|
79 |
+
)
|
80 |
+
|| !check_admin_referer('ws_ame_test_access')
|
81 |
+
) {
|
82 |
+
return;
|
83 |
+
}
|
84 |
+
|
85 |
+
|
86 |
+
$configurations = get_user_meta(get_current_user_id(), self::TEST_DATA_META_KEY, false);
|
87 |
+
if ( empty($configurations) ) {
|
88 |
+
exit('Error: Test data not found.');
|
89 |
+
}
|
90 |
+
|
91 |
+
//Use the most recent config. It's usually the last one.
|
92 |
+
$json = array_pop($configurations);
|
93 |
+
//Clean up the database.
|
94 |
+
delete_user_meta(get_current_user_id(), self::TEST_DATA_META_KEY, wp_slash($json));
|
95 |
+
|
96 |
+
try {
|
97 |
+
$test_menu = ameMenu::load_json($json);
|
98 |
+
} catch (InvalidMenuException $e) {
|
99 |
+
exit($e->getMessage());
|
100 |
+
}
|
101 |
+
$this->test_menu = $test_menu;
|
102 |
+
|
103 |
+
$user = get_user_by('login', strval($this->get['ame-test-menu-access-as']));
|
104 |
+
if ( !$user ) {
|
105 |
+
exit('Error: User not found.');
|
106 |
+
}
|
107 |
+
|
108 |
+
//Everything looks good, proceed with the test.
|
109 |
+
$this->menuEditor->is_access_test = true;
|
110 |
+
|
111 |
+
$this->access_test_results = array();
|
112 |
+
$this->test_target_item = strval($this->get['ame-test-target-item']);
|
113 |
+
$this->test_target_parent = ameUtils::get($this->get, 'ame-test-target-parent', null);
|
114 |
+
$this->test_relevant_role = ameUtils::get($this->get, 'ame-test-relevant-role', null);
|
115 |
+
|
116 |
+
if ( $this->test_target_parent === '' ) {
|
117 |
+
$this->test_target_parent = null;
|
118 |
+
}
|
119 |
+
if ( $this->test_relevant_role === null ) {
|
120 |
+
$this->test_relevant_role = null;
|
121 |
+
}
|
122 |
+
|
123 |
+
wp_set_current_user($user->ID, $user->user_login);
|
124 |
+
|
125 |
+
$this->menuEditor->set_plugin_option('security_logging_enabled', true);
|
126 |
+
add_action('admin_print_scripts', array($this, 'output_access_test_results'));
|
127 |
+
add_filter('wp_die_handler', array($this, 'replace_die_handler_for_access_test'), 25, 1);
|
128 |
+
}
|
129 |
+
|
130 |
+
public function output_access_test_results() {
|
131 |
+
echo $this->get_access_test_result_script();
|
132 |
+
}
|
133 |
+
|
134 |
+
private function get_access_test_result_script() {
|
135 |
+
$response = array_merge(
|
136 |
+
$this->access_test_results,
|
137 |
+
array(
|
138 |
+
'securityLog' => $this->menuEditor->get_security_log(),
|
139 |
+
)
|
140 |
+
);
|
141 |
+
|
142 |
+
$script = '<script type="text/javascript">
|
143 |
+
window.parent.postMessage((' . $this->menuEditor->json_encode($response) . '), "*");
|
144 |
+
</script>';
|
145 |
+
return $script;
|
146 |
+
}
|
147 |
+
|
148 |
+
public function replace_die_handler_for_access_test($callback = null) {
|
149 |
+
$this->original_wp_die_handler = $callback;
|
150 |
+
return array($this, 'die_during_an_access_test');
|
151 |
+
}
|
152 |
+
|
153 |
+
public function die_during_an_access_test($message, $title = '', $args = array()) {
|
154 |
+
if ( $this->original_wp_die_handler ) {
|
155 |
+
$script = $this->get_access_test_result_script();
|
156 |
+
if ( $message instanceof WP_Error ) {
|
157 |
+
$message->add('ame-access-test-response', '[Access test]' . $script);
|
158 |
+
} else if ( is_string($message) ) {
|
159 |
+
$message .= $script;
|
160 |
+
}
|
161 |
+
|
162 |
+
call_user_func($this->original_wp_die_handler, $message, $title, $args);
|
163 |
+
} else {
|
164 |
+
exit('Unexpected error: wp_die() was called but there is no default handler.');
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
private function find_target_menu_item($items, $item_file, $parent_file = null, $current_parent = null) {
|
169 |
+
foreach ($items as $item) {
|
170 |
+
$this_file = ameMenuItem::get($item, 'file', null);
|
171 |
+
if ( ($this_file === $item_file) && ($parent_file === $current_parent) ) {
|
172 |
+
return $item;
|
173 |
+
}
|
174 |
+
|
175 |
+
if ( !empty($item['items']) ) {
|
176 |
+
$result = $this->find_target_menu_item($item['items'], $item_file, $parent_file, $this_file);
|
177 |
+
if ( $result !== null ) {
|
178 |
+
return $result;
|
179 |
+
}
|
180 |
+
}
|
181 |
+
}
|
182 |
+
return null;
|
183 |
+
}
|
184 |
+
|
185 |
+
public function setCurrentMenuItem($menuItem) {
|
186 |
+
$this->access_test_results['currentMenuItem'] = $menuItem;
|
187 |
+
|
188 |
+
$this->access_test_results['currentMenuItemIsTarget'] =
|
189 |
+
isset($this->access_test_results['currentMenuItem'])
|
190 |
+
&& (ameMenuItem::get($this->access_test_results['currentMenuItem'], 'file', null) === $this->test_target_item)
|
191 |
+
&& (ameMenuItem::get($this->access_test_results['currentMenuItem'], 'parent', null) === $this->test_target_parent);
|
192 |
+
|
193 |
+
$this->access_test_results['isIdentity'] =
|
194 |
+
($this->access_test_results['currentMenuItem'] === $this->access_test_results['targetMenuItem']);
|
195 |
+
}
|
196 |
+
|
197 |
+
public function onFinalTreeReady($tree) {
|
198 |
+
//Find the target item. It might not be the same as the current item.
|
199 |
+
$this->access_test_results['targetMenuItem'] = $this->find_target_menu_item(
|
200 |
+
$tree,
|
201 |
+
$this->test_target_item,
|
202 |
+
$this->test_target_parent
|
203 |
+
);
|
204 |
+
}
|
205 |
+
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Whether a offset exists
|
209 |
+
*
|
210 |
+
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
|
211 |
+
* @param mixed $offset <p>
|
212 |
+
* An offset to check for.
|
213 |
+
* </p>
|
214 |
+
* @return boolean true on success or false on failure.
|
215 |
+
* </p>
|
216 |
+
* <p>
|
217 |
+
* The return value will be casted to boolean if non-boolean was returned.
|
218 |
+
* @since 5.0.0
|
219 |
+
*/
|
220 |
+
public function offsetExists($offset) {
|
221 |
+
return array_key_exists($offset, $this->access_test_results);
|
222 |
+
}
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Offset to retrieve
|
226 |
+
*
|
227 |
+
* @link http://php.net/manual/en/arrayaccess.offsetget.php
|
228 |
+
* @param mixed $offset <p>
|
229 |
+
* The offset to retrieve.
|
230 |
+
* </p>
|
231 |
+
* @return mixed Can return all value types.
|
232 |
+
* @since 5.0.0
|
233 |
+
*/
|
234 |
+
public function offsetGet($offset) {
|
235 |
+
return $this->access_test_results[$offset];
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Offset to set
|
240 |
+
*
|
241 |
+
* @link http://php.net/manual/en/arrayaccess.offsetset.php
|
242 |
+
* @param mixed $offset <p>
|
243 |
+
* The offset to assign the value to.
|
244 |
+
* </p>
|
245 |
+
* @param mixed $value <p>
|
246 |
+
* The value to set.
|
247 |
+
* </p>
|
248 |
+
* @return void
|
249 |
+
* @since 5.0.0
|
250 |
+
*/
|
251 |
+
public function offsetSet($offset, $value) {
|
252 |
+
$this->access_test_results[$offset] = $value;
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Offset to unset
|
257 |
+
*
|
258 |
+
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
|
259 |
+
* @param mixed $offset <p>
|
260 |
+
* The offset to unset.
|
261 |
+
* </p>
|
262 |
+
* @return void
|
263 |
+
* @since 5.0.0
|
264 |
+
*/
|
265 |
+
public function offsetUnset($offset) {
|
266 |
+
unset($this->access_test_results[$offset]);
|
267 |
+
}
|
268 |
+
}
|
includes/editor-page.php
CHANGED
@@ -270,6 +270,10 @@ function ame_output_sort_buttons($icons) {
|
|
270 |
<input type="button" id='ws_reset_menu' value="Undo changes" class="button ws_main_button" />
|
271 |
<input type="button" id='ws_load_menu' value="Load default menu" class="button ws_main_button" />
|
272 |
|
|
|
|
|
|
|
|
|
273 |
<?php
|
274 |
$compact_layout_title = 'Compact layout';
|
275 |
if ( $is_compact_layout_enabled ) {
|
@@ -309,17 +313,23 @@ function ame_output_sort_buttons($icons) {
|
|
309 |
<?php
|
310 |
endif;
|
311 |
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
$box_class = $is_how_to_box_open ? '' : 'closed';
|
318 |
|
319 |
-
|
320 |
-
$
|
|
|
|
|
|
|
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>
|
@@ -327,43 +337,58 @@ function ame_output_sort_buttons($icons) {
|
|
327 |
<h2 class="hndle">How To</h2>
|
328 |
<div class="inside">
|
329 |
<ul class="ame-tutorial-list">
|
330 |
-
|
331 |
-
|
|
|
332 |
?>
|
333 |
-
<
|
334 |
-
|
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 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
360 |
?>
|
361 |
</ul>
|
362 |
</div>
|
363 |
</div>
|
364 |
-
<?php
|
365 |
-
endif;
|
366 |
-
?>
|
367 |
</div> <!-- / .metabox-holder -->
|
368 |
|
369 |
<?php
|
@@ -664,6 +689,8 @@ function ame_output_sort_buttons($icons) {
|
|
664 |
|
665 |
<?php include dirname(__FILE__) . '/cap-suggestion-box.php'; ?>
|
666 |
|
|
|
|
|
667 |
<?php
|
668 |
if ( $is_pro_version ) {
|
669 |
include $extrasDirectory . '/page-dropdown.php';
|
270 |
<input type="button" id='ws_reset_menu' value="Undo changes" class="button ws_main_button" />
|
271 |
<input type="button" id='ws_load_menu' value="Load default menu" class="button ws_main_button" />
|
272 |
|
273 |
+
<!--
|
274 |
+
<input type="button" id='ws_test_access' value="Test access..." class="button ws_main_button" />
|
275 |
+
-->
|
276 |
+
|
277 |
<?php
|
278 |
$compact_layout_title = 'Compact layout';
|
279 |
if ( $is_compact_layout_enabled ) {
|
313 |
<?php
|
314 |
endif;
|
315 |
|
316 |
+
$is_how_to_box_open = true;
|
317 |
+
if ( isset($_COOKIE['ame_how_to_box_open']) ) {
|
318 |
+
$is_how_to_box_open = ($_COOKIE['ame_how_to_box_open'] === '1');
|
319 |
+
}
|
320 |
+
$box_class = $is_how_to_box_open ? '' : 'closed';
|
|
|
321 |
|
322 |
+
if ( $is_pro_version ) {
|
323 |
+
$tutorial_base_url = 'https://adminmenueditor.com/documentation/';
|
324 |
+
} else {
|
325 |
+
$tutorial_base_url = 'https://adminmenueditor.com/free-version-docs/';
|
326 |
+
}
|
327 |
|
328 |
+
/** @noinspection HtmlUnknownTarget */
|
329 |
+
$how_to_link_template = '<a href="' . htmlspecialchars($tutorial_base_url) . '%1$s" target="_blank" title="Opens in a new tab">%2$s</a>';
|
330 |
+
$how_to_item_template = '<li>' . $how_to_link_template . '</li>';
|
331 |
+
|
332 |
+
?>
|
333 |
<div class="postbox ws_ame_custom_postbox <?php echo $box_class; ?>" id="ws_ame_how_to_box">
|
334 |
<button type="button" class="handlediv button-link">
|
335 |
<span class="toggle-indicator"></span>
|
337 |
<h2 class="hndle">How To</h2>
|
338 |
<div class="inside">
|
339 |
<ul class="ame-tutorial-list">
|
340 |
+
<?php
|
341 |
+
if ( $is_pro_version ):
|
342 |
+
//Pro version tutorials.
|
343 |
?>
|
344 |
+
<li><?php
|
345 |
+
printf($how_to_link_template, 'how-to-hide-a-menu-item/', 'Hide a Menu...');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
346 |
?>
|
347 |
+
<ul class="ame-tutorial-list">
|
348 |
+
<?php
|
349 |
+
foreach (
|
350 |
+
array(
|
351 |
+
'how-to-hide-a-menu-item/#how-to-hide-a-menu-from-a-role' => 'From a Role',
|
352 |
+
'how-to-hide-a-menu-item/#how-to-hide-a-menu-from-a-user' => 'From a User',
|
353 |
+
'how-to-hide-a-menu-item/#how-to-hide-a-menu-from-everyone-except-yourself' => 'From Everyone Except You',
|
354 |
+
'how-to-hide-menu-without-preventing-access/' => 'Without Preventing Access',
|
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 |
+
</li>
|
363 |
+
<?php
|
364 |
+
foreach (
|
365 |
+
array(
|
366 |
+
'how-to-give-access-to-menu/' => 'Show a Menu',
|
367 |
+
'how-to-move-and-sort-menus/' => 'Move and Sort Menus',
|
368 |
+
'how-to-add-a-new-menu-item/' => 'Add a New Menu',
|
369 |
+
)
|
370 |
+
as $how_to_url => $how_to_title
|
371 |
+
) {
|
372 |
+
printf($how_to_item_template, esc_attr($how_to_url), $how_to_title);
|
373 |
+
}
|
374 |
+
|
375 |
+
else:
|
376 |
+
//Free version tutorials.
|
377 |
+
foreach (
|
378 |
+
array(
|
379 |
+
'how-to-hide-menus/' => 'Hide a Menu Item',
|
380 |
+
'how-to-hide-menus-cosmetic/' => 'Hide Without Blocking Access',
|
381 |
+
'how-to-add-new-menu/' => 'Add a New Menu',
|
382 |
+
)
|
383 |
+
as $how_to_url => $how_to_title
|
384 |
+
) {
|
385 |
+
printf($how_to_item_template, esc_attr($how_to_url), $how_to_title);
|
386 |
+
}
|
387 |
+
endif;
|
388 |
?>
|
389 |
</ul>
|
390 |
</div>
|
391 |
</div>
|
|
|
|
|
|
|
392 |
</div> <!-- / .metabox-holder -->
|
393 |
|
394 |
<?php
|
689 |
|
690 |
<?php include dirname(__FILE__) . '/cap-suggestion-box.php'; ?>
|
691 |
|
692 |
+
<?php include dirname(__FILE__) . '/test-access-screen.php'; ?>
|
693 |
+
|
694 |
<?php
|
695 |
if ( $is_pro_version ) {
|
696 |
include $extrasDirectory . '/page-dropdown.php';
|
includes/menu-editor-core.php
CHANGED
@@ -17,6 +17,7 @@ require $thisDirectory . '/menu.php';
|
|
17 |
require $thisDirectory . '/auto-versioning.php';
|
18 |
require $thisDirectory . '/../ajax-wrapper/AjaxWrapper.php';
|
19 |
require $thisDirectory . '/module.php';
|
|
|
20 |
|
21 |
class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
22 |
const WPML_CONTEXT = 'admin-menu-editor menu texts';
|
@@ -119,6 +120,13 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
119 |
*/
|
120 |
private $caps_used_in_menu = array();
|
121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
function init(){
|
123 |
$this->sitewide_options = true;
|
124 |
|
@@ -168,6 +176,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
168 |
//the current site but did not exist on the site where the user last edited the menu configuration.
|
169 |
'unused_item_position' => 'relative', //"relative" or "bottom".
|
170 |
|
|
|
|
|
|
|
|
|
171 |
//Verbosity level of menu permission errors.
|
172 |
'error_verbosity' => self::VERBOSITY_NORMAL,
|
173 |
|
@@ -293,6 +305,12 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
293 |
//Multisite: Clear role and capability caches when switching to another site.
|
294 |
add_action('switch_blog', array($this, 'clear_site_specific_caches'), 10, 0);
|
295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
296 |
//Utility actions. Modules can use them in their templates.
|
297 |
add_action('admin_menu_editor-display_tabs', array($this, 'display_editor_tabs'));
|
298 |
add_action('admin_menu_editor-display_header', array($this, 'display_settings_page_header'));
|
@@ -455,7 +473,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
455 |
if ( is_network_admin() ) {
|
456 |
$screen_hook_name .= '-network';
|
457 |
}
|
458 |
-
|
|
|
|
|
459 |
}
|
460 |
|
461 |
//Compatibility fix for the WooCommerce order count bubble. Must be run before storing or processing $submenu.
|
@@ -508,8 +528,17 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
508 |
$this->build_custom_wp_menu($this->merged_custom_menu['tree']);
|
509 |
$this->user_cap_cache_enabled = false;
|
510 |
|
|
|
|
|
|
|
|
|
|
|
511 |
if ( !$this->user_can_access_current_page() ) {
|
512 |
$this->log_security_note('DENY access.');
|
|
|
|
|
|
|
|
|
513 |
$message = 'You do not have sufficient permissions to access this admin page.';
|
514 |
|
515 |
if ( ($this->options['error_verbosity'] >= self::VERBOSITY_NORMAL) ) {
|
@@ -532,6 +561,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
532 |
wp_die($message);
|
533 |
} else {
|
534 |
$this->log_security_note('ALLOW access.');
|
|
|
|
|
|
|
|
|
535 |
}
|
536 |
|
537 |
//Replace the admin menu just before it is displayed and restore it afterwards.
|
@@ -1032,7 +1065,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1032 |
return array(
|
1033 |
'user_login' => $user->get('user_login'),
|
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,
|
@@ -1228,6 +1261,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1228 |
*
|
1229 |
* @param null $config_id
|
1230 |
* @return array|null Either a menu in the internal format, or NULL if there is no custom menu available.
|
|
|
1231 |
*/
|
1232 |
public function load_custom_menu($config_id = null) {
|
1233 |
if ( $config_id === null ) {
|
@@ -1240,6 +1274,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1240 |
|
1241 |
$this->loaded_menu_config_id = $config_id;
|
1242 |
|
|
|
|
|
|
|
|
|
1243 |
if ( $config_id === 'network-admin' ) {
|
1244 |
if ( empty($this->options['custom_network_menu']) ) {
|
1245 |
return null;
|
@@ -1292,6 +1330,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1292 |
return ($this->options['menu_config_scope'] === 'site');
|
1293 |
}
|
1294 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1295 |
/**
|
1296 |
* Determine if the current user may use the menu editor.
|
1297 |
*
|
@@ -1549,6 +1595,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1549 |
|
1550 |
//Lets merge in the unused items.
|
1551 |
$max_menu_position = !empty($positions_by_template) ? max($positions_by_template) : 100;
|
|
|
1552 |
foreach ($this->item_templates as $template_id => $template){
|
1553 |
//Skip used menus and separators
|
1554 |
if ( !empty($template['used']) || !empty($template['defaults']['separator'])) {
|
@@ -1561,6 +1608,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1561 |
$entry['defaults'] = $template['defaults'];
|
1562 |
$entry['unused'] = true; //Note that this item is unused
|
1563 |
|
|
|
|
|
1564 |
if ($this->options['unused_item_position'] === 'relative') {
|
1565 |
|
1566 |
//Attempt to maintain relative menu order.
|
@@ -1677,6 +1726,20 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1677 |
$this->page_access_lookup[$item['url']][$priority] = $item['access_level'];
|
1678 |
}
|
1679 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1680 |
/**
|
1681 |
* Generate WP-compatible $menu and $submenu arrays from a custom menu tree.
|
1682 |
*
|
@@ -1747,6 +1810,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1747 |
$this->page_access_lookup[$url] = reset($capabilities);
|
1748 |
}
|
1749 |
|
|
|
|
|
|
|
|
|
1750 |
//Convert the prepared tree to the internal WordPress format.
|
1751 |
foreach($new_tree as $topmenu) {
|
1752 |
$trueAccess = isset($this->page_access_lookup[$topmenu['url']]) ? $this->page_access_lookup[$topmenu['url']] : null;
|
@@ -2398,6 +2465,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2398 |
}
|
2399 |
}
|
2400 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2401 |
//How verbose "access denied" errors should be.
|
2402 |
if ( !empty($this->post['error_verbosity']) ) {
|
2403 |
$error_verbosity = intval($this->post['error_verbosity']);
|
@@ -3466,6 +3541,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
3466 |
return $log;
|
3467 |
}
|
3468 |
|
|
|
|
|
|
|
|
|
3469 |
/**
|
3470 |
* WPML support: Update strings that need translation.
|
3471 |
*
|
@@ -4050,6 +4129,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
4050 |
'className' => 'ameAdminCss',
|
4051 |
'title' => 'Admin CSS',
|
4052 |
),*/
|
|
|
|
|
|
|
|
|
|
|
4053 |
'hide-admin-menu' => array(
|
4054 |
'relativePath' => 'extras/modules/hide-admin-menu/hide-admin-menu.php',
|
4055 |
'className' => 'ameAdminMenuHider',
|
17 |
require $thisDirectory . '/auto-versioning.php';
|
18 |
require $thisDirectory . '/../ajax-wrapper/AjaxWrapper.php';
|
19 |
require $thisDirectory . '/module.php';
|
20 |
+
require $thisDirectory . '/persistent-module.php';
|
21 |
|
22 |
class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
23 |
const WPML_CONTEXT = 'admin-menu-editor menu texts';
|
120 |
*/
|
121 |
private $caps_used_in_menu = array();
|
122 |
|
123 |
+
public $is_access_test = false;
|
124 |
+
private $test_menu = null;
|
125 |
+
/**
|
126 |
+
* @var ameAccessTestRunner|null
|
127 |
+
*/
|
128 |
+
private $access_test_runner = null;
|
129 |
+
|
130 |
function init(){
|
131 |
$this->sitewide_options = true;
|
132 |
|
176 |
//the current site but did not exist on the site where the user last edited the menu configuration.
|
177 |
'unused_item_position' => 'relative', //"relative" or "bottom".
|
178 |
|
179 |
+
//Permissions for menu items that are not part of the save menu configuration.
|
180 |
+
//The default is to leave the permissions unchanged.
|
181 |
+
'unused_item_permissions' => 'unchanged', //"unchanged" or "match_plugin_access".
|
182 |
+
|
183 |
//Verbosity level of menu permission errors.
|
184 |
'error_verbosity' => self::VERBOSITY_NORMAL,
|
185 |
|
305 |
//Multisite: Clear role and capability caches when switching to another site.
|
306 |
add_action('switch_blog', array($this, 'clear_site_specific_caches'), 10, 0);
|
307 |
|
308 |
+
//"Test Access" feature.
|
309 |
+
if ( (defined('DOING_AJAX') && DOING_AJAX) || isset($this->get['ame-test-menu-access-as']) ) {
|
310 |
+
require_once 'access-test-runner.php';
|
311 |
+
$this->access_test_runner = new ameAccessTestRunner($this, $this->get);
|
312 |
+
}
|
313 |
+
|
314 |
//Utility actions. Modules can use them in their templates.
|
315 |
add_action('admin_menu_editor-display_tabs', array($this, 'display_editor_tabs'));
|
316 |
add_action('admin_menu_editor-display_header', array($this, 'display_settings_page_header'));
|
473 |
if ( is_network_admin() ) {
|
474 |
$screen_hook_name .= '-network';
|
475 |
}
|
476 |
+
if ( $this->current_tab === 'editor' ) {
|
477 |
+
add_meta_box("ws-ame-screen-options", "[AME placeholder]", '__return_false', $screen_hook_name);
|
478 |
+
}
|
479 |
}
|
480 |
|
481 |
//Compatibility fix for the WooCommerce order count bubble. Must be run before storing or processing $submenu.
|
528 |
$this->build_custom_wp_menu($this->merged_custom_menu['tree']);
|
529 |
$this->user_cap_cache_enabled = false;
|
530 |
|
531 |
+
if ( $this->is_access_test ) {
|
532 |
+
$this->access_test_runner['wasCustomMenuApplied'] = true;
|
533 |
+
$this->access_test_runner->setCurrentMenuItem($this->get_current_menu_item());
|
534 |
+
}
|
535 |
+
|
536 |
if ( !$this->user_can_access_current_page() ) {
|
537 |
$this->log_security_note('DENY access.');
|
538 |
+
if ( $this->is_access_test ) {
|
539 |
+
$this->access_test_runner['userCanAccessCurrentPage'] = false;
|
540 |
+
}
|
541 |
+
|
542 |
$message = 'You do not have sufficient permissions to access this admin page.';
|
543 |
|
544 |
if ( ($this->options['error_verbosity'] >= self::VERBOSITY_NORMAL) ) {
|
561 |
wp_die($message);
|
562 |
} else {
|
563 |
$this->log_security_note('ALLOW access.');
|
564 |
+
if ( $this->is_access_test ) {
|
565 |
+
$this->access_test_runner['userCanAccessCurrentPage'] =
|
566 |
+
($this->access_test_runner['currentMenuItem'] !== null);
|
567 |
+
}
|
568 |
}
|
569 |
|
570 |
//Replace the admin menu just before it is displayed and restore it afterwards.
|
1065 |
return array(
|
1066 |
'user_login' => $user->get('user_login'),
|
1067 |
'id' => $user->ID,
|
1068 |
+
'roles' => !empty($user->roles) ? array_values((array)($user->roles)) : array(),
|
1069 |
'capabilities' => $this->castValuesToBool($user->caps),
|
1070 |
'meta_capabilities' => array(),
|
1071 |
'display_name' => $user->display_name,
|
1261 |
*
|
1262 |
* @param null $config_id
|
1263 |
* @return array|null Either a menu in the internal format, or NULL if there is no custom menu available.
|
1264 |
+
* @throws InvalidMenuException
|
1265 |
*/
|
1266 |
public function load_custom_menu($config_id = null) {
|
1267 |
if ( $config_id === null ) {
|
1274 |
|
1275 |
$this->loaded_menu_config_id = $config_id;
|
1276 |
|
1277 |
+
if ( $this->is_access_test ) {
|
1278 |
+
return $this->test_menu;
|
1279 |
+
}
|
1280 |
+
|
1281 |
if ( $config_id === 'network-admin' ) {
|
1282 |
if ( empty($this->options['custom_network_menu']) ) {
|
1283 |
return null;
|
1330 |
return ($this->options['menu_config_scope'] === 'site');
|
1331 |
}
|
1332 |
|
1333 |
+
function save_options() {
|
1334 |
+
if ( $this->is_access_test ) {
|
1335 |
+
//Don't change live settings during an access test.
|
1336 |
+
return false;
|
1337 |
+
}
|
1338 |
+
return parent::save_options();
|
1339 |
+
}
|
1340 |
+
|
1341 |
/**
|
1342 |
* Determine if the current user may use the menu editor.
|
1343 |
*
|
1595 |
|
1596 |
//Lets merge in the unused items.
|
1597 |
$max_menu_position = !empty($positions_by_template) ? max($positions_by_template) : 100;
|
1598 |
+
$new_grant_access = $this->get_new_menu_grant_access();
|
1599 |
foreach ($this->item_templates as $template_id => $template){
|
1600 |
//Skip used menus and separators
|
1601 |
if ( !empty($template['used']) || !empty($template['defaults']['separator'])) {
|
1608 |
$entry['defaults'] = $template['defaults'];
|
1609 |
$entry['unused'] = true; //Note that this item is unused
|
1610 |
|
1611 |
+
$entry['grant_access'] = $new_grant_access;
|
1612 |
+
|
1613 |
if ($this->options['unused_item_position'] === 'relative') {
|
1614 |
|
1615 |
//Attempt to maintain relative menu order.
|
1726 |
$this->page_access_lookup[$item['url']][$priority] = $item['access_level'];
|
1727 |
}
|
1728 |
|
1729 |
+
/**
|
1730 |
+
* Get the access settings for menu items that are not part of the saved menu configuration.
|
1731 |
+
*
|
1732 |
+
* Typically, this applies to new menus that were added by recently activated plugins.
|
1733 |
+
*
|
1734 |
+
* @return array
|
1735 |
+
*/
|
1736 |
+
public function get_new_menu_grant_access() {
|
1737 |
+
if ( $this->options['unused_item_permissions'] === 'unchanged' ) {
|
1738 |
+
return array();
|
1739 |
+
}
|
1740 |
+
return apply_filters('admin_menu_editor-new_menu_grant_access', array());
|
1741 |
+
}
|
1742 |
+
|
1743 |
/**
|
1744 |
* Generate WP-compatible $menu and $submenu arrays from a custom menu tree.
|
1745 |
*
|
1810 |
$this->page_access_lookup[$url] = reset($capabilities);
|
1811 |
}
|
1812 |
|
1813 |
+
if ( $this->is_access_test ) {
|
1814 |
+
$this->access_test_runner->onFinalTreeReady($new_tree);
|
1815 |
+
}
|
1816 |
+
|
1817 |
//Convert the prepared tree to the internal WordPress format.
|
1818 |
foreach($new_tree as $topmenu) {
|
1819 |
$trueAccess = isset($this->page_access_lookup[$topmenu['url']]) ? $this->page_access_lookup[$topmenu['url']] : null;
|
2465 |
}
|
2466 |
}
|
2467 |
|
2468 |
+
//Permissions for unused menu items.
|
2469 |
+
if (
|
2470 |
+
isset($this->post['unused_item_permissions'])
|
2471 |
+
&& in_array($this->post['unused_item_permissions'], array('unchanged', 'match_plugin_access'), true)
|
2472 |
+
) {
|
2473 |
+
$this->options['unused_item_permissions'] = strval($this->post['unused_item_permissions']);
|
2474 |
+
}
|
2475 |
+
|
2476 |
//How verbose "access denied" errors should be.
|
2477 |
if ( !empty($this->post['error_verbosity']) ) {
|
2478 |
$error_verbosity = intval($this->post['error_verbosity']);
|
3541 |
return $log;
|
3542 |
}
|
3543 |
|
3544 |
+
public function get_security_log() {
|
3545 |
+
return $this->security_log;
|
3546 |
+
}
|
3547 |
+
|
3548 |
/**
|
3549 |
* WPML support: Update strings that need translation.
|
3550 |
*
|
4129 |
'className' => 'ameAdminCss',
|
4130 |
'title' => 'Admin CSS',
|
4131 |
),*/
|
4132 |
+
/*'tweaks' => array(
|
4133 |
+
'relativePath' => 'modules/tweaks/tweaks.php',
|
4134 |
+
'className' => 'ameTweakManager',
|
4135 |
+
'title' => 'Tweaks',
|
4136 |
+
),*/
|
4137 |
'hide-admin-menu' => array(
|
4138 |
'relativePath' => 'extras/modules/hide-admin-menu/hide-admin-menu.php',
|
4139 |
'className' => 'ameAdminMenuHider',
|
includes/module.php
CHANGED
@@ -131,4 +131,20 @@ abstract class ameModule {
|
|
131 |
public function handleSettingsForm($post = array()) {
|
132 |
//Override this method to process a form submitted from the module's tab.
|
133 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
131 |
public function handleSettingsForm($post = array()) {
|
132 |
//Override this method to process a form submitted from the module's tab.
|
133 |
}
|
134 |
+
|
135 |
+
protected function getScopedOption($name, $defaultValue = null) {
|
136 |
+
if ( $this->menuEditor->get_plugin_option('menu_config_scope') === 'site' ) {
|
137 |
+
return get_option($name, $defaultValue);
|
138 |
+
} else {
|
139 |
+
return get_site_option($name, $defaultValue);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
protected function setScopedOption($name, $value, $autoload = null) {
|
144 |
+
if ( $this->menuEditor->get_plugin_option('menu_config_scope') === 'site' ) {
|
145 |
+
update_option($name, $value, $autoload);
|
146 |
+
} else {
|
147 |
+
WPMenuEditor::atomic_update_site_option($name, $value);
|
148 |
+
}
|
149 |
+
}
|
150 |
}
|
includes/persistent-module.php
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class amePersistentModule extends ameModule {
|
4 |
+
/**
|
5 |
+
* @var string Database option where module settings are stored.
|
6 |
+
*/
|
7 |
+
protected $optionName = '';
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var array|null Module settings. NULL when settings haven't been loaded yet.
|
11 |
+
*/
|
12 |
+
protected $settings = null;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var array Default module settings.
|
16 |
+
*/
|
17 |
+
protected $defaultSettings = array();
|
18 |
+
|
19 |
+
public function __construct($menuEditor) {
|
20 |
+
if ( $this->optionName === '' ) {
|
21 |
+
throw new LogicException(__CLASS__ . '::$optionName is an empty string. You must set it to a valid option name.');
|
22 |
+
}
|
23 |
+
|
24 |
+
parent::__construct($menuEditor);
|
25 |
+
}
|
26 |
+
|
27 |
+
public function loadSettings() {
|
28 |
+
if ( isset($this->settings) ) {
|
29 |
+
return $this->settings;
|
30 |
+
}
|
31 |
+
|
32 |
+
$json = $this->getScopedOption($this->optionName, null);
|
33 |
+
if ( is_string($json) && !empty($json) ) {
|
34 |
+
$settings = json_decode($json, true);
|
35 |
+
} else {
|
36 |
+
$settings = array();
|
37 |
+
}
|
38 |
+
|
39 |
+
$this->settings = array_merge($this->defaultSettings, $settings);
|
40 |
+
|
41 |
+
return $this->settings;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function saveSettings() {
|
45 |
+
$settings = json_encode($this->settings);
|
46 |
+
//Save per site or site-wide based on plugin configuration.
|
47 |
+
$this->setScopedOption($this->optionName, $settings);
|
48 |
+
}
|
49 |
+
|
50 |
+
protected function getTemplateVariables($templateName) {
|
51 |
+
$variables = parent::getTemplateVariables($templateName);
|
52 |
+
if ( $templateName === $this->moduleId ) {
|
53 |
+
$variables = array_merge(
|
54 |
+
$variables,
|
55 |
+
array(
|
56 |
+
'settings' => $this->loadSettings(),
|
57 |
+
)
|
58 |
+
);
|
59 |
+
}
|
60 |
+
return $variables;
|
61 |
+
}
|
62 |
+
}
|
includes/settings-page.php
CHANGED
@@ -117,6 +117,8 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
117 |
</td>
|
118 |
</tr>
|
119 |
|
|
|
|
|
120 |
<tr>
|
121 |
<th scope="row">
|
122 |
Modules
|
@@ -261,6 +263,51 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
261 |
</fieldset>
|
262 |
</td>
|
263 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
<?php endif; ?>
|
265 |
|
266 |
<tr>
|
117 |
</td>
|
118 |
</tr>
|
119 |
|
120 |
+
<?php do_action('admin-menu-editor-display_addons'); ?>
|
121 |
+
|
122 |
<tr>
|
123 |
<th scope="row">
|
124 |
Modules
|
263 |
</fieldset>
|
264 |
</td>
|
265 |
</tr>
|
266 |
+
|
267 |
+
<tr>
|
268 |
+
<th scope="row">
|
269 |
+
New menu visibility
|
270 |
+
<a class="ws_tooltip_trigger"
|
271 |
+
title="This setting controls the default permissions of menu items that are
|
272 |
+
not present in the last saved menu configuration.
|
273 |
+
<br><br>
|
274 |
+
This includes new menus added by plugins and themes.
|
275 |
+
In Multisite, it also applies to menus that exist on some sites but not others.
|
276 |
+
It doesn't affect menu items that you add through the Admin Menu Editor interface.">
|
277 |
+
<div class="dashicons dashicons-info"></div>
|
278 |
+
</a>
|
279 |
+
</th>
|
280 |
+
<td>
|
281 |
+
<fieldset>
|
282 |
+
<p>
|
283 |
+
<label>
|
284 |
+
<input type="radio" name="unused_item_permissions" value="unchanged"
|
285 |
+
<?php checked('unchanged', $settings['unused_item_permissions']); ?>>
|
286 |
+
Leave unchanged (default)
|
287 |
+
|
288 |
+
<br><span class="description">
|
289 |
+
No special restrictions. Visibility will depend on the plugin
|
290 |
+
that added the menus.
|
291 |
+
</span>
|
292 |
+
</label>
|
293 |
+
</p>
|
294 |
+
|
295 |
+
<p>
|
296 |
+
<label>
|
297 |
+
<input type="radio" name="unused_item_permissions" value="match_plugin_access"
|
298 |
+
<?php checked('match_plugin_access', $settings['unused_item_permissions']); ?>>
|
299 |
+
Show only to users who can access this plugin
|
300 |
+
|
301 |
+
<br><span class="description">
|
302 |
+
Automatically hides all new and unrecognized menus from regular users.
|
303 |
+
To make new menus visible, you have to manually enable them in the menu editor.
|
304 |
+
</span>
|
305 |
+
</label>
|
306 |
+
</p>
|
307 |
+
|
308 |
+
</fieldset>
|
309 |
+
</td>
|
310 |
+
</tr>
|
311 |
<?php endif; ?>
|
312 |
|
313 |
<tr>
|
includes/shadow_plugin_framework.php
CHANGED
@@ -58,8 +58,8 @@ class MenuEd_ShadowPluginFramework {
|
|
58 |
/************************************
|
59 |
Add the default hooks
|
60 |
************************************/
|
61 |
-
add_action('activate_'.$this->plugin_basename, array(
|
62 |
-
add_action('deactivate_'.$this->plugin_basename, array(
|
63 |
|
64 |
$this->init(); //Call the plugin's init() function
|
65 |
$this->init_finish(); //Complete initialization by loading settings, etc
|
@@ -97,7 +97,7 @@ class MenuEd_ShadowPluginFramework {
|
|
97 |
|
98 |
//Add a "Settings" action link
|
99 |
if ($this->settings_link)
|
100 |
-
add_filter('plugin_action_links', array(
|
101 |
|
102 |
if ($this->magic_hooks)
|
103 |
$this->set_magic_hooks();
|
@@ -240,7 +240,7 @@ class MenuEd_ShadowPluginFramework {
|
|
240 |
//Get the hook's tag from the method name
|
241 |
$hook = substr($method->name, 5);
|
242 |
//Add the hook. Uses add_filter because add_action is simply a wrapper of the same.
|
243 |
-
add_filter($hook, array(
|
244 |
$this->get_magic_hook_priority(), $method->getNumberOfParameters());
|
245 |
}
|
246 |
}
|
@@ -282,8 +282,9 @@ class MenuEd_ShadowPluginFramework {
|
|
282 |
* @return array
|
283 |
*/
|
284 |
function plugin_action_links($links, $file) {
|
285 |
-
if ($file == $this->plugin_basename)
|
286 |
-
|
|
|
287 |
return $links;
|
288 |
}
|
289 |
|
58 |
/************************************
|
59 |
Add the default hooks
|
60 |
************************************/
|
61 |
+
add_action('activate_'.$this->plugin_basename, array($this,'activate'));
|
62 |
+
add_action('deactivate_'.$this->plugin_basename, array($this,'deactivate'));
|
63 |
|
64 |
$this->init(); //Call the plugin's init() function
|
65 |
$this->init_finish(); //Complete initialization by loading settings, etc
|
97 |
|
98 |
//Add a "Settings" action link
|
99 |
if ($this->settings_link)
|
100 |
+
add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
|
101 |
|
102 |
if ($this->magic_hooks)
|
103 |
$this->set_magic_hooks();
|
240 |
//Get the hook's tag from the method name
|
241 |
$hook = substr($method->name, 5);
|
242 |
//Add the hook. Uses add_filter because add_action is simply a wrapper of the same.
|
243 |
+
add_filter($hook, array($this, $method->name),
|
244 |
$this->get_magic_hook_priority(), $method->getNumberOfParameters());
|
245 |
}
|
246 |
}
|
282 |
* @return array
|
283 |
*/
|
284 |
function plugin_action_links($links, $file) {
|
285 |
+
if (($file == $this->plugin_basename) && is_array($links)) {
|
286 |
+
$links[] = "<a href='" . $this->settings_link . "'>" . __('Settings') . "</a>";
|
287 |
+
}
|
288 |
return $links;
|
289 |
}
|
290 |
|
includes/test-access-screen.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="ws_ame_test_access_screen">
|
2 |
+
<div id="ws_ame_test_inputs">
|
3 |
+
<label class="ws_ame_test_input">
|
4 |
+
<span class="ws_ame_test_input_name">Menu item</span>
|
5 |
+
<select name="ws_ame_test_menu_item" id="ws_ame_test_menu_item" class="ws_ame_test_input_value"></select>
|
6 |
+
</label>
|
7 |
+
|
8 |
+
<label class="ws_ame_test_input">
|
9 |
+
<span class="ws_ame_test_input_name">Log in as user</span>
|
10 |
+
<input type="text" class="ws_ame_test_input_value" id="ws_ame_test_access_username">
|
11 |
+
</label>
|
12 |
+
|
13 |
+
<label class="ws_ame_test_input">
|
14 |
+
<span class="ws_ame_test_input_name">Relevant role (optional)</span>
|
15 |
+
<select name="ws_ame_test_relevant_actor" id="ws_ame_test_relevant_actor" class="ws_ame_test_input_value"></select>
|
16 |
+
</label>
|
17 |
+
|
18 |
+
<div class="ws_ame_test_input">
|
19 |
+
<span class="ws_ame_test_input_name">What you want to happen</span>
|
20 |
+
<fieldset class="ws_ame_test_input_value">
|
21 |
+
<label>
|
22 |
+
<input type="radio" name="ws_ame_desired_test_outcome" value="visible" checked>
|
23 |
+
Menu is <strong>visible</strong>
|
24 |
+
</label><br>
|
25 |
+
<label>
|
26 |
+
<input type="radio" name="ws_ame_desired_test_outcome" value="hidden">
|
27 |
+
Menu is <strong>hidden</strong>
|
28 |
+
</label><br>
|
29 |
+
</fieldset>
|
30 |
+
</div>
|
31 |
+
|
32 |
+
<div id="ws_ame_test_actions">
|
33 |
+
<div id="ws_ame_test_button_container">
|
34 |
+
<input type="button" class="button-primary" value="Start Test" id="ws_ame_start_access_test">
|
35 |
+
</div>
|
36 |
+
<div id="ws_ame_test_progress">
|
37 |
+
<span class="spinner is-active"></span>
|
38 |
+
<span id="ws_ame_test_progress_text">
|
39 |
+
Test hasn't started yet.
|
40 |
+
</span>
|
41 |
+
</div>
|
42 |
+
</div>
|
43 |
+
|
44 |
+
<div class="clear"></div>
|
45 |
+
</div>
|
46 |
+
|
47 |
+
<div id="ws_ame_test_access_body">
|
48 |
+
<div id="ws_ame_test_frame_container">
|
49 |
+
<span id="ws_ame_test_frame_placeholder">
|
50 |
+
<em>Test page will appear here.</em><br>
|
51 |
+
</span>
|
52 |
+
<iframe src="" frameborder="0" sandbox="allow-scripts" id="ws_ame_test_access_frame"></iframe>
|
53 |
+
</div>
|
54 |
+
|
55 |
+
<div id="ws_ame_test_access_sidebar">
|
56 |
+
<span id="ws_ame_test_output_placeholder">
|
57 |
+
<em>Analysis will appear here.</em>
|
58 |
+
</span>
|
59 |
+
<div id="ws_ame_test_output">
|
60 |
+
<h4>Result</h4>
|
61 |
+
|
62 |
+
<h4>Analysis</h4>
|
63 |
+
<h4>Suggestions</h4>
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
</div>
|
67 |
+
</div>
|
js/menu-editor.js
CHANGED
@@ -46,6 +46,9 @@
|
|
46 |
* @property {string|null} wsEditorData.selectedMenu
|
47 |
* @property {string|null} wsEditorData.selectedSubmenu
|
48 |
*
|
|
|
|
|
|
|
49 |
* @property {boolean} wsEditorData.isDemoMode
|
50 |
* @property {boolean} wsEditorData.isMasterMode
|
51 |
*/
|
@@ -774,6 +777,15 @@ var knownMenuFields = {
|
|
774 |
}
|
775 |
}),
|
776 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
777 |
'icon_url' : $.extend({}, baseField, {
|
778 |
caption: 'Icon URL',
|
779 |
type : 'icon_selector',
|
@@ -834,10 +846,50 @@ var knownMenuFields = {
|
|
834 |
}
|
835 |
}),
|
836 |
|
837 |
-
'
|
838 |
-
caption: '
|
|
|
|
|
|
|
|
|
839 |
advanced : true,
|
840 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
841 |
}),
|
842 |
|
843 |
'open_in' : $.extend({}, baseField, {
|
@@ -888,48 +940,24 @@ var knownMenuFields = {
|
|
888 |
}
|
889 |
}),
|
890 |
|
891 |
-
'
|
892 |
-
caption: '
|
893 |
-
defaultValue: 'Default',
|
894 |
-
type: 'color_scheme_editor',
|
895 |
-
onlyForTopMenus: true,
|
896 |
-
visible: false,
|
897 |
advanced : true,
|
|
|
|
|
898 |
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
colorList.empty();
|
904 |
-
var count = 0, maxColorsToShow = 7;
|
905 |
-
|
906 |
-
$.each(colors, function(name, value) {
|
907 |
-
if ( !value || (count >= maxColorsToShow) ) {
|
908 |
-
return;
|
909 |
-
}
|
910 |
-
|
911 |
-
colorList.append(
|
912 |
-
$('<span></span>').addClass('ws_color_display_item').css('background-color', value)
|
913 |
-
);
|
914 |
-
count++;
|
915 |
-
});
|
916 |
-
|
917 |
-
if (count === 0) {
|
918 |
-
colorList.append('Default');
|
919 |
-
}
|
920 |
-
|
921 |
-
return 'Placeholder. You should never see this.';
|
922 |
-
},
|
923 |
-
|
924 |
-
write: function(menuItem) {
|
925 |
-
//Menu colors can't be directly edited.
|
926 |
-
}
|
927 |
}),
|
928 |
|
929 |
-
'
|
930 |
-
caption:
|
931 |
-
|
932 |
-
|
|
|
|
|
933 |
}),
|
934 |
|
935 |
'page_heading' : $.extend({}, baseField, {
|
@@ -939,14 +967,14 @@ var knownMenuFields = {
|
|
939 |
visible: false
|
940 |
}),
|
941 |
|
942 |
-
'
|
943 |
-
caption:
|
944 |
-
|
945 |
-
|
946 |
}),
|
947 |
|
948 |
'is_always_open' : $.extend({}, baseField, {
|
949 |
-
caption: 'Keep this menu
|
950 |
advanced : true,
|
951 |
onlyForTopMenus: true,
|
952 |
type: 'checkbox',
|
@@ -1054,6 +1082,10 @@ function buildEditboxField(entry, field_name, field_settings){
|
|
1054 |
.add('<input type="button" class="button ws_open_color_editor" value="Edit...">');
|
1055 |
break;
|
1056 |
|
|
|
|
|
|
|
|
|
1057 |
case 'text':
|
1058 |
/* falls through */
|
1059 |
default:
|
@@ -1068,6 +1100,9 @@ function buildEditboxField(entry, field_name, field_settings){
|
|
1068 |
if (!field_settings.standardCaption) {
|
1069 |
className += ' ws_no_field_caption';
|
1070 |
}
|
|
|
|
|
|
|
1071 |
|
1072 |
var caption = '';
|
1073 |
if (field_settings.standardCaption) {
|
@@ -1094,7 +1129,7 @@ function buildEditboxField(entry, field_name, field_settings){
|
|
1094 |
|
1095 |
editField
|
1096 |
.append(
|
1097 |
-
$('<img class="ws_reset_button" title="Reset to default value">')
|
1098 |
.attr('src', wsEditorData.imagesUrl + '/transparent16.png')
|
1099 |
).data('field_name', field_name);
|
1100 |
|
@@ -1725,6 +1760,10 @@ function readAllFields(container){
|
|
1725 |
if (field_name === 'embedded_page_id') {
|
1726 |
return true;
|
1727 |
}
|
|
|
|
|
|
|
|
|
1728 |
|
1729 |
//Find the field (usually an input or select element).
|
1730 |
var input_box = field.find('.ws_field_value');
|
@@ -1997,6 +2036,8 @@ function ameOnDomReady() {
|
|
1997 |
knownMenuFields.access_level.visible = true;
|
1998 |
knownMenuFields.page_heading.visible = true;
|
1999 |
knownMenuFields.colors.visible = true;
|
|
|
|
|
2000 |
knownMenuFields.extra_capability.visible = false; //Superseded by the "access_level" field.
|
2001 |
|
2002 |
//The Pro version supports submenu icons, but they can be disabled by the user.
|
@@ -4787,6 +4828,180 @@ function ameOnDomReady() {
|
|
4787 |
}
|
4788 |
}
|
4789 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4790 |
//Finally, show the menu
|
4791 |
loadMenuConfiguration(customMenu);
|
4792 |
|
46 |
* @property {string|null} wsEditorData.selectedMenu
|
47 |
* @property {string|null} wsEditorData.selectedSubmenu
|
48 |
*
|
49 |
+
* @property {string} wsEditorData.setTestConfigurationNonce
|
50 |
+
* @property {string} wsEditorData.testAccessNonce
|
51 |
+
*
|
52 |
* @property {boolean} wsEditorData.isDemoMode
|
53 |
* @property {boolean} wsEditorData.isMasterMode
|
54 |
*/
|
777 |
}
|
778 |
}),
|
779 |
|
780 |
+
'appearance_heading' : $.extend({}, baseField, {
|
781 |
+
caption: 'Appearance',
|
782 |
+
advanced : true,
|
783 |
+
onlyForTopMenus: false,
|
784 |
+
type: 'heading',
|
785 |
+
standardCaption: false,
|
786 |
+
visible: false //Only visible in the Pro version.
|
787 |
+
}),
|
788 |
+
|
789 |
'icon_url' : $.extend({}, baseField, {
|
790 |
caption: 'Icon URL',
|
791 |
type : 'icon_selector',
|
846 |
}
|
847 |
}),
|
848 |
|
849 |
+
'colors' : $.extend({}, baseField, {
|
850 |
+
caption: 'Color scheme',
|
851 |
+
defaultValue: 'Default',
|
852 |
+
type: 'color_scheme_editor',
|
853 |
+
onlyForTopMenus: true,
|
854 |
+
visible: false,
|
855 |
advanced : true,
|
856 |
+
|
857 |
+
display: function(menuItem, displayValue, input, containerNode) {
|
858 |
+
var colors = getFieldValue(menuItem, 'colors', {}) || {};
|
859 |
+
var colorList = containerNode.find('.ws_color_scheme_display');
|
860 |
+
|
861 |
+
colorList.empty();
|
862 |
+
var count = 0, maxColorsToShow = 7;
|
863 |
+
|
864 |
+
$.each(colors, function(name, value) {
|
865 |
+
if ( !value || (count >= maxColorsToShow) ) {
|
866 |
+
return;
|
867 |
+
}
|
868 |
+
|
869 |
+
colorList.append(
|
870 |
+
$('<span></span>').addClass('ws_color_display_item').css('background-color', value)
|
871 |
+
);
|
872 |
+
count++;
|
873 |
+
});
|
874 |
+
|
875 |
+
if (count === 0) {
|
876 |
+
colorList.append('Default');
|
877 |
+
}
|
878 |
+
|
879 |
+
return 'Placeholder. You should never see this.';
|
880 |
+
},
|
881 |
+
|
882 |
+
write: function(menuItem) {
|
883 |
+
//Menu colors can't be directly edited.
|
884 |
+
}
|
885 |
+
}),
|
886 |
+
|
887 |
+
'html_heading' : $.extend({}, baseField, {
|
888 |
+
caption: 'HTML',
|
889 |
+
advanced : true,
|
890 |
+
onlyForTopMenus: true,
|
891 |
+
type: 'heading',
|
892 |
+
standardCaption: false
|
893 |
}),
|
894 |
|
895 |
'open_in' : $.extend({}, baseField, {
|
940 |
}
|
941 |
}),
|
942 |
|
943 |
+
'css_class' : $.extend({}, baseField, {
|
944 |
+
caption: 'CSS classes',
|
|
|
|
|
|
|
|
|
945 |
advanced : true,
|
946 |
+
onlyForTopMenus: true
|
947 |
+
}),
|
948 |
|
949 |
+
'hookname' : $.extend({}, baseField, {
|
950 |
+
caption: 'ID attribute',
|
951 |
+
advanced : true,
|
952 |
+
onlyForTopMenus: true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
953 |
}),
|
954 |
|
955 |
+
'page_properties_heading' : $.extend({}, baseField, {
|
956 |
+
caption: 'Page',
|
957 |
+
advanced : true,
|
958 |
+
onlyForTopMenus: true,
|
959 |
+
type: 'heading',
|
960 |
+
standardCaption: false
|
961 |
}),
|
962 |
|
963 |
'page_heading' : $.extend({}, baseField, {
|
967 |
visible: false
|
968 |
}),
|
969 |
|
970 |
+
'page_title' : $.extend({}, baseField, {
|
971 |
+
caption: "Window title",
|
972 |
+
standardCaption : true,
|
973 |
+
advanced : true
|
974 |
}),
|
975 |
|
976 |
'is_always_open' : $.extend({}, baseField, {
|
977 |
+
caption: 'Keep this menu expanded',
|
978 |
advanced : true,
|
979 |
onlyForTopMenus: true,
|
980 |
type: 'checkbox',
|
1082 |
.add('<input type="button" class="button ws_open_color_editor" value="Edit...">');
|
1083 |
break;
|
1084 |
|
1085 |
+
case 'heading':
|
1086 |
+
inputBox = $('<span>' + field_settings.caption + '</span>');
|
1087 |
+
break;
|
1088 |
+
|
1089 |
case 'text':
|
1090 |
/* falls through */
|
1091 |
default:
|
1100 |
if (!field_settings.standardCaption) {
|
1101 |
className += ' ws_no_field_caption';
|
1102 |
}
|
1103 |
+
if (field_settings.type === 'heading') {
|
1104 |
+
className += ' ws_field_group_heading';
|
1105 |
+
}
|
1106 |
|
1107 |
var caption = '';
|
1108 |
if (field_settings.standardCaption) {
|
1129 |
|
1130 |
editField
|
1131 |
.append(
|
1132 |
+
$('<img class="ws_reset_button" title="Reset to default value" src="">')
|
1133 |
.attr('src', wsEditorData.imagesUrl + '/transparent16.png')
|
1134 |
).data('field_name', field_name);
|
1135 |
|
1760 |
if (field_name === 'embedded_page_id') {
|
1761 |
return true;
|
1762 |
}
|
1763 |
+
//Headings contain no useful data.
|
1764 |
+
if (field.hasClass('ws_field_group_heading')) {
|
1765 |
+
return true;
|
1766 |
+
}
|
1767 |
|
1768 |
//Find the field (usually an input or select element).
|
1769 |
var input_box = field.find('.ws_field_value');
|
2036 |
knownMenuFields.access_level.visible = true;
|
2037 |
knownMenuFields.page_heading.visible = true;
|
2038 |
knownMenuFields.colors.visible = true;
|
2039 |
+
knownMenuFields.appearance_heading.visible = true;
|
2040 |
+
knownMenuFields.appearance_heading.onlyForTopMenus = false;
|
2041 |
knownMenuFields.extra_capability.visible = false; //Superseded by the "access_level" field.
|
2042 |
|
2043 |
//The Pro version supports submenu icons, but they can be disabled by the user.
|
4828 |
}
|
4829 |
}
|
4830 |
|
4831 |
+
/******************************************************************
|
4832 |
+
"Test Access" feature
|
4833 |
+
******************************************************************/
|
4834 |
+
var testAccessDialog = $('#ws_ame_test_access_screen').dialog({
|
4835 |
+
autoOpen: false,
|
4836 |
+
modal: true,
|
4837 |
+
closeText: ' ',
|
4838 |
+
title: 'Test access',
|
4839 |
+
width: 900
|
4840 |
+
//draggable: false
|
4841 |
+
}),
|
4842 |
+
testMenuItemList = $('#ws_ame_test_menu_item'),
|
4843 |
+
testActorList = $('#ws_ame_test_relevant_actor'),
|
4844 |
+
testAccessButton = $('#ws_ame_start_access_test'),
|
4845 |
+
testAccessFrame = $('#ws_ame_test_access_frame'),
|
4846 |
+
testConfig = null,
|
4847 |
+
|
4848 |
+
testProgress = $('#ws_ame_test_progress'),
|
4849 |
+
testProgressText = $('#ws_ame_test_progress_text');
|
4850 |
+
|
4851 |
+
$('#ws_test_access').click(function () {
|
4852 |
+
testConfig = readMenuTreeState();
|
4853 |
+
|
4854 |
+
var selectedMenuContainer = getSelectedMenu(),
|
4855 |
+
selectedItemContainer = getSelectedSubmenuItem(),
|
4856 |
+
selectedMenu = null,
|
4857 |
+
selectedItem = null,
|
4858 |
+
selectedUrl = null;
|
4859 |
+
if (selectedMenuContainer.length > 0) {
|
4860 |
+
selectedMenu = selectedMenuContainer.data('menu_item');
|
4861 |
+
selectedUrl = getFieldValue(selectedMenu, 'url');
|
4862 |
+
}
|
4863 |
+
if (selectedItemContainer.length > 0) {
|
4864 |
+
selectedItem = selectedItemContainer.data('menu_item');
|
4865 |
+
selectedUrl = getFieldValue(selectedItem, 'url');
|
4866 |
+
}
|
4867 |
+
|
4868 |
+
function addMenuItems(collection, parentTitle, parentFile) {
|
4869 |
+
_.each(collection, function (menuItem) {
|
4870 |
+
if (menuItem.separator) {
|
4871 |
+
return;
|
4872 |
+
}
|
4873 |
+
|
4874 |
+
var title = formatMenuTitle(getFieldValue(menuItem, 'menu_title', '[Untitled menu]'));
|
4875 |
+
if (parentTitle) {
|
4876 |
+
title = parentTitle + ' -> ' + title;
|
4877 |
+
}
|
4878 |
+
var url = getFieldValue(menuItem, 'url', '[no-url]');
|
4879 |
+
|
4880 |
+
var option = $(
|
4881 |
+
'<option>', {
|
4882 |
+
val: url,
|
4883 |
+
text: title
|
4884 |
+
}
|
4885 |
+
);
|
4886 |
+
option.data('menu_item', menuItem);
|
4887 |
+
option.data('parent_file', parentFile || '');
|
4888 |
+
option.prop('selected', (url === selectedUrl));
|
4889 |
+
|
4890 |
+
testMenuItemList.append(option);
|
4891 |
+
|
4892 |
+
if (menuItem.items) {
|
4893 |
+
addMenuItems(menuItem.items, title, getFieldValue(menuItem, 'file', ''));
|
4894 |
+
}
|
4895 |
+
});
|
4896 |
+
}
|
4897 |
+
|
4898 |
+
//Populate the list of menu items.
|
4899 |
+
testMenuItemList.empty();
|
4900 |
+
addMenuItems(testConfig.tree);
|
4901 |
+
|
4902 |
+
//Populate the actor list.
|
4903 |
+
testActorList.empty();
|
4904 |
+
testActorList.append($('<option>', {text: 'Not selected', val: ''}));
|
4905 |
+
_.each(actorSelectorWidget.getVisibleActors(), function (actor) {
|
4906 |
+
//TODO: Skip anything that isn't a role
|
4907 |
+
var option = $('<option>', {
|
4908 |
+
val: actor.id,
|
4909 |
+
text: actorSelectorWidget.getNiceName(actor)
|
4910 |
+
});
|
4911 |
+
testActorList.append(option);
|
4912 |
+
});
|
4913 |
+
|
4914 |
+
//Pre-select the current actor.
|
4915 |
+
if (actorSelectorWidget.selectedActor !== null) {
|
4916 |
+
testActorList.val(actorSelectorWidget.selectedActor);
|
4917 |
+
}
|
4918 |
+
|
4919 |
+
testAccessDialog.dialog('open');
|
4920 |
+
});
|
4921 |
+
|
4922 |
+
testAccessButton.click(function () {
|
4923 |
+
testAccessButton.prop('disabled', true);
|
4924 |
+
testProgress.show();
|
4925 |
+
testProgressText.text('Sending menu settings...');
|
4926 |
+
|
4927 |
+
var selectedOption = testMenuItemList.find('option:selected').first(),
|
4928 |
+
selectedMenu = selectedOption.data('menu_item'),
|
4929 |
+
menuUrl = selectedOption.val();
|
4930 |
+
|
4931 |
+
$.ajax(
|
4932 |
+
wsEditorData.adminAjaxUrl,
|
4933 |
+
{
|
4934 |
+
data: {
|
4935 |
+
'action': 'ws_ame_set_test_configuration',
|
4936 |
+
'data': encodeMenuAsJSON(testConfig),
|
4937 |
+
'_ajax_nonce': wsEditorData.setTestConfigurationNonce
|
4938 |
+
},
|
4939 |
+
method: 'post',
|
4940 |
+
dataType: 'json',
|
4941 |
+
success: function(response, textStatus) {
|
4942 |
+
if (!response) {
|
4943 |
+
alert('Error: Could not parse the server response.');
|
4944 |
+
testAccessButton.prop('disabled', false);
|
4945 |
+
return;
|
4946 |
+
}
|
4947 |
+
if (response.error) {
|
4948 |
+
alert(response.error);
|
4949 |
+
testAccessButton.prop('disabled', false);
|
4950 |
+
return;
|
4951 |
+
}
|
4952 |
+
if (!response.success) {
|
4953 |
+
alert('Error: The request failed, but there is no error information available.');
|
4954 |
+
testAccessButton.prop('disabled', false);
|
4955 |
+
return;
|
4956 |
+
}
|
4957 |
+
|
4958 |
+
//Caution: Won't work in IE. Needs compat checks.
|
4959 |
+
var testPageUrl = new URL(menuUrl, window.location.href);
|
4960 |
+
testPageUrl.searchParams.append('ame-test-menu-access-as', $('#ws_ame_test_access_username').val());
|
4961 |
+
testPageUrl.searchParams.append('_wpnonce', wsEditorData.testAccessNonce);
|
4962 |
+
testPageUrl.searchParams.append('ame-test-relevant-role', testActorList.val());
|
4963 |
+
|
4964 |
+
testPageUrl.searchParams.append('ame-test-target-item', getFieldValue(selectedMenu, 'file', ''));
|
4965 |
+
testPageUrl.searchParams.append('ame-test-target-parent', selectedOption.data('parent_file'));
|
4966 |
+
|
4967 |
+
testProgressText.text('Loading the test page....');
|
4968 |
+
$('#ws_ame_test_frame_placeholder').hide();
|
4969 |
+
|
4970 |
+
$(window).on('message', receiveTestAccessResults);
|
4971 |
+
testAccessFrame
|
4972 |
+
.show()
|
4973 |
+
.on('load', onAccessTestLoaded)
|
4974 |
+
.prop('src', testPageUrl.href);
|
4975 |
+
},
|
4976 |
+
error: function(jqXHR, textStatus) {
|
4977 |
+
alert('HTTP Error: ' + textStatus);
|
4978 |
+
testAccessButton.prop('disabled', false);
|
4979 |
+
}
|
4980 |
+
}
|
4981 |
+
);
|
4982 |
+
});
|
4983 |
+
|
4984 |
+
function onAccessTestLoaded() {
|
4985 |
+
testAccessFrame.off('load', onAccessTestLoaded);
|
4986 |
+
testProgress.hide();
|
4987 |
+
|
4988 |
+
testAccessButton.prop('disabled', false);
|
4989 |
+
}
|
4990 |
+
|
4991 |
+
function receiveTestAccessResults(event) {
|
4992 |
+
if (event.originalEvent.source !== testAccessFrame.get(0).contentWindow) {
|
4993 |
+
if (console && console.warn) {
|
4994 |
+
console.warn('AME: Received a message from an unexpected source. Message ignored.');
|
4995 |
+
}
|
4996 |
+
return;
|
4997 |
+
}
|
4998 |
+
var message = event.originalEvent.data || event.originalEvent.message;
|
4999 |
+
console.log('message received', message);
|
5000 |
+
|
5001 |
+
$(window).off('message', receiveTestAccessResults);
|
5002 |
+
}
|
5003 |
+
|
5004 |
+
|
5005 |
//Finally, show the menu
|
5006 |
loadMenuConfiguration(customMenu);
|
5007 |
|
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.3
|
7 |
Author: Janis Elsts
|
8 |
Author URI: http://w-shadow.com/blog/
|
9 |
*/
|
modules/tweaks/default-tweaks.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
return array(
|
3 |
+
'hide-screen-meta-links' => array(
|
4 |
+
'label' => 'Hide screen meta links',
|
5 |
+
'selector' => '#screen-meta-links'
|
6 |
+
),
|
7 |
+
'hide-screen-options' => array(
|
8 |
+
'label' => 'Hide the "Screen Options" button',
|
9 |
+
'selector' => '#screen-options-link-wrap',
|
10 |
+
'parent' => 'hide-screen-meta-links',
|
11 |
+
),
|
12 |
+
'hide-help-panel' => array(
|
13 |
+
'label' => 'Hide the "Help" button',
|
14 |
+
'selector' => '#contextual-help-link-wrap',
|
15 |
+
'parent' => 'hide-screen-meta-links',
|
16 |
+
),
|
17 |
+
'hide-all-admin-notices' => array(
|
18 |
+
'label' => 'Hide ALL admin notices',
|
19 |
+
'selector' => '.wrap .notice, .wrap .updated',
|
20 |
+
),
|
21 |
+
);
|
modules/tweaks/tweaks-template.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @var string $tabUrl Fully qualified URL of the tab.
|
4 |
+
* @var array $tweaks
|
5 |
+
*/
|
6 |
+
|
7 |
+
?>
|
8 |
+
<div id="ame-tweak-manager">
|
9 |
+
<?php require AME_ROOT_DIR . '/modules/actor-selector/actor-selector-template.php'; ?>
|
10 |
+
|
11 |
+
<pre><?php print_r($tweaks); ?></pre>
|
12 |
+
</div>
|
13 |
+
|
modules/tweaks/tweaks.php
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* Idea: Show tweaks as options in menu properties, e.g. in a "Tweaks" section styled like the collapsible
|
5 |
+
* property sheets in Delphi.
|
6 |
+
*/
|
7 |
+
|
8 |
+
class ameTweakManager extends amePersistentModule {
|
9 |
+
protected $tabSlug = 'tweaks';
|
10 |
+
protected $tabTitle = 'Tweaks';
|
11 |
+
protected $optionName = 'ws_ame_tweak_settings';
|
12 |
+
|
13 |
+
private $tweaks = array();
|
14 |
+
|
15 |
+
private $postponedTweaks = array();
|
16 |
+
private $pendingSelectorTweaks = array();
|
17 |
+
|
18 |
+
public function __construct($menuEditor) {
|
19 |
+
parent::__construct($menuEditor);
|
20 |
+
|
21 |
+
add_action('init', array($this, 'processTweaks'), 200);
|
22 |
+
add_action('admin_head', array($this, 'outputSelectors'));
|
23 |
+
}
|
24 |
+
|
25 |
+
private function registerTweaks() {
|
26 |
+
$this->tweaks = require (__DIR__ . '/default-tweaks.php');
|
27 |
+
do_action('admin-menu-editor-register_tweaks', $this);
|
28 |
+
}
|
29 |
+
|
30 |
+
public function processTweaks() {
|
31 |
+
$settings = $this->loadSettings();
|
32 |
+
$isTweakEnabled = ameUtils::get($settings, 'isTweakEnabled');
|
33 |
+
|
34 |
+
$this->registerTweaks();
|
35 |
+
|
36 |
+
$currentUser = wp_get_current_user();
|
37 |
+
$roles = $this->menuEditor->get_user_roles($currentUser);
|
38 |
+
$isSuperAdmin = is_multisite() && is_super_admin($currentUser->ID);
|
39 |
+
|
40 |
+
foreach ($this->tweaks as $id => $tweak) {
|
41 |
+
if ( empty($isTweakEnabled[$id]) ) {
|
42 |
+
continue; //This tweak is not enabled for anyone.
|
43 |
+
}
|
44 |
+
|
45 |
+
if ( !$this->appliesToUser($isTweakEnabled[$id], $currentUser, $roles, $isSuperAdmin) ) {
|
46 |
+
continue;
|
47 |
+
}
|
48 |
+
|
49 |
+
if ( isset($tweak['initFilter']) && !call_user_func($tweak['initFilter']) ) {
|
50 |
+
continue;
|
51 |
+
}
|
52 |
+
|
53 |
+
if ( !empty($tweak['screens']) || !empty($tweak['screenFilter']) ) {
|
54 |
+
$this->postponedTweaks[$id] = $tweak;
|
55 |
+
continue;
|
56 |
+
}
|
57 |
+
|
58 |
+
$this->applyTweak($id, $tweak);
|
59 |
+
}
|
60 |
+
|
61 |
+
if ( !empty($this->postponedTweaks) ) {
|
62 |
+
add_action('current_screen', array($this, 'processPostponedTweaks'), 10, 1);
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @param array $enabledForActor
|
68 |
+
* @param WP_User $user
|
69 |
+
* @param array $roles
|
70 |
+
* @param bool $isSuperAdmin
|
71 |
+
* @return bool
|
72 |
+
*/
|
73 |
+
private function appliesToUser($enabledForActor, $user, $roles, $isSuperAdmin = false) {
|
74 |
+
//User-specific settings have priority over everything else.
|
75 |
+
$userActor = 'user:' . $user->user_login;
|
76 |
+
if ( isset($enabledForActor[$userActor]) ) {
|
77 |
+
return $enabledForActor[$userActor];
|
78 |
+
}
|
79 |
+
|
80 |
+
//The "Super Admin" flag has priority over regular roles.
|
81 |
+
if ( $isSuperAdmin && isset($enabledForActor['special:super_admin']) ) {
|
82 |
+
return $enabledForActor['special:super_admin'];
|
83 |
+
}
|
84 |
+
|
85 |
+
//If it's enabled for any role, it's enabled for the user.
|
86 |
+
foreach($roles as $role) {
|
87 |
+
if ( !empty($enabledForActor['role:' . $role]) ) {
|
88 |
+
return true;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
//By default, all tweaks are disabled.
|
93 |
+
return false;
|
94 |
+
}
|
95 |
+
|
96 |
+
private function applyTweak($id, $tweak) {
|
97 |
+
//Run callbacks immediately.
|
98 |
+
if ( isset($tweak['callback']) ) {
|
99 |
+
call_user_func($tweak['callback']);
|
100 |
+
}
|
101 |
+
|
102 |
+
//Queue selectors for later.
|
103 |
+
if ( !empty($tweak['selector']) ) {
|
104 |
+
$this->pendingSelectorTweaks[$id] = $tweak;
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* @param WP_Screen $screen
|
110 |
+
*/
|
111 |
+
public function processPostponedTweaks($screen = null) {
|
112 |
+
if ( empty($screen) && function_exists('get_current_screen') ) {
|
113 |
+
$screen = get_current_screen();
|
114 |
+
}
|
115 |
+
$screenId = isset($screen, $screen->id) ? $screen->id : null;
|
116 |
+
|
117 |
+
foreach($this->postponedTweaks as $id => $tweak) {
|
118 |
+
if ( !empty($tweak['screens']) && !in_array($screenId, $tweak['screens']) ) {
|
119 |
+
continue;
|
120 |
+
}
|
121 |
+
|
122 |
+
if ( !empty($tweak['screenFilter']) && !call_user_func($tweak['screenFilter'], $screen) ) {
|
123 |
+
continue;
|
124 |
+
}
|
125 |
+
|
126 |
+
$this->applyTweak($id, $tweak);
|
127 |
+
}
|
128 |
+
|
129 |
+
$this->postponedTweaks = array();
|
130 |
+
}
|
131 |
+
|
132 |
+
public function outputSelectors() {
|
133 |
+
if ( empty($this->pendingSelectorTweaks) ) {
|
134 |
+
return;
|
135 |
+
}
|
136 |
+
|
137 |
+
$selectors = array();
|
138 |
+
foreach($this->pendingSelectorTweaks as $tweak) {
|
139 |
+
$selectors[] = $tweak['selector'];
|
140 |
+
}
|
141 |
+
$css = sprintf(
|
142 |
+
'<style type="text/css">%s { display: none; }</style>',
|
143 |
+
implode(',', $selectors)
|
144 |
+
);
|
145 |
+
|
146 |
+
echo '<!-- AME selector tweaks -->', "\n", $css, "\n";
|
147 |
+
|
148 |
+
$this->pendingSelectorTweaks = array();
|
149 |
+
}
|
150 |
+
|
151 |
+
protected function getTemplateVariables($templateName) {
|
152 |
+
$variables = parent::getTemplateVariables($templateName);
|
153 |
+
$variables['tweaks'] = $this->tweaks;
|
154 |
+
return $variables;
|
155 |
+
}
|
156 |
+
|
157 |
+
|
158 |
+
}
|
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.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.
|
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.5
|
7 |
+
Stable tag: 1.8.3
|
8 |
|
9 |
Lets you edit the WordPress admin menu. You can re-order, hide or rename menus, add custom menus and more.
|
10 |
|
63 |
|
64 |
== Changelog ==
|
65 |
|
66 |
+
= 1.8.3 =
|
67 |
+
* Added a couple of tutorial links to the settings page.
|
68 |
+
* Fixed a potential crash that was caused by a bug in the "WP Editor" plugin version 1.2.6.3.
|
69 |
+
* Fixed some obsolete callback syntax that was still using "&$this".
|
70 |
+
* Changed the order of some menu settings and added separators between groups of settings.
|
71 |
+
* Removed the "Screen Options" panel from AME tabs that didn't need it like "Plugins".
|
72 |
+
* Tested with WP 4.9.5.
|
73 |
+
|
74 |
= 1.8.2 =
|
75 |
* Fixed the PHP warning "count(): Parameter must be an array or an object that implements Countable in menu-editor-core.php".
|
76 |
* Fixed a bug that could cause some network admin menus to be highlighted in green as if they were new.
|