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 | |
| 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.
|
