Version Description
- You can edit plugin names and descriptions through the "Plugins" tab. This only changes how plugins are displayed on the "Plugins" page. It doesn't affect plugin files on disk.
- Added an option to highlight new menu items. This feature is off by default. You can enable it in the "Settings" tab.
- Added an option to compress menu data that the plugin stores in the database.
- Added a compatibility workaround for the Divi Training plugin. The hidden menu items that it adds to the "Dashboard" menu should no longer show up when you activate AME.
- Added a workaround that improves compatibility with plugins that set their menu icons using CSS.
- Fixed an old bug where sorting menu items would put all separators at the top. Now they'll stay near their preceding menu item.
- Fixed incorrect shadows on custom screen options links.
- Fixed a couple of UI layout issues that were caused by bugs in other plugins.
- Fixed a rare issue where hiding the admin bar would leave behind empty space.
- When you use the "A-Z" button to sort top level menus, it also sorts submenu items. To avoid compatibility issues, the first item of each submenu stays in its original position.
- Automatically reset plugin access if the only allowed user no longer exists. This should cut down on the number of users who accidentally lock themselves out by setting "Who can access the plugin" to "Only the current user" and then later deleting that user account.
- Minor performance optimizations.
Download this release
Release Info
Developer | whiteshadow |
Plugin | Admin Menu Editor |
Version | 1.8 |
Comparing to | |
See all releases |
Code changes from version 1.7.3 to 1.8
- ajax-wrapper/AjaxWrapper.php +464 -0
- ajax-wrapper/README.md +23 -0
- ajax-wrapper/ajax-action-wrapper.d.ts +15 -0
- ajax-wrapper/ajax-action-wrapper.js +139 -0
- css/_dashicons.scss +224 -0
- css/force-dashicons.css +460 -0
- css/force-dashicons.css.map +7 -0
- css/force-dashicons.scss +20 -0
- css/menu-editor.css +19 -6
- css/menu-editor.scss +24 -6
- css/screen-meta.css +5 -3
- css/style-modern-one.css +27 -27
- css/style-modern-one.scss +39 -32
- includes/ajax-helper.php +0 -178
- includes/auto-versioning.php +11 -8
- includes/editor-page.php +21 -1
- includes/generate-menu-dashicons.php +21 -3
- includes/menu-editor-core.php +346 -83
- includes/menu-item.php +10 -0
- includes/menu.php +60 -6
- includes/reflection-callable.php +16 -2
- includes/settings-page.php +105 -0
- js/actor-manager.js +38 -28
- js/actor-manager.ts +21 -19
- js/menu-editor.js +23 -6
- menu-editor.php +1 -1
- modules/actor-selector/actor-selector.js +1 -1
- modules/actor-selector/actor-selector.php +13 -8
- modules/actor-selector/actor-selector.ts +9 -9
- modules/admin-css/admin-css.php +35 -0
- modules/highlight-new-menus/assets/highlight-menus.js +135 -0
- modules/highlight-new-menus/assets/menu-highlights.css +12 -0
- modules/highlight-new-menus/assets/menu-highlights.css.map +7 -0
- modules/highlight-new-menus/assets/menu-highlights.scss +23 -0
- modules/highlight-new-menus/highlight-new-menus.php +12 -0
- modules/highlight-new-menus/plugin.php +15 -0
- modules/highlight-new-menus/uninstall.php +5 -0
- modules/highlight-new-menus/wsNewMenuHighlighter.php +266 -0
- modules/plugin-visibility/plugin-visibility-template.php +61 -1
- modules/plugin-visibility/plugin-visibility.css +19 -0
- modules/plugin-visibility/plugin-visibility.js +63 -11
- modules/plugin-visibility/plugin-visibility.php +27 -9
- modules/plugin-visibility/plugin-visibility.scss +34 -1
- modules/plugin-visibility/plugin-visibility.ts +97 -27
- readme.txt +16 -2
ajax-wrapper/AjaxWrapper.php
ADDED
@@ -0,0 +1,464 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if (!class_exists('Ajaw_v1_ActionBuilder', false)):
|
3 |
+
|
4 |
+
class Ajaw_v1_ActionBuilder {
|
5 |
+
private $action;
|
6 |
+
private $callback = '__return_null';
|
7 |
+
private $params = array();
|
8 |
+
private $httpMethod = null;
|
9 |
+
|
10 |
+
private $capability = null;
|
11 |
+
private $permissionCheckCallback = null;
|
12 |
+
|
13 |
+
private $mustBeLoggedIn = true;
|
14 |
+
private $checkNonce = true;
|
15 |
+
|
16 |
+
public function __construct($action) {
|
17 |
+
$this->action = $action;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param callable $callback
|
22 |
+
* @return $this
|
23 |
+
*/
|
24 |
+
public function handler($callback) {
|
25 |
+
$this->callback = $callback;
|
26 |
+
return $this;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function requiredParam($name, $type = null, $validateCallback = null) {
|
30 |
+
return $this->addParameter($name, $type, true, null, $validateCallback);
|
31 |
+
}
|
32 |
+
|
33 |
+
public function optionalParam($name, $defaultValue = null, $type = null, $validateCallback = null) {
|
34 |
+
return $this->addParameter($name, $type, false, $defaultValue, $validateCallback);
|
35 |
+
}
|
36 |
+
|
37 |
+
private function addParameter($name, $type, $required, $defaultValue, $validateCallback) {
|
38 |
+
if (isset($type) && !isset(Ajaw_v1_Action::$defaultValidators[$type])) {
|
39 |
+
throw new LogicException(sprintf(
|
40 |
+
'Unknown parameter type "%s". Supported types are: %s.',
|
41 |
+
$type,
|
42 |
+
implode(', ', array_keys(Ajaw_v1_Action::$defaultValidators[$type]))
|
43 |
+
));
|
44 |
+
}
|
45 |
+
|
46 |
+
$this->params[$name] = array(
|
47 |
+
'required' => $required,
|
48 |
+
'defaultValue' => $defaultValue,
|
49 |
+
'type' => $type,
|
50 |
+
'validateCallback' => $validateCallback,
|
51 |
+
);
|
52 |
+
return $this;
|
53 |
+
}
|
54 |
+
|
55 |
+
public function method($httpMethod) {
|
56 |
+
$this->httpMethod = strtoupper($httpMethod);
|
57 |
+
return $this;
|
58 |
+
}
|
59 |
+
|
60 |
+
public function requiredCap($capability) {
|
61 |
+
$this->capability = $capability;
|
62 |
+
return $this;
|
63 |
+
}
|
64 |
+
|
65 |
+
public function permissionCallback($callback) {
|
66 |
+
$this->permissionCheckCallback = $callback;
|
67 |
+
return $this;
|
68 |
+
}
|
69 |
+
|
70 |
+
public function allowUnprivilegedUsers() {
|
71 |
+
$this->mustBeLoggedIn = false;
|
72 |
+
return $this;
|
73 |
+
}
|
74 |
+
|
75 |
+
public function withoutNonce() {
|
76 |
+
$this->checkNonce = false;
|
77 |
+
return $this;
|
78 |
+
}
|
79 |
+
|
80 |
+
public function build() {
|
81 |
+
$instance = new Ajaw_v1_Action($this->action, $this->callback, $this->params);
|
82 |
+
|
83 |
+
$instance->mustBeLoggedIn = $this->mustBeLoggedIn;
|
84 |
+
$instance->requiredCap = $this->capability;
|
85 |
+
$instance->nonceCheckEnabled = $this->checkNonce;
|
86 |
+
$instance->method = $this->httpMethod;
|
87 |
+
$instance->permissionCallback = $this->permissionCheckCallback;
|
88 |
+
|
89 |
+
return $instance;
|
90 |
+
}
|
91 |
+
|
92 |
+
public function register() {
|
93 |
+
$instance = $this->build();
|
94 |
+
$instance->register();
|
95 |
+
return $instance;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
endif;
|
100 |
+
|
101 |
+
if (!class_exists('Ajaw_v1_Action', false)):
|
102 |
+
|
103 |
+
class Ajaw_v1_Action {
|
104 |
+
public $action;
|
105 |
+
public $callback;
|
106 |
+
public $params = array();
|
107 |
+
public $method = null;
|
108 |
+
|
109 |
+
public $requiredCap = null;
|
110 |
+
public $mustBeLoggedIn = false;
|
111 |
+
public $nonceCheckEnabled = true;
|
112 |
+
public $permissionCallback = null;
|
113 |
+
|
114 |
+
private $isScriptRegistered = false;
|
115 |
+
|
116 |
+
public $get = array();
|
117 |
+
public $post = array();
|
118 |
+
public $request = array();
|
119 |
+
|
120 |
+
public static $defaultValidators = array(
|
121 |
+
'int' => array(__CLASS__, 'validateInt'),
|
122 |
+
'float' => array(__CLASS__, 'validateFloat'),
|
123 |
+
'boolean' => array(__CLASS__, 'validateBoolean'),
|
124 |
+
'string' => array(__CLASS__, 'validateString'),
|
125 |
+
);
|
126 |
+
|
127 |
+
public function __construct($action, $callback, $params) {
|
128 |
+
$this->action = $action;
|
129 |
+
$this->callback = $callback;
|
130 |
+
$this->params = $params;
|
131 |
+
|
132 |
+
if (empty($this->action)) {
|
133 |
+
throw new LogicException(sprintf(
|
134 |
+
'AJAX action name is missing. You must either pass it to the %1$s constructor '
|
135 |
+
. 'or give the %1$s::$action property a valid default value.',
|
136 |
+
get_class($this)
|
137 |
+
));
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Set up hooks for AJAX and helper scripts.
|
143 |
+
*/
|
144 |
+
public function register() {
|
145 |
+
//Register the AJAX handler(s).
|
146 |
+
$hookNames = array('wp_ajax_' . $this->action);
|
147 |
+
if (!$this->mustBeLoggedIn) {
|
148 |
+
$hookNames[] = 'wp_ajax_nopriv_' . $this->action;
|
149 |
+
}
|
150 |
+
|
151 |
+
foreach($hookNames as $hook) {
|
152 |
+
if (has_action($hook)) {
|
153 |
+
throw new RuntimeException(sprintf('The action name "%s" is already in use.', $this->action));
|
154 |
+
}
|
155 |
+
add_action($hook, array($this, 'processAjaxRequest'));
|
156 |
+
}
|
157 |
+
|
158 |
+
//Register the utility JS library after WP is fully loaded.
|
159 |
+
if (did_action('wp_loaded')) {
|
160 |
+
$this->registerScript();
|
161 |
+
} else {
|
162 |
+
add_action('wp_loaded', array($this, 'registerScript'), 2);
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* @access protected
|
168 |
+
*/
|
169 |
+
public function processAjaxRequest() {
|
170 |
+
$result = $this->handleAction();
|
171 |
+
|
172 |
+
if (is_wp_error($result)) {
|
173 |
+
$statusCode = $result->get_error_data();
|
174 |
+
if (isset($statusCode) && is_int($statusCode) ) {
|
175 |
+
status_header($statusCode);
|
176 |
+
}
|
177 |
+
|
178 |
+
$errorResponse = array(
|
179 |
+
'error' => array(
|
180 |
+
'message' => $result->get_error_message(),
|
181 |
+
'code' => $result->get_error_code()
|
182 |
+
)
|
183 |
+
);
|
184 |
+
|
185 |
+
$result = $errorResponse;
|
186 |
+
}
|
187 |
+
|
188 |
+
if (isset($result)) {
|
189 |
+
$this->outputJSON($result);
|
190 |
+
}
|
191 |
+
exit;
|
192 |
+
}
|
193 |
+
|
194 |
+
protected function handleAction() {
|
195 |
+
$method = strtoupper(filter_input(INPUT_SERVER, 'REQUEST_METHOD'));
|
196 |
+
if (isset($this->method) && ($method !== $this->method)) {
|
197 |
+
return new WP_Error(
|
198 |
+
'http_method_not_allowed',
|
199 |
+
'The HTTP method is not supported by the request handler.',
|
200 |
+
405
|
201 |
+
);
|
202 |
+
}
|
203 |
+
|
204 |
+
$isAuthorized = $this->checkAuthorization();
|
205 |
+
if ($isAuthorized !== true) {
|
206 |
+
return $isAuthorized;
|
207 |
+
}
|
208 |
+
|
209 |
+
$params = $this->parseParameters();
|
210 |
+
if ($params instanceof WP_Error) {
|
211 |
+
return $params;
|
212 |
+
}
|
213 |
+
|
214 |
+
//Call the user-specified action handler.
|
215 |
+
if (is_callable($this->callback)) {
|
216 |
+
return call_user_func($this->callback, $params);
|
217 |
+
} else {
|
218 |
+
return new WP_Error(
|
219 |
+
'missing_ajax_handler',
|
220 |
+
sprintf(
|
221 |
+
'There is no request handler assigned to the "%1$s" action. '
|
222 |
+
. 'Either pass a valid callback to $builder->request() or override the %2$s::%3$s method.',
|
223 |
+
$this->action,
|
224 |
+
__CLASS__,
|
225 |
+
__METHOD__
|
226 |
+
),
|
227 |
+
500
|
228 |
+
);
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Check if the current user is authorized to perform this action.
|
234 |
+
*
|
235 |
+
* @return bool|WP_Error
|
236 |
+
*/
|
237 |
+
protected function checkAuthorization() {
|
238 |
+
if ($this->mustBeLoggedIn && !is_user_logged_in()) {
|
239 |
+
return new WP_Error('login_required', 'You must be logged in to perform this action.', 403);
|
240 |
+
}
|
241 |
+
|
242 |
+
if (isset($this->requiredCap) && !current_user_can($this->requiredCap)) {
|
243 |
+
return new WP_Error('capability_missing', 'You don\'t have permission to perform this action.', 403);
|
244 |
+
}
|
245 |
+
|
246 |
+
if ($this->nonceCheckEnabled && !check_ajax_referer($this->action, false, false)) {
|
247 |
+
return new WP_Error('nonce_check_failed', 'Invalid or missing nonce.', 403);
|
248 |
+
}
|
249 |
+
|
250 |
+
if (isset($this->permissionCallback)) {
|
251 |
+
$result = call_user_func($this->permissionCallback);
|
252 |
+
if ($result === false) {
|
253 |
+
return new WP_Error(
|
254 |
+
'permission_callback_failed',
|
255 |
+
'You don\'t have permission to perform this action.',
|
256 |
+
403
|
257 |
+
);
|
258 |
+
} else if (is_wp_error($result)) {
|
259 |
+
return $result;
|
260 |
+
}
|
261 |
+
}
|
262 |
+
|
263 |
+
return true;
|
264 |
+
}
|
265 |
+
|
266 |
+
protected function parseParameters() {
|
267 |
+
$method = strtoupper(filter_input(INPUT_SERVER, 'REQUEST_METHOD'));
|
268 |
+
|
269 |
+
//Retrieve request parameters.
|
270 |
+
if ($method === 'GET') {
|
271 |
+
$rawParams = $_GET;
|
272 |
+
} else if ($method === 'POST') {
|
273 |
+
$rawParams = $_POST;
|
274 |
+
} else {
|
275 |
+
$rawParams = $_REQUEST;
|
276 |
+
}
|
277 |
+
|
278 |
+
//Remove magic quotes. WordPress applies them in wp-settings.php.
|
279 |
+
//There's no hook for wp_magic_quotes, so we use one that's closest in execution order.
|
280 |
+
if (did_action('sanitize_comment_cookies') && function_exists('wp_magic_quotes')) {
|
281 |
+
$rawParams = wp_unslash($rawParams);
|
282 |
+
}
|
283 |
+
|
284 |
+
//Validate all parameters.
|
285 |
+
$inputParams = $rawParams;
|
286 |
+
foreach($this->params as $name => $settings) {
|
287 |
+
//Verify that all of the required parameters are present.
|
288 |
+
//Empty strings are treated as missing parameters.
|
289 |
+
if (isset($inputParams[$name]) && ($inputParams[$name] !== '')) {
|
290 |
+
$value = $this->validateParameter($settings, $inputParams[$name], $name);
|
291 |
+
if (is_wp_error($value)) {
|
292 |
+
return $value;
|
293 |
+
} else {
|
294 |
+
$inputParams[$name] = $value;
|
295 |
+
}
|
296 |
+
} else if (empty($settings['required'])) {
|
297 |
+
//It's an optional parameter. Use the default value.
|
298 |
+
$inputParams[$name] = $settings['defaultValue'];
|
299 |
+
} else {
|
300 |
+
return new WP_Error(
|
301 |
+
'missing_required_parameter',
|
302 |
+
sprintf('Required parameter is missing or empty: "%s".', $name),
|
303 |
+
400
|
304 |
+
);
|
305 |
+
}
|
306 |
+
}
|
307 |
+
|
308 |
+
return $inputParams;
|
309 |
+
}
|
310 |
+
|
311 |
+
protected function validateParameter($settings, $value, $name) {
|
312 |
+
if (isset($settings['type'])) {
|
313 |
+
$value = call_user_func(self::$defaultValidators[$settings['type']], $value, $name);
|
314 |
+
if (is_wp_error($value)) {
|
315 |
+
return $value;
|
316 |
+
}
|
317 |
+
}
|
318 |
+
if (isset($settings['validateCallback'])) {
|
319 |
+
$success = call_user_func($settings['validateCallback'], $value);
|
320 |
+
if (is_wp_error($success)) {
|
321 |
+
return $success;
|
322 |
+
} else if ($success === false) {
|
323 |
+
return new WP_Error(
|
324 |
+
'invalid_parameter_value',
|
325 |
+
sprintf('The value of the parameter "%s" is invalid.', $name),
|
326 |
+
400
|
327 |
+
);
|
328 |
+
}
|
329 |
+
}
|
330 |
+
return $value;
|
331 |
+
}
|
332 |
+
|
333 |
+
private static function validateInt($value, $name) {
|
334 |
+
$result = filter_var($value, FILTER_VALIDATE_INT);
|
335 |
+
if ($result === false) {
|
336 |
+
return new WP_Error(
|
337 |
+
'invalid_parameter_value',
|
338 |
+
sprintf('The value of the parameter "%s" is invalid. It must be an integer.', $name),
|
339 |
+
400
|
340 |
+
);
|
341 |
+
}
|
342 |
+
return $result;
|
343 |
+
}
|
344 |
+
|
345 |
+
private static function validateFloat($value, $name) {
|
346 |
+
$result = filter_var($value, FILTER_VALIDATE_FLOAT);
|
347 |
+
if ($result === false) {
|
348 |
+
return new WP_Error(
|
349 |
+
'invalid_parameter_value',
|
350 |
+
sprintf('The value of the parameter "%s" is invalid. It must be a float.', $name),
|
351 |
+
400
|
352 |
+
);
|
353 |
+
}
|
354 |
+
return $result;
|
355 |
+
}
|
356 |
+
|
357 |
+
private static function validateBoolean($value, $name) {
|
358 |
+
$result = filter_var($value, FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE));
|
359 |
+
if ($result === null) {
|
360 |
+
return new WP_Error(
|
361 |
+
'invalid_parameter_value',
|
362 |
+
sprintf('The value of the parameter "%s" is invalid. It must be a boolean.', $name),
|
363 |
+
400
|
364 |
+
);
|
365 |
+
}
|
366 |
+
return $result;
|
367 |
+
}
|
368 |
+
|
369 |
+
private static function validateString($value, $name) {
|
370 |
+
if (!is_string($value)) {
|
371 |
+
return new WP_Error(
|
372 |
+
'invalid_parameter_value',
|
373 |
+
sprintf('The value of the parameter "%s" is invalid. It must be a string.', $name),
|
374 |
+
400
|
375 |
+
);
|
376 |
+
}
|
377 |
+
return $value;
|
378 |
+
}
|
379 |
+
|
380 |
+
protected function outputJSON($response) {
|
381 |
+
@header('Content-Type: application/json; charset=' . get_option('blog_charset'));
|
382 |
+
echo json_encode($response);
|
383 |
+
}
|
384 |
+
|
385 |
+
public function registerScript() {
|
386 |
+
if ($this->isScriptRegistered) {
|
387 |
+
return;
|
388 |
+
}
|
389 |
+
$this->isScriptRegistered = true;
|
390 |
+
|
391 |
+
//There could be multiple instances of this class, but we only need to register the script once.
|
392 |
+
$handle = $this->getScriptHandle();
|
393 |
+
if (!wp_script_is($handle, 'registered')) {
|
394 |
+
wp_register_script(
|
395 |
+
$handle,
|
396 |
+
plugins_url('ajax-action-wrapper.js', __FILE__),
|
397 |
+
array('jquery'),
|
398 |
+
'20161105'
|
399 |
+
);
|
400 |
+
}
|
401 |
+
|
402 |
+
//Pass the action to the script.
|
403 |
+
if (function_exists('wp_add_inline_script')) {
|
404 |
+
wp_add_inline_script($handle, $this->generateActionJs(), 'after'); //WP 4.5+
|
405 |
+
} else {
|
406 |
+
add_filter('script_loader_tag', array($this, 'addRegistrationScript'), 10, 2); //WP 4.1+
|
407 |
+
}
|
408 |
+
}
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Backwards compatibility for older versions of WP that don't have wp_add_inline_script().
|
412 |
+
* @internal
|
413 |
+
*
|
414 |
+
* @param string $tag
|
415 |
+
* @param string $handle
|
416 |
+
* @return string
|
417 |
+
*/
|
418 |
+
public function addRegistrationScript($tag, $handle) {
|
419 |
+
if ($handle === $this->getScriptHandle()) {
|
420 |
+
$tag .= '<script type="text/javascript">' . $this->generateActionJs() . '</script>';
|
421 |
+
}
|
422 |
+
return $tag;
|
423 |
+
}
|
424 |
+
|
425 |
+
protected function generateActionJs() {
|
426 |
+
$properties = array(
|
427 |
+
'ajaxUrl' => admin_url('admin-ajax.php'),
|
428 |
+
'method' => $this->method,
|
429 |
+
'nonce' => $this->nonceCheckEnabled ? wp_create_nonce($this->action) : null,
|
430 |
+
);
|
431 |
+
|
432 |
+
return sprintf(
|
433 |
+
'AjawV1.actionRegistry.add("%s", %s);' . "\n",
|
434 |
+
esc_js($this->action),
|
435 |
+
json_encode($properties)
|
436 |
+
);
|
437 |
+
}
|
438 |
+
|
439 |
+
public function getScriptHandle() {
|
440 |
+
return 'ajaw-v1-ajax-action-wrapper';
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* Capture $_GET, $_POST and $_REQUEST without magic quotes.
|
445 |
+
*/
|
446 |
+
function captureRequestVars() {
|
447 |
+
$this->post = $_POST;
|
448 |
+
$this->get = $_GET;
|
449 |
+
$this->request = $_REQUEST;
|
450 |
+
|
451 |
+
if ( function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() ) {
|
452 |
+
$this->post = stripslashes_deep($this->post);
|
453 |
+
$this->get = stripslashes_deep($this->get);
|
454 |
+
}
|
455 |
+
}
|
456 |
+
}
|
457 |
+
|
458 |
+
endif;
|
459 |
+
|
460 |
+
if (!function_exists('ajaw_v1_CreateAction')) {
|
461 |
+
function ajaw_v1_CreateAction($action) {
|
462 |
+
return new Ajaw_v1_ActionBuilder($action);
|
463 |
+
}
|
464 |
+
}
|
ajax-wrapper/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# AJAX Action Wrapper
|
2 |
+
|
3 |
+
**Warning: Work in progress.** Not intended for public consumption. There is no documentation.
|
4 |
+
|
5 |
+
This helper library makes it easier to handle AJAX requests in WordPress plugins.
|
6 |
+
|
7 |
+
### Goals
|
8 |
+
- Automate common, boring stuff.
|
9 |
+
- [x] Automatically pass the `admin-ajax.php` URL and nonce to JS.
|
10 |
+
- [x] Define required parameters.
|
11 |
+
- [x] Define optional parameters with default values.
|
12 |
+
- [x] Automatically remove "magic quotes" that WordPress adds to `$_GET`, `$_POST` and `$_REQUEST`.
|
13 |
+
- [x] Encode return values as JSON.
|
14 |
+
- Security should be the default.
|
15 |
+
- [x] Generate and verify nonces. Nonce verification is on by default, but can be disabled.
|
16 |
+
- [x] Check capabilities.
|
17 |
+
- [x] Verify that all required parameters are set.
|
18 |
+
- [x] Validate parameter values.
|
19 |
+
- [x] Set the required HTTP method.
|
20 |
+
- Resilience.
|
21 |
+
- [ ] Lenient response parsing to work around bugs in other plugins. For example, deal with extraneous whitespace and PHP notices in AJAX responses.
|
22 |
+
- [ ] Multiple versions of the library can coexist on the same site.
|
23 |
+
|
ajax-wrapper/ajax-action-wrapper.d.ts
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Basic type definitions for the Ajaw AJAX wrapper library 1.0
|
2 |
+
|
3 |
+
declare namespace AjawV1 {
|
4 |
+
interface RequestParams { [name: string]: any }
|
5 |
+
interface SuccessCallback { (data, textStatus: string, jqXHR): string }
|
6 |
+
interface ErrorCallback { (data, textStatus: string, jqXHR, errorThrown): string }
|
7 |
+
|
8 |
+
class AjawAjaxAction {
|
9 |
+
get(params?: RequestParams, success?: SuccessCallback, error?: ErrorCallback): void;
|
10 |
+
post(params?: RequestParams, success?: SuccessCallback, error?: ErrorCallback): void;
|
11 |
+
request(params?: RequestParams, success?: SuccessCallback, error?: ErrorCallback, method?: string): void;
|
12 |
+
}
|
13 |
+
|
14 |
+
function getAction(action: string): AjawAjaxAction;
|
15 |
+
}
|
ajax-wrapper/ajax-action-wrapper.js
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
var AjawV1 = window.AjawV1 || {};
|
2 |
+
|
3 |
+
AjawV1.AjaxAction = (function () {
|
4 |
+
"use strict";
|
5 |
+
|
6 |
+
function AjawAjaxAction(action, properties) {
|
7 |
+
this.action = action;
|
8 |
+
this.ajaxUrl = properties['ajaxUrl'];
|
9 |
+
this.nonce = properties['nonce'];
|
10 |
+
this.requiredMethod = (typeof properties['method'] !== 'undefined') ? properties['method'] : null;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Send a POST request.
|
15 |
+
*
|
16 |
+
* @param {Object} params
|
17 |
+
* @param {Function} success
|
18 |
+
* @param {Function} [error]
|
19 |
+
*/
|
20 |
+
AjawAjaxAction.prototype.post = function (params, success, error) {
|
21 |
+
return this.request(params, success, error, 'POST');
|
22 |
+
};
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Send a GET request.
|
26 |
+
*
|
27 |
+
* @param {Object} params
|
28 |
+
* @param {Function} success
|
29 |
+
* @param {Function} [error]
|
30 |
+
*/
|
31 |
+
AjawAjaxAction.prototype.get = function(params, success, error) {
|
32 |
+
return this.request(params, success, error, 'GET');
|
33 |
+
};
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Send an AJAX request using the specified HTTP method.
|
37 |
+
*
|
38 |
+
* @param {Object} params
|
39 |
+
* @param {Function} success
|
40 |
+
* @param {Function} [error]
|
41 |
+
* @param {String} [method]
|
42 |
+
*/
|
43 |
+
AjawAjaxAction.prototype.request = function(params, success, error, method) {
|
44 |
+
if (typeof params === 'function') {
|
45 |
+
//It looks like "params" was omitted and the first argument is actually the success callback.
|
46 |
+
//Shift all arguments left one step. The reverse order is due to argument binding shenanigans.
|
47 |
+
method = arguments[2];
|
48 |
+
error = arguments[1];
|
49 |
+
success = arguments[0];
|
50 |
+
params = {};
|
51 |
+
}
|
52 |
+
|
53 |
+
if (typeof params === 'undefined') {
|
54 |
+
params = {};
|
55 |
+
} else if (typeof params !== 'object') {
|
56 |
+
//While jQuery accepts request data in object and string form, this library only supports objects.
|
57 |
+
throw 'Data that\'s to be sent to the server must be an object, not ' + (typeof params);
|
58 |
+
}
|
59 |
+
|
60 |
+
if (typeof method === 'undefined') {
|
61 |
+
method = this.requiredMethod || 'POST';
|
62 |
+
}
|
63 |
+
if (this.requiredMethod && (method !== this.requiredMethod)) {
|
64 |
+
throw 'Wrong HTTP method. This action requires ' + this.requiredMethod;
|
65 |
+
}
|
66 |
+
|
67 |
+
//noinspection JSUnusedGlobalSymbols
|
68 |
+
return jQuery.ajax(
|
69 |
+
this.ajaxUrl,
|
70 |
+
{
|
71 |
+
method: method,
|
72 |
+
data: this.prepareRequestParams(params),
|
73 |
+
success: function(data, textStatus, jqXHR) {
|
74 |
+
if (success) {
|
75 |
+
success(data, textStatus, jqXHR);
|
76 |
+
}
|
77 |
+
},
|
78 |
+
error: function(jqXHR, textStatus, errorThrown) {
|
79 |
+
var data = jqXHR.responseText;
|
80 |
+
if (typeof jqXHR['responseJSON'] !== 'undefined') {
|
81 |
+
data = jqXHR['responseJSON'];
|
82 |
+
} else if (typeof jqXHR['responseXML'] !== 'undefined') {
|
83 |
+
data = jqXHR['responseXML'];
|
84 |
+
}
|
85 |
+
|
86 |
+
if (error) {
|
87 |
+
error(data, textStatus, jqXHR, errorThrown);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
);
|
92 |
+
};
|
93 |
+
|
94 |
+
AjawAjaxAction.prototype.prepareRequestParams = function(params) {
|
95 |
+
if (params === null) {
|
96 |
+
params = {};
|
97 |
+
}
|
98 |
+
|
99 |
+
params['action'] = this.action;
|
100 |
+
if (this.nonce !== null) {
|
101 |
+
params['_ajax_nonce'] = this.nonce;
|
102 |
+
}
|
103 |
+
return params;
|
104 |
+
};
|
105 |
+
|
106 |
+
return AjawAjaxAction;
|
107 |
+
}());
|
108 |
+
|
109 |
+
AjawV1.actionRegistry = (function() {
|
110 |
+
var actions = {};
|
111 |
+
|
112 |
+
return {
|
113 |
+
/**
|
114 |
+
*
|
115 |
+
* @param {String} actionName
|
116 |
+
* @return {AjawAjaxAction}
|
117 |
+
*/
|
118 |
+
get: function(actionName) {
|
119 |
+
if (actions.hasOwnProperty(actionName)) {
|
120 |
+
return actions[actionName];
|
121 |
+
}
|
122 |
+
return null;
|
123 |
+
},
|
124 |
+
|
125 |
+
add: function(actionName, properties) {
|
126 |
+
actions[actionName] = new AjawV1.AjaxAction(actionName, properties);
|
127 |
+
}
|
128 |
+
}
|
129 |
+
})();
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Get a registered action wrapper.
|
133 |
+
*
|
134 |
+
* @param {string} action
|
135 |
+
* @return {AjawAjaxAction|null}
|
136 |
+
*/
|
137 |
+
AjawV1.getAction = function(action) {
|
138 |
+
return this.actionRegistry.get(action);
|
139 |
+
};
|
css/_dashicons.scss
ADDED
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
This file was automatically generated from /wp-includes/css/dashicons.css.
|
3 |
+
Last update: 2017-06-07T16:55:55+00:00
|
4 |
+
*/
|
5 |
+
.dashicons-menu:before { content: "\f333" !important; }
|
6 |
+
.dashicons-admin-site:before { content: "\f319" !important; }
|
7 |
+
.dashicons-admin-media:before { content: "\f104" !important; }
|
8 |
+
.dashicons-admin-page:before { content: "\f105" !important; }
|
9 |
+
.dashicons-admin-comments:before { content: "\f101" !important; }
|
10 |
+
.dashicons-admin-appearance:before { content: "\f100" !important; }
|
11 |
+
.dashicons-admin-plugins:before { content: "\f106" !important; }
|
12 |
+
.dashicons-admin-users:before { content: "\f110" !important; }
|
13 |
+
.dashicons-admin-tools:before { content: "\f107" !important; }
|
14 |
+
.dashicons-admin-settings:before { content: "\f108" !important; }
|
15 |
+
.dashicons-admin-network:before { content: "\f112" !important; }
|
16 |
+
.dashicons-admin-generic:before { content: "\f111" !important; }
|
17 |
+
.dashicons-admin-home:before { content: "\f102" !important; }
|
18 |
+
.dashicons-admin-collapse:before { content: "\f148" !important; }
|
19 |
+
.dashicons-filter:before { content: "\f536" !important; }
|
20 |
+
.dashicons-admin-customizer:before { content: "\f540" !important; }
|
21 |
+
.dashicons-admin-multisite:before { content: "\f541" !important; }
|
22 |
+
.dashicons-admin-links:before, .dashicons-format-links:before { content: "\f103" !important; }
|
23 |
+
.dashicons-admin-post:before, .dashicons-format-standard:before { content: "\f109" !important; }
|
24 |
+
.dashicons-format-image:before { content: "\f128" !important; }
|
25 |
+
.dashicons-format-gallery:before { content: "\f161" !important; }
|
26 |
+
.dashicons-format-audio:before { content: "\f127" !important; }
|
27 |
+
.dashicons-format-video:before { content: "\f126" !important; }
|
28 |
+
.dashicons-format-chat:before { content: "\f125" !important; }
|
29 |
+
.dashicons-format-status:before { content: "\f130" !important; }
|
30 |
+
.dashicons-format-aside:before { content: "\f123" !important; }
|
31 |
+
.dashicons-format-quote:before { content: "\f122" !important; }
|
32 |
+
.dashicons-welcome-write-blog:before, .dashicons-welcome-edit-page:before { content: "\f119" !important; }
|
33 |
+
.dashicons-welcome-add-page:before { content: "\f133" !important; }
|
34 |
+
.dashicons-welcome-view-site:before { content: "\f115" !important; }
|
35 |
+
.dashicons-welcome-widgets-menus:before { content: "\f116" !important; }
|
36 |
+
.dashicons-welcome-comments:before { content: "\f117" !important; }
|
37 |
+
.dashicons-welcome-learn-more:before { content: "\f118" !important; }
|
38 |
+
.dashicons-image-crop:before { content: "\f165" !important; }
|
39 |
+
.dashicons-image-rotate:before { content: "\f531" !important; }
|
40 |
+
.dashicons-image-rotate-left:before { content: "\f166" !important; }
|
41 |
+
.dashicons-image-rotate-right:before { content: "\f167" !important; }
|
42 |
+
.dashicons-image-flip-vertical:before { content: "\f168" !important; }
|
43 |
+
.dashicons-image-flip-horizontal:before { content: "\f169" !important; }
|
44 |
+
.dashicons-image-filter:before { content: "\f533" !important; }
|
45 |
+
.dashicons-undo:before { content: "\f171" !important; }
|
46 |
+
.dashicons-redo:before { content: "\f172" !important; }
|
47 |
+
.dashicons-editor-ul:before { content: "\f203" !important; }
|
48 |
+
.dashicons-editor-ol:before { content: "\f204" !important; }
|
49 |
+
.dashicons-editor-quote:before { content: "\f205" !important; }
|
50 |
+
.dashicons-editor-alignleft:before { content: "\f206" !important; }
|
51 |
+
.dashicons-editor-aligncenter:before { content: "\f207" !important; }
|
52 |
+
.dashicons-editor-alignright:before { content: "\f208" !important; }
|
53 |
+
.dashicons-editor-insertmore:before { content: "\f209" !important; }
|
54 |
+
.dashicons-editor-spellcheck:before { content: "\f210" !important; }
|
55 |
+
.dashicons-editor-distractionfree:before, .dashicons-editor-expand:before { content: "\f211" !important; }
|
56 |
+
.dashicons-editor-contract:before { content: "\f506" !important; }
|
57 |
+
.dashicons-editor-kitchensink:before { content: "\f212" !important; }
|
58 |
+
.dashicons-editor-underline:before { content: "\f213" !important; }
|
59 |
+
.dashicons-editor-justify:before { content: "\f214" !important; }
|
60 |
+
.dashicons-editor-textcolor:before { content: "\f215" !important; }
|
61 |
+
.dashicons-editor-paste-word:before { content: "\f216" !important; }
|
62 |
+
.dashicons-editor-paste-text:before { content: "\f217" !important; }
|
63 |
+
.dashicons-editor-removeformatting:before { content: "\f218" !important; }
|
64 |
+
.dashicons-editor-video:before { content: "\f219" !important; }
|
65 |
+
.dashicons-editor-customchar:before { content: "\f220" !important; }
|
66 |
+
.dashicons-editor-outdent:before { content: "\f221" !important; }
|
67 |
+
.dashicons-editor-indent:before { content: "\f222" !important; }
|
68 |
+
.dashicons-editor-help:before { content: "\f223" !important; }
|
69 |
+
.dashicons-editor-strikethrough:before { content: "\f224" !important; }
|
70 |
+
.dashicons-editor-unlink:before { content: "\f225" !important; }
|
71 |
+
.dashicons-editor-rtl:before { content: "\f320" !important; }
|
72 |
+
.dashicons-editor-break:before { content: "\f474" !important; }
|
73 |
+
.dashicons-editor-code:before { content: "\f475" !important; }
|
74 |
+
.dashicons-editor-paragraph:before { content: "\f476" !important; }
|
75 |
+
.dashicons-editor-table:before { content: "\f535" !important; }
|
76 |
+
.dashicons-align-left:before { content: "\f135" !important; }
|
77 |
+
.dashicons-align-right:before { content: "\f136" !important; }
|
78 |
+
.dashicons-align-center:before { content: "\f134" !important; }
|
79 |
+
.dashicons-align-none:before { content: "\f138" !important; }
|
80 |
+
.dashicons-lock:before { content: "\f160" !important; }
|
81 |
+
.dashicons-unlock:before { content: "\f528" !important; }
|
82 |
+
.dashicons-calendar:before { content: "\f145" !important; }
|
83 |
+
.dashicons-calendar-alt:before { content: "\f508" !important; }
|
84 |
+
.dashicons-visibility:before { content: "\f177" !important; }
|
85 |
+
.dashicons-hidden:before { content: "\f530" !important; }
|
86 |
+
.dashicons-post-status:before { content: "\f173" !important; }
|
87 |
+
.dashicons-edit:before { content: "\f464" !important; }
|
88 |
+
.dashicons-post-trash:before, .dashicons-trash:before { content: "\f182" !important; }
|
89 |
+
.dashicons-sticky:before { content: "\f537" !important; }
|
90 |
+
.dashicons-external:before { content: "\f504" !important; }
|
91 |
+
.dashicons-leftright:before { content: "\f229" !important; }
|
92 |
+
.dashicons-sort:before { content: "\f156" !important; }
|
93 |
+
.dashicons-randomize:before { content: "\f503" !important; }
|
94 |
+
.dashicons-list-view:before { content: "\f163" !important; }
|
95 |
+
.dashicons-exerpt-view:before, .dashicons-excerpt-view:before { content: "\f164" !important; }
|
96 |
+
.dashicons-grid-view:before { content: "\f509" !important; }
|
97 |
+
.dashicons-move:before { content: "\f545" !important; }
|
98 |
+
.dashicons-hammer:before { content: "\f308" !important; }
|
99 |
+
.dashicons-art:before { content: "\f309" !important; }
|
100 |
+
.dashicons-migrate:before { content: "\f310" !important; }
|
101 |
+
.dashicons-performance:before { content: "\f311" !important; }
|
102 |
+
.dashicons-universal-access:before { content: "\f483" !important; }
|
103 |
+
.dashicons-universal-access-alt:before { content: "\f507" !important; }
|
104 |
+
.dashicons-tickets:before { content: "\f486" !important; }
|
105 |
+
.dashicons-nametag:before { content: "\f484" !important; }
|
106 |
+
.dashicons-clipboard:before { content: "\f481" !important; }
|
107 |
+
.dashicons-heart:before { content: "\f487" !important; }
|
108 |
+
.dashicons-megaphone:before { content: "\f488" !important; }
|
109 |
+
.dashicons-schedule:before { content: "\f489" !important; }
|
110 |
+
.dashicons-wordpress:before { content: "\f120" !important; }
|
111 |
+
.dashicons-wordpress-alt:before { content: "\f324" !important; }
|
112 |
+
.dashicons-pressthis:before { content: "\f157" !important; }
|
113 |
+
.dashicons-update:before { content: "\f463" !important; }
|
114 |
+
.dashicons-screenoptions:before { content: "\f180" !important; }
|
115 |
+
.dashicons-cart:before { content: "\f174" !important; }
|
116 |
+
.dashicons-feedback:before { content: "\f175" !important; }
|
117 |
+
.dashicons-cloud:before { content: "\f176" !important; }
|
118 |
+
.dashicons-translation:before { content: "\f326" !important; }
|
119 |
+
.dashicons-tag:before { content: "\f323" !important; }
|
120 |
+
.dashicons-category:before { content: "\f318" !important; }
|
121 |
+
.dashicons-archive:before { content: "\f480" !important; }
|
122 |
+
.dashicons-tagcloud:before { content: "\f479" !important; }
|
123 |
+
.dashicons-text:before { content: "\f478" !important; }
|
124 |
+
.dashicons-media-archive:before { content: "\f501" !important; }
|
125 |
+
.dashicons-media-audio:before { content: "\f500" !important; }
|
126 |
+
.dashicons-media-code:before { content: "\f499" !important; }
|
127 |
+
.dashicons-media-default:before { content: "\f498" !important; }
|
128 |
+
.dashicons-media-document:before { content: "\f497" !important; }
|
129 |
+
.dashicons-media-interactive:before { content: "\f496" !important; }
|
130 |
+
.dashicons-media-spreadsheet:before { content: "\f495" !important; }
|
131 |
+
.dashicons-media-text:before { content: "\f491" !important; }
|
132 |
+
.dashicons-media-video:before { content: "\f490" !important; }
|
133 |
+
.dashicons-playlist-audio:before { content: "\f492" !important; }
|
134 |
+
.dashicons-playlist-video:before { content: "\f493" !important; }
|
135 |
+
.dashicons-controls-play:before { content: "\f522" !important; }
|
136 |
+
.dashicons-controls-pause:before { content: "\f523" !important; }
|
137 |
+
.dashicons-controls-forward:before { content: "\f519" !important; }
|
138 |
+
.dashicons-controls-skipforward:before { content: "\f517" !important; }
|
139 |
+
.dashicons-controls-back:before { content: "\f518" !important; }
|
140 |
+
.dashicons-controls-skipback:before { content: "\f516" !important; }
|
141 |
+
.dashicons-controls-repeat:before { content: "\f515" !important; }
|
142 |
+
.dashicons-controls-volumeon:before { content: "\f521" !important; }
|
143 |
+
.dashicons-controls-volumeoff:before { content: "\f520" !important; }
|
144 |
+
.dashicons-yes:before { content: "\f147" !important; }
|
145 |
+
.dashicons-no:before { content: "\f158" !important; }
|
146 |
+
.dashicons-no-alt:before { content: "\f335" !important; }
|
147 |
+
.dashicons-plus:before { content: "\f132" !important; }
|
148 |
+
.dashicons-plus-alt:before { content: "\f502" !important; }
|
149 |
+
.dashicons-plus-alt2:before { content: "\f543" !important; }
|
150 |
+
.dashicons-minus:before { content: "\f460" !important; }
|
151 |
+
.dashicons-dismiss:before { content: "\f153" !important; }
|
152 |
+
.dashicons-marker:before { content: "\f159" !important; }
|
153 |
+
.dashicons-star-filled:before { content: "\f155" !important; }
|
154 |
+
.dashicons-star-half:before { content: "\f459" !important; }
|
155 |
+
.dashicons-star-empty:before { content: "\f154" !important; }
|
156 |
+
.dashicons-flag:before { content: "\f227" !important; }
|
157 |
+
.dashicons-info:before { content: "\f348" !important; }
|
158 |
+
.dashicons-warning:before { content: "\f534" !important; }
|
159 |
+
.dashicons-share:before { content: "\f237" !important; }
|
160 |
+
.dashicons-share1:before { content: "\f237" !important; }
|
161 |
+
.dashicons-share-alt:before { content: "\f240" !important; }
|
162 |
+
.dashicons-share-alt2:before { content: "\f242" !important; }
|
163 |
+
.dashicons-twitter:before { content: "\f301" !important; }
|
164 |
+
.dashicons-rss:before { content: "\f303" !important; }
|
165 |
+
.dashicons-email:before { content: "\f465" !important; }
|
166 |
+
.dashicons-email-alt:before { content: "\f466" !important; }
|
167 |
+
.dashicons-facebook:before { content: "\f304" !important; }
|
168 |
+
.dashicons-facebook-alt:before { content: "\f305" !important; }
|
169 |
+
.dashicons-networking:before { content: "\f325" !important; }
|
170 |
+
.dashicons-googleplus:before { content: "\f462" !important; }
|
171 |
+
.dashicons-location:before { content: "\f230" !important; }
|
172 |
+
.dashicons-location-alt:before { content: "\f231" !important; }
|
173 |
+
.dashicons-camera:before { content: "\f306" !important; }
|
174 |
+
.dashicons-images-alt:before { content: "\f232" !important; }
|
175 |
+
.dashicons-images-alt2:before { content: "\f233" !important; }
|
176 |
+
.dashicons-video-alt:before { content: "\f234" !important; }
|
177 |
+
.dashicons-video-alt2:before { content: "\f235" !important; }
|
178 |
+
.dashicons-video-alt3:before { content: "\f236" !important; }
|
179 |
+
.dashicons-vault:before { content: "\f178" !important; }
|
180 |
+
.dashicons-shield:before { content: "\f332" !important; }
|
181 |
+
.dashicons-shield-alt:before { content: "\f334" !important; }
|
182 |
+
.dashicons-sos:before { content: "\f468" !important; }
|
183 |
+
.dashicons-search:before { content: "\f179" !important; }
|
184 |
+
.dashicons-slides:before { content: "\f181" !important; }
|
185 |
+
.dashicons-analytics:before { content: "\f183" !important; }
|
186 |
+
.dashicons-chart-pie:before { content: "\f184" !important; }
|
187 |
+
.dashicons-chart-bar:before { content: "\f185" !important; }
|
188 |
+
.dashicons-chart-line:before { content: "\f238" !important; }
|
189 |
+
.dashicons-chart-area:before { content: "\f239" !important; }
|
190 |
+
.dashicons-groups:before { content: "\f307" !important; }
|
191 |
+
.dashicons-businessman:before { content: "\f338" !important; }
|
192 |
+
.dashicons-id:before { content: "\f336" !important; }
|
193 |
+
.dashicons-id-alt:before { content: "\f337" !important; }
|
194 |
+
.dashicons-products:before { content: "\f312" !important; }
|
195 |
+
.dashicons-awards:before { content: "\f313" !important; }
|
196 |
+
.dashicons-forms:before { content: "\f314" !important; }
|
197 |
+
.dashicons-testimonial:before { content: "\f473" !important; }
|
198 |
+
.dashicons-portfolio:before { content: "\f322" !important; }
|
199 |
+
.dashicons-book:before { content: "\f330" !important; }
|
200 |
+
.dashicons-book-alt:before { content: "\f331" !important; }
|
201 |
+
.dashicons-download:before { content: "\f316" !important; }
|
202 |
+
.dashicons-upload:before { content: "\f317" !important; }
|
203 |
+
.dashicons-backup:before { content: "\f321" !important; }
|
204 |
+
.dashicons-clock:before { content: "\f469" !important; }
|
205 |
+
.dashicons-lightbulb:before { content: "\f339" !important; }
|
206 |
+
.dashicons-microphone:before { content: "\f482" !important; }
|
207 |
+
.dashicons-desktop:before { content: "\f472" !important; }
|
208 |
+
.dashicons-laptop:before { content: "\f547" !important; }
|
209 |
+
.dashicons-tablet:before { content: "\f471" !important; }
|
210 |
+
.dashicons-smartphone:before { content: "\f470" !important; }
|
211 |
+
.dashicons-phone:before { content: "\f525" !important; }
|
212 |
+
.dashicons-smiley:before { content: "\f328" !important; }
|
213 |
+
.dashicons-index-card:before { content: "\f510" !important; }
|
214 |
+
.dashicons-carrot:before { content: "\f511" !important; }
|
215 |
+
.dashicons-building:before { content: "\f512" !important; }
|
216 |
+
.dashicons-store:before { content: "\f513" !important; }
|
217 |
+
.dashicons-album:before { content: "\f514" !important; }
|
218 |
+
.dashicons-palmtree:before { content: "\f527" !important; }
|
219 |
+
.dashicons-tickets-alt:before { content: "\f524" !important; }
|
220 |
+
.dashicons-money:before { content: "\f526" !important; }
|
221 |
+
.dashicons-thumbs-up:before { content: "\f529" !important; }
|
222 |
+
.dashicons-thumbs-down:before { content: "\f542" !important; }
|
223 |
+
.dashicons-layout:before { content: "\f538" !important; }
|
224 |
+
.dashicons-paperclip:before { content: "\f546" !important; }
|
css/force-dashicons.css
ADDED
@@ -0,0 +1,460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
Forcibly set menu icons to the selected custom Dashicons.
|
3 |
+
|
4 |
+
Problem:
|
5 |
+
Some plugins use CSS to assign icons to their admin menu items. Users want to change the icons.
|
6 |
+
In many cases, simply changing the icon URL doesn't work because the plugin CSS overrides it.
|
7 |
+
|
8 |
+
Workaround:
|
9 |
+
Add more CSS that overrides the icon styles that were set by other plugins.
|
10 |
+
*/
|
11 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon {
|
12 |
+
/*
|
13 |
+
This file was automatically generated from /wp-includes/css/dashicons.css.
|
14 |
+
Last update: 2017-06-07T16:55:55+00:00
|
15 |
+
*/ }
|
16 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon > .wp-menu-image::before {
|
17 |
+
font-family: "dashicons", sans-serif !important;
|
18 |
+
font-size: 20px !important; }
|
19 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-menu:before {
|
20 |
+
content: "\f333" !important; }
|
21 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-site:before {
|
22 |
+
content: "\f319" !important; }
|
23 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-media:before {
|
24 |
+
content: "\f104" !important; }
|
25 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-page:before {
|
26 |
+
content: "\f105" !important; }
|
27 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-comments:before {
|
28 |
+
content: "\f101" !important; }
|
29 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-appearance:before {
|
30 |
+
content: "\f100" !important; }
|
31 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-plugins:before {
|
32 |
+
content: "\f106" !important; }
|
33 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-users:before {
|
34 |
+
content: "\f110" !important; }
|
35 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-tools:before {
|
36 |
+
content: "\f107" !important; }
|
37 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-settings:before {
|
38 |
+
content: "\f108" !important; }
|
39 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-network:before {
|
40 |
+
content: "\f112" !important; }
|
41 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-generic:before {
|
42 |
+
content: "\f111" !important; }
|
43 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-home:before {
|
44 |
+
content: "\f102" !important; }
|
45 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-collapse:before {
|
46 |
+
content: "\f148" !important; }
|
47 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-filter:before {
|
48 |
+
content: "\f536" !important; }
|
49 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-customizer:before {
|
50 |
+
content: "\f540" !important; }
|
51 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-multisite:before {
|
52 |
+
content: "\f541" !important; }
|
53 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-links:before, #adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-links:before {
|
54 |
+
content: "\f103" !important; }
|
55 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-admin-post:before, #adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-standard:before {
|
56 |
+
content: "\f109" !important; }
|
57 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-image:before {
|
58 |
+
content: "\f128" !important; }
|
59 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-gallery:before {
|
60 |
+
content: "\f161" !important; }
|
61 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-audio:before {
|
62 |
+
content: "\f127" !important; }
|
63 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-video:before {
|
64 |
+
content: "\f126" !important; }
|
65 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-chat:before {
|
66 |
+
content: "\f125" !important; }
|
67 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-status:before {
|
68 |
+
content: "\f130" !important; }
|
69 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-aside:before {
|
70 |
+
content: "\f123" !important; }
|
71 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-format-quote:before {
|
72 |
+
content: "\f122" !important; }
|
73 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-write-blog:before, #adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-edit-page:before {
|
74 |
+
content: "\f119" !important; }
|
75 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-add-page:before {
|
76 |
+
content: "\f133" !important; }
|
77 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-view-site:before {
|
78 |
+
content: "\f115" !important; }
|
79 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-widgets-menus:before {
|
80 |
+
content: "\f116" !important; }
|
81 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-comments:before {
|
82 |
+
content: "\f117" !important; }
|
83 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-welcome-learn-more:before {
|
84 |
+
content: "\f118" !important; }
|
85 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-crop:before {
|
86 |
+
content: "\f165" !important; }
|
87 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-rotate:before {
|
88 |
+
content: "\f531" !important; }
|
89 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-rotate-left:before {
|
90 |
+
content: "\f166" !important; }
|
91 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-rotate-right:before {
|
92 |
+
content: "\f167" !important; }
|
93 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-flip-vertical:before {
|
94 |
+
content: "\f168" !important; }
|
95 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-flip-horizontal:before {
|
96 |
+
content: "\f169" !important; }
|
97 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-image-filter:before {
|
98 |
+
content: "\f533" !important; }
|
99 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-undo:before {
|
100 |
+
content: "\f171" !important; }
|
101 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-redo:before {
|
102 |
+
content: "\f172" !important; }
|
103 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-ul:before {
|
104 |
+
content: "\f203" !important; }
|
105 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-ol:before {
|
106 |
+
content: "\f204" !important; }
|
107 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-quote:before {
|
108 |
+
content: "\f205" !important; }
|
109 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-alignleft:before {
|
110 |
+
content: "\f206" !important; }
|
111 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-aligncenter:before {
|
112 |
+
content: "\f207" !important; }
|
113 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-alignright:before {
|
114 |
+
content: "\f208" !important; }
|
115 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-insertmore:before {
|
116 |
+
content: "\f209" !important; }
|
117 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-spellcheck:before {
|
118 |
+
content: "\f210" !important; }
|
119 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-distractionfree:before, #adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-expand:before {
|
120 |
+
content: "\f211" !important; }
|
121 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-contract:before {
|
122 |
+
content: "\f506" !important; }
|
123 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-kitchensink:before {
|
124 |
+
content: "\f212" !important; }
|
125 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-underline:before {
|
126 |
+
content: "\f213" !important; }
|
127 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-justify:before {
|
128 |
+
content: "\f214" !important; }
|
129 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-textcolor:before {
|
130 |
+
content: "\f215" !important; }
|
131 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-paste-word:before {
|
132 |
+
content: "\f216" !important; }
|
133 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-paste-text:before {
|
134 |
+
content: "\f217" !important; }
|
135 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-removeformatting:before {
|
136 |
+
content: "\f218" !important; }
|
137 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-video:before {
|
138 |
+
content: "\f219" !important; }
|
139 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-customchar:before {
|
140 |
+
content: "\f220" !important; }
|
141 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-outdent:before {
|
142 |
+
content: "\f221" !important; }
|
143 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-indent:before {
|
144 |
+
content: "\f222" !important; }
|
145 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-help:before {
|
146 |
+
content: "\f223" !important; }
|
147 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-strikethrough:before {
|
148 |
+
content: "\f224" !important; }
|
149 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-unlink:before {
|
150 |
+
content: "\f225" !important; }
|
151 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-rtl:before {
|
152 |
+
content: "\f320" !important; }
|
153 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-break:before {
|
154 |
+
content: "\f474" !important; }
|
155 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-code:before {
|
156 |
+
content: "\f475" !important; }
|
157 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-paragraph:before {
|
158 |
+
content: "\f476" !important; }
|
159 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-editor-table:before {
|
160 |
+
content: "\f535" !important; }
|
161 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-align-left:before {
|
162 |
+
content: "\f135" !important; }
|
163 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-align-right:before {
|
164 |
+
content: "\f136" !important; }
|
165 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-align-center:before {
|
166 |
+
content: "\f134" !important; }
|
167 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-align-none:before {
|
168 |
+
content: "\f138" !important; }
|
169 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-lock:before {
|
170 |
+
content: "\f160" !important; }
|
171 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-unlock:before {
|
172 |
+
content: "\f528" !important; }
|
173 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-calendar:before {
|
174 |
+
content: "\f145" !important; }
|
175 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-calendar-alt:before {
|
176 |
+
content: "\f508" !important; }
|
177 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-visibility:before {
|
178 |
+
content: "\f177" !important; }
|
179 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-hidden:before {
|
180 |
+
content: "\f530" !important; }
|
181 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-post-status:before {
|
182 |
+
content: "\f173" !important; }
|
183 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-edit:before {
|
184 |
+
content: "\f464" !important; }
|
185 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-post-trash:before, #adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-trash:before {
|
186 |
+
content: "\f182" !important; }
|
187 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-sticky:before {
|
188 |
+
content: "\f537" !important; }
|
189 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-external:before {
|
190 |
+
content: "\f504" !important; }
|
191 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-leftright:before {
|
192 |
+
content: "\f229" !important; }
|
193 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-sort:before {
|
194 |
+
content: "\f156" !important; }
|
195 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-randomize:before {
|
196 |
+
content: "\f503" !important; }
|
197 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-list-view:before {
|
198 |
+
content: "\f163" !important; }
|
199 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-exerpt-view:before, #adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-excerpt-view:before {
|
200 |
+
content: "\f164" !important; }
|
201 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-grid-view:before {
|
202 |
+
content: "\f509" !important; }
|
203 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-move:before {
|
204 |
+
content: "\f545" !important; }
|
205 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-hammer:before {
|
206 |
+
content: "\f308" !important; }
|
207 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-art:before {
|
208 |
+
content: "\f309" !important; }
|
209 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-migrate:before {
|
210 |
+
content: "\f310" !important; }
|
211 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-performance:before {
|
212 |
+
content: "\f311" !important; }
|
213 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-universal-access:before {
|
214 |
+
content: "\f483" !important; }
|
215 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-universal-access-alt:before {
|
216 |
+
content: "\f507" !important; }
|
217 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-tickets:before {
|
218 |
+
content: "\f486" !important; }
|
219 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-nametag:before {
|
220 |
+
content: "\f484" !important; }
|
221 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-clipboard:before {
|
222 |
+
content: "\f481" !important; }
|
223 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-heart:before {
|
224 |
+
content: "\f487" !important; }
|
225 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-megaphone:before {
|
226 |
+
content: "\f488" !important; }
|
227 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-schedule:before {
|
228 |
+
content: "\f489" !important; }
|
229 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-wordpress:before {
|
230 |
+
content: "\f120" !important; }
|
231 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-wordpress-alt:before {
|
232 |
+
content: "\f324" !important; }
|
233 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-pressthis:before {
|
234 |
+
content: "\f157" !important; }
|
235 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-update:before {
|
236 |
+
content: "\f463" !important; }
|
237 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-screenoptions:before {
|
238 |
+
content: "\f180" !important; }
|
239 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-cart:before {
|
240 |
+
content: "\f174" !important; }
|
241 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-feedback:before {
|
242 |
+
content: "\f175" !important; }
|
243 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-cloud:before {
|
244 |
+
content: "\f176" !important; }
|
245 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-translation:before {
|
246 |
+
content: "\f326" !important; }
|
247 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-tag:before {
|
248 |
+
content: "\f323" !important; }
|
249 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-category:before {
|
250 |
+
content: "\f318" !important; }
|
251 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-archive:before {
|
252 |
+
content: "\f480" !important; }
|
253 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-tagcloud:before {
|
254 |
+
content: "\f479" !important; }
|
255 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-text:before {
|
256 |
+
content: "\f478" !important; }
|
257 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-archive:before {
|
258 |
+
content: "\f501" !important; }
|
259 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-audio:before {
|
260 |
+
content: "\f500" !important; }
|
261 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-code:before {
|
262 |
+
content: "\f499" !important; }
|
263 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-default:before {
|
264 |
+
content: "\f498" !important; }
|
265 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-document:before {
|
266 |
+
content: "\f497" !important; }
|
267 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-interactive:before {
|
268 |
+
content: "\f496" !important; }
|
269 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-spreadsheet:before {
|
270 |
+
content: "\f495" !important; }
|
271 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-text:before {
|
272 |
+
content: "\f491" !important; }
|
273 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-media-video:before {
|
274 |
+
content: "\f490" !important; }
|
275 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-playlist-audio:before {
|
276 |
+
content: "\f492" !important; }
|
277 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-playlist-video:before {
|
278 |
+
content: "\f493" !important; }
|
279 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-play:before {
|
280 |
+
content: "\f522" !important; }
|
281 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-pause:before {
|
282 |
+
content: "\f523" !important; }
|
283 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-forward:before {
|
284 |
+
content: "\f519" !important; }
|
285 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-skipforward:before {
|
286 |
+
content: "\f517" !important; }
|
287 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-back:before {
|
288 |
+
content: "\f518" !important; }
|
289 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-skipback:before {
|
290 |
+
content: "\f516" !important; }
|
291 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-repeat:before {
|
292 |
+
content: "\f515" !important; }
|
293 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-volumeon:before {
|
294 |
+
content: "\f521" !important; }
|
295 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-controls-volumeoff:before {
|
296 |
+
content: "\f520" !important; }
|
297 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-yes:before {
|
298 |
+
content: "\f147" !important; }
|
299 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-no:before {
|
300 |
+
content: "\f158" !important; }
|
301 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-no-alt:before {
|
302 |
+
content: "\f335" !important; }
|
303 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-plus:before {
|
304 |
+
content: "\f132" !important; }
|
305 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-plus-alt:before {
|
306 |
+
content: "\f502" !important; }
|
307 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-plus-alt2:before {
|
308 |
+
content: "\f543" !important; }
|
309 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-minus:before {
|
310 |
+
content: "\f460" !important; }
|
311 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-dismiss:before {
|
312 |
+
content: "\f153" !important; }
|
313 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-marker:before {
|
314 |
+
content: "\f159" !important; }
|
315 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-star-filled:before {
|
316 |
+
content: "\f155" !important; }
|
317 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-star-half:before {
|
318 |
+
content: "\f459" !important; }
|
319 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-star-empty:before {
|
320 |
+
content: "\f154" !important; }
|
321 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-flag:before {
|
322 |
+
content: "\f227" !important; }
|
323 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-info:before {
|
324 |
+
content: "\f348" !important; }
|
325 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-warning:before {
|
326 |
+
content: "\f534" !important; }
|
327 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-share:before {
|
328 |
+
content: "\f237" !important; }
|
329 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-share1:before {
|
330 |
+
content: "\f237" !important; }
|
331 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-share-alt:before {
|
332 |
+
content: "\f240" !important; }
|
333 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-share-alt2:before {
|
334 |
+
content: "\f242" !important; }
|
335 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-twitter:before {
|
336 |
+
content: "\f301" !important; }
|
337 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-rss:before {
|
338 |
+
content: "\f303" !important; }
|
339 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-email:before {
|
340 |
+
content: "\f465" !important; }
|
341 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-email-alt:before {
|
342 |
+
content: "\f466" !important; }
|
343 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-facebook:before {
|
344 |
+
content: "\f304" !important; }
|
345 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-facebook-alt:before {
|
346 |
+
content: "\f305" !important; }
|
347 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-networking:before {
|
348 |
+
content: "\f325" !important; }
|
349 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-googleplus:before {
|
350 |
+
content: "\f462" !important; }
|
351 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-location:before {
|
352 |
+
content: "\f230" !important; }
|
353 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-location-alt:before {
|
354 |
+
content: "\f231" !important; }
|
355 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-camera:before {
|
356 |
+
content: "\f306" !important; }
|
357 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-images-alt:before {
|
358 |
+
content: "\f232" !important; }
|
359 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-images-alt2:before {
|
360 |
+
content: "\f233" !important; }
|
361 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-video-alt:before {
|
362 |
+
content: "\f234" !important; }
|
363 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-video-alt2:before {
|
364 |
+
content: "\f235" !important; }
|
365 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-video-alt3:before {
|
366 |
+
content: "\f236" !important; }
|
367 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-vault:before {
|
368 |
+
content: "\f178" !important; }
|
369 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-shield:before {
|
370 |
+
content: "\f332" !important; }
|
371 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-shield-alt:before {
|
372 |
+
content: "\f334" !important; }
|
373 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-sos:before {
|
374 |
+
content: "\f468" !important; }
|
375 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-search:before {
|
376 |
+
content: "\f179" !important; }
|
377 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-slides:before {
|
378 |
+
content: "\f181" !important; }
|
379 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-analytics:before {
|
380 |
+
content: "\f183" !important; }
|
381 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-chart-pie:before {
|
382 |
+
content: "\f184" !important; }
|
383 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-chart-bar:before {
|
384 |
+
content: "\f185" !important; }
|
385 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-chart-line:before {
|
386 |
+
content: "\f238" !important; }
|
387 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-chart-area:before {
|
388 |
+
content: "\f239" !important; }
|
389 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-groups:before {
|
390 |
+
content: "\f307" !important; }
|
391 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-businessman:before {
|
392 |
+
content: "\f338" !important; }
|
393 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-id:before {
|
394 |
+
content: "\f336" !important; }
|
395 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-id-alt:before {
|
396 |
+
content: "\f337" !important; }
|
397 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-products:before {
|
398 |
+
content: "\f312" !important; }
|
399 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-awards:before {
|
400 |
+
content: "\f313" !important; }
|
401 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-forms:before {
|
402 |
+
content: "\f314" !important; }
|
403 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-testimonial:before {
|
404 |
+
content: "\f473" !important; }
|
405 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-portfolio:before {
|
406 |
+
content: "\f322" !important; }
|
407 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-book:before {
|
408 |
+
content: "\f330" !important; }
|
409 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-book-alt:before {
|
410 |
+
content: "\f331" !important; }
|
411 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-download:before {
|
412 |
+
content: "\f316" !important; }
|
413 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-upload:before {
|
414 |
+
content: "\f317" !important; }
|
415 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-backup:before {
|
416 |
+
content: "\f321" !important; }
|
417 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-clock:before {
|
418 |
+
content: "\f469" !important; }
|
419 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-lightbulb:before {
|
420 |
+
content: "\f339" !important; }
|
421 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-microphone:before {
|
422 |
+
content: "\f482" !important; }
|
423 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-desktop:before {
|
424 |
+
content: "\f472" !important; }
|
425 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-laptop:before {
|
426 |
+
content: "\f547" !important; }
|
427 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-tablet:before {
|
428 |
+
content: "\f471" !important; }
|
429 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-smartphone:before {
|
430 |
+
content: "\f470" !important; }
|
431 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-phone:before {
|
432 |
+
content: "\f525" !important; }
|
433 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-smiley:before {
|
434 |
+
content: "\f328" !important; }
|
435 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-index-card:before {
|
436 |
+
content: "\f510" !important; }
|
437 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-carrot:before {
|
438 |
+
content: "\f511" !important; }
|
439 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-building:before {
|
440 |
+
content: "\f512" !important; }
|
441 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-store:before {
|
442 |
+
content: "\f513" !important; }
|
443 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-album:before {
|
444 |
+
content: "\f514" !important; }
|
445 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-palmtree:before {
|
446 |
+
content: "\f527" !important; }
|
447 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-tickets-alt:before {
|
448 |
+
content: "\f524" !important; }
|
449 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-money:before {
|
450 |
+
content: "\f526" !important; }
|
451 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-thumbs-up:before {
|
452 |
+
content: "\f529" !important; }
|
453 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-thumbs-down:before {
|
454 |
+
content: "\f542" !important; }
|
455 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-layout:before {
|
456 |
+
content: "\f538" !important; }
|
457 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon .dashicons-paperclip:before {
|
458 |
+
content: "\f546" !important; }
|
459 |
+
|
460 |
+
/*# sourceMappingURL=force-dashicons.css.map */
|
css/force-dashicons.css.map
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"version": 3,
|
3 |
+
"mappings": "AAAA;;;;;;;;;EASE;AAGF,wDAAyD;ECZzD;;;IAGE;EDUD,iFAA2B;IAC1B,WAAW,EAAE,kCAAkC;IAC/C,SAAS,EAAE,eAAe;ECX5B,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,0FAAkC;IAAE,OAAO,EAAE,kBAAkB;EAC/D,+KAA8D;IAAE,OAAO,EAAE,kBAAkB;EAC3F,iLAAgE;IAAE,OAAO,EAAE,kBAAkB;EAC7F,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,2LAA0E;IAAE,OAAO,EAAE,kBAAkB;EACvG,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,gGAAwC;IAAE,OAAO,EAAE,kBAAkB;EACrE,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,6FAAqC;IAAE,OAAO,EAAE,kBAAkB;EAClE,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,6FAAqC;IAAE,OAAO,EAAE,kBAAkB;EAClE,8FAAsC;IAAE,OAAO,EAAE,kBAAkB;EACnE,gGAAwC;IAAE,OAAO,EAAE,kBAAkB;EACrE,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,6FAAqC;IAAE,OAAO,EAAE,kBAAkB;EAClE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,2LAA0E;IAAE,OAAO,EAAE,kBAAkB;EACvG,0FAAkC;IAAE,OAAO,EAAE,kBAAkB;EAC/D,6FAAqC;IAAE,OAAO,EAAE,kBAAkB;EAClE,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,kGAA0C;IAAE,OAAO,EAAE,kBAAkB;EACvE,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,+FAAuC;IAAE,OAAO,EAAE,kBAAkB;EACpE,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,uKAAsD;IAAE,OAAO,EAAE,kBAAkB;EACnF,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,+KAA8D;IAAE,OAAO,EAAE,kBAAkB;EAC3F,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,8EAAsB;IAAE,OAAO,EAAE,kBAAkB;EACnD,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,+FAAuC;IAAE,OAAO,EAAE,kBAAkB;EACpE,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,8EAAsB;IAAE,OAAO,EAAE,kBAAkB;EACnD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,yFAAiC;IAAE,OAAO,EAAE,kBAAkB;EAC9D,2FAAmC;IAAE,OAAO,EAAE,kBAAkB;EAChE,+FAAuC;IAAE,OAAO,EAAE,kBAAkB;EACpE,wFAAgC;IAAE,OAAO,EAAE,kBAAkB;EAC7D,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,0FAAkC;IAAE,OAAO,EAAE,kBAAkB;EAC/D,4FAAoC;IAAE,OAAO,EAAE,kBAAkB;EACjE,6FAAqC;IAAE,OAAO,EAAE,kBAAkB;EAClE,8EAAsB;IAAE,OAAO,EAAE,kBAAkB;EACnD,6EAAqB;IAAE,OAAO,EAAE,kBAAkB;EAClD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,8EAAsB;IAAE,OAAO,EAAE,kBAAkB;EACnD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,uFAA+B;IAAE,OAAO,EAAE,kBAAkB;EAC5D,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,8EAAsB;IAAE,OAAO,EAAE,kBAAkB;EACnD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,6EAAqB;IAAE,OAAO,EAAE,kBAAkB;EAClD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,+EAAuB;IAAE,OAAO,EAAE,kBAAkB;EACpD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,kFAA0B;IAAE,OAAO,EAAE,kBAAkB;EACvD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,qFAA6B;IAAE,OAAO,EAAE,kBAAkB;EAC1D,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,mFAA2B;IAAE,OAAO,EAAE,kBAAkB;EACxD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,gFAAwB;IAAE,OAAO,EAAE,kBAAkB;EACrD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB;EACzD,sFAA8B;IAAE,OAAO,EAAE,kBAAkB;EAC3D,iFAAyB;IAAE,OAAO,EAAE,kBAAkB;EACtD,oFAA4B;IAAE,OAAO,EAAE,kBAAkB",
|
4 |
+
"sources": ["force-dashicons.scss","_dashicons.scss"],
|
5 |
+
"names": [],
|
6 |
+
"file": "force-dashicons.css"
|
7 |
+
}
|
css/force-dashicons.scss
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
Forcibly set menu icons to the selected custom Dashicons.
|
3 |
+
|
4 |
+
Problem:
|
5 |
+
Some plugins use CSS to assign icons to their admin menu items. Users want to change the icons.
|
6 |
+
In many cases, simply changing the icon URL doesn't work because the plugin CSS overrides it.
|
7 |
+
|
8 |
+
Workaround:
|
9 |
+
Add more CSS that overrides the icon styles that were set by other plugins.
|
10 |
+
*/
|
11 |
+
|
12 |
+
//Artificially increase selector specificity by repeating the ID.
|
13 |
+
#adminmenu#adminmenu#adminmenu a.ame-has-custom-dashicon {
|
14 |
+
& > .wp-menu-image::before {
|
15 |
+
font-family: "dashicons", sans-serif !important;
|
16 |
+
font-size: 20px !important;
|
17 |
+
}
|
18 |
+
|
19 |
+
@import '_dashicons';
|
20 |
+
}
|
css/menu-editor.css
CHANGED
@@ -144,6 +144,9 @@
|
|
144 |
width: 290px;
|
145 |
padding: 3px;
|
146 |
margin: 2px 0 2px 6px; }
|
|
|
|
|
|
|
147 |
|
148 |
.ws_submenu {
|
149 |
min-height: 2em; }
|
@@ -530,8 +533,8 @@ select.ws_dropdown optgroup option {
|
|
530 |
margin-bottom: 0; }
|
531 |
.ws_tool_tab_nav li.ui-tabs-active {
|
532 |
border-color: #dfdfdf;
|
533 |
-
|
534 |
-
|
535 |
.ws_tool_tab_nav a {
|
536 |
text-decoration: none; }
|
537 |
.ws_tool_tab_nav li.ui-tabs-active a {
|
@@ -837,6 +840,9 @@ a#ws-ame-delete-color-preset:hover {
|
|
837 |
-moz-border-radius: 5px;
|
838 |
-webkit-border-radius: 5px;
|
839 |
border-radius: 5px; }
|
|
|
|
|
|
|
840 |
|
841 |
.ui-dialog-titlebar {
|
842 |
display: block;
|
@@ -873,10 +879,6 @@ a#ws-ame-delete-color-preset:hover {
|
|
873 |
/*background-image: url(../images/x-light.png);*/
|
874 |
background-color: #a6c2f5; }
|
875 |
|
876 |
-
.ui-dialog-content {
|
877 |
-
padding: 8px 8px 8px 8px;
|
878 |
-
font-size: 1.1em; }
|
879 |
-
|
880 |
#export_dialog .ws_dialog_panel {
|
881 |
height: 50px; }
|
882 |
|
@@ -1370,6 +1372,17 @@ a#ws-ame-delete-color-preset:hover {
|
|
1370 |
#ws_capability_suggestions .ws_ame_suggested_capability:hover {
|
1371 |
background-color: #d0f2d0; }
|
1372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1373 |
#ws_sidebar_pro_ad {
|
1374 |
min-width: 225px;
|
1375 |
margin-top: 5px;
|
144 |
width: 290px;
|
145 |
padding: 3px;
|
146 |
margin: 2px 0 2px 6px; }
|
147 |
+
body.rtl .ws_container {
|
148 |
+
margin-right: 6px;
|
149 |
+
margin-left: 0; }
|
150 |
|
151 |
.ws_submenu {
|
152 |
min-height: 2em; }
|
533 |
margin-bottom: 0; }
|
534 |
.ws_tool_tab_nav li.ui-tabs-active {
|
535 |
border-color: #dfdfdf;
|
536 |
+
border-bottom-color: #FDFDFD;
|
537 |
+
background: #FDFDFD none; }
|
538 |
.ws_tool_tab_nav a {
|
539 |
text-decoration: none; }
|
540 |
.ws_tool_tab_nav li.ui-tabs-active a {
|
840 |
-moz-border-radius: 5px;
|
841 |
-webkit-border-radius: 5px;
|
842 |
border-radius: 5px; }
|
843 |
+
.ui-dialog .ui-dialog-content {
|
844 |
+
padding: 8px 8px 8px 8px;
|
845 |
+
font-size: 1.1em; }
|
846 |
|
847 |
.ui-dialog-titlebar {
|
848 |
display: block;
|
879 |
/*background-image: url(../images/x-light.png);*/
|
880 |
background-color: #a6c2f5; }
|
881 |
|
|
|
|
|
|
|
|
|
882 |
#export_dialog .ws_dialog_panel {
|
883 |
height: 50px; }
|
884 |
|
1372 |
#ws_capability_suggestions .ws_ame_suggested_capability:hover {
|
1373 |
background-color: #d0f2d0; }
|
1374 |
|
1375 |
+
/*********************************************
|
1376 |
+
Settings page stuff
|
1377 |
+
**********************************************/
|
1378 |
+
#ws_plugin_settings_form figure {
|
1379 |
+
margin-left: 0;
|
1380 |
+
margin-top: 0;
|
1381 |
+
margin-bottom: 1em; }
|
1382 |
+
|
1383 |
+
/*********************************************
|
1384 |
+
Miscellaneous
|
1385 |
+
**********************************************/
|
1386 |
#ws_sidebar_pro_ad {
|
1387 |
min-width: 225px;
|
1388 |
margin-top: 5px;
|
css/menu-editor.scss
CHANGED
@@ -215,6 +215,11 @@ $mainContainerBorderRadius: 0px;
|
|
215 |
|
216 |
padding : $itemPadding;
|
217 |
margin: 2px 0 2px $itemHorizontalMargin;
|
|
|
|
|
|
|
|
|
|
|
218 |
}
|
219 |
|
220 |
.ws_active { }
|
@@ -731,8 +736,8 @@ $activeToolTabBackground: #FDFDFD;
|
|
731 |
|
732 |
li.ui-tabs-active {
|
733 |
border-color: #dfdfdf;
|
734 |
-
background-color: #FDFDFD;
|
735 |
border-bottom-color: $activeToolTabBackground;
|
|
|
736 |
}
|
737 |
|
738 |
a {
|
@@ -1130,6 +1135,11 @@ a#ws-ame-delete-color-preset:hover {
|
|
1130 |
-moz-border-radius: 5px;
|
1131 |
-webkit-border-radius: 5px;
|
1132 |
border-radius: 5px;
|
|
|
|
|
|
|
|
|
|
|
1133 |
}
|
1134 |
|
1135 |
.ui-dialog-titlebar {
|
@@ -1181,11 +1191,6 @@ a#ws-ame-delete-color-preset:hover {
|
|
1181 |
|
1182 |
}
|
1183 |
|
1184 |
-
.ui-dialog-content {
|
1185 |
-
padding: 8px 8px 8px 8px;
|
1186 |
-
font-size: 1.1em;
|
1187 |
-
}
|
1188 |
-
|
1189 |
#export_dialog .ws_dialog_panel {
|
1190 |
height: 50px;
|
1191 |
}
|
@@ -1933,6 +1938,19 @@ $userSelectionPanelPadding: 10px;
|
|
1933 |
}
|
1934 |
}
|
1935 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1936 |
|
1937 |
#ws_sidebar_pro_ad {
|
1938 |
min-width: 225px;
|
215 |
|
216 |
padding : $itemPadding;
|
217 |
margin: 2px 0 2px $itemHorizontalMargin;
|
218 |
+
|
219 |
+
body.rtl & {
|
220 |
+
margin-right: $itemHorizontalMargin;
|
221 |
+
margin-left: 0;
|
222 |
+
}
|
223 |
}
|
224 |
|
225 |
.ws_active { }
|
736 |
|
737 |
li.ui-tabs-active {
|
738 |
border-color: #dfdfdf;
|
|
|
739 |
border-bottom-color: $activeToolTabBackground;
|
740 |
+
background: #FDFDFD none;
|
741 |
}
|
742 |
|
743 |
a {
|
1135 |
-moz-border-radius: 5px;
|
1136 |
-webkit-border-radius: 5px;
|
1137 |
border-radius: 5px;
|
1138 |
+
|
1139 |
+
.ui-dialog-content {
|
1140 |
+
padding: 8px 8px 8px 8px;
|
1141 |
+
font-size: 1.1em;
|
1142 |
+
}
|
1143 |
}
|
1144 |
|
1145 |
.ui-dialog-titlebar {
|
1191 |
|
1192 |
}
|
1193 |
|
|
|
|
|
|
|
|
|
|
|
1194 |
#export_dialog .ws_dialog_panel {
|
1195 |
height: 50px;
|
1196 |
}
|
1938 |
}
|
1939 |
}
|
1940 |
|
1941 |
+
/*********************************************
|
1942 |
+
Settings page stuff
|
1943 |
+
**********************************************/
|
1944 |
+
|
1945 |
+
#ws_plugin_settings_form figure {
|
1946 |
+
margin-left: 0;
|
1947 |
+
margin-top: 0;
|
1948 |
+
margin-bottom: 1em;
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
/*********************************************
|
1952 |
+
Miscellaneous
|
1953 |
+
**********************************************/
|
1954 |
|
1955 |
#ws_sidebar_pro_ad {
|
1956 |
min-width: 225px;
|
css/screen-meta.css
CHANGED
@@ -12,8 +12,8 @@
|
|
12 |
border: 1px solid #ddd;
|
13 |
border-top: none;
|
14 |
background: #fff;
|
15 |
-
-webkit-box-shadow:
|
16 |
-
box-shadow:
|
17 |
}
|
18 |
|
19 |
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
@@ -23,6 +23,7 @@
|
|
23 |
text-decoration: none;
|
24 |
display: block;
|
25 |
min-height: 22px;
|
|
|
26 |
}
|
27 |
|
28 |
#screen-meta-links a.custom-screen-meta-link::after {
|
@@ -35,10 +36,11 @@
|
|
35 |
border-color: #0a0;
|
36 |
}
|
37 |
|
38 |
-
#ws-pro-version-notice a.show-settings {
|
39 |
font-weight: bold;
|
40 |
color: #DEFFD8;
|
41 |
text-shadow: none;
|
|
|
42 |
}
|
43 |
|
44 |
#ws-pro-version-notice a.show-settings:hover {
|
12 |
border: 1px solid #ddd;
|
13 |
border-top: none;
|
14 |
background: #fff;
|
15 |
+
-webkit-box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1);
|
16 |
+
box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1);
|
17 |
}
|
18 |
|
19 |
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
23 |
text-decoration: none;
|
24 |
display: block;
|
25 |
min-height: 22px;
|
26 |
+
box-shadow: 0 1px 0 #cccccc;
|
27 |
}
|
28 |
|
29 |
#screen-meta-links a.custom-screen-meta-link::after {
|
36 |
border-color: #0a0;
|
37 |
}
|
38 |
|
39 |
+
#screen-meta-links #ws-pro-version-notice a.show-settings {
|
40 |
font-weight: bold;
|
41 |
color: #DEFFD8;
|
42 |
text-shadow: none;
|
43 |
+
box-shadow: none;
|
44 |
}
|
45 |
|
46 |
#ws-pro-version-notice a.show-settings:hover {
|
css/style-modern-one.css
CHANGED
@@ -39,16 +39,16 @@ $hiddenItemBorder: #f1acb1;
|
|
39 |
-moz-border-radius: 0;
|
40 |
border-radius: 0; }
|
41 |
|
42 |
-
.ws_edit_link {
|
43 |
background: transparent;
|
44 |
color: #A0A5AA;
|
45 |
text-align: center;
|
46 |
border-radius: 0; }
|
47 |
-
.ws_edit_link::before {
|
48 |
content: "\f140";
|
49 |
font: normal 20px/1 dashicons;
|
50 |
display: block; }
|
51 |
-
.ws_edit_link:hover {
|
52 |
color: #777; }
|
53 |
|
54 |
.ws_edit_link.ws_edit_link_expanded::before {
|
@@ -147,6 +147,30 @@ $hiddenItemBorder: #f1acb1;
|
|
147 |
border-bottom: 1px solid #dfdfdf;
|
148 |
height: auto;
|
149 |
padding: 0; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
|
151 |
.ui-dialog-title {
|
152 |
color: #444444;
|
@@ -156,28 +180,4 @@ $hiddenItemBorder: #f1acb1;
|
|
156 |
padding: 0 36px 0 8px;
|
157 |
display: block; }
|
158 |
|
159 |
-
.ui-dialog-titlebar-close {
|
160 |
-
background: none;
|
161 |
-
border-style: none;
|
162 |
-
color: #666;
|
163 |
-
cursor: pointer;
|
164 |
-
padding: 0;
|
165 |
-
position: absolute;
|
166 |
-
top: 0;
|
167 |
-
right: 0;
|
168 |
-
width: 36px;
|
169 |
-
height: 36px;
|
170 |
-
text-align: center; }
|
171 |
-
|
172 |
-
.ui-dialog-titlebar-close::before {
|
173 |
-
font: normal 20px/36px 'dashicons';
|
174 |
-
content: '\f158';
|
175 |
-
vertical-align: middle;
|
176 |
-
width: 36px;
|
177 |
-
height: 36px; }
|
178 |
-
|
179 |
-
.ui-dialog-titlebar-close:hover {
|
180 |
-
background: transparent none;
|
181 |
-
color: #2ea2cc; }
|
182 |
-
|
183 |
/*# sourceMappingURL=style-modern-one.css.map */
|
39 |
-moz-border-radius: 0;
|
40 |
border-radius: 0; }
|
41 |
|
42 |
+
a.ws_edit_link {
|
43 |
background: transparent;
|
44 |
color: #A0A5AA;
|
45 |
text-align: center;
|
46 |
border-radius: 0; }
|
47 |
+
a.ws_edit_link::before {
|
48 |
content: "\f140";
|
49 |
font: normal 20px/1 dashicons;
|
50 |
display: block; }
|
51 |
+
a.ws_edit_link:hover {
|
52 |
color: #777; }
|
53 |
|
54 |
.ws_edit_link.ws_edit_link_expanded::before {
|
147 |
border-bottom: 1px solid #dfdfdf;
|
148 |
height: auto;
|
149 |
padding: 0; }
|
150 |
+
.ui-dialog-titlebar .ui-dialog-titlebar-close {
|
151 |
+
background: none;
|
152 |
+
border-style: none;
|
153 |
+
color: #666;
|
154 |
+
cursor: pointer;
|
155 |
+
padding: 0;
|
156 |
+
margin: 0;
|
157 |
+
position: absolute;
|
158 |
+
top: 0;
|
159 |
+
right: 0;
|
160 |
+
width: 36px;
|
161 |
+
height: 36px;
|
162 |
+
text-align: center; }
|
163 |
+
.ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon, .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-button-text {
|
164 |
+
display: none; }
|
165 |
+
.ui-dialog-titlebar .ui-dialog-titlebar-close::before {
|
166 |
+
font: normal 20px/36px 'dashicons';
|
167 |
+
content: '\f158';
|
168 |
+
vertical-align: middle;
|
169 |
+
width: 36px;
|
170 |
+
height: 36px; }
|
171 |
+
.ui-dialog-titlebar .ui-dialog-titlebar-close:hover {
|
172 |
+
background: transparent none;
|
173 |
+
color: #2ea2cc; }
|
174 |
|
175 |
.ui-dialog-title {
|
176 |
color: #444444;
|
180 |
padding: 0 36px 0 8px;
|
181 |
display: block; }
|
182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
/*# sourceMappingURL=style-modern-one.css.map */
|
css/style-modern-one.scss
CHANGED
@@ -62,6 +62,8 @@ $mainContainerWidth: $itemWidth + $columnPadding * 2;
|
|
62 |
}
|
63 |
|
64 |
.ws_flag_container {
|
|
|
|
|
65 |
.ws_custom_actor_permissions_flag,
|
66 |
.ws_custom_flag {
|
67 |
display: none;
|
@@ -85,7 +87,7 @@ $mainContainerWidth: $itemWidth + $columnPadding * 2;
|
|
85 |
border-radius: 0;
|
86 |
}
|
87 |
|
88 |
-
.ws_edit_link {
|
89 |
background: transparent;
|
90 |
color: #A0A5AA;
|
91 |
|
@@ -295,45 +297,50 @@ $mainContainerWidth: $itemWidth + $columnPadding * 2;
|
|
295 |
border-bottom: 1px solid #dfdfdf;
|
296 |
height: auto;
|
297 |
padding: 0;
|
298 |
-
}
|
299 |
|
300 |
-
.ui-dialog-
|
301 |
-
|
302 |
-
|
303 |
-
font-weight: 600;
|
304 |
-
line-height: 36px;
|
305 |
|
306 |
-
|
307 |
-
|
308 |
-
|
|
|
|
|
|
|
|
|
309 |
|
310 |
-
|
311 |
-
|
312 |
-
border-style: none;
|
313 |
|
314 |
-
|
315 |
-
cursor: pointer;
|
316 |
-
padding: 0;
|
317 |
-
position: absolute;
|
318 |
-
top: 0;
|
319 |
-
right: 0;
|
320 |
|
321 |
-
|
322 |
-
|
|
|
|
|
323 |
|
324 |
-
|
325 |
-
|
|
|
326 |
|
327 |
-
|
328 |
-
|
329 |
-
|
|
|
330 |
|
331 |
-
|
332 |
-
|
333 |
-
|
|
|
334 |
}
|
335 |
|
336 |
-
.ui-dialog-
|
337 |
-
|
338 |
-
|
|
|
|
|
|
|
|
|
|
|
339 |
}
|
62 |
}
|
63 |
|
64 |
.ws_flag_container {
|
65 |
+
//Hide low-importance flags. It's debatable (knowing which roles have custom permissions is useful
|
66 |
+
//when debugging configuration issues), but lets leave them hidden for now.
|
67 |
.ws_custom_actor_permissions_flag,
|
68 |
.ws_custom_flag {
|
69 |
display: none;
|
87 |
border-radius: 0;
|
88 |
}
|
89 |
|
90 |
+
a.ws_edit_link {
|
91 |
background: transparent;
|
92 |
color: #A0A5AA;
|
93 |
|
297 |
border-bottom: 1px solid #dfdfdf;
|
298 |
height: auto;
|
299 |
padding: 0;
|
|
|
300 |
|
301 |
+
.ui-dialog-titlebar-close {
|
302 |
+
background: none;
|
303 |
+
border-style: none;
|
|
|
|
|
304 |
|
305 |
+
color: #666;
|
306 |
+
cursor: pointer;
|
307 |
+
padding: 0;
|
308 |
+
margin: 0;
|
309 |
+
position: absolute;
|
310 |
+
top: 0;
|
311 |
+
right: 0;
|
312 |
|
313 |
+
width: 36px;
|
314 |
+
height: 36px;
|
|
|
315 |
|
316 |
+
text-align: center;
|
|
|
|
|
|
|
|
|
|
|
317 |
|
318 |
+
.ui-icon, .ui-button-text {
|
319 |
+
display: none;
|
320 |
+
}
|
321 |
+
}
|
322 |
|
323 |
+
.ui-dialog-titlebar-close::before {
|
324 |
+
font: normal 20px/36px 'dashicons';
|
325 |
+
content: '\f158';
|
326 |
|
327 |
+
vertical-align: middle;
|
328 |
+
width: 36px;
|
329 |
+
height: 36px;
|
330 |
+
}
|
331 |
|
332 |
+
.ui-dialog-titlebar-close:hover {
|
333 |
+
background: transparent none;
|
334 |
+
color: #2ea2cc;
|
335 |
+
}
|
336 |
}
|
337 |
|
338 |
+
.ui-dialog-title {
|
339 |
+
color: #444444;
|
340 |
+
font-size: 18px;
|
341 |
+
font-weight: 600;
|
342 |
+
line-height: 36px;
|
343 |
+
|
344 |
+
padding: 0 36px 0 8px;
|
345 |
+
display: block;
|
346 |
}
|
includes/ajax-helper.php
DELETED
@@ -1,178 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
class ameAjaxAction {
|
3 |
-
protected $action = '';
|
4 |
-
protected $handler;
|
5 |
-
|
6 |
-
protected $requiredParameters = array();
|
7 |
-
protected $defaultParameters = array();
|
8 |
-
protected $checkAuthorization;
|
9 |
-
|
10 |
-
public function __construct($uniqueActionName = null, $handler = null) {
|
11 |
-
if (isset($uniqueActionName)) {
|
12 |
-
$this->action = $uniqueActionName;
|
13 |
-
}
|
14 |
-
if (isset($handler)) {
|
15 |
-
$this->handler = $handler;
|
16 |
-
}
|
17 |
-
|
18 |
-
if (empty($this->action)) {
|
19 |
-
throw new LogicException(sprintf(
|
20 |
-
'AJAX action name is missing. You must either pass it to the %1$s constructor '
|
21 |
-
. 'or give the %1$s::$action property a valid default value.',
|
22 |
-
get_class($this)
|
23 |
-
));
|
24 |
-
}
|
25 |
-
|
26 |
-
$hookName = 'wp_ajax_' . $this->action;
|
27 |
-
if (has_action($hookName)) {
|
28 |
-
throw new RuntimeException(sprintf('The action name "%s" is already in use.', $this->action));
|
29 |
-
}
|
30 |
-
add_action('wp_ajax_' . $this->action, array($this, '_processRequest'));
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* @access protected
|
35 |
-
*/
|
36 |
-
public function _processRequest() {
|
37 |
-
//Check nonce.
|
38 |
-
if (!check_ajax_referer($this->action, false, false)) {
|
39 |
-
$this->exitWithError(
|
40 |
-
'Access denied. Invalid nonce',
|
41 |
-
'invalid_nonce'
|
42 |
-
);
|
43 |
-
}
|
44 |
-
|
45 |
-
$method = filter_input(INPUT_SERVER, 'REQUEST_METHOD');
|
46 |
-
|
47 |
-
//Retrieve request parameters.
|
48 |
-
$params = array();
|
49 |
-
if ($method === 'GET') {
|
50 |
-
$params = $_GET;
|
51 |
-
} else if ($method === 'POST') {
|
52 |
-
$params = $_POST;
|
53 |
-
}
|
54 |
-
|
55 |
-
//Remove magic quotes. WordPress applies them in wp-settings.php.
|
56 |
-
if (did_action('sanitize_comment_cookies') && function_exists('wp_magic_quotes')) {
|
57 |
-
$params = wp_unslash($params);
|
58 |
-
}
|
59 |
-
|
60 |
-
//Verify that all of the required parameters are present. Empty strings are not allowed.
|
61 |
-
foreach($this->requiredParameters as $name) {
|
62 |
-
if (!isset($params[$name]) || ($params[$name] === '')) {
|
63 |
-
$this->exitWithError(
|
64 |
-
sprintf('The required parameter "%s" is missing or empty.', $name),
|
65 |
-
'missing_required_parameter'
|
66 |
-
);
|
67 |
-
}
|
68 |
-
}
|
69 |
-
|
70 |
-
//Apply defaults.
|
71 |
-
$params = array_merge($this->defaultParameters, $params);
|
72 |
-
|
73 |
-
//Run custom authorization checks.
|
74 |
-
$isAllowed = $this->isUserAuthorized($params);
|
75 |
-
if ($isAllowed instanceof WP_Error) {
|
76 |
-
$this->exitWithError($isAllowed->get_error_message(), $isAllowed->get_error_code());
|
77 |
-
} else if (!$isAllowed) {
|
78 |
-
$this->exitWithError(
|
79 |
-
sprintf('You don\'t have permission to perform the "%s" action.', $this->action),
|
80 |
-
'access_denied'
|
81 |
-
);
|
82 |
-
}
|
83 |
-
|
84 |
-
//Finally, perform the action.
|
85 |
-
$response = $this->handleAction($params);
|
86 |
-
if ($response instanceof WP_Error) {
|
87 |
-
$this->exitWithError($response->get_error_message(), $response->get_error_code());
|
88 |
-
}
|
89 |
-
$this->outputResponse($response);
|
90 |
-
exit;
|
91 |
-
}
|
92 |
-
|
93 |
-
protected function handleAction($params) {
|
94 |
-
if (is_callable($this->handler)) {
|
95 |
-
return call_user_func($this->handler, $params);
|
96 |
-
} else {
|
97 |
-
$this->exitWithError(
|
98 |
-
sprintf(
|
99 |
-
'There is no request handler assigned to the "%1$s" action. '
|
100 |
-
. 'Either override the %3$s method or set %2$s::$handler to a valid callback.',
|
101 |
-
$this->action,
|
102 |
-
__CLASS__,
|
103 |
-
__METHOD__
|
104 |
-
),
|
105 |
-
'missing_ajax_handler'
|
106 |
-
);
|
107 |
-
return null;
|
108 |
-
}
|
109 |
-
}
|
110 |
-
|
111 |
-
protected function exitWithError($message, $code = null) {
|
112 |
-
if ( ($message === '') && !empty($code) ) {
|
113 |
-
$message = $code;
|
114 |
-
}
|
115 |
-
|
116 |
-
$response = array(
|
117 |
-
'error' => array(
|
118 |
-
'message' => $message,
|
119 |
-
'code' => $code,
|
120 |
-
)
|
121 |
-
);
|
122 |
-
$this->outputResponse($response);
|
123 |
-
exit;
|
124 |
-
}
|
125 |
-
|
126 |
-
protected function outputResponse($response) {
|
127 |
-
header('Content-Type: application/json');
|
128 |
-
echo json_encode($response);
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Check if the current user is authorized to perform this action.
|
133 |
-
*
|
134 |
-
* @param array $params Request parameters.
|
135 |
-
* @return bool|WP_Error
|
136 |
-
*/
|
137 |
-
protected function isUserAuthorized($params) {
|
138 |
-
if (isset($this->checkAuthorization)) {
|
139 |
-
return call_user_func($this->checkAuthorization, $params);
|
140 |
-
}
|
141 |
-
return true;
|
142 |
-
}
|
143 |
-
|
144 |
-
//Just a bunch of fluent setters.
|
145 |
-
//-------------------------------
|
146 |
-
|
147 |
-
/**
|
148 |
-
* @param string ...$param One or more parameter names.
|
149 |
-
* @return $this
|
150 |
-
*/
|
151 |
-
public function setRequiredParams($param) {
|
152 |
-
$params = func_get_args();
|
153 |
-
if (count($params) === 1 && is_array($params[0])) {
|
154 |
-
$params = $params[0];
|
155 |
-
}
|
156 |
-
|
157 |
-
$this->requiredParameters = $params;
|
158 |
-
return $this;
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* @param callable $handler
|
163 |
-
* @return $this
|
164 |
-
*/
|
165 |
-
public function setHandler($handler) {
|
166 |
-
$this->handler = $handler;
|
167 |
-
return $this;
|
168 |
-
}
|
169 |
-
|
170 |
-
/**
|
171 |
-
* @param callable $callback
|
172 |
-
* @return $this
|
173 |
-
*/
|
174 |
-
public function setAuthCallback($callback) {
|
175 |
-
$this->checkAuthorization = $callback;
|
176 |
-
return $this;
|
177 |
-
}
|
178 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/auto-versioning.php
CHANGED
@@ -54,14 +54,17 @@ class AutoVersioning {
|
|
54 |
}
|
55 |
|
56 |
private static function guess_filename_from_url($url) {
|
57 |
-
$url_mappings =
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
65 |
|
66 |
$filename = null;
|
67 |
foreach($url_mappings as $root_url => $directory) {
|
54 |
}
|
55 |
|
56 |
private static function guess_filename_from_url($url) {
|
57 |
+
static $url_mappings = null;
|
58 |
+
if ( $url_mappings === null ) {
|
59 |
+
$url_mappings = array(
|
60 |
+
plugins_url() => WP_PLUGIN_DIR,
|
61 |
+
plugins_url('', WPMU_PLUGIN_DIR . '/dummy') => WPMU_PLUGIN_DIR,
|
62 |
+
get_stylesheet_directory_uri() => get_stylesheet_directory(),
|
63 |
+
get_template_directory_uri() => get_template_directory(),
|
64 |
+
content_url() => WP_CONTENT_DIR,
|
65 |
+
site_url('/' . WPINC) => ABSPATH . WPINC,
|
66 |
+
);
|
67 |
+
}
|
68 |
|
69 |
$filename = null;
|
70 |
foreach($url_mappings as $root_url => $directory) {
|
includes/editor-page.php
CHANGED
@@ -33,10 +33,30 @@ $hide_button_extra_tooltip = 'When "All" is selected, this will hide the menu fr
|
|
33 |
|
34 |
//Output the "Upgrade to Pro" message
|
35 |
if ( !apply_filters('admin_menu_editor_is_pro', false) ){
|
|
|
|
|
36 |
?>
|
37 |
<script type="text/javascript">
|
38 |
(function($){
|
39 |
-
$('#screen-meta-links')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
'<div id="ws-pro-version-notice" class="custom-screen-meta-link-wrap">' +
|
41 |
'<a href="http://adminmenueditor.com/upgrade-to-pro/?utm_source=Admin%2BMenu%2BEditor%2Bfree&utm_medium=text_link&utm_content=top_upgrade_link&utm_campaign=Plugins" id="ws-pro-version-notice-link" class="show-settings custom-screen-meta-link" target="_blank" title="View Pro version details">Upgrade to Pro</a>' +
|
42 |
'</div>'
|
33 |
|
34 |
//Output the "Upgrade to Pro" message
|
35 |
if ( !apply_filters('admin_menu_editor_is_pro', false) ){
|
36 |
+
//Pseudo-randomly decide whether to show the VAC link.
|
37 |
+
$is_vac_link_visible = (hexdec( substr(md5(get_site_url() . 'vc3'), -3) ) % 100) <= 20; //20% of sites will see it.
|
38 |
?>
|
39 |
<script type="text/javascript">
|
40 |
(function($){
|
41 |
+
var screenLinks = $('#screen-meta-links'),
|
42 |
+
showVacLink = (<?php echo $is_vac_link_visible ? 'true' : 'false' ?>);
|
43 |
+
|
44 |
+
if (showVacLink) {
|
45 |
+
screenLinks.append(
|
46 |
+
$('<div>', {
|
47 |
+
'class' : 'custom-screen-meta-link-wrap',
|
48 |
+
'id' : 'ws-visual-admin-customizer-ad'
|
49 |
+
}).append($('<a>', {
|
50 |
+
'href' : 'https://wordpress.org/plugins/visual-admin-customizer/',
|
51 |
+
'class' : 'show-settings custom-screen-meta-link',
|
52 |
+
'title' : 'A free plugin for customizing the WordPress admin interface',
|
53 |
+
'target': '_blank',
|
54 |
+
'text' : 'Visual Admin Customizer'
|
55 |
+
}))
|
56 |
+
);
|
57 |
+
}
|
58 |
+
|
59 |
+
screenLinks.append(
|
60 |
'<div id="ws-pro-version-notice" class="custom-screen-meta-link-wrap">' +
|
61 |
'<a href="http://adminmenueditor.com/upgrade-to-pro/?utm_source=Admin%2BMenu%2BEditor%2Bfree&utm_medium=text_link&utm_content=top_upgrade_link&utm_campaign=Plugins" id="ws-pro-version-notice-link" class="show-settings custom-screen-meta-link" target="_blank" title="View Pro version details">Upgrade to Pro</a>' +
|
62 |
'</div>'
|
includes/generate-menu-dashicons.php
CHANGED
@@ -16,6 +16,8 @@ $dashiconsStylesheet = ABSPATH . WPINC . '/css/dashicons.css';
|
|
16 |
|
17 |
$icons = array();
|
18 |
|
|
|
|
|
19 |
$ignoreIcons = array('dashboard', 'editor-bold', 'editor-italic');
|
20 |
$ignoreIcons = array_flip($ignoreIcons);
|
21 |
|
@@ -33,10 +35,10 @@ foreach($blocks as $block) {
|
|
33 |
|
34 |
if ( preg_match('/\.dashicons-(?P<name>[\w\-]+):before/', $selector->getSelector(), $matches) ) {
|
35 |
$name = $matches['name'];
|
|
|
36 |
|
37 |
-
//
|
38 |
-
|
39 |
-
if ( preg_match('/^(admin|arrow)-/', $name) ) {
|
40 |
break;
|
41 |
}
|
42 |
|
@@ -57,12 +59,28 @@ foreach($blocks as $block) {
|
|
57 |
}
|
58 |
}
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
break;
|
62 |
}
|
63 |
}
|
64 |
}
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
?>
|
67 |
<div class="wrap">
|
68 |
<h2>Dashicons to Menu Icons</h2>
|
16 |
|
17 |
$icons = array();
|
18 |
|
19 |
+
$allDashiconDefinitions = '';
|
20 |
+
|
21 |
$ignoreIcons = array('dashboard', 'editor-bold', 'editor-italic');
|
22 |
$ignoreIcons = array_flip($ignoreIcons);
|
23 |
|
35 |
|
36 |
if ( preg_match('/\.dashicons-(?P<name>[\w\-]+):before/', $selector->getSelector(), $matches) ) {
|
37 |
$name = $matches['name'];
|
38 |
+
$char = null;
|
39 |
|
40 |
+
//The arrow icons aren't really suitable as menu icons.
|
41 |
+
if ( preg_match('/^(arrow)-/', $name) ) {
|
|
|
42 |
break;
|
43 |
}
|
44 |
|
59 |
}
|
60 |
}
|
61 |
|
62 |
+
if (isset($char) && ($name !== 'before')) {
|
63 |
+
$allDashiconDefinitions .= sprintf(
|
64 |
+
'%s { content: "\%s" !important; }',
|
65 |
+
implode(', ', $selectors),
|
66 |
+
$char
|
67 |
+
) . "\n";
|
68 |
+
}
|
69 |
|
70 |
break;
|
71 |
}
|
72 |
}
|
73 |
}
|
74 |
|
75 |
+
$dashiconComment = sprintf(
|
76 |
+
"/*\nThis file was automatically generated from /wp-includes/css/dashicons.css.\nLast update: %s\n*/",
|
77 |
+
date('c')
|
78 |
+
);
|
79 |
+
file_put_contents(
|
80 |
+
dirname(__FILE__) . '/../css/_dashicons.scss',
|
81 |
+
$dashiconComment . "\n" . $allDashiconDefinitions
|
82 |
+
);
|
83 |
+
|
84 |
?>
|
85 |
<div class="wrap">
|
86 |
<h2>Dashicons to Menu Icons</h2>
|
includes/menu-editor-core.php
CHANGED
@@ -15,7 +15,7 @@ require $thisDirectory . '/ame-utils.php';
|
|
15 |
require $thisDirectory . '/menu-item.php';
|
16 |
require $thisDirectory . '/menu.php';
|
17 |
require $thisDirectory . '/auto-versioning.php';
|
18 |
-
require $thisDirectory . '
|
19 |
require $thisDirectory . '/module.php';
|
20 |
|
21 |
class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
@@ -141,6 +141,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
141 |
//When to show submenu icons.
|
142 |
'submenu_icons_enabled' => 'if_custom', //"never", "if_custom" or "always".
|
143 |
|
|
|
|
|
|
|
144 |
//Menu editor UI colour scheme. "Classic" is the old blue/yellow scheme, and "wp-grey" is more WP-like.
|
145 |
'ui_colour_scheme' => 'classic',
|
146 |
|
@@ -157,6 +160,15 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
157 |
|
158 |
//Verbosity level of menu permission errors.
|
159 |
'error_verbosity' => self::VERBOSITY_NORMAL,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
);
|
161 |
$this->serialize_with_json = false; //(Don't) store the options in JSON format
|
162 |
|
@@ -241,6 +253,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
241 |
//Tell first-time users where they can find the plugin settings page.
|
242 |
add_action('all_admin_notices', array($this, 'display_plugin_menu_notice'));
|
243 |
|
|
|
|
|
|
|
244 |
//Workaround for buggy plugins that unintentionally remove user roles.
|
245 |
/** @see WPMenuEditor::get_user_roles */
|
246 |
add_action('set_current_user', array($this, 'update_current_user_cache'), 1, 0); //Run before most plugins.
|
@@ -257,34 +272,6 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
257 |
add_action('admin_menu_editor-display_header', array($this, 'display_settings_page_header'));
|
258 |
add_action('admin_menu_editor-display_footer', array($this, 'display_settings_page_footer'));
|
259 |
|
260 |
-
//Modules
|
261 |
-
include dirname(__FILE__) . '/../modules/actor-selector/actor-selector.php';
|
262 |
-
new ameActorSelector($this);
|
263 |
-
|
264 |
-
include dirname(__FILE__) . '/../modules/plugin-visibility/plugin-visibility.php';
|
265 |
-
new amePluginVisibility($this);
|
266 |
-
|
267 |
-
$proModuleDirectory = AME_ROOT_DIR . '/extras/modules';
|
268 |
-
if ( @is_dir($proModuleDirectory) ) {
|
269 |
-
//The widget module requires PHP 5.3.
|
270 |
-
if (
|
271 |
-
version_compare(phpversion(), '5.3', '>=')
|
272 |
-
&& is_file($proModuleDirectory . '/dashboard-widget-editor/load.php')
|
273 |
-
) {
|
274 |
-
require_once $proModuleDirectory . '/dashboard-widget-editor/load.php';
|
275 |
-
new ameWidgetEditor($this);
|
276 |
-
}
|
277 |
-
|
278 |
-
if ( is_file($proModuleDirectory . '/super-users/super-users.php') ) {
|
279 |
-
require $proModuleDirectory . '/super-users/super-users.php';
|
280 |
-
new ameSuperUsers($this);
|
281 |
-
}
|
282 |
-
}
|
283 |
-
|
284 |
-
//Set up the tabs for the menu editor page.
|
285 |
-
$this->tabs = apply_filters('admin_menu_editor-tabs', array( 'editor' => 'Admin Menu', ));
|
286 |
-
//The "Settings" tab is always last.
|
287 |
-
$this->tabs['settings'] = 'Settings';
|
288 |
}
|
289 |
|
290 |
function init_finish() {
|
@@ -327,6 +314,20 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
327 |
if ( $this->options['security_logging_enabled'] ) {
|
328 |
add_action('admin_notices', array($this, 'display_security_log'));
|
329 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
}
|
331 |
|
332 |
/**
|
@@ -423,6 +424,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
423 |
$this->apply_woocommerce_compat_fix();
|
424 |
//Compatibility fix for WordPress Mu Domain Mapping.
|
425 |
$this->apply_wpmu_domain_mapping_fix();
|
|
|
|
|
426 |
//As of WP 3.5, the "Links" menu is hidden by default.
|
427 |
if ( !current_user_can('manage_links') ) {
|
428 |
$this->remove_link_manager_menus();
|
@@ -495,6 +498,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
495 |
add_action('in_admin_header', array($this, 'replace_wp_menu'), $ozh_adminmenu_priority - 1);
|
496 |
add_action('in_admin_header', array($this, 'restore_wp_menu'), $ozh_adminmenu_priority + 1);
|
497 |
}
|
|
|
|
|
498 |
}
|
499 |
}
|
500 |
|
@@ -517,6 +522,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
517 |
list($menu, $submenu) = $this->filter_menu($menu, $submenu);
|
518 |
$this->user_cap_cache_enabled = false;
|
519 |
|
|
|
520 |
return $parent_file;
|
521 |
}
|
522 |
|
@@ -644,16 +650,15 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
644 |
return array($menu, $submenu);
|
645 |
}
|
646 |
|
|
|
|
|
|
|
|
|
|
|
|
|
647 |
|
648 |
-
|
649 |
-
|
650 |
-
*
|
651 |
-
* @return void
|
652 |
-
*/
|
653 |
-
function enqueue_scripts() {
|
654 |
-
//Optimization: Remove wp-emoji.js from the plugin page. wpEmoji makes DOM manipulation slow because
|
655 |
-
//it tracks *all* DOM changes using MutationObserver.
|
656 |
-
remove_action('admin_print_scripts', 'print_emoji_detection_script');
|
657 |
|
658 |
//jQuery JSON plugin
|
659 |
wp_register_auto_versioned_script('jquery-json', plugins_url('js/jquery.json.js', $this->plugin_file), array('jquery'));
|
@@ -666,20 +671,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
666 |
//jQuery cookie plugin
|
667 |
wp_register_auto_versioned_script('jquery-cookie', plugins_url('js/jquery.biscuit.js', $this->plugin_file), array('jquery'));
|
668 |
|
669 |
-
//Lodash library
|
670 |
-
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
|
671 |
//Knockout
|
672 |
wp_register_auto_versioned_script('knockout', plugins_url('js/knockout.js', $this->plugin_file));
|
673 |
|
674 |
-
//Move admin notices (e.g. "Settings saved") below editor tabs.
|
675 |
-
//This is a separate script because it has to run after common.js which is loaded in the page footer.
|
676 |
-
wp_enqueue_auto_versioned_script(
|
677 |
-
'ame-editor-tab-fix',
|
678 |
-
plugins_url('js/editor-tab-fix.js', $this->plugin_file),
|
679 |
-
array('jquery', 'common'),
|
680 |
-
true
|
681 |
-
);
|
682 |
-
|
683 |
//Actor manager.
|
684 |
wp_register_auto_versioned_script(
|
685 |
'ame-actor-manager',
|
@@ -687,6 +681,43 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
687 |
array('ame-lodash')
|
688 |
);
|
689 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
690 |
//Modules
|
691 |
wp_register_auto_versioned_script(
|
692 |
'ame-access-editor',
|
@@ -696,6 +727,29 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
696 |
|
697 |
//Let extras register their scripts.
|
698 |
do_action('admin_menu_editor-register_scripts');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
699 |
|
700 |
//Editor's scripts
|
701 |
$editor_dependencies = array(
|
@@ -714,55 +768,24 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
714 |
do_action('admin_menu_editor-enqueue_scripts-' . $this->current_tab);
|
715 |
|
716 |
//Actors (roles and users) are used in the permissions UI, so we need to pass them along.
|
|
|
717 |
$actors = array();
|
718 |
-
$roles = array();
|
719 |
|
720 |
$wp_roles = ameRoleUtils::get_roles();
|
721 |
foreach($wp_roles->roles as $role_id => $role) {
|
722 |
$actors['role:' . $role_id] = $role['name'];
|
723 |
-
$role['capabilities'] = $this->castValuesToBool($role['capabilities']);
|
724 |
-
$roles[$role_id] = $role;
|
725 |
}
|
726 |
|
727 |
if ( is_multisite() && is_super_admin() ) {
|
728 |
$actors['special:super_admin'] = 'Super Admin';
|
729 |
}
|
730 |
|
731 |
-
//Known users.
|
732 |
-
$users = array();
|
733 |
$current_user = wp_get_current_user();
|
734 |
-
|
735 |
-
$visible_users = isset($this->options['visible_users']) ? $this->options['visible_users'] : array();
|
736 |
-
$logins_to_include = $visible_users;
|
737 |
-
|
738 |
-
//Always include the current user.
|
739 |
-
$logins_to_include[] = $current_user->get('user_login');
|
740 |
-
$logins_to_include = array_unique($logins_to_include);
|
741 |
-
|
742 |
-
//Load user details.
|
743 |
-
foreach($logins_to_include as $login) {
|
744 |
-
$user = get_user_by('login', $login);
|
745 |
-
if ( !empty($user) ) {
|
746 |
-
$users[$login] = $this->user_to_property_map($user);
|
747 |
-
}
|
748 |
-
}
|
749 |
-
|
750 |
-
//Compatibility workaround: Get the real roles of the current user even if other plugins corrupt the list.
|
751 |
-
$users[$current_user->get('user_login')]['roles'] = array_values($this->get_user_roles($current_user));
|
752 |
-
|
753 |
$actors['user:' . $current_user->get('user_login')] = sprintf(
|
754 |
'Current user (%s)',
|
755 |
$current_user->get('user_login')
|
756 |
);
|
757 |
|
758 |
-
$actor_data = array(
|
759 |
-
'roles' => $roles,
|
760 |
-
'users' => $users,
|
761 |
-
'isMultisite' => is_multisite(),
|
762 |
-
'capPower' => $this->load_cap_power(),
|
763 |
-
);
|
764 |
-
wp_localize_script('ame-actor-manager', 'wsAmeActorData', $actor_data);
|
765 |
-
|
766 |
//Add only certain scripts to the settings sub-section.
|
767 |
if ( $this->is_settings_page() ) {
|
768 |
wp_enqueue_script('jquery-qtip');
|
@@ -1003,6 +1026,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1003 |
$previous_custom_menu = $this->load_custom_menu();
|
1004 |
$this->update_wpml_strings($previous_custom_menu, $custom_menu);
|
1005 |
|
|
|
|
|
|
|
|
|
1006 |
if ( $this->should_use_site_specific_menu() ) {
|
1007 |
$site_specific_options = get_option($this->option_name);
|
1008 |
if ( !is_array($site_specific_options) ) {
|
@@ -1077,6 +1104,41 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1077 |
return current_user_can($capability);
|
1078 |
}
|
1079 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1080 |
|
1081 |
/**
|
1082 |
* Apply the custom page title, if any.
|
@@ -1278,6 +1340,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1278 |
//Now we have some items marked as missing, and some items in lookup arrays
|
1279 |
//that are not marked as used. Lets remove the missing items from the tree.
|
1280 |
$tree = ameMenu::remove_missing_items($tree);
|
|
|
1281 |
|
1282 |
//Lets merge in the unused items.
|
1283 |
$max_menu_position = !empty($positions_by_template) ? max($positions_by_template) : 100;
|
@@ -1640,6 +1703,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1640 |
}
|
1641 |
}
|
1642 |
|
|
|
|
|
|
|
|
|
1643 |
//WPML support: Translate only custom titles. See further below.
|
1644 |
$hasCustomMenuTitle = isset($item['menu_title']);
|
1645 |
|
@@ -1944,6 +2011,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
1944 |
$menu['granted_capabilities'] = $capFilter->clean_up($menu['granted_capabilities']);
|
1945 |
}
|
1946 |
|
|
|
|
|
|
|
1947 |
//Save the custom menu
|
1948 |
$this->set_custom_menu($menu);
|
1949 |
|
@@ -2041,6 +2111,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2041 |
}
|
2042 |
}
|
2043 |
|
|
|
|
|
|
|
2044 |
//Where to put new or unused menu items.
|
2045 |
if ( !empty($this->post['unused_item_position']) ) {
|
2046 |
$unused_item_position = strval($this->post['unused_item_position']);
|
@@ -2059,6 +2132,17 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2059 |
}
|
2060 |
}
|
2061 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2062 |
$this->save_options();
|
2063 |
wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url()));
|
2064 |
}
|
@@ -2077,8 +2161,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2077 |
);
|
2078 |
|
2079 |
//Build a tree struct. for the default menu
|
2080 |
-
$
|
2081 |
-
$default_menu = ameMenu::load_array($default_tree);
|
2082 |
|
2083 |
//Is there a custom menu?
|
2084 |
if (!empty($this->merged_custom_menu)){
|
@@ -2126,6 +2209,34 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2126 |
require dirname(__FILE__) . '/editor-page.php';
|
2127 |
}
|
2128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2129 |
/**
|
2130 |
* Display the header of the "Menu Editor" page.
|
2131 |
* This includes the page heading and tab list.
|
@@ -2181,6 +2292,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2181 |
$settings_page_url = $this->get_settings_page_url();
|
2182 |
/** @noinspection PhpUnusedLocalVariableInspection */
|
2183 |
$editor_page_url = admin_url($this->settings_link);
|
|
|
|
|
2184 |
|
2185 |
require dirname(__FILE__) . '/settings-page.php';
|
2186 |
}
|
@@ -2926,6 +3039,19 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
2926 |
array(),
|
2927 |
'20140630-3'
|
2928 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2929 |
}
|
2930 |
|
2931 |
/**
|
@@ -3210,6 +3336,35 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
3210 |
}
|
3211 |
}
|
3212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3213 |
/**
|
3214 |
* As of WP 3.5, the Links Manager is hidden by default. It's only visible if the user has existing links
|
3215 |
* or they choose to enable it by installing the Links Manager plugin.
|
@@ -3502,6 +3657,112 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
|
|
3502 |
return $cap_power;
|
3503 |
}
|
3504 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3505 |
} //class
|
3506 |
|
3507 |
|
@@ -3584,6 +3845,8 @@ class ameMenuTemplateBuilder {
|
|
3584 |
}
|
3585 |
|
3586 |
$templateId = ameMenuItem::template_id($item);
|
|
|
|
|
3587 |
$this->templates[$templateId] = array(
|
3588 |
'name' => $name,
|
3589 |
'used' => false,
|
15 |
require $thisDirectory . '/menu-item.php';
|
16 |
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 {
|
141 |
//When to show submenu icons.
|
142 |
'submenu_icons_enabled' => 'if_custom', //"never", "if_custom" or "always".
|
143 |
|
144 |
+
//Enable/disable CSS workaround that helps override menu icons set by other plugins.
|
145 |
+
'force_custom_dashicons' => true,
|
146 |
+
|
147 |
//Menu editor UI colour scheme. "Classic" is the old blue/yellow scheme, and "wp-grey" is more WP-like.
|
148 |
'ui_colour_scheme' => 'classic',
|
149 |
|
160 |
|
161 |
//Verbosity level of menu permission errors.
|
162 |
'error_verbosity' => self::VERBOSITY_NORMAL,
|
163 |
+
|
164 |
+
//Enable/disable menu configuration compression. Enabling it makes the DB row much smaller,
|
165 |
+
//but adds decompression overhead to very admin page.
|
166 |
+
'compress_custom_menu' => false,
|
167 |
+
|
168 |
+
//Which modules are active or inactive. Format: ['module-id' => true/false].
|
169 |
+
'is_active_module' => array(
|
170 |
+
'highlight-new-menus' => false,
|
171 |
+
),
|
172 |
);
|
173 |
$this->serialize_with_json = false; //(Don't) store the options in JSON format
|
174 |
|
253 |
//Tell first-time users where they can find the plugin settings page.
|
254 |
add_action('all_admin_notices', array($this, 'display_plugin_menu_notice'));
|
255 |
|
256 |
+
//Reset plugin access if the only allowed user gets deleted or their ID changes.
|
257 |
+
add_action('wp_login', array($this, 'maybe_reset_plugin_access'), 10, 2);
|
258 |
+
|
259 |
//Workaround for buggy plugins that unintentionally remove user roles.
|
260 |
/** @see WPMenuEditor::get_user_roles */
|
261 |
add_action('set_current_user', array($this, 'update_current_user_cache'), 1, 0); //Run before most plugins.
|
272 |
add_action('admin_menu_editor-display_header', array($this, 'display_settings_page_header'));
|
273 |
add_action('admin_menu_editor-display_footer', array($this, 'display_settings_page_footer'));
|
274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
}
|
276 |
|
277 |
function init_finish() {
|
314 |
if ( $this->options['security_logging_enabled'] ) {
|
315 |
add_action('admin_notices', array($this, 'display_security_log'));
|
316 |
}
|
317 |
+
|
318 |
+
//Modules
|
319 |
+
foreach($this->get_active_modules() as $module) {
|
320 |
+
/** @noinspection PhpIncludeInspection */
|
321 |
+
include ($module['path']);
|
322 |
+
if ( !empty($module['className']) ) {
|
323 |
+
new $module['className']($this);
|
324 |
+
}
|
325 |
+
}
|
326 |
+
|
327 |
+
//Set up the tabs for the menu editor page.
|
328 |
+
$this->tabs = apply_filters('admin_menu_editor-tabs', array( 'editor' => 'Admin Menu', ));
|
329 |
+
//The "Settings" tab is always last.
|
330 |
+
$this->tabs['settings'] = 'Settings';
|
331 |
}
|
332 |
|
333 |
/**
|
424 |
$this->apply_woocommerce_compat_fix();
|
425 |
//Compatibility fix for WordPress Mu Domain Mapping.
|
426 |
$this->apply_wpmu_domain_mapping_fix();
|
427 |
+
//Compatibility fix for Divi Training.
|
428 |
+
$this->apply_divi_training_fix();
|
429 |
//As of WP 3.5, the "Links" menu is hidden by default.
|
430 |
if ( !current_user_can('manage_links') ) {
|
431 |
$this->remove_link_manager_menus();
|
498 |
add_action('in_admin_header', array($this, 'replace_wp_menu'), $ozh_adminmenu_priority - 1);
|
499 |
add_action('in_admin_header', array($this, 'restore_wp_menu'), $ozh_adminmenu_priority + 1);
|
500 |
}
|
501 |
+
} else {
|
502 |
+
do_action('admin_menu_editor-menu_replacement_skipped');
|
503 |
}
|
504 |
}
|
505 |
|
522 |
list($menu, $submenu) = $this->filter_menu($menu, $submenu);
|
523 |
$this->user_cap_cache_enabled = false;
|
524 |
|
525 |
+
do_action('admin_menu_editor-menu_replaced');
|
526 |
return $parent_file;
|
527 |
}
|
528 |
|
650 |
return array($menu, $submenu);
|
651 |
}
|
652 |
|
653 |
+
public function register_base_dependencies() {
|
654 |
+
static $done = false;
|
655 |
+
if ( $done ) {
|
656 |
+
return;
|
657 |
+
}
|
658 |
+
$done = true;
|
659 |
|
660 |
+
//Lodash library
|
661 |
+
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
662 |
|
663 |
//jQuery JSON plugin
|
664 |
wp_register_auto_versioned_script('jquery-json', plugins_url('js/jquery.json.js', $this->plugin_file), array('jquery'));
|
671 |
//jQuery cookie plugin
|
672 |
wp_register_auto_versioned_script('jquery-cookie', plugins_url('js/jquery.biscuit.js', $this->plugin_file), array('jquery'));
|
673 |
|
|
|
|
|
674 |
//Knockout
|
675 |
wp_register_auto_versioned_script('knockout', plugins_url('js/knockout.js', $this->plugin_file));
|
676 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
677 |
//Actor manager.
|
678 |
wp_register_auto_versioned_script(
|
679 |
'ame-actor-manager',
|
681 |
array('ame-lodash')
|
682 |
);
|
683 |
|
684 |
+
$roles = array();
|
685 |
+
|
686 |
+
$wp_roles = ameRoleUtils::get_roles();
|
687 |
+
foreach($wp_roles->roles as $role_id => $role) {
|
688 |
+
$role['capabilities'] = $this->castValuesToBool($role['capabilities']);
|
689 |
+
$roles[$role_id] = $role;
|
690 |
+
}
|
691 |
+
|
692 |
+
//Known users.
|
693 |
+
$users = array();
|
694 |
+
$current_user = wp_get_current_user();
|
695 |
+
$logins_to_include = apply_filters('admin_menu_editor-users_to_load', array());
|
696 |
+
|
697 |
+
//Always include the current user.
|
698 |
+
$logins_to_include[] = $current_user->get('user_login');
|
699 |
+
$logins_to_include = array_unique($logins_to_include);
|
700 |
+
|
701 |
+
//Load user details.
|
702 |
+
foreach($logins_to_include as $login) {
|
703 |
+
$user = get_user_by('login', $login);
|
704 |
+
if ( !empty($user) ) {
|
705 |
+
$users[$login] = $this->user_to_property_map($user);
|
706 |
+
}
|
707 |
+
}
|
708 |
+
|
709 |
+
//Compatibility workaround: Get the real roles of the current user even if other plugins corrupt the list.
|
710 |
+
$users[$current_user->get('user_login')]['roles'] = array_values($this->get_user_roles($current_user));
|
711 |
+
|
712 |
+
//TODO: Include currentUserLogin
|
713 |
+
$actor_data = array(
|
714 |
+
'roles' => $roles,
|
715 |
+
'users' => $users,
|
716 |
+
'isMultisite' => is_multisite(),
|
717 |
+
'capPower' => $this->load_cap_power(),
|
718 |
+
);
|
719 |
+
wp_localize_script('ame-actor-manager', 'wsAmeActorData', $actor_data);
|
720 |
+
|
721 |
//Modules
|
722 |
wp_register_auto_versioned_script(
|
723 |
'ame-access-editor',
|
727 |
|
728 |
//Let extras register their scripts.
|
729 |
do_action('admin_menu_editor-register_scripts');
|
730 |
+
}
|
731 |
+
|
732 |
+
|
733 |
+
/**
|
734 |
+
* Add the JS required by the editor to the page header
|
735 |
+
*
|
736 |
+
* @return void
|
737 |
+
*/
|
738 |
+
function enqueue_scripts() {
|
739 |
+
//Optimization: Remove wp-emoji.js from the plugin page. wpEmoji makes DOM manipulation slow because
|
740 |
+
//it tracks *all* DOM changes using MutationObserver.
|
741 |
+
remove_action('admin_print_scripts', 'print_emoji_detection_script');
|
742 |
+
|
743 |
+
$this->register_base_dependencies();
|
744 |
+
|
745 |
+
//Move admin notices (e.g. "Settings saved") below editor tabs.
|
746 |
+
//This is a separate script because it has to run after common.js which is loaded in the page footer.
|
747 |
+
wp_enqueue_auto_versioned_script(
|
748 |
+
'ame-editor-tab-fix',
|
749 |
+
plugins_url('js/editor-tab-fix.js', $this->plugin_file),
|
750 |
+
array('jquery', 'common'),
|
751 |
+
true
|
752 |
+
);
|
753 |
|
754 |
//Editor's scripts
|
755 |
$editor_dependencies = array(
|
768 |
do_action('admin_menu_editor-enqueue_scripts-' . $this->current_tab);
|
769 |
|
770 |
//Actors (roles and users) are used in the permissions UI, so we need to pass them along.
|
771 |
+
//TODO: This is redundant. Consider using the actor manager or selector instead.
|
772 |
$actors = array();
|
|
|
773 |
|
774 |
$wp_roles = ameRoleUtils::get_roles();
|
775 |
foreach($wp_roles->roles as $role_id => $role) {
|
776 |
$actors['role:' . $role_id] = $role['name'];
|
|
|
|
|
777 |
}
|
778 |
|
779 |
if ( is_multisite() && is_super_admin() ) {
|
780 |
$actors['special:super_admin'] = 'Super Admin';
|
781 |
}
|
782 |
|
|
|
|
|
783 |
$current_user = wp_get_current_user();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
784 |
$actors['user:' . $current_user->get('user_login')] = sprintf(
|
785 |
'Current user (%s)',
|
786 |
$current_user->get('user_login')
|
787 |
);
|
788 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
789 |
//Add only certain scripts to the settings sub-section.
|
790 |
if ( $this->is_settings_page() ) {
|
791 |
wp_enqueue_script('jquery-qtip');
|
1026 |
$previous_custom_menu = $this->load_custom_menu();
|
1027 |
$this->update_wpml_strings($previous_custom_menu, $custom_menu);
|
1028 |
|
1029 |
+
if ( !empty($custom_menu) && $this->options['compress_custom_menu'] ) {
|
1030 |
+
$custom_menu = ameMenu::compress($custom_menu);
|
1031 |
+
}
|
1032 |
+
|
1033 |
if ( $this->should_use_site_specific_menu() ) {
|
1034 |
$site_specific_options = get_option($this->option_name);
|
1035 |
if ( !is_array($site_specific_options) ) {
|
1104 |
return current_user_can($capability);
|
1105 |
}
|
1106 |
}
|
1107 |
+
|
1108 |
+
/**
|
1109 |
+
* Reset plugin access if the only allowed user no longer exists.
|
1110 |
+
*
|
1111 |
+
* Some people use security plugins like iThemes Security to replace the default admin account
|
1112 |
+
* with a new one or change the user ID. This can be a problem when AME is configured to allow
|
1113 |
+
* only one user to edit the admin menu. Deleting that user ID makes the plugin inaccessible.
|
1114 |
+
* As a workaround, allow any admin if the configured user is missing.
|
1115 |
+
*
|
1116 |
+
* @internal
|
1117 |
+
* @param string $login
|
1118 |
+
* @param WP_User $current_user
|
1119 |
+
*/
|
1120 |
+
public function maybe_reset_plugin_access(/** @noinspection PhpUnusedParameterInspection */ $login, $current_user) {
|
1121 |
+
if ( ($this->options['plugin_access'] !== 'specific_user') || !$current_user || !$current_user->exists() ) {
|
1122 |
+
return;
|
1123 |
+
}
|
1124 |
+
|
1125 |
+
//For performance, only run this check when an admin logs in.
|
1126 |
+
//Note that current_user_can() and friends don't work at this point in the login flow.
|
1127 |
+
$current_user_is_admin = is_multisite()
|
1128 |
+
? is_super_admin($current_user->ID)
|
1129 |
+
: $current_user->has_cap('manage_options');
|
1130 |
+
|
1131 |
+
if ( !$current_user_is_admin ) {
|
1132 |
+
return;
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
$allowed_user = get_user_by('id', $this->options['allowed_user_id']);
|
1136 |
+
if ( !$allowed_user || !$allowed_user->exists() ) {
|
1137 |
+
//The allowed user no longer exists. Allow any administrator to use the plugin.
|
1138 |
+
$this->options['plugin_access'] = 'manage_options';
|
1139 |
+
$this->save_options();
|
1140 |
+
}
|
1141 |
+
}
|
1142 |
|
1143 |
/**
|
1144 |
* Apply the custom page title, if any.
|
1340 |
//Now we have some items marked as missing, and some items in lookup arrays
|
1341 |
//that are not marked as used. Lets remove the missing items from the tree.
|
1342 |
$tree = ameMenu::remove_missing_items($tree);
|
1343 |
+
//TODO: What would happen if we kept missing items?
|
1344 |
|
1345 |
//Lets merge in the unused items.
|
1346 |
$max_menu_position = !empty($positions_by_template) ? max($positions_by_template) : 100;
|
1703 |
}
|
1704 |
}
|
1705 |
|
1706 |
+
if ( $hasCustomIconUrl && (strpos(ameMenuItem::get($item, 'icon_url'), 'dashicons-') === 0) ) {
|
1707 |
+
$item['css_class'] = ameMenuItem::get($item, 'css_class', '') . ' ame-has-custom-dashicon';
|
1708 |
+
}
|
1709 |
+
|
1710 |
//WPML support: Translate only custom titles. See further below.
|
1711 |
$hasCustomMenuTitle = isset($item['menu_title']);
|
1712 |
|
2011 |
$menu['granted_capabilities'] = $capFilter->clean_up($menu['granted_capabilities']);
|
2012 |
}
|
2013 |
|
2014 |
+
//Remember if the user has changed any menu icons to different Dashicons.
|
2015 |
+
$menu['has_modified_dashicons'] = ameModifiedIconDetector::detect($menu);
|
2016 |
+
|
2017 |
//Save the custom menu
|
2018 |
$this->set_custom_menu($menu);
|
2019 |
|
2111 |
}
|
2112 |
}
|
2113 |
|
2114 |
+
//Work around icon CSS problems.
|
2115 |
+
$this->options['force_custom_dashicons'] = !empty($this->post['force_custom_dashicons']);
|
2116 |
+
|
2117 |
//Where to put new or unused menu items.
|
2118 |
if ( !empty($this->post['unused_item_position']) ) {
|
2119 |
$unused_item_position = strval($this->post['unused_item_position']);
|
2132 |
}
|
2133 |
}
|
2134 |
|
2135 |
+
//Menu data compression.
|
2136 |
+
$this->options['compress_custom_menu'] = !empty($this->post['compress_custom_menu']);
|
2137 |
+
|
2138 |
+
//Active modules.
|
2139 |
+
$activeModules = isset($this->post['active_modules']) ? (array)$this->post['active_modules'] : array();
|
2140 |
+
$activeModules = array_fill_keys(array_map('strval', $activeModules), true);
|
2141 |
+
$this->options['is_active_module'] = array_merge(
|
2142 |
+
array_map('__return_false', $this->get_available_modules()),
|
2143 |
+
$activeModules
|
2144 |
+
);
|
2145 |
+
|
2146 |
$this->save_options();
|
2147 |
wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url()));
|
2148 |
}
|
2161 |
);
|
2162 |
|
2163 |
//Build a tree struct. for the default menu
|
2164 |
+
$default_menu = $this->get_default_menu();
|
|
|
2165 |
|
2166 |
//Is there a custom menu?
|
2167 |
if (!empty($this->merged_custom_menu)){
|
2209 |
require dirname(__FILE__) . '/editor-page.php';
|
2210 |
}
|
2211 |
|
2212 |
+
/**
|
2213 |
+
* Get the default admin menu configuration.
|
2214 |
+
*
|
2215 |
+
* @return array
|
2216 |
+
*/
|
2217 |
+
private function get_default_menu() {
|
2218 |
+
$default_tree = ameMenu::wp2tree($this->default_wp_menu, $this->default_wp_submenu, $this->menu_url_blacklist);
|
2219 |
+
$default_menu = ameMenu::load_array($default_tree);
|
2220 |
+
return $default_menu;
|
2221 |
+
}
|
2222 |
+
|
2223 |
+
/**
|
2224 |
+
* Get the admin menu configuration that was used during this page load.
|
2225 |
+
*
|
2226 |
+
* @return array
|
2227 |
+
*/
|
2228 |
+
public function get_active_admin_menu() {
|
2229 |
+
if ( !did_action('admin_menu') && !did_action('network_admin_menu') ) {
|
2230 |
+
throw new LogicException(__METHOD__ . ' was called too early. You must only call it after the admin menu is ready.');
|
2231 |
+
}
|
2232 |
+
|
2233 |
+
if (!empty($this->merged_custom_menu)){
|
2234 |
+
return $this->merged_custom_menu;
|
2235 |
+
} else {
|
2236 |
+
return $this->get_default_menu();
|
2237 |
+
}
|
2238 |
+
}
|
2239 |
+
|
2240 |
/**
|
2241 |
* Display the header of the "Menu Editor" page.
|
2242 |
* This includes the page heading and tab list.
|
2292 |
$settings_page_url = $this->get_settings_page_url();
|
2293 |
/** @noinspection PhpUnusedLocalVariableInspection */
|
2294 |
$editor_page_url = admin_url($this->settings_link);
|
2295 |
+
/** @noinspection PhpUnusedLocalVariableInspection */
|
2296 |
+
$db_option_name = $this->option_name;
|
2297 |
|
2298 |
require dirname(__FILE__) . '/settings-page.php';
|
2299 |
}
|
3039 |
array(),
|
3040 |
'20140630-3'
|
3041 |
);
|
3042 |
+
|
3043 |
+
if ( $this->options['force_custom_dashicons'] ) {
|
3044 |
+
//Optimization: Only add the stylesheet if the menu actually has custom dashicons.
|
3045 |
+
$menu = $this->load_custom_menu();
|
3046 |
+
if ( $menu && !empty($menu['has_modified_dashicons']) ) {
|
3047 |
+
wp_enqueue_style(
|
3048 |
+
'ame-force-dashicons',
|
3049 |
+
plugins_url('css/force-dashicons.css', $this->plugin_file),
|
3050 |
+
array(),
|
3051 |
+
'20170607'
|
3052 |
+
);
|
3053 |
+
}
|
3054 |
+
}
|
3055 |
}
|
3056 |
|
3057 |
/**
|
3336 |
}
|
3337 |
}
|
3338 |
|
3339 |
+
/**
|
3340 |
+
* Compatibility fix for Divi Training 1.3.5.
|
3341 |
+
*
|
3342 |
+
* The Divi Training plugin adds a whole lot of "hidden" submenu items to the Dashboard menu
|
3343 |
+
* and then removes them later. Lets get rid of them.
|
3344 |
+
*/
|
3345 |
+
private function apply_divi_training_fix() {
|
3346 |
+
if ( !class_exists('Wm_Divi_Training_Admin', false) ) {
|
3347 |
+
return;
|
3348 |
+
}
|
3349 |
+
if ( !isset($this->default_wp_submenu, $this->default_wp_submenu['index.php']) ) {
|
3350 |
+
return;
|
3351 |
+
}
|
3352 |
+
|
3353 |
+
$items_to_remove = array();
|
3354 |
+
foreach($this->default_wp_submenu['index.php'] as $index => $menu) {
|
3355 |
+
//There's a lot of items, so we search for a common prefix instead of of including an explicit list.
|
3356 |
+
//
|
3357 |
+
if ( (strpos($menu[2], 'wm-divi-training-the-divi-') === 0) || ($menu[2] === 'wm-divi-training-updates')) {
|
3358 |
+
$items_to_remove[] = $index;
|
3359 |
+
}
|
3360 |
+
}
|
3361 |
+
foreach($items_to_remove as $index) {
|
3362 |
+
if ( isset($index, $this->default_wp_submenu['index.php'][$index]) ) {
|
3363 |
+
unset($this->default_wp_submenu['index.php'][$index]);
|
3364 |
+
}
|
3365 |
+
}
|
3366 |
+
}
|
3367 |
+
|
3368 |
/**
|
3369 |
* As of WP 3.5, the Links Manager is hidden by default. It's only visible if the user has existing links
|
3370 |
* or they choose to enable it by installing the Links Manager plugin.
|
3657 |
return $cap_power;
|
3658 |
}
|
3659 |
|
3660 |
+
private function get_active_modules() {
|
3661 |
+
$modules = $this->get_available_modules();
|
3662 |
+
|
3663 |
+
$activeModules = array();
|
3664 |
+
foreach ($modules as $id => $module) {
|
3665 |
+
if ( $this->is_module_active($id, $module) ) {
|
3666 |
+
$activeModules[$id] = $module;
|
3667 |
+
}
|
3668 |
+
}
|
3669 |
+
|
3670 |
+
return $activeModules;
|
3671 |
+
}
|
3672 |
+
|
3673 |
+
public function get_available_modules() {
|
3674 |
+
$modules = array(
|
3675 |
+
'actor-selector' => array(
|
3676 |
+
'relativePath' => 'modules/actor-selector/actor-selector.php',
|
3677 |
+
'className' => 'ameActorSelector',
|
3678 |
+
'isAlwaysActive' => true,
|
3679 |
+
),
|
3680 |
+
'visible-users' => array(
|
3681 |
+
'relativePath' => 'extras/modules/visible-users/visible-users.php',
|
3682 |
+
'className' => 'ameVisibleUsers',
|
3683 |
+
'isAlwaysActive' => true,
|
3684 |
+
),
|
3685 |
+
'metaboxes' => array(
|
3686 |
+
'relativePath' => 'extras/modules/metaboxes/load.php',
|
3687 |
+
'className' => 'ameMetaBoxEditor',
|
3688 |
+
'requiredPhpVersion' => '5.3',
|
3689 |
+
'title' => 'Meta Boxes',
|
3690 |
+
),
|
3691 |
+
'dashboard-widget-editor' => array(
|
3692 |
+
'relativePath' => 'extras/modules/dashboard-widget-editor/load.php',
|
3693 |
+
'className' => 'ameWidgetEditor',
|
3694 |
+
'requiredPhpVersion' => '5.3',
|
3695 |
+
'title' => 'Dashboard Widgets',
|
3696 |
+
),
|
3697 |
+
'plugin-visibility' => array(
|
3698 |
+
'relativePath' => 'modules/plugin-visibility/plugin-visibility.php',
|
3699 |
+
'className' => 'amePluginVisibility',
|
3700 |
+
'title' => 'Plugins',
|
3701 |
+
),
|
3702 |
+
'super-users' => array(
|
3703 |
+
'relativePath' => 'extras/modules/super-users/super-users.php',
|
3704 |
+
'className' => 'ameSuperUsers',
|
3705 |
+
'title' => 'Hidden Users',
|
3706 |
+
),
|
3707 |
+
/*'admin-css' => array(
|
3708 |
+
'relativePath' => 'modules/admin-css/admin-css.php',
|
3709 |
+
'className' => 'ameAdminCss',
|
3710 |
+
'title' => 'Admin CSS',
|
3711 |
+
),*/
|
3712 |
+
'hide-admin-menu' => array(
|
3713 |
+
'relativePath' => 'extras/modules/hide-admin-menu/hide-admin-menu.php',
|
3714 |
+
'className' => 'ameAdminMenuHider',
|
3715 |
+
'title' => '"Show the admin menu" checkbox',
|
3716 |
+
),
|
3717 |
+
'hide-admin-bar' => array(
|
3718 |
+
'relativePath' => 'extras/modules/hide-admin-bar/hide-admin-bar.php',
|
3719 |
+
'className' => 'ameAdminBarHider',
|
3720 |
+
'title' => '"Show the Toolbar" checkbox',
|
3721 |
+
),
|
3722 |
+
'highlight-new-menus' => array(
|
3723 |
+
'relativePath' => 'modules/highlight-new-menus/highlight-new-menus.php',
|
3724 |
+
'className' => 'ameMenuHighlighterWrapper',
|
3725 |
+
'title' => 'Highlight new menu items',
|
3726 |
+
'requiredPhpVersion' => '5.3',
|
3727 |
+
),
|
3728 |
+
);
|
3729 |
+
|
3730 |
+
foreach($modules as &$module) {
|
3731 |
+
if (!empty($module['relativePath'])) {
|
3732 |
+
$module['path'] = AME_ROOT_DIR . '/' . $module['relativePath'];
|
3733 |
+
}
|
3734 |
+
}
|
3735 |
+
unset($module);
|
3736 |
+
|
3737 |
+
$modules = array_filter($modules, array($this, 'module_path_exists'));
|
3738 |
+
|
3739 |
+
return $modules;
|
3740 |
+
}
|
3741 |
+
|
3742 |
+
private function module_path_exists($module) {
|
3743 |
+
return !empty($module['path']) && file_exists($module['path']);
|
3744 |
+
}
|
3745 |
+
|
3746 |
+
public function is_module_compatible($module) {
|
3747 |
+
if ( !empty($module['requiredPhpVersion']) ) {
|
3748 |
+
return version_compare(phpversion(), $module['requiredPhpVersion'], '>=');
|
3749 |
+
}
|
3750 |
+
return true;
|
3751 |
+
}
|
3752 |
+
|
3753 |
+
public function is_module_active($id, $module) {
|
3754 |
+
if ( !$this->is_module_compatible($module) ) {
|
3755 |
+
return false;
|
3756 |
+
}
|
3757 |
+
if ( !empty($module['isAlwaysActive']) ) {
|
3758 |
+
return true;
|
3759 |
+
}
|
3760 |
+
if ( isset($this->options['is_active_module'][$id]) ) {
|
3761 |
+
return $this->options['is_active_module'][$id];
|
3762 |
+
}
|
3763 |
+
return true;
|
3764 |
+
}
|
3765 |
+
|
3766 |
} //class
|
3767 |
|
3768 |
|
3845 |
}
|
3846 |
|
3847 |
$templateId = ameMenuItem::template_id($item);
|
3848 |
+
unset($item['template_id']);
|
3849 |
+
|
3850 |
$this->templates[$templateId] = array(
|
3851 |
'name' => $name,
|
3852 |
'used' => false,
|
includes/menu-item.php
CHANGED
@@ -354,6 +354,16 @@ abstract class ameMenuItem {
|
|
354 |
unset($item['role_access']);
|
355 |
}
|
356 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
357 |
if ( isset($item['items']) ) {
|
358 |
foreach($item['items'] as $index => $sub_item) {
|
359 |
$item['items'][$index] = self::normalize($sub_item);
|
354 |
unset($item['role_access']);
|
355 |
}
|
356 |
|
357 |
+
//There's no need to store the default position if a custom position is set.
|
358 |
+
//The default position will not be used, and there's no option to reset the position to default.
|
359 |
+
if ( isset($item['position'], $item['defaults']['position']) && ($item['defaults']['position'] === $item['position'])) {
|
360 |
+
unset($item['defaults']['position']);
|
361 |
+
}
|
362 |
+
//The same goes for template ID.
|
363 |
+
if ( isset($item['template_id']) ) {
|
364 |
+
unset($item['defaults']['template_id']);
|
365 |
+
}
|
366 |
+
|
367 |
if ( isset($item['items']) ) {
|
368 |
foreach($item['items'] as $index => $sub_item) {
|
369 |
$item['items'][$index] = self::normalize($sub_item);
|
includes/menu.php
CHANGED
@@ -142,6 +142,11 @@ abstract class ameMenu {
|
|
142 |
$menu['component_visibility'] = $visibility;
|
143 |
}
|
144 |
|
|
|
|
|
|
|
|
|
|
|
145 |
return $menu;
|
146 |
}
|
147 |
|
@@ -412,16 +417,25 @@ abstract class ameMenu {
|
|
412 |
}
|
413 |
|
414 |
$common = $menu['format']['common'];
|
415 |
-
$menu['tree'] = self::
|
416 |
-
$menu['tree'],
|
417 |
-
array(__CLASS__, 'decompress_item'),
|
418 |
-
array($common)
|
419 |
-
);
|
420 |
|
421 |
unset($menu['format']['compressed'], $menu['format']['common']);
|
422 |
return $menu;
|
423 |
}
|
424 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
425 |
protected static function decompress_item($item, $common) {
|
426 |
$item = array_merge($common['properties'], $item);
|
427 |
|
@@ -444,10 +458,11 @@ abstract class ameMenu {
|
|
444 |
if ( $extra_params === null ) {
|
445 |
$extra_params = array();
|
446 |
}
|
|
|
447 |
|
448 |
$result = array();
|
449 |
foreach($items as $key => $item) {
|
450 |
-
$args =
|
451 |
$item = call_user_func_array($callback, $args);
|
452 |
|
453 |
if ( !empty($item['items']) ) {
|
@@ -457,6 +472,19 @@ abstract class ameMenu {
|
|
457 |
}
|
458 |
return $result;
|
459 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
460 |
}
|
461 |
|
462 |
class ameGrantedCapabilityFilter {
|
@@ -498,6 +526,32 @@ class ameGrantedCapabilityFilter {
|
|
498 |
}
|
499 |
}
|
500 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
501 |
|
502 |
class InvalidMenuException extends Exception {}
|
503 |
|
142 |
$menu['component_visibility'] = $visibility;
|
143 |
}
|
144 |
|
145 |
+
//Copy the "modified icons" flag.
|
146 |
+
if ( isset($arr['has_modified_dashicons']) ) {
|
147 |
+
$menu['has_modified_dashicons'] = (bool)$arr['has_modified_dashicons'];
|
148 |
+
}
|
149 |
+
|
150 |
return $menu;
|
151 |
}
|
152 |
|
417 |
}
|
418 |
|
419 |
$common = $menu['format']['common'];
|
420 |
+
$menu['tree'] = self::decompress_list($menu['tree'], $common);
|
|
|
|
|
|
|
|
|
421 |
|
422 |
unset($menu['format']['compressed'], $menu['format']['common']);
|
423 |
return $menu;
|
424 |
}
|
425 |
|
426 |
+
protected static function decompress_list($list, $common) {
|
427 |
+
//Optimization: Direct iteration is about 40% faster than map_items.
|
428 |
+
$result = array();
|
429 |
+
foreach($list as $key => $item) {
|
430 |
+
$item = self::decompress_item($item, $common);
|
431 |
+
if ( !empty($item['items']) ) {
|
432 |
+
$item['items'] = self::decompress_list($item['items'], $common);
|
433 |
+
}
|
434 |
+
$result[$key] = $item;
|
435 |
+
}
|
436 |
+
return $result;
|
437 |
+
}
|
438 |
+
|
439 |
protected static function decompress_item($item, $common) {
|
440 |
$item = array_merge($common['properties'], $item);
|
441 |
|
458 |
if ( $extra_params === null ) {
|
459 |
$extra_params = array();
|
460 |
}
|
461 |
+
$args = array_merge(array(null), $extra_params);
|
462 |
|
463 |
$result = array();
|
464 |
foreach($items as $key => $item) {
|
465 |
+
$args[0] = $item;
|
466 |
$item = call_user_func_array($callback, $args);
|
467 |
|
468 |
if ( !empty($item['items']) ) {
|
472 |
}
|
473 |
return $result;
|
474 |
}
|
475 |
+
|
476 |
+
/**
|
477 |
+
* @param array $items
|
478 |
+
* @param callable $callback
|
479 |
+
*/
|
480 |
+
public static function for_each($items, $callback) {
|
481 |
+
foreach($items as $key => $item) {
|
482 |
+
call_user_func($callback, $item);
|
483 |
+
if ( !empty($item['items']) ) {
|
484 |
+
self::for_each($item['items'], $callback);
|
485 |
+
}
|
486 |
+
}
|
487 |
+
}
|
488 |
}
|
489 |
|
490 |
class ameGrantedCapabilityFilter {
|
526 |
}
|
527 |
}
|
528 |
|
529 |
+
/**
|
530 |
+
* This could just be a closure, but we want to support PHP 5.2.
|
531 |
+
*/
|
532 |
+
class ameModifiedIconDetector {
|
533 |
+
private $result = false;
|
534 |
+
|
535 |
+
public static function detect($menu) {
|
536 |
+
$detector = new self();
|
537 |
+
ameMenu::for_each($menu['tree'], array($detector, 'checkItem'));
|
538 |
+
return $detector->getResult();
|
539 |
+
}
|
540 |
+
|
541 |
+
public function checkItem($item) {
|
542 |
+
$this->result = $this->result || $this->hasModifiedDashicon($item);
|
543 |
+
}
|
544 |
+
|
545 |
+
private function hasModifiedDashicon($item) {
|
546 |
+
return !ameMenuItem::is_default($item, 'icon_url')
|
547 |
+
&& (strpos(ameMenuItem::get($item, 'icon_url'), 'dashicons-') === 0);
|
548 |
+
}
|
549 |
+
|
550 |
+
private function getResult() {
|
551 |
+
return $this->result;
|
552 |
+
}
|
553 |
+
}
|
554 |
+
|
555 |
|
556 |
class InvalidMenuException extends Exception {}
|
557 |
|
includes/reflection-callable.php
CHANGED
@@ -40,13 +40,27 @@ class AmeReflectionCallable {
|
|
40 |
$callback = array($callback, '__invoke');
|
41 |
}
|
42 |
|
43 |
-
if (is_object($callback[0])) {
|
44 |
$reflectionObject = new ReflectionObject($callback[0]);
|
45 |
} else {
|
46 |
$reflectionObject = new ReflectionClass($callback[0]);
|
47 |
}
|
48 |
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
}
|
51 |
|
52 |
/**
|
40 |
$callback = array($callback, '__invoke');
|
41 |
}
|
42 |
|
43 |
+
if ( is_object($callback[0]) ) {
|
44 |
$reflectionObject = new ReflectionObject($callback[0]);
|
45 |
} else {
|
46 |
$reflectionObject = new ReflectionClass($callback[0]);
|
47 |
}
|
48 |
|
49 |
+
$methodName = $callback[1];
|
50 |
+
if ( !$reflectionObject->hasMethod($methodName) ) {
|
51 |
+
//The callback appears to use magic methods.
|
52 |
+
if ( is_string($callback[0]) && $reflectionObject->hasMethod('__callStatic') ) {
|
53 |
+
$methodName = '__callStatic';
|
54 |
+
} else if (is_object($callback[0]) && $reflectionObject->hasMethod('__call')) {
|
55 |
+
$methodName = '__call';
|
56 |
+
} else {
|
57 |
+
//Probably an invalid callback. It could be a relative static method call,
|
58 |
+
//but we don't support those at the moment.
|
59 |
+
//See http://php.net/manual/en/language.types.callable.php
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
return $reflectionObject->getMethod($methodName);
|
64 |
}
|
65 |
|
66 |
/**
|
includes/settings-page.php
CHANGED
@@ -6,6 +6,7 @@
|
|
6 |
* @var array $settings Plugin settings.
|
7 |
* @var string $editor_page_url A fully qualified URL of the admin menu editor page.
|
8 |
* @var string $settings_page_url
|
|
|
9 |
*/
|
10 |
|
11 |
$currentUser = wp_get_current_user();
|
@@ -116,6 +117,62 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
116 |
</td>
|
117 |
</tr>
|
118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
<tr>
|
120 |
<th scope="row">Interface</th>
|
121 |
<td>
|
@@ -298,6 +355,7 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
298 |
<tr>
|
299 |
<th scope="row">Debugging</th>
|
300 |
<td>
|
|
|
301 |
<label>
|
302 |
<input type="checkbox" name="security_logging_enabled"
|
303 |
<?php checked($settings['security_logging_enabled']); ?>>
|
@@ -310,6 +368,53 @@ $isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
|
310 |
Note: It's not recommended to use this option on a live site as
|
311 |
it can reveal information about your menu configuration.
|
312 |
</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
</td>
|
314 |
</tr>
|
315 |
</tbody>
|
6 |
* @var array $settings Plugin settings.
|
7 |
* @var string $editor_page_url A fully qualified URL of the admin menu editor page.
|
8 |
* @var string $settings_page_url
|
9 |
+
* @var string $db_option_name
|
10 |
*/
|
11 |
|
12 |
$currentUser = wp_get_current_user();
|
117 |
</td>
|
118 |
</tr>
|
119 |
|
120 |
+
<tr>
|
121 |
+
<th scope="row">
|
122 |
+
Modules
|
123 |
+
<a class="ws_tooltip_trigger"
|
124 |
+
title="Modules are plugin features that can be turned on or off.
|
125 |
+
<br>
|
126 |
+
Turning off unused features will slightly increase performance and may help with certain compatibility issues.
|
127 |
+
">
|
128 |
+
<div class="dashicons dashicons-info"></div>
|
129 |
+
</a>
|
130 |
+
</th>
|
131 |
+
<td>
|
132 |
+
<fieldset>
|
133 |
+
<?php
|
134 |
+
global $wp_menu_editor;
|
135 |
+
foreach ($wp_menu_editor->get_available_modules() as $id => $module) {
|
136 |
+
if ( !empty($module['isAlwaysActive']) ) {
|
137 |
+
continue;
|
138 |
+
}
|
139 |
+
|
140 |
+
$isCompatible = $wp_menu_editor->is_module_compatible($module);
|
141 |
+
$compatibilityNote = '';
|
142 |
+
if ( !$isCompatible && !empty($module['requiredPhpVersion']) ) {
|
143 |
+
if ( version_compare(phpversion(), $module['requiredPhpVersion'], '<') ) {
|
144 |
+
$compatibilityNote = sprintf(
|
145 |
+
'Required PHP version: %1$s or later. Installed PHP version: %2$s',
|
146 |
+
htmlentities($module['requiredPhpVersion']),
|
147 |
+
htmlentities(phpversion())
|
148 |
+
);
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
echo '<p>';
|
153 |
+
/** @noinspection HtmlUnknownAttribute */
|
154 |
+
printf(
|
155 |
+
'<label>
|
156 |
+
<input type="checkbox" name="active_modules[]" value="%1$s" %2$s %3$s>
|
157 |
+
%4$s
|
158 |
+
</label>',
|
159 |
+
esc_attr($id),
|
160 |
+
$wp_menu_editor->is_module_active($id, $module) ? 'checked="checked"' : '',
|
161 |
+
$isCompatible ? '' : 'disabled="disabled"',
|
162 |
+
!empty($module['title']) ? $module['title'] : htmlentities($id)
|
163 |
+
);
|
164 |
+
|
165 |
+
if ( !empty($compatibilityNote) ) {
|
166 |
+
printf('<br><span class="description">%s</span>', $compatibilityNote);
|
167 |
+
}
|
168 |
+
|
169 |
+
echo '</p>';
|
170 |
+
}
|
171 |
+
?>
|
172 |
+
</fieldset>
|
173 |
+
</td>
|
174 |
+
</tr>
|
175 |
+
|
176 |
<tr>
|
177 |
<th scope="row">Interface</th>
|
178 |
<td>
|
355 |
<tr>
|
356 |
<th scope="row">Debugging</th>
|
357 |
<td>
|
358 |
+
<p>
|
359 |
<label>
|
360 |
<input type="checkbox" name="security_logging_enabled"
|
361 |
<?php checked($settings['security_logging_enabled']); ?>>
|
368 |
Note: It's not recommended to use this option on a live site as
|
369 |
it can reveal information about your menu configuration.
|
370 |
</span>
|
371 |
+
</p>
|
372 |
+
|
373 |
+
<p>
|
374 |
+
<label>
|
375 |
+
<input type="checkbox" name="force_custom_dashicons"
|
376 |
+
<?php checked($settings['force_custom_dashicons']); ?>>
|
377 |
+
Attempt to override menu icon CSS that was added by other plugins
|
378 |
+
</label>
|
379 |
+
</p>
|
380 |
+
|
381 |
+
<p>
|
382 |
+
<label>
|
383 |
+
<input type="checkbox" name="compress_custom_menu"
|
384 |
+
<?php checked($settings['compress_custom_menu']); ?>>
|
385 |
+
Compress menu configuration data that's stored in the database
|
386 |
+
</label>
|
387 |
+
<br><span class="description">
|
388 |
+
Significantly reduces the size of
|
389 |
+
the <code><?php echo esc_html($db_option_name); ?></code> DB option,
|
390 |
+
but adds decompression overhead to every page.
|
391 |
+
</span>
|
392 |
+
</p>
|
393 |
+
</td>
|
394 |
+
</tr>
|
395 |
+
|
396 |
+
<tr>
|
397 |
+
<th scope="row">Server info</th>
|
398 |
+
<td>
|
399 |
+
<figure>
|
400 |
+
<figcaption>PHP error log:</figcaption>
|
401 |
+
|
402 |
+
<code><?php
|
403 |
+
echo esc_html(ini_get('error_log'));
|
404 |
+
?></code>
|
405 |
+
</figure>
|
406 |
+
|
407 |
+
<figure>
|
408 |
+
<figcaption>PHP memory usage:</figcaption>
|
409 |
+
|
410 |
+
<?php
|
411 |
+
printf(
|
412 |
+
'%.2f MiB of %s',
|
413 |
+
memory_get_peak_usage() / (1024 * 1024),
|
414 |
+
esc_html(ini_get('memory_limit'))
|
415 |
+
);
|
416 |
+
?>
|
417 |
+
</figure>
|
418 |
</td>
|
419 |
</tr>
|
420 |
</tbody>
|
js/actor-manager.js
CHANGED
@@ -1,10 +1,15 @@
|
|
1 |
/// <reference path="lodash-3.10.d.ts" />
|
2 |
/// <reference path="common.d.ts" />
|
3 |
-
var __extends = (this && this.__extends) || function (
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
8 |
var AmeBaseActor = (function () {
|
9 |
function AmeBaseActor(id, displayName, capabilities) {
|
10 |
this.displayName = '[Error: No displayName set]';
|
@@ -54,9 +59,10 @@ var AmeBaseActor = (function () {
|
|
54 |
var AmeRole = (function (_super) {
|
55 |
__extends(AmeRole, _super);
|
56 |
function AmeRole(roleId, displayName, capabilities) {
|
57 |
-
_super.call(this, 'role:' + roleId, displayName, capabilities);
|
58 |
-
|
59 |
-
|
|
|
60 |
}
|
61 |
AmeRole.prototype.hasOwnCap = function (capability) {
|
62 |
//In WordPress, a role name is also a capability name. Users that have the role "foo" always
|
@@ -73,21 +79,22 @@ var AmeUser = (function (_super) {
|
|
73 |
__extends(AmeUser, _super);
|
74 |
function AmeUser(userLogin, displayName, capabilities, roles, isSuperAdmin, userId) {
|
75 |
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
76 |
-
_super.call(this, 'user:' + userLogin, displayName, capabilities);
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
if (
|
86 |
-
|
87 |
}
|
88 |
-
for (var i = 0; i <
|
89 |
-
|
90 |
}
|
|
|
91 |
}
|
92 |
AmeUser.createFromProperties = function (properties) {
|
93 |
var user = new AmeUser(properties.user_login, properties.display_name, properties.capabilities, properties.roles, properties.is_super_admin, properties.hasOwnProperty('id') ? properties.id : null);
|
@@ -101,20 +108,21 @@ var AmeUser = (function (_super) {
|
|
101 |
var AmeSuperAdmin = (function (_super) {
|
102 |
__extends(AmeSuperAdmin, _super);
|
103 |
function AmeSuperAdmin() {
|
104 |
-
_super.call(this, AmeSuperAdmin.permanentActorId, 'Super Admin', {});
|
105 |
-
|
|
|
106 |
}
|
107 |
AmeSuperAdmin.prototype.hasOwnCap = function (capability) {
|
108 |
//The Super Admin has all possible capabilities except the special "do_not_allow" flag.
|
109 |
return (capability !== 'do_not_allow');
|
110 |
};
|
111 |
-
AmeSuperAdmin.permanentActorId = 'special:super_admin';
|
112 |
return AmeSuperAdmin;
|
113 |
}(AmeBaseActor));
|
|
|
114 |
var AmeActorManager = (function () {
|
115 |
function AmeActorManager(roles, users, isMultisite) {
|
116 |
-
var _this = this;
|
117 |
if (isMultisite === void 0) { isMultisite = false; }
|
|
|
118 |
this.roles = {};
|
119 |
this.users = {};
|
120 |
this.grantedCapabilities = {};
|
@@ -187,11 +195,12 @@ var AmeActorManager = (function () {
|
|
187 |
return true;
|
188 |
}
|
189 |
capability = AmeActorManager.mapMetaCap(capability);
|
|
|
190 |
//Step #1: Check temporary context - unsaved caps, etc. Optional.
|
191 |
//Step #2: Check granted capabilities. Default on, but can be skipped.
|
192 |
if (contextList) {
|
193 |
//Check for explicit settings first.
|
194 |
-
var
|
195 |
for (var i = 0; i < len; i++) {
|
196 |
if (contextList[i].hasOwnProperty(actorId)) {
|
197 |
actorValue = contextList[i][actorId];
|
@@ -363,7 +372,8 @@ var AmeActorManager = (function () {
|
|
363 |
var rolesByPower = _.values(this.getRoles()).sort(function (a, b) {
|
364 |
var aCaps = capsByPower(a), bCaps = capsByPower(b);
|
365 |
//Prioritise roles with the highest number of the most powerful capabilities.
|
366 |
-
|
|
|
367 |
var delta_1 = bCaps[i].power - aCaps[i].power;
|
368 |
if (delta_1 !== 0) {
|
369 |
return delta_1;
|
@@ -430,9 +440,9 @@ var AmeActorManager = (function () {
|
|
430 |
AmeActorManager.prototype.getSuggestedCapabilities = function () {
|
431 |
return this.suggestedCapabilities;
|
432 |
};
|
433 |
-
AmeActorManager._ = wsAmeLodash;
|
434 |
return AmeActorManager;
|
435 |
}());
|
|
|
436 |
if (typeof wsAmeActorData !== 'undefined') {
|
437 |
AmeActors = new AmeActorManager(wsAmeActorData.roles, wsAmeActorData.users, wsAmeActorData.isMultisite);
|
438 |
if (typeof wsAmeActorData['capPower'] !== 'undefined') {
|
1 |
/// <reference path="lodash-3.10.d.ts" />
|
2 |
/// <reference path="common.d.ts" />
|
3 |
+
var __extends = (this && this.__extends) || (function () {
|
4 |
+
var extendStatics = Object.setPrototypeOf ||
|
5 |
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
6 |
+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
7 |
+
return function (d, b) {
|
8 |
+
extendStatics(d, b);
|
9 |
+
function __() { this.constructor = d; }
|
10 |
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
11 |
+
};
|
12 |
+
})();
|
13 |
var AmeBaseActor = (function () {
|
14 |
function AmeBaseActor(id, displayName, capabilities) {
|
15 |
this.displayName = '[Error: No displayName set]';
|
59 |
var AmeRole = (function (_super) {
|
60 |
__extends(AmeRole, _super);
|
61 |
function AmeRole(roleId, displayName, capabilities) {
|
62 |
+
var _this = _super.call(this, 'role:' + roleId, displayName, capabilities) || this;
|
63 |
+
_this.actorTypeSpecificity = 1;
|
64 |
+
_this.name = roleId;
|
65 |
+
return _this;
|
66 |
}
|
67 |
AmeRole.prototype.hasOwnCap = function (capability) {
|
68 |
//In WordPress, a role name is also a capability name. Users that have the role "foo" always
|
79 |
__extends(AmeUser, _super);
|
80 |
function AmeUser(userLogin, displayName, capabilities, roles, isSuperAdmin, userId) {
|
81 |
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
82 |
+
var _this = _super.call(this, 'user:' + userLogin, displayName, capabilities) || this;
|
83 |
+
_this.userId = 0;
|
84 |
+
_this.isSuperAdmin = false;
|
85 |
+
_this.avatarHTML = '';
|
86 |
+
_this.actorTypeSpecificity = 10;
|
87 |
+
_this.userLogin = userLogin;
|
88 |
+
_this.roles = roles;
|
89 |
+
_this.isSuperAdmin = isSuperAdmin;
|
90 |
+
_this.userId = userId || 0;
|
91 |
+
if (_this.isSuperAdmin) {
|
92 |
+
_this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
93 |
}
|
94 |
+
for (var i = 0; i < _this.roles.length; i++) {
|
95 |
+
_this.groupActors.push('role:' + _this.roles[i]);
|
96 |
}
|
97 |
+
return _this;
|
98 |
}
|
99 |
AmeUser.createFromProperties = function (properties) {
|
100 |
var user = new AmeUser(properties.user_login, properties.display_name, properties.capabilities, properties.roles, properties.is_super_admin, properties.hasOwnProperty('id') ? properties.id : null);
|
108 |
var AmeSuperAdmin = (function (_super) {
|
109 |
__extends(AmeSuperAdmin, _super);
|
110 |
function AmeSuperAdmin() {
|
111 |
+
var _this = _super.call(this, AmeSuperAdmin.permanentActorId, 'Super Admin', {}) || this;
|
112 |
+
_this.actorTypeSpecificity = 2;
|
113 |
+
return _this;
|
114 |
}
|
115 |
AmeSuperAdmin.prototype.hasOwnCap = function (capability) {
|
116 |
//The Super Admin has all possible capabilities except the special "do_not_allow" flag.
|
117 |
return (capability !== 'do_not_allow');
|
118 |
};
|
|
|
119 |
return AmeSuperAdmin;
|
120 |
}(AmeBaseActor));
|
121 |
+
AmeSuperAdmin.permanentActorId = 'special:super_admin';
|
122 |
var AmeActorManager = (function () {
|
123 |
function AmeActorManager(roles, users, isMultisite) {
|
|
|
124 |
if (isMultisite === void 0) { isMultisite = false; }
|
125 |
+
var _this = this;
|
126 |
this.roles = {};
|
127 |
this.users = {};
|
128 |
this.grantedCapabilities = {};
|
195 |
return true;
|
196 |
}
|
197 |
capability = AmeActorManager.mapMetaCap(capability);
|
198 |
+
var result = null;
|
199 |
//Step #1: Check temporary context - unsaved caps, etc. Optional.
|
200 |
//Step #2: Check granted capabilities. Default on, but can be skipped.
|
201 |
if (contextList) {
|
202 |
//Check for explicit settings first.
|
203 |
+
var actorValue = void 0, len = contextList.length;
|
204 |
for (var i = 0; i < len; i++) {
|
205 |
if (contextList[i].hasOwnProperty(actorId)) {
|
206 |
actorValue = contextList[i][actorId];
|
372 |
var rolesByPower = _.values(this.getRoles()).sort(function (a, b) {
|
373 |
var aCaps = capsByPower(a), bCaps = capsByPower(b);
|
374 |
//Prioritise roles with the highest number of the most powerful capabilities.
|
375 |
+
var i = 0, limit = Math.min(aCaps.length, bCaps.length);
|
376 |
+
for (; i < limit; i++) {
|
377 |
var delta_1 = bCaps[i].power - aCaps[i].power;
|
378 |
if (delta_1 !== 0) {
|
379 |
return delta_1;
|
440 |
AmeActorManager.prototype.getSuggestedCapabilities = function () {
|
441 |
return this.suggestedCapabilities;
|
442 |
};
|
|
|
443 |
return AmeActorManager;
|
444 |
}());
|
445 |
+
AmeActorManager._ = wsAmeLodash;
|
446 |
if (typeof wsAmeActorData !== 'undefined') {
|
447 |
AmeActors = new AmeActorManager(wsAmeActorData.roles, wsAmeActorData.users, wsAmeActorData.isMultisite);
|
448 |
if (typeof wsAmeActorData['capPower'] !== 'undefined') {
|
js/actor-manager.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
/// <reference path="lodash-3.10.d.ts" />
|
2 |
/// <reference path="common.d.ts" />
|
3 |
|
4 |
-
declare
|
5 |
declare var wsAmeLodash: _.LoDashStatic;
|
6 |
-
declare
|
7 |
|
8 |
interface CapabilityMap {
|
9 |
[capabilityName: string] : boolean;
|
@@ -41,7 +41,7 @@ abstract class AmeBaseActor {
|
|
41 |
}
|
42 |
|
43 |
static getActorSpecificity(actorId: string) {
|
44 |
-
|
45 |
specificity = 0;
|
46 |
switch (actorType) {
|
47 |
case 'role':
|
@@ -122,7 +122,7 @@ class AmeUser extends AmeBaseActor {
|
|
122 |
if (this.isSuperAdmin) {
|
123 |
this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
124 |
}
|
125 |
-
for (
|
126 |
this.groupActors.push('role:' + this.roles[i]);
|
127 |
}
|
128 |
}
|
@@ -186,12 +186,12 @@ class AmeActorManager {
|
|
186 |
this.isMultisite = !!isMultisite;
|
187 |
|
188 |
AmeActorManager._.forEach(roles, (roleDetails, id) => {
|
189 |
-
|
190 |
this.roles[role.name] = role;
|
191 |
});
|
192 |
|
193 |
AmeActorManager._.forEach(users, (userDetails: AmeUserPropertyMap) => {
|
194 |
-
|
195 |
this.users[user.userLogin] = user;
|
196 |
});
|
197 |
|
@@ -219,7 +219,7 @@ class AmeActorManager {
|
|
219 |
return this.superAdmin;
|
220 |
}
|
221 |
|
222 |
-
|
223 |
actorType = actorId.substring(0, separator),
|
224 |
actorKey = actorId.substring(separator + 1);
|
225 |
|
@@ -266,13 +266,14 @@ class AmeActorManager {
|
|
266 |
}
|
267 |
|
268 |
capability = AmeActorManager.mapMetaCap(capability);
|
|
|
269 |
|
270 |
//Step #1: Check temporary context - unsaved caps, etc. Optional.
|
271 |
//Step #2: Check granted capabilities. Default on, but can be skipped.
|
272 |
if (contextList) {
|
273 |
//Check for explicit settings first.
|
274 |
-
|
275 |
-
for (
|
276 |
if (contextList[i].hasOwnProperty(actorId)) {
|
277 |
actorValue = contextList[i][actorId];
|
278 |
if (typeof actorValue === 'boolean') {
|
@@ -289,7 +290,7 @@ class AmeActorManager {
|
|
289 |
}
|
290 |
|
291 |
//Step #3: Check owned/default capabilities. Always checked.
|
292 |
-
|
293 |
hasOwnCap = actor.hasOwnCap(capability);
|
294 |
if (hasOwnCap !== null) {
|
295 |
return hasOwnCap;
|
@@ -305,7 +306,7 @@ class AmeActorManager {
|
|
305 |
|
306 |
//Check if any of the user's roles have the capability.
|
307 |
result = false;
|
308 |
-
for (
|
309 |
result = result || this.actorHasCap('role:' + actor.roles[index], capability, contextList);
|
310 |
}
|
311 |
return result;
|
@@ -390,7 +391,7 @@ class AmeActorManager {
|
|
390 |
) {
|
391 |
capability = AmeActorManager.mapMetaCap(capability);
|
392 |
|
393 |
-
|
394 |
AmeActorManager._.set(context, [actor, capability], grant);
|
395 |
}
|
396 |
|
@@ -413,13 +414,13 @@ class AmeActorManager {
|
|
413 |
* the direct grant is redundant. We can remove it. Jane will still have "edit_posts" because she's an editor.
|
414 |
*/
|
415 |
pruneGrantedUserCapabilities(): AmeGrantedCapabilityMap {
|
416 |
-
|
417 |
pruned = _.cloneDeep(this.grantedCapabilities),
|
418 |
context = [pruned];
|
419 |
|
420 |
-
|
421 |
//Skip users that are not loaded.
|
422 |
-
|
423 |
if (actor === null) {
|
424 |
return false;
|
425 |
}
|
@@ -428,10 +429,10 @@ class AmeActorManager {
|
|
428 |
|
429 |
_.forEach(actorKeys, (actor) => {
|
430 |
_.forEach(_.keys(pruned[actor]), (capability) => {
|
431 |
-
|
432 |
delete pruned[actor][capability];
|
433 |
|
434 |
-
|
435 |
hasCapWhenPruned = this.actorHasCap(actor, capability, context);
|
436 |
|
437 |
if (hasCap !== hasCapWhenPruned) {
|
@@ -454,7 +455,7 @@ class AmeActorManager {
|
|
454 |
* @return {Number}
|
455 |
*/
|
456 |
static compareActorSpecificity(actor1: string, actor2: string): Number {
|
457 |
-
|
458 |
if (delta !== 0) {
|
459 |
delta = (delta > 0) ? 1 : -1;
|
460 |
}
|
@@ -484,7 +485,8 @@ class AmeActorManager {
|
|
484 |
bCaps = capsByPower(b);
|
485 |
|
486 |
//Prioritise roles with the highest number of the most powerful capabilities.
|
487 |
-
|
|
|
488 |
let delta = bCaps[i].power - aCaps[i].power;
|
489 |
if (delta !== 0) {
|
490 |
return delta;
|
1 |
/// <reference path="lodash-3.10.d.ts" />
|
2 |
/// <reference path="common.d.ts" />
|
3 |
|
4 |
+
declare let wsAmeActorData: any;
|
5 |
declare var wsAmeLodash: _.LoDashStatic;
|
6 |
+
declare let AmeActors: AmeActorManager;
|
7 |
|
8 |
interface CapabilityMap {
|
9 |
[capabilityName: string] : boolean;
|
41 |
}
|
42 |
|
43 |
static getActorSpecificity(actorId: string) {
|
44 |
+
let actorType = actorId.substring(0, actorId.indexOf(':')),
|
45 |
specificity = 0;
|
46 |
switch (actorType) {
|
47 |
case 'role':
|
122 |
if (this.isSuperAdmin) {
|
123 |
this.groupActors.push(AmeSuperAdmin.permanentActorId);
|
124 |
}
|
125 |
+
for (let i = 0; i < this.roles.length; i++) {
|
126 |
this.groupActors.push('role:' + this.roles[i]);
|
127 |
}
|
128 |
}
|
186 |
this.isMultisite = !!isMultisite;
|
187 |
|
188 |
AmeActorManager._.forEach(roles, (roleDetails, id) => {
|
189 |
+
const role = new AmeRole(id, roleDetails.name, roleDetails.capabilities);
|
190 |
this.roles[role.name] = role;
|
191 |
});
|
192 |
|
193 |
AmeActorManager._.forEach(users, (userDetails: AmeUserPropertyMap) => {
|
194 |
+
const user = AmeUser.createFromProperties(userDetails);
|
195 |
this.users[user.userLogin] = user;
|
196 |
});
|
197 |
|
219 |
return this.superAdmin;
|
220 |
}
|
221 |
|
222 |
+
const separator = actorId.indexOf(':'),
|
223 |
actorType = actorId.substring(0, separator),
|
224 |
actorKey = actorId.substring(separator + 1);
|
225 |
|
266 |
}
|
267 |
|
268 |
capability = AmeActorManager.mapMetaCap(capability);
|
269 |
+
let result = null;
|
270 |
|
271 |
//Step #1: Check temporary context - unsaved caps, etc. Optional.
|
272 |
//Step #2: Check granted capabilities. Default on, but can be skipped.
|
273 |
if (contextList) {
|
274 |
//Check for explicit settings first.
|
275 |
+
let actorValue, len = contextList.length;
|
276 |
+
for (let i = 0; i < len; i++) {
|
277 |
if (contextList[i].hasOwnProperty(actorId)) {
|
278 |
actorValue = contextList[i][actorId];
|
279 |
if (typeof actorValue === 'boolean') {
|
290 |
}
|
291 |
|
292 |
//Step #3: Check owned/default capabilities. Always checked.
|
293 |
+
let actor = this.getActor(actorId),
|
294 |
hasOwnCap = actor.hasOwnCap(capability);
|
295 |
if (hasOwnCap !== null) {
|
296 |
return hasOwnCap;
|
306 |
|
307 |
//Check if any of the user's roles have the capability.
|
308 |
result = false;
|
309 |
+
for (let index = 0; index < actor.roles.length; index++) {
|
310 |
result = result || this.actorHasCap('role:' + actor.roles[index], capability, contextList);
|
311 |
}
|
312 |
return result;
|
391 |
) {
|
392 |
capability = AmeActorManager.mapMetaCap(capability);
|
393 |
|
394 |
+
const grant = sourceType ? [hasCap, sourceType, sourceName || null] : hasCap;
|
395 |
AmeActorManager._.set(context, [actor, capability], grant);
|
396 |
}
|
397 |
|
414 |
* the direct grant is redundant. We can remove it. Jane will still have "edit_posts" because she's an editor.
|
415 |
*/
|
416 |
pruneGrantedUserCapabilities(): AmeGrantedCapabilityMap {
|
417 |
+
let _ = AmeActorManager._,
|
418 |
pruned = _.cloneDeep(this.grantedCapabilities),
|
419 |
context = [pruned];
|
420 |
|
421 |
+
let actorKeys = _(pruned).keys().filter((actorId) => {
|
422 |
//Skip users that are not loaded.
|
423 |
+
const actor = this.getActor(actorId);
|
424 |
if (actor === null) {
|
425 |
return false;
|
426 |
}
|
429 |
|
430 |
_.forEach(actorKeys, (actor) => {
|
431 |
_.forEach(_.keys(pruned[actor]), (capability) => {
|
432 |
+
const grant = pruned[actor][capability];
|
433 |
delete pruned[actor][capability];
|
434 |
|
435 |
+
const hasCap = _.isArray(grant) ? grant[0] : grant,
|
436 |
hasCapWhenPruned = this.actorHasCap(actor, capability, context);
|
437 |
|
438 |
if (hasCap !== hasCapWhenPruned) {
|
455 |
* @return {Number}
|
456 |
*/
|
457 |
static compareActorSpecificity(actor1: string, actor2: string): Number {
|
458 |
+
let delta = AmeBaseActor.getActorSpecificity(actor1) - AmeBaseActor.getActorSpecificity(actor2);
|
459 |
if (delta !== 0) {
|
460 |
delta = (delta > 0) ? 1 : -1;
|
461 |
}
|
485 |
bCaps = capsByPower(b);
|
486 |
|
487 |
//Prioritise roles with the highest number of the most powerful capabilities.
|
488 |
+
let i = 0, limit = Math.min(aCaps.length, bCaps.length);
|
489 |
+
for (; i < limit; i++) {
|
490 |
let delta = bCaps[i].power - aCaps[i].power;
|
491 |
if (delta !== 0) {
|
492 |
return delta;
|
js/menu-editor.js
CHANGED
@@ -1907,7 +1907,7 @@ function setActorAccess(containerNode, actor, allowAccess) {
|
|
1907 |
}
|
1908 |
|
1909 |
if (typeof actor === 'string') {
|
1910 |
-
menuItem.grant_access[actor] =
|
1911 |
} else {
|
1912 |
_.assign(menuItem.grant_access, actor);
|
1913 |
}
|
@@ -3924,6 +3924,7 @@ function ameOnDomReady() {
|
|
3924 |
event.preventDefault();
|
3925 |
|
3926 |
var button = $(this),
|
|
|
3927 |
menuBox = $(this).closest('.ws_main_container').find('.ws_box').first();
|
3928 |
|
3929 |
if (menuBox.is('#ws_submenu_box')) {
|
@@ -3931,7 +3932,16 @@ function ameOnDomReady() {
|
|
3931 |
}
|
3932 |
|
3933 |
if (menuBox.length > 0) {
|
3934 |
-
sortMenuItems(menuBox,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3935 |
}
|
3936 |
});
|
3937 |
|
@@ -3940,10 +3950,12 @@ function ameOnDomReady() {
|
|
3940 |
*
|
3941 |
* @param $menuBox A DOM node that contains multiple menu items.
|
3942 |
* @param {string} direction 'asc' or 'desc'
|
|
|
3943 |
*/
|
3944 |
-
function sortMenuItems($menuBox, direction) {
|
3945 |
var multiplier = (direction === 'desc') ? -1 : 1,
|
3946 |
-
items = $menuBox.find('.ws_container')
|
|
|
3947 |
|
3948 |
//Separators don't have a title, but we don't want them to end up at the top of the list.
|
3949 |
//Instead, lets keep their position the same relative to the previous item.
|
@@ -3960,8 +3972,8 @@ function ameOnDomReady() {
|
|
3960 |
}));
|
3961 |
|
3962 |
function compareMenus(a, b){
|
3963 |
-
var aTitle =
|
3964 |
-
bTitle =
|
3965 |
|
3966 |
aTitle = aTitle.toLowerCase();
|
3967 |
bTitle = bTitle.toLowerCase();
|
@@ -3975,6 +3987,11 @@ function ameOnDomReady() {
|
|
3975 |
}
|
3976 |
|
3977 |
items.sort(compareMenus);
|
|
|
|
|
|
|
|
|
|
|
3978 |
}
|
3979 |
|
3980 |
//Toggle the second row of toolbar buttons.
|
1907 |
}
|
1908 |
|
1909 |
if (typeof actor === 'string') {
|
1910 |
+
menuItem.grant_access[actor] = Boolean(allowAccess);
|
1911 |
} else {
|
1912 |
_.assign(menuItem.grant_access, actor);
|
1913 |
}
|
3924 |
event.preventDefault();
|
3925 |
|
3926 |
var button = $(this),
|
3927 |
+
direction = button.data('sort-direction') || 'asc',
|
3928 |
menuBox = $(this).closest('.ws_main_container').find('.ws_box').first();
|
3929 |
|
3930 |
if (menuBox.is('#ws_submenu_box')) {
|
3932 |
}
|
3933 |
|
3934 |
if (menuBox.length > 0) {
|
3935 |
+
sortMenuItems(menuBox, direction);
|
3936 |
+
}
|
3937 |
+
|
3938 |
+
//When sorting the top level menu also sort submenus, but leave the first item unmoved.
|
3939 |
+
//Moving the first item would change the parent menu URL (WP always links it to the first item),
|
3940 |
+
//which can be unexpected and confusing. The user can always move the first item manually.
|
3941 |
+
if (menuBox.is('#ws_menu_box')) {
|
3942 |
+
$('#ws_submenu_box').find('.ws_submenu').each(function() {
|
3943 |
+
sortMenuItems($(this), direction, true);
|
3944 |
+
});
|
3945 |
}
|
3946 |
});
|
3947 |
|
3950 |
*
|
3951 |
* @param $menuBox A DOM node that contains multiple menu items.
|
3952 |
* @param {string} direction 'asc' or 'desc'
|
3953 |
+
* @param {boolean} [leaveFirstItem] Leave the first item in its original position. Defaults to false.
|
3954 |
*/
|
3955 |
+
function sortMenuItems($menuBox, direction, leaveFirstItem) {
|
3956 |
var multiplier = (direction === 'desc') ? -1 : 1,
|
3957 |
+
items = $menuBox.find('.ws_container'),
|
3958 |
+
firstItem = items.first();
|
3959 |
|
3960 |
//Separators don't have a title, but we don't want them to end up at the top of the list.
|
3961 |
//Instead, lets keep their position the same relative to the previous item.
|
3972 |
}));
|
3973 |
|
3974 |
function compareMenus(a, b){
|
3975 |
+
var aTitle = $(a).data('ame-sort-value'),
|
3976 |
+
bTitle = $(b).data('ame-sort-value');
|
3977 |
|
3978 |
aTitle = aTitle.toLowerCase();
|
3979 |
bTitle = bTitle.toLowerCase();
|
3987 |
}
|
3988 |
|
3989 |
items.sort(compareMenus);
|
3990 |
+
|
3991 |
+
if (leaveFirstItem) {
|
3992 |
+
//Move the first item back to the top.
|
3993 |
+
firstItem.prependTo($menuBox);
|
3994 |
+
}
|
3995 |
}
|
3996 |
|
3997 |
//Toggle the second row of toolbar buttons.
|
menu-editor.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: Admin Menu Editor
|
4 |
Plugin URI: http://w-shadow.com/blog/2008/12/20/admin-menu-editor-for-wordpress/
|
5 |
Description: Lets you directly edit the WordPress admin menu. You can re-order, hide or rename existing menus, add custom menus and more.
|
6 |
-
Version: 1.
|
7 |
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
|
7 |
Author: Janis Elsts
|
8 |
Author URI: http://w-shadow.com/blog/
|
9 |
*/
|
modules/actor-selector/actor-selector.js
CHANGED
@@ -196,7 +196,7 @@ var AmeActorSelector = (function () {
|
|
196 |
}
|
197 |
return name;
|
198 |
};
|
199 |
-
AmeActorSelector._ = wsAmeLodash;
|
200 |
return AmeActorSelector;
|
201 |
}());
|
|
|
202 |
//# sourceMappingURL=actor-selector.js.map
|
196 |
}
|
197 |
return name;
|
198 |
};
|
|
|
199 |
return AmeActorSelector;
|
200 |
}());
|
201 |
+
AmeActorSelector._ = wsAmeLodash;
|
202 |
//# sourceMappingURL=actor-selector.js.map
|
modules/actor-selector/actor-selector.php
CHANGED
@@ -1,20 +1,17 @@
|
|
1 |
<?php
|
2 |
-
class ameActorSelector {
|
3 |
const ajaxUpdateAction = 'ws_ame_set_visible_users';
|
4 |
|
5 |
-
/**
|
6 |
-
* @var WPMenuEditor
|
7 |
-
*/
|
8 |
-
private $menuEditor;
|
9 |
-
|
10 |
public function __construct($menuEditor) {
|
11 |
-
$
|
12 |
|
13 |
add_action('wp_ajax_' . self::ajaxUpdateAction, array($this, 'ajaxSetVisibleUsers'));
|
14 |
-
add_action('admin_menu_editor-
|
15 |
}
|
16 |
|
17 |
public function registerScripts() {
|
|
|
|
|
18 |
$isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
19 |
$dependencies = array('ame-actor-manager', 'ame-lodash', 'jquery');
|
20 |
if ( $isProVersion || wp_script_is('ame-visible-users', 'registered') ) {
|
@@ -58,4 +55,12 @@ class ameActorSelector {
|
|
58 |
$this->menuEditor->set_plugin_option('visible_users', $visibleUsers);
|
59 |
die('OK');
|
60 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
1 |
<?php
|
2 |
+
class ameActorSelector extends ameModule {
|
3 |
const ajaxUpdateAction = 'ws_ame_set_visible_users';
|
4 |
|
|
|
|
|
|
|
|
|
|
|
5 |
public function __construct($menuEditor) {
|
6 |
+
parent::__construct($menuEditor);
|
7 |
|
8 |
add_action('wp_ajax_' . self::ajaxUpdateAction, array($this, 'ajaxSetVisibleUsers'));
|
9 |
+
add_action('admin_menu_editor-users_to_load', array($this, 'addVisibleUsersToLoginList'));
|
10 |
}
|
11 |
|
12 |
public function registerScripts() {
|
13 |
+
parent::registerScripts();
|
14 |
+
|
15 |
$isProVersion = apply_filters('admin_menu_editor_is_pro', false);
|
16 |
$dependencies = array('ame-actor-manager', 'ame-lodash', 'jquery');
|
17 |
if ( $isProVersion || wp_script_is('ame-visible-users', 'registered') ) {
|
55 |
$this->menuEditor->set_plugin_option('visible_users', $visibleUsers);
|
56 |
die('OK');
|
57 |
}
|
58 |
+
|
59 |
+
public function addVisibleUsersToLoginList($userLogins) {
|
60 |
+
$visibleUsers = $this->menuEditor->get_plugin_option('visible_users');
|
61 |
+
if ( is_array($visibleUsers) ) {
|
62 |
+
$userLogins = array_merge($userLogins, $visibleUsers);
|
63 |
+
}
|
64 |
+
return $userLogins;
|
65 |
+
}
|
66 |
}
|
modules/actor-selector/actor-selector.ts
CHANGED
@@ -87,7 +87,7 @@ class AmeActorSelector {
|
|
87 |
|
88 |
//Select an actor on click.
|
89 |
this.selectorNode.on('click', 'li a.ws_actor_option', (event) => {
|
90 |
-
|
91 |
if (actor === '') {
|
92 |
actor = null;
|
93 |
}
|
@@ -124,13 +124,13 @@ class AmeActorSelector {
|
|
124 |
return;
|
125 |
}
|
126 |
|
127 |
-
|
128 |
this.selectedActor = actorId;
|
129 |
this.highlightSelectedActor();
|
130 |
|
131 |
//Notify subscribers that the selection has changed.
|
132 |
if (this.selectedActor !== previousSelection) {
|
133 |
-
for (
|
134 |
this.subscribers[i](this.selectedActor, previousSelection);
|
135 |
}
|
136 |
}
|
@@ -145,7 +145,7 @@ class AmeActorSelector {
|
|
145 |
this.selectorNode.find('.current').removeClass('current');
|
146 |
|
147 |
//Select the new one or "All".
|
148 |
-
|
149 |
if (this.selectedActor === null) {
|
150 |
selector = 'a.ws_no_actor';
|
151 |
} else {
|
@@ -157,13 +157,13 @@ class AmeActorSelector {
|
|
157 |
private populateActorSelector() {
|
158 |
const actorSelector = this.selectorNode,
|
159 |
$ = jQuery;
|
160 |
-
|
161 |
|
162 |
//Build the list of available actors.
|
163 |
actorSelector.empty();
|
164 |
actorSelector.append('<li><a href="#" class="current ws_actor_option ws_no_actor" data-text="All">All</a></li>');
|
165 |
|
166 |
-
|
167 |
for (let i = 0; i < visibleActors.length; i++) {
|
168 |
const actor = visibleActors[i],
|
169 |
name = this.getNiceName(actor);
|
@@ -181,7 +181,7 @@ class AmeActorSelector {
|
|
181 |
}
|
182 |
|
183 |
if (this.isProVersion) {
|
184 |
-
|
185 |
actorSelector.append(
|
186 |
$('<li>').append(
|
187 |
$('<a></a>')
|
@@ -211,7 +211,7 @@ class AmeActorSelector {
|
|
211 |
}
|
212 |
|
213 |
const _ = AmeActorSelector._;
|
214 |
-
|
215 |
|
216 |
//Include all roles.
|
217 |
//Idea: Sort roles either alphabetically or by typical privilege level (admin, editor, author, ...).
|
@@ -230,7 +230,7 @@ class AmeActorSelector {
|
|
230 |
.without(this.currentUserLogin)
|
231 |
.sortBy()
|
232 |
.forEach((login) => {
|
233 |
-
|
234 |
actors.push(user);
|
235 |
})
|
236 |
.value();
|
87 |
|
88 |
//Select an actor on click.
|
89 |
this.selectorNode.on('click', 'li a.ws_actor_option', (event) => {
|
90 |
+
let actor = jQuery(event.target).attr('href').substring(1);
|
91 |
if (actor === '') {
|
92 |
actor = null;
|
93 |
}
|
124 |
return;
|
125 |
}
|
126 |
|
127 |
+
const previousSelection = this.selectedActor;
|
128 |
this.selectedActor = actorId;
|
129 |
this.highlightSelectedActor();
|
130 |
|
131 |
//Notify subscribers that the selection has changed.
|
132 |
if (this.selectedActor !== previousSelection) {
|
133 |
+
for (let i = 0; i < this.subscribers.length; i++) {
|
134 |
this.subscribers[i](this.selectedActor, previousSelection);
|
135 |
}
|
136 |
}
|
145 |
this.selectorNode.find('.current').removeClass('current');
|
146 |
|
147 |
//Select the new one or "All".
|
148 |
+
let selector;
|
149 |
if (this.selectedActor === null) {
|
150 |
selector = 'a.ws_no_actor';
|
151 |
} else {
|
157 |
private populateActorSelector() {
|
158 |
const actorSelector = this.selectorNode,
|
159 |
$ = jQuery;
|
160 |
+
let isSelectedActorVisible = false;
|
161 |
|
162 |
//Build the list of available actors.
|
163 |
actorSelector.empty();
|
164 |
actorSelector.append('<li><a href="#" class="current ws_actor_option ws_no_actor" data-text="All">All</a></li>');
|
165 |
|
166 |
+
const visibleActors = this.getVisibleActors();
|
167 |
for (let i = 0; i < visibleActors.length; i++) {
|
168 |
const actor = visibleActors[i],
|
169 |
name = this.getNiceName(actor);
|
181 |
}
|
182 |
|
183 |
if (this.isProVersion) {
|
184 |
+
const moreUsersText = 'Choose users\u2026';
|
185 |
actorSelector.append(
|
186 |
$('<li>').append(
|
187 |
$('<a></a>')
|
211 |
}
|
212 |
|
213 |
const _ = AmeActorSelector._;
|
214 |
+
let actors = [];
|
215 |
|
216 |
//Include all roles.
|
217 |
//Idea: Sort roles either alphabetically or by typical privilege level (admin, editor, author, ...).
|
230 |
.without(this.currentUserLogin)
|
231 |
.sortBy()
|
232 |
.forEach((login) => {
|
233 |
+
const user = this.actorManager.getUser(login);
|
234 |
actors.push(user);
|
235 |
})
|
236 |
.value();
|
modules/admin-css/admin-css.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ameAdminCss extends ameModule {
|
4 |
+
protected $tabSlug = 'admin-css';
|
5 |
+
protected $tabTitle = 'CSS';
|
6 |
+
|
7 |
+
public function enqueueTabScripts() {
|
8 |
+
parent::enqueueTabScripts();
|
9 |
+
|
10 |
+
$menuConfig = $this->menuEditor->get_active_admin_menu();
|
11 |
+
|
12 |
+
//We really only need a couple of menu properties for this feature, like the titles and URLs.
|
13 |
+
$items = array_values(array_map(array($this, 'getRelevantMenuProperties'), $menuConfig['tree']));
|
14 |
+
}
|
15 |
+
|
16 |
+
private function getRelevantMenuProperties($menuItem) {
|
17 |
+
$properties = array(
|
18 |
+
'menu_title' => ameMenuItem::get($menuItem, 'menu_title', '(Untitled Item)'),
|
19 |
+
'url' => ameMenuItem::get($menuItem, 'url'),
|
20 |
+
);
|
21 |
+
|
22 |
+
if ( ameMenuItem::get($menuItem, 'separator', false) ) {
|
23 |
+
$properties['separator'] = true;
|
24 |
+
}
|
25 |
+
|
26 |
+
if ( !empty($menuItem['items']) ) {
|
27 |
+
$properties['items'] = array_values(array_map(
|
28 |
+
array($this, 'getRelevantMenuProperties'),
|
29 |
+
$menuItem['items']
|
30 |
+
));
|
31 |
+
}
|
32 |
+
|
33 |
+
return $properties;
|
34 |
+
}
|
35 |
+
}
|
modules/highlight-new-menus/assets/highlight-menus.js
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* global wsNmhData */
|
2 |
+
|
3 |
+
jQuery(function($) {
|
4 |
+
'use strict';
|
5 |
+
|
6 |
+
var $adminMenu = $('#adminmenu'),
|
7 |
+
seenOnThisPage = {},
|
8 |
+
foundNewMenus;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Flag a menu URL as seen (i.e. no longer new).
|
12 |
+
*
|
13 |
+
* This function is both debounced and throttled. As long as you continue to call it,
|
14 |
+
* the AJAX request won't be triggered. It will be sent only once the function stops
|
15 |
+
* being called for N milliseconds. Additionally, it will wait at least N milliseconds
|
16 |
+
* between requests.
|
17 |
+
*
|
18 |
+
* @param string menuUrls
|
19 |
+
*/
|
20 |
+
var flagAsSeen = (function() {
|
21 |
+
var queue = [],
|
22 |
+
timeout = null,
|
23 |
+
waitMs = 500,
|
24 |
+
isRequestInProgress = false;
|
25 |
+
|
26 |
+
function sendQueuedUrls() {
|
27 |
+
|
28 |
+
if (queue.length > 0) {
|
29 |
+
if (isRequestInProgress) {
|
30 |
+
//console.warn('A request is already in progress');
|
31 |
+
}
|
32 |
+
isRequestInProgress = true;
|
33 |
+
|
34 |
+
$.ajax(
|
35 |
+
ajaxurl,
|
36 |
+
{
|
37 |
+
'method': 'POST',
|
38 |
+
'data': {
|
39 |
+
'action': wsNmhData['flagAction'],
|
40 |
+
'_ajax_nonce': wsNmhData['flagNonce'],
|
41 |
+
'urls' : JSON.stringify(queue)
|
42 |
+
},
|
43 |
+
'complete': function() {
|
44 |
+
isRequestInProgress = false;
|
45 |
+
if (queue.length > 0) {
|
46 |
+
timeout = setTimeout(sendQueuedUrls, waitMs);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
}
|
50 |
+
);
|
51 |
+
}
|
52 |
+
|
53 |
+
queue = [];
|
54 |
+
timeout = null;
|
55 |
+
}
|
56 |
+
|
57 |
+
return function(menuUrl) {
|
58 |
+
if ((menuUrl === '') || seenOnThisPage.hasOwnProperty(menuUrl)) {
|
59 |
+
return;
|
60 |
+
}
|
61 |
+
seenOnThisPage[menuUrl] = true;
|
62 |
+
|
63 |
+
//In case the AJAX request doesn't succeed for whatever reason, lets *also*
|
64 |
+
//set a session cookie that contains the seen URLs.
|
65 |
+
if ($.cookie) {
|
66 |
+
$.cookie('ws_nmh_pending_seen_urls', JSON.stringify(seenOnThisPage));
|
67 |
+
}
|
68 |
+
|
69 |
+
queue.push(menuUrl);
|
70 |
+
|
71 |
+
if (isRequestInProgress) {
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
if (timeout) {
|
76 |
+
//Move the timeout forward.
|
77 |
+
clearTimeout(timeout);
|
78 |
+
}
|
79 |
+
timeout = setTimeout(sendQueuedUrls, waitMs);
|
80 |
+
}
|
81 |
+
})();
|
82 |
+
|
83 |
+
function maybeFlagItem($item) {
|
84 |
+
var shouldFlagThis = true,
|
85 |
+
shouldFlagParent = false,
|
86 |
+
$link, $flag, $parent;
|
87 |
+
|
88 |
+
if ($item.hasClass('menu-top')) {
|
89 |
+
//Only flag top level menus when they no longer have any new submenus.
|
90 |
+
shouldFlagThis = $item
|
91 |
+
.find('> ul li.ws-nmh-is-new-menu')
|
92 |
+
.not('.wp-submenu-head')
|
93 |
+
.length === 0;
|
94 |
+
} else {
|
95 |
+
//If all of the submenus on this level are seen/not new, flag the parent menu as well.
|
96 |
+
shouldFlagParent = $item.siblings('li.ws-nmh-is-new-menu').not('.wp-submenu-head').length === 0;
|
97 |
+
}
|
98 |
+
|
99 |
+
if (!shouldFlagThis) {
|
100 |
+
return;
|
101 |
+
}
|
102 |
+
|
103 |
+
$link = $item.children('a').first();
|
104 |
+
$flag = $link.find('.ws-nmh-new-menu-flag');
|
105 |
+
|
106 |
+
$item.removeClass('ws-nmh-is-new-menu');
|
107 |
+
$link.removeClass('ws-nmh-is-new-menu');
|
108 |
+
|
109 |
+
if ($flag.length > 0) {
|
110 |
+
flagAsSeen($flag.data('nmh-menu-url'));
|
111 |
+
$flag.remove();
|
112 |
+
}
|
113 |
+
|
114 |
+
if (shouldFlagParent) {
|
115 |
+
$parent = $item.parentsUntil($adminMenu, 'li');
|
116 |
+
if (($parent.length > 0) && !$parent.is($item)) {
|
117 |
+
maybeFlagItem($parent);
|
118 |
+
}
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
var $newItems = $adminMenu.find('.ws-nmh-new-menu-flag').closest('li').addClass('ws-nmh-is-new-menu');
|
123 |
+
foundNewMenus = $newItems.length > 0;
|
124 |
+
|
125 |
+
//Flag the current item as seen.
|
126 |
+
$newItems.filter('.current, .wp-has-current-submenu').each(function() {
|
127 |
+
maybeFlagItem($(this));
|
128 |
+
});
|
129 |
+
|
130 |
+
if (foundNewMenus) {
|
131 |
+
$adminMenu.on('mouseenter click focusin', 'li.ws-nmh-is-new-menu', function() {
|
132 |
+
maybeFlagItem($(this).closest('li'));
|
133 |
+
});
|
134 |
+
}
|
135 |
+
});
|
modules/highlight-new-menus/assets/menu-highlights.css
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#adminmenu a.ws-nmh-is-new-menu,
|
2 |
+
#adminmenu li.ws-nmh-is-new-menu > a.menu-top,
|
3 |
+
#adminmenu .wp-submenu > li.ws-nmh-is-new-menu {
|
4 |
+
background-color: #73aa00 !important; }
|
5 |
+
#adminmenu li.ws-nmh-is-new-menu > a {
|
6 |
+
color: #ffe !important; }
|
7 |
+
#adminmenu li.ws-nmh-is-new-menu > a div.wp-menu-image::before {
|
8 |
+
color: rgba(255, 255, 238, 0.6); }
|
9 |
+
#adminmenu .ws-nmh-new-menu-flag {
|
10 |
+
display: none; }
|
11 |
+
|
12 |
+
/*# sourceMappingURL=menu-highlights.css.map */
|
modules/highlight-new-menus/assets/menu-highlights.css.map
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"version": 3,
|
3 |
+
"mappings": "AAIC;;8CAEoC;EACnC,gBAAgB,EAAE,kBAAsB;AAGzC,oCAA0B;EACzB,KAAK,EAAE,eAAgB;EAEvB,8DAA0B;IACzB,KAAK,EAAE,wBAAgB;AAIzB,gCAAsB;EACrB,OAAO,EAAE,IAAI",
|
4 |
+
"sources": ["menu-highlights.scss"],
|
5 |
+
"names": [],
|
6 |
+
"file": "menu-highlights.css"
|
7 |
+
}
|
modules/highlight-new-menus/assets/menu-highlights.scss
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#adminmenu {
|
2 |
+
$background: #73aa00;
|
3 |
+
$text: #ffe;
|
4 |
+
|
5 |
+
a.ws-nmh-is-new-menu,
|
6 |
+
li.ws-nmh-is-new-menu > a.menu-top,
|
7 |
+
.wp-submenu > li.ws-nmh-is-new-menu {
|
8 |
+
background-color: $background !important;
|
9 |
+
}
|
10 |
+
|
11 |
+
li.ws-nmh-is-new-menu > a {
|
12 |
+
color: $text !important;
|
13 |
+
|
14 |
+
div.wp-menu-image::before {
|
15 |
+
color: rgba($text, 0.6);
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
.ws-nmh-new-menu-flag {
|
20 |
+
display: none;
|
21 |
+
}
|
22 |
+
}
|
23 |
+
|
modules/highlight-new-menus/highlight-new-menus.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ameMenuHighlighterWrapper extends ameModule {
|
4 |
+
public function __construct($menuEditor) {
|
5 |
+
parent::__construct($menuEditor);
|
6 |
+
|
7 |
+
if ( is_admin() ) {
|
8 |
+
require dirname(__FILE__) . '/wsNewMenuHighlighter.php';
|
9 |
+
new wsNewMenuHighlighter();
|
10 |
+
}
|
11 |
+
}
|
12 |
+
}
|
modules/highlight-new-menus/plugin.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Plugin Name: Highlight New Admin Menus
|
5 |
+
* Plugin URI: http://adminmenueditor.com
|
6 |
+
* Version: 1.0
|
7 |
+
* Author: Janis Elsts
|
8 |
+
* Author URI: http://w-shadow.com/
|
9 |
+
* Description: Highlights new admin menu items.
|
10 |
+
*/
|
11 |
+
|
12 |
+
require 'wsNewMenuHighlighter.php';
|
13 |
+
if ( is_admin() ) {
|
14 |
+
new wsNewMenuHighlighter();
|
15 |
+
}
|
modules/highlight-new-menus/uninstall.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//Remove "user has seen this menu" records.
|
3 |
+
if ( defined('ABSPATH') && defined('WP_UNINSTALL_PLUGIN') ) {
|
4 |
+
delete_metadata('user', 0, 'ws_nmh_seen_menus', null, true);
|
5 |
+
}
|
modules/highlight-new-menus/wsNewMenuHighlighter.php
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class wsNewMenuHighlighter {
|
4 |
+
const ITEM_SLUG_INDEX = 2;
|
5 |
+
const ITEM_TITLE_INDEX = 0;
|
6 |
+
const ITEM_CLASS_INDEX = 4;
|
7 |
+
|
8 |
+
const STORAGE_KEY = 'ws_nmh_seen_menus';
|
9 |
+
const AJAX_FLAG_ACTION = 'nmh-flag-as-seen';
|
10 |
+
const COOKIE_NAME = 'ws_nmh_pending_seen_urls';
|
11 |
+
|
12 |
+
static $blacklist = array(
|
13 |
+
//These items are invisible when the theme customizer is available.
|
14 |
+
'themes.php?page=custom-header' => true,
|
15 |
+
'themes.php?page=custom-background' => true,
|
16 |
+
//Files in /wp-admin.
|
17 |
+
'customize.php' => true,
|
18 |
+
'edit-comments.php' => true,
|
19 |
+
'edit-tags.php' => true,
|
20 |
+
'edit.php' => true,
|
21 |
+
'export.php' => true,
|
22 |
+
'import.php' => true,
|
23 |
+
'index.php' => true,
|
24 |
+
'link-add.php' => true,
|
25 |
+
'link-manager.php' => true,
|
26 |
+
'media-new.php' => true,
|
27 |
+
'nav-menus.php' => true,
|
28 |
+
'options-discussion.php' => true,
|
29 |
+
'options-general.php' => true,
|
30 |
+
'options-media.php' => true,
|
31 |
+
'options-permalink.php' => true,
|
32 |
+
'options-reading.php' => true,
|
33 |
+
'options-writing.php' => true,
|
34 |
+
'plugin-editor.php' => true,
|
35 |
+
'plugin-install.php' => true,
|
36 |
+
'plugins.php' => true,
|
37 |
+
'post-new.php' => true,
|
38 |
+
'profile.php' => true,
|
39 |
+
'theme-editor.php' => true,
|
40 |
+
'themes.php' => true,
|
41 |
+
'tools.php' => true,
|
42 |
+
'update-core.php' => true,
|
43 |
+
'upload.php' => true,
|
44 |
+
'user-new.php' => true,
|
45 |
+
'users.php' => true,
|
46 |
+
'widgets.php' => true,
|
47 |
+
);
|
48 |
+
|
49 |
+
private $menusWithNewSubmenus = array();
|
50 |
+
private $seenMenuUrls = array();
|
51 |
+
private $isFirstRun = false;
|
52 |
+
|
53 |
+
public function __construct() {
|
54 |
+
//Run after AME replaces the menu so that we don't pollute the menu editor with our flags and classes.
|
55 |
+
if ( class_exists('WPMenuEditor', false) ) {
|
56 |
+
add_action('admin_menu_editor-menu_replaced', array($this, 'parseAdminMenu'));
|
57 |
+
add_action('admin_menu_editor-menu_replacement_skipped', array($this, 'parseAdminMenu'));
|
58 |
+
} else {
|
59 |
+
add_action('admin_menu', array($this, 'parseAdminMenu'), 9000);
|
60 |
+
}
|
61 |
+
|
62 |
+
add_action('admin_enqueue_scripts', array($this, 'enqueueDependencies'));
|
63 |
+
add_action('wp_ajax_' . self::AJAX_FLAG_ACTION, array($this, 'ajaxFlagAsSeen'));
|
64 |
+
|
65 |
+
add_action('admin_init', array($this, 'flagUrlsFromCookie'));
|
66 |
+
}
|
67 |
+
|
68 |
+
public function parseAdminMenu() {
|
69 |
+
if ( !current_user_can('activate_plugins') ) {
|
70 |
+
return;
|
71 |
+
}
|
72 |
+
|
73 |
+
global $menu, $submenu;
|
74 |
+
$this->seenMenuUrls = $this->loadSeenMenus();
|
75 |
+
|
76 |
+
if ( empty($this->seenMenuUrls) ) {
|
77 |
+
$this->isFirstRun = true;
|
78 |
+
}
|
79 |
+
|
80 |
+
foreach ($submenu as $parent => &$items) {
|
81 |
+
foreach ($items as &$submenuItem) {
|
82 |
+
$submenuItem = $this->processItem($submenuItem, $parent);
|
83 |
+
}
|
84 |
+
}
|
85 |
+
unset($items, $submenuItem);
|
86 |
+
|
87 |
+
foreach ($menu as &$item) {
|
88 |
+
$item = $this->processItem($item);
|
89 |
+
}
|
90 |
+
|
91 |
+
if ( $this->isFirstRun ) {
|
92 |
+
$urls = array_keys($this->seenMenuUrls);
|
93 |
+
$this->seenMenuUrls = array();
|
94 |
+
$this->flagAsSeen($urls);
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
private function loadSeenMenus() {
|
99 |
+
$seenMenuUrls = get_user_meta(get_current_user_id(), self::STORAGE_KEY, true);
|
100 |
+
if ( !is_array($seenMenuUrls) ) {
|
101 |
+
$seenMenuUrls = array();
|
102 |
+
}
|
103 |
+
return $seenMenuUrls;
|
104 |
+
}
|
105 |
+
|
106 |
+
private function processItem($item, $parentSlug = null) {
|
107 |
+
if ( $this->isIgnoredItem($item) ) {
|
108 |
+
return $item;
|
109 |
+
}
|
110 |
+
|
111 |
+
$itemSlug = $item[self::ITEM_SLUG_INDEX];
|
112 |
+
$url = $this->getMenuUrl($itemSlug, $parentSlug);
|
113 |
+
$isBlacklisted = empty($url) || isset(self::$blacklist[$url]);
|
114 |
+
|
115 |
+
//On first run, just collect all items and flag them as seen.
|
116 |
+
if ( $this->isFirstRun ) {
|
117 |
+
if ( !$isBlacklisted ) {
|
118 |
+
$this->seenMenuUrls[$url] = true;
|
119 |
+
}
|
120 |
+
return $item;
|
121 |
+
}
|
122 |
+
|
123 |
+
if ( ($this->isNewMenu($url) && !$isBlacklisted) || $this->hasNewSubmenus($itemSlug) ) {
|
124 |
+
$item[self::ITEM_TITLE_INDEX] .= sprintf(
|
125 |
+
'<span class="ws-nmh-new-menu-flag" data-nmh-menu-url="%s"></span>',
|
126 |
+
esc_attr($url)
|
127 |
+
);
|
128 |
+
|
129 |
+
if ( ($parentSlug === null) && isset($item[self::ITEM_CLASS_INDEX]) ) {
|
130 |
+
$item[self::ITEM_CLASS_INDEX] .= ' ws-nmh-is-new-menu';
|
131 |
+
}
|
132 |
+
|
133 |
+
if ( $parentSlug !== null ) {
|
134 |
+
$this->menusWithNewSubmenus[$parentSlug] = true;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
return $item;
|
139 |
+
}
|
140 |
+
|
141 |
+
private function getMenuUrl($itemSlug, $parentSlug) {
|
142 |
+
if ( class_exists('ameMenuItem') ) {
|
143 |
+
return ameMenuItem::generate_url($itemSlug, $parentSlug);
|
144 |
+
} else {
|
145 |
+
return $itemSlug;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
private function isIgnoredItem($item) {
|
150 |
+
if ( !isset($item[self::ITEM_SLUG_INDEX]) ) {
|
151 |
+
return true; //That's either an invalid item or an improvised separator.
|
152 |
+
}
|
153 |
+
|
154 |
+
//Skip separators and unnamed menus.
|
155 |
+
$isSeparator = isset($item[self::ITEM_CLASS_INDEX])
|
156 |
+
&& (strpos($item[self::ITEM_CLASS_INDEX], 'wp-menu-separator') !== false);
|
157 |
+
|
158 |
+
if ( $isSeparator || empty($item[self::ITEM_SLUG_INDEX]) || ($item[self::ITEM_TITLE_INDEX] === '') ) {
|
159 |
+
return true;
|
160 |
+
}
|
161 |
+
|
162 |
+
//Skip customizer links. They have a different URL on every admin page, so they'd always show up as new.
|
163 |
+
if ( strpos($item[self::ITEM_SLUG_INDEX], 'customize.php') === 0 ) {
|
164 |
+
return true;
|
165 |
+
}
|
166 |
+
|
167 |
+
return false;
|
168 |
+
}
|
169 |
+
|
170 |
+
private function isNewMenu($url) {
|
171 |
+
return empty($this->seenMenuUrls[$url]);
|
172 |
+
}
|
173 |
+
|
174 |
+
private function hasNewSubmenus($slug) {
|
175 |
+
return !empty($this->menusWithNewSubmenus[$slug]);
|
176 |
+
}
|
177 |
+
|
178 |
+
public function enqueueDependencies() {
|
179 |
+
$dependencies = array('jquery');
|
180 |
+
|
181 |
+
if ( isset($GLOBALS['wp_menu_editor']) && is_callable(array(
|
182 |
+
$GLOBALS['wp_menu_editor'],
|
183 |
+
'register_base_dependencies',
|
184 |
+
))
|
185 |
+
) {
|
186 |
+
$GLOBALS['wp_menu_editor']->register_base_dependencies();
|
187 |
+
$dependencies[] = 'jquery-cookie';
|
188 |
+
}
|
189 |
+
|
190 |
+
wp_enqueue_script(
|
191 |
+
'ws-nmh-admin-script',
|
192 |
+
plugins_url('assets/highlight-menus.js', __FILE__),
|
193 |
+
$dependencies,
|
194 |
+
'20170503'
|
195 |
+
);
|
196 |
+
|
197 |
+
wp_localize_script(
|
198 |
+
'ws-nmh-admin-script',
|
199 |
+
'wsNmhData',
|
200 |
+
array(
|
201 |
+
'flagAction' => self::AJAX_FLAG_ACTION,
|
202 |
+
'flagNonce' => wp_create_nonce(self::AJAX_FLAG_ACTION),
|
203 |
+
)
|
204 |
+
);
|
205 |
+
|
206 |
+
wp_enqueue_style(
|
207 |
+
'ws-nmh-admin-style',
|
208 |
+
plugins_url('assets/menu-highlights.css', __FILE__),
|
209 |
+
array(),
|
210 |
+
'20170503'
|
211 |
+
);
|
212 |
+
}
|
213 |
+
|
214 |
+
public function ajaxFlagAsSeen() {
|
215 |
+
check_ajax_referer(self::AJAX_FLAG_ACTION);
|
216 |
+
if ( empty($_POST['urls']) ) {
|
217 |
+
if ( function_exists('status_header') ) {
|
218 |
+
status_header(400);
|
219 |
+
}
|
220 |
+
exit('Error: The required "urls" parameter is missing.');
|
221 |
+
}
|
222 |
+
|
223 |
+
$json = strval($_POST['urls']);
|
224 |
+
//Unfortunately, WP applies magic quotes to POST data.
|
225 |
+
if ( function_exists('wp_magic_quotes') && did_action('plugins_loaded') ) {
|
226 |
+
$json = stripslashes($json);
|
227 |
+
}
|
228 |
+
|
229 |
+
if ( $this->flagAsSeen(json_decode($json)) ) {
|
230 |
+
exit('Success');
|
231 |
+
} else {
|
232 |
+
exit('Failure');
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
+
public function flagUrlsFromCookie() {
|
237 |
+
if ( !is_user_logged_in() || empty($_COOKIE[self::COOKIE_NAME]) || defined('DOING_AJAX') ) {
|
238 |
+
return;
|
239 |
+
}
|
240 |
+
|
241 |
+
$urls = json_decode(stripslashes($_COOKIE[self::COOKIE_NAME]), true);
|
242 |
+
if ( is_array($urls) ) {
|
243 |
+
$this->flagAsSeen(array_keys($urls));
|
244 |
+
}
|
245 |
+
|
246 |
+
setcookie(self::COOKIE_NAME, '', time() - (24 * 3600));
|
247 |
+
}
|
248 |
+
|
249 |
+
private function flagAsSeen($menuUrls) {
|
250 |
+
if ( empty($menuUrls) || !is_array($menuUrls) ) {
|
251 |
+
return false;
|
252 |
+
}
|
253 |
+
$menuUrls = array_filter($menuUrls);
|
254 |
+
$this->seenMenuUrls = $this->loadSeenMenus();
|
255 |
+
|
256 |
+
//Optimization: Save only if there are changes / new URLs.
|
257 |
+
$urlIndex = array_fill_keys($menuUrls, true);
|
258 |
+
$newUrls = array_diff_key($urlIndex, $this->seenMenuUrls);
|
259 |
+
if ( !empty($newUrls) ) {
|
260 |
+
$this->seenMenuUrls = array_merge($this->seenMenuUrls, $urlIndex);
|
261 |
+
return update_user_meta(get_current_user_id(), self::STORAGE_KEY, $this->seenMenuUrls);
|
262 |
+
} else {
|
263 |
+
return false;
|
264 |
+
}
|
265 |
+
}
|
266 |
+
}
|
modules/plugin-visibility/plugin-visibility-template.php
CHANGED
@@ -41,7 +41,8 @@
|
|
41 |
css: {
|
42 |
'active': isActive,
|
43 |
'inactive': !isActive
|
44 |
-
}
|
|
|
45 |
">
|
46 |
|
47 |
<!--
|
@@ -64,10 +65,69 @@
|
|
64 |
<label data-bind="attr: { 'for': 'ame-plugin-visible-' + $index() }">
|
65 |
<strong data-bind="text: name"></strong>
|
66 |
</label>
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
</td>
|
68 |
|
69 |
<td><p data-bind="text: description"></p></td>
|
70 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
</tbody>
|
72 |
|
73 |
<tfoot>
|
41 |
css: {
|
42 |
'active': isActive,
|
43 |
'inactive': !isActive
|
44 |
+
},
|
45 |
+
visible: !isBeingEdited()
|
46 |
">
|
47 |
|
48 |
<!--
|
65 |
<label data-bind="attr: { 'for': 'ame-plugin-visible-' + $index() }">
|
66 |
<strong data-bind="text: name"></strong>
|
67 |
</label>
|
68 |
+
<div class="row-actions">
|
69 |
+
<span class="edit">
|
70 |
+
<a href="#" title="Edit plugin name and description. This is a cosmetic change - the actual plugin files are not affected."
|
71 |
+
data-bind="click: openInlineEditor.bind($data)">Edit</a>
|
72 |
+
</span>
|
73 |
+
</div>
|
74 |
</td>
|
75 |
|
76 |
<td><p data-bind="text: description"></p></td>
|
77 |
</tr>
|
78 |
+
<tr class="inline-edit-row" data-bind="if: isBeingEdited">
|
79 |
+
<td class="colspanchange" colspan="3">
|
80 |
+
<fieldset class="ame-pv-inline-edit-left">
|
81 |
+
<div class="inline-edit-col">
|
82 |
+
<label>
|
83 |
+
<span class="title">Name</span>
|
84 |
+
<input type="text" data-bind="value: editableName" class="ame-pv-custom-name">
|
85 |
+
</label>
|
86 |
+
</div>
|
87 |
+
</fieldset>
|
88 |
+
<fieldset class="ame-pv-inline-edit-right">
|
89 |
+
<div class="inline-edit-col">
|
90 |
+
<label>
|
91 |
+
<span class="title">Description</span>
|
92 |
+
<textarea name="plugin-description" cols="30" rows="5"
|
93 |
+
class="ame-pv-custom-description"
|
94 |
+
data-bind="value: editableDescription"></textarea>
|
95 |
+
</label>
|
96 |
+
</div>
|
97 |
+
</fieldset>
|
98 |
+
|
99 |
+
<p class="submit">
|
100 |
+
<?php
|
101 |
+
submit_button(
|
102 |
+
'Cancel',
|
103 |
+
'secondary cancel alignleft',
|
104 |
+
'pv-cancel',
|
105 |
+
false,
|
106 |
+
array(
|
107 |
+
'data-bind' => 'click: cancelEdit.bind($data)'
|
108 |
+
)
|
109 |
+
);
|
110 |
+
?>
|
111 |
+
|
112 |
+
<a class="alignleft ame-pv-inline-reset" href="#"
|
113 |
+
title="Reset name and description to default values"
|
114 |
+
data-bind="click: resetNameAndDescription.bind($data)">Reset to default</a>
|
115 |
+
|
116 |
+
<?php
|
117 |
+
submit_button(
|
118 |
+
'Update',
|
119 |
+
'primary save alignright',
|
120 |
+
'pv-update',
|
121 |
+
false,
|
122 |
+
array(
|
123 |
+
'data-bind' => 'click: confirmEdit.bind($data)'
|
124 |
+
)
|
125 |
+
);
|
126 |
+
?>
|
127 |
+
<br class="clear">
|
128 |
+
</p>
|
129 |
+
</td>
|
130 |
+
</tr>
|
131 |
</tbody>
|
132 |
|
133 |
<tfoot>
|
modules/plugin-visibility/plugin-visibility.css
CHANGED
@@ -41,4 +41,23 @@
|
|
41 |
#ws_actor_selector_container {
|
42 |
margin-right: 130px; }
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
/*# sourceMappingURL=plugin-visibility.css.map */
|
41 |
#ws_actor_selector_container {
|
42 |
margin-right: 130px; }
|
43 |
|
44 |
+
/*
|
45 |
+
Inline editor
|
46 |
+
*/
|
47 |
+
#ame-plugin-visibility-editor .inline-edit-row .ame-pv-inline-edit-left {
|
48 |
+
width: 30%; }
|
49 |
+
#ame-plugin-visibility-editor .inline-edit-row .ame-pv-inline-edit-right {
|
50 |
+
width: 70%; }
|
51 |
+
#ame-plugin-visibility-editor .inline-edit-row span.title {
|
52 |
+
width: auto; }
|
53 |
+
#ame-plugin-visibility-editor .inline-edit-row input[type="text"] {
|
54 |
+
width: 100%; }
|
55 |
+
#ame-plugin-visibility-editor .inline-edit-row .ame-pv-inline-reset {
|
56 |
+
line-height: 28px;
|
57 |
+
margin-left: 1em; }
|
58 |
+
#ame-plugin-visibility-editor .inline-edit-row td {
|
59 |
+
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1); }
|
60 |
+
#ame-plugin-visibility-editor .inline-edit-row p.submit {
|
61 |
+
margin-bottom: 0.2em; }
|
62 |
+
|
63 |
/*# sourceMappingURL=plugin-visibility.css.map */
|
modules/plugin-visibility/plugin-visibility.js
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
/// <reference path="../../js/jqueryui.d.ts" />
|
4 |
/// <reference path="../../js/lodash-3.10.d.ts" />
|
5 |
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
|
|
|
6 |
var AmePluginVisibilityModule = (function () {
|
7 |
function AmePluginVisibilityModule(scriptData) {
|
8 |
var _this = this;
|
@@ -32,6 +33,10 @@ var AmePluginVisibilityModule = (function () {
|
|
32 |
this.plugins = _.map(scriptData.installedPlugins, function (plugin) {
|
33 |
return new AmePlugin(plugin, _.get(scriptData.settings.plugins, plugin.fileName, {}), _this);
|
34 |
});
|
|
|
|
|
|
|
|
|
35 |
this.privilegedActors = [this.actorSelector.getCurrentUserActor()];
|
36 |
if (this.isMultisite) {
|
37 |
this.privilegedActors.push(AmeActors.getSuperAdmin());
|
@@ -132,11 +137,14 @@ var AmePluginVisibilityModule = (function () {
|
|
132 |
isVisibleByDefault: plugin.isVisibleByDefault(),
|
133 |
grantAccess: _.mapValues(plugin.grantAccess, function (allow) {
|
134 |
return allow();
|
135 |
-
})
|
|
|
|
|
136 |
};
|
137 |
});
|
138 |
return result;
|
139 |
};
|
|
|
140 |
AmePluginVisibilityModule.prototype.saveChanges = function () {
|
141 |
var settings = this.getSettings();
|
142 |
//Remove settings associated with roles and users that no longer exist or are not visible.
|
@@ -152,16 +160,35 @@ var AmePluginVisibilityModule = (function () {
|
|
152 |
return AmePluginVisibilityModule;
|
153 |
}());
|
154 |
var AmePlugin = (function () {
|
155 |
-
function AmePlugin(details,
|
156 |
var _this = this;
|
157 |
-
|
158 |
-
this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
this.fileName = details.fileName;
|
160 |
this.isActive = details.isActive;
|
161 |
-
|
162 |
-
this.
|
|
|
|
|
163 |
var emptyGrant = {};
|
164 |
-
this.grantAccess = _.mapValues(_.get(
|
165 |
return ko.observable(hasAccess);
|
166 |
});
|
167 |
this.isChecked = ko.computed({
|
@@ -180,6 +207,34 @@ var AmePlugin = (function () {
|
|
180 |
}
|
181 |
return this.grantAccess[actorId];
|
182 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
AmePlugin.stripAllTags = function (input) {
|
184 |
//Based on: http://phpjs.org/functions/strip_tags/
|
185 |
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
@@ -192,10 +247,7 @@ jQuery(function ($) {
|
|
192 |
ko.applyBindings(amePluginVisibility, document.getElementById('ame-plugin-visibility-editor'));
|
193 |
//Permanently dismiss the usage hint via AJAX.
|
194 |
$('#ame-pv-usage-notice').on('click', '.notice-dismiss', function () {
|
195 |
-
|
196 |
-
'action': 'ws_ame_dismiss_pv_usage_notice',
|
197 |
-
'_ajax_nonce': wsPluginVisibilityData.dismissNoticeNonce
|
198 |
-
});
|
199 |
});
|
200 |
});
|
201 |
//# sourceMappingURL=plugin-visibility.js.map
|
3 |
/// <reference path="../../js/jqueryui.d.ts" />
|
4 |
/// <reference path="../../js/lodash-3.10.d.ts" />
|
5 |
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
|
6 |
+
/// <reference path="../../ajax-wrapper/ajax-action-wrapper.d.ts" />
|
7 |
var AmePluginVisibilityModule = (function () {
|
8 |
function AmePluginVisibilityModule(scriptData) {
|
9 |
var _this = this;
|
33 |
this.plugins = _.map(scriptData.installedPlugins, function (plugin) {
|
34 |
return new AmePlugin(plugin, _.get(scriptData.settings.plugins, plugin.fileName, {}), _this);
|
35 |
});
|
36 |
+
//Normally, the plugin list is sorted by the (real) plugin name. Re-sort taking custom names into account.
|
37 |
+
this.plugins.sort(function (a, b) {
|
38 |
+
return a.name().localeCompare(b.name());
|
39 |
+
});
|
40 |
this.privilegedActors = [this.actorSelector.getCurrentUserActor()];
|
41 |
if (this.isMultisite) {
|
42 |
this.privilegedActors.push(AmeActors.getSuperAdmin());
|
137 |
isVisibleByDefault: plugin.isVisibleByDefault(),
|
138 |
grantAccess: _.mapValues(plugin.grantAccess, function (allow) {
|
139 |
return allow();
|
140 |
+
}),
|
141 |
+
customName: plugin.customName(),
|
142 |
+
customDescription: plugin.customDescription()
|
143 |
};
|
144 |
});
|
145 |
return result;
|
146 |
};
|
147 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
148 |
AmePluginVisibilityModule.prototype.saveChanges = function () {
|
149 |
var settings = this.getSettings();
|
150 |
//Remove settings associated with roles and users that no longer exist or are not visible.
|
160 |
return AmePluginVisibilityModule;
|
161 |
}());
|
162 |
var AmePlugin = (function () {
|
163 |
+
function AmePlugin(details, settings, module) {
|
164 |
var _this = this;
|
165 |
+
var _ = AmePluginVisibilityModule._;
|
166 |
+
this.defaultName = ko.observable(details.name);
|
167 |
+
this.defaultDescription = ko.observable(details.description);
|
168 |
+
this.customName = ko.observable(_.get(settings, 'customName', ''));
|
169 |
+
this.customDescription = ko.observable(_.get(settings, 'customDescription', ''));
|
170 |
+
this.name = ko.computed(function () {
|
171 |
+
var value = _this.customName();
|
172 |
+
if (value === '') {
|
173 |
+
value = _this.defaultName();
|
174 |
+
}
|
175 |
+
return AmePlugin.stripAllTags(value);
|
176 |
+
});
|
177 |
+
this.description = ko.computed(function () {
|
178 |
+
var value = _this.customDescription();
|
179 |
+
if (value === '') {
|
180 |
+
value = _this.defaultDescription();
|
181 |
+
}
|
182 |
+
return AmePlugin.stripAllTags(value);
|
183 |
+
});
|
184 |
this.fileName = details.fileName;
|
185 |
this.isActive = details.isActive;
|
186 |
+
this.isBeingEdited = ko.observable(false);
|
187 |
+
this.editableName = ko.observable(this.defaultName());
|
188 |
+
this.editableDescription = ko.observable(this.defaultDescription());
|
189 |
+
this.isVisibleByDefault = ko.observable(_.get(settings, 'isVisibleByDefault', true));
|
190 |
var emptyGrant = {};
|
191 |
+
this.grantAccess = _.mapValues(_.get(settings, 'grantAccess', emptyGrant), function (hasAccess) {
|
192 |
return ko.observable(hasAccess);
|
193 |
});
|
194 |
this.isChecked = ko.computed({
|
207 |
}
|
208 |
return this.grantAccess[actorId];
|
209 |
};
|
210 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
211 |
+
AmePlugin.prototype.openInlineEditor = function () {
|
212 |
+
this.editableName(this.customName() === '' ? this.defaultName() : this.customName());
|
213 |
+
this.editableDescription(this.customDescription() === '' ? this.defaultDescription() : this.customDescription());
|
214 |
+
this.isBeingEdited(true);
|
215 |
+
};
|
216 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
217 |
+
AmePlugin.prototype.cancelEdit = function () {
|
218 |
+
this.isBeingEdited(false);
|
219 |
+
};
|
220 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
221 |
+
AmePlugin.prototype.confirmEdit = function () {
|
222 |
+
this.customName(this.editableName());
|
223 |
+
this.customDescription(this.editableDescription());
|
224 |
+
if (this.customName() === this.defaultName()) {
|
225 |
+
this.customName('');
|
226 |
+
}
|
227 |
+
if (this.customDescription() === this.defaultDescription()) {
|
228 |
+
this.customDescription('');
|
229 |
+
}
|
230 |
+
this.isBeingEdited(false);
|
231 |
+
};
|
232 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
233 |
+
AmePlugin.prototype.resetNameAndDescription = function () {
|
234 |
+
this.customName('');
|
235 |
+
this.customDescription('');
|
236 |
+
this.isBeingEdited(false);
|
237 |
+
};
|
238 |
AmePlugin.stripAllTags = function (input) {
|
239 |
//Based on: http://phpjs.org/functions/strip_tags/
|
240 |
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
247 |
ko.applyBindings(amePluginVisibility, document.getElementById('ame-plugin-visibility-editor'));
|
248 |
//Permanently dismiss the usage hint via AJAX.
|
249 |
$('#ame-pv-usage-notice').on('click', '.notice-dismiss', function () {
|
250 |
+
AjawV1.getAction('ws_ame_dismiss_pv_usage_notice').request();
|
|
|
|
|
|
|
251 |
});
|
252 |
});
|
253 |
//# sourceMappingURL=plugin-visibility.js.map
|
modules/plugin-visibility/plugin-visibility.php
CHANGED
@@ -13,6 +13,8 @@ class amePluginVisibility {
|
|
13 |
private $menuEditor;
|
14 |
private $settings = array();
|
15 |
|
|
|
|
|
16 |
public function __construct($menuEditor) {
|
17 |
$this->menuEditor = $menuEditor;
|
18 |
self::$lastInstance = $this;
|
@@ -36,10 +38,11 @@ class amePluginVisibility {
|
|
36 |
|
37 |
//Display a usage hint in our tab.
|
38 |
add_action('admin_notices', array($this, 'displayUsageNotice'));
|
39 |
-
$dismissNoticeAction =
|
40 |
-
|
41 |
-
->
|
42 |
-
->
|
|
|
43 |
}
|
44 |
|
45 |
public function getSettings() {
|
@@ -187,12 +190,24 @@ class amePluginVisibility {
|
|
187 |
*/
|
188 |
public function filterPluginList($plugins) {
|
189 |
$user = wp_get_current_user();
|
|
|
190 |
|
191 |
-
//Remove all hidden plugins.
|
192 |
$pluginFileNames = array_keys($plugins);
|
193 |
foreach($pluginFileNames as $fileName) {
|
|
|
194 |
if ( !$this->isPluginVisible($fileName, $user) ) {
|
195 |
unset($plugins[$fileName]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
}
|
197 |
}
|
198 |
|
@@ -311,7 +326,10 @@ class amePluginVisibility {
|
|
311 |
wp_register_auto_versioned_script(
|
312 |
'ame-plugin-visibility',
|
313 |
plugins_url('plugin-visibility.js', __FILE__),
|
314 |
-
array(
|
|
|
|
|
|
|
315 |
);
|
316 |
wp_enqueue_script('ame-plugin-visibility');
|
317 |
|
@@ -348,6 +366,9 @@ class amePluginVisibility {
|
|
348 |
'name' => $header['Name'],
|
349 |
'description' => isset($header['Description']) ? $header['Description'] : '',
|
350 |
'isActive' => $isActive || $isActiveForNetwork,
|
|
|
|
|
|
|
351 |
);
|
352 |
}
|
353 |
|
@@ -364,9 +385,6 @@ class amePluginVisibility {
|
|
364 |
'canManagePlugins' => $canManagePlugins,
|
365 |
'isMultisite' => is_multisite(),
|
366 |
'isProVersion' => $this->menuEditor->is_pro_version(),
|
367 |
-
|
368 |
-
'dismissNoticeNonce' => wp_create_nonce('ws_ame_dismiss_pv_usage_notice'),
|
369 |
-
'adminAjaxUrl' => admin_url('admin-ajax.php'),
|
370 |
);
|
371 |
}
|
372 |
|
13 |
private $menuEditor;
|
14 |
private $settings = array();
|
15 |
|
16 |
+
private $dismissNoticeAction;
|
17 |
+
|
18 |
public function __construct($menuEditor) {
|
19 |
$this->menuEditor = $menuEditor;
|
20 |
self::$lastInstance = $this;
|
38 |
|
39 |
//Display a usage hint in our tab.
|
40 |
add_action('admin_notices', array($this, 'displayUsageNotice'));
|
41 |
+
$this->dismissNoticeAction = ajaw_v1_CreateAction('ws_ame_dismiss_pv_usage_notice')
|
42 |
+
->handler(array($this, 'ajaxDismissUsageNotice'))
|
43 |
+
->permissionCallback(array($this->menuEditor, 'current_user_can_edit_menu'))
|
44 |
+
->method('post')
|
45 |
+
->register();
|
46 |
}
|
47 |
|
48 |
public function getSettings() {
|
190 |
*/
|
191 |
public function filterPluginList($plugins) {
|
192 |
$user = wp_get_current_user();
|
193 |
+
$settings = $this->getSettings();
|
194 |
|
|
|
195 |
$pluginFileNames = array_keys($plugins);
|
196 |
foreach($pluginFileNames as $fileName) {
|
197 |
+
//Remove all hidden plugins.
|
198 |
if ( !$this->isPluginVisible($fileName, $user) ) {
|
199 |
unset($plugins[$fileName]);
|
200 |
+
continue;
|
201 |
+
}
|
202 |
+
|
203 |
+
//Set custom names and descriptions.
|
204 |
+
$customName = ameUtils::get($settings, array('plugins', $fileName, 'customName'), '');
|
205 |
+
$customDescription = ameUtils::get($settings, array('plugins', $fileName, 'customDescription'), '');
|
206 |
+
if ( $customName !== '' ) {
|
207 |
+
$plugins[$fileName]['Name'] = $customName;
|
208 |
+
}
|
209 |
+
if ( $customDescription !== '' ) {
|
210 |
+
$plugins[$fileName]['Description'] = $customDescription;
|
211 |
}
|
212 |
}
|
213 |
|
326 |
wp_register_auto_versioned_script(
|
327 |
'ame-plugin-visibility',
|
328 |
plugins_url('plugin-visibility.js', __FILE__),
|
329 |
+
array(
|
330 |
+
'ame-lodash', 'knockout', 'ame-actor-selector', 'jquery-json',
|
331 |
+
$this->dismissNoticeAction->getScriptHandle(),
|
332 |
+
)
|
333 |
);
|
334 |
wp_enqueue_script('ame-plugin-visibility');
|
335 |
|
366 |
'name' => $header['Name'],
|
367 |
'description' => isset($header['Description']) ? $header['Description'] : '',
|
368 |
'isActive' => $isActive || $isActiveForNetwork,
|
369 |
+
|
370 |
+
'customName' => '',
|
371 |
+
'customDescription' => '',
|
372 |
);
|
373 |
}
|
374 |
|
385 |
'canManagePlugins' => $canManagePlugins,
|
386 |
'isMultisite' => is_multisite(),
|
387 |
'isProVersion' => $this->menuEditor->is_pro_version(),
|
|
|
|
|
|
|
388 |
);
|
389 |
}
|
390 |
|
modules/plugin-visibility/plugin-visibility.scss
CHANGED
@@ -50,4 +50,37 @@
|
|
50 |
//Make room for th save button.
|
51 |
#ws_actor_selector_container {
|
52 |
margin-right: 130px;
|
53 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
//Make room for th save button.
|
51 |
#ws_actor_selector_container {
|
52 |
margin-right: 130px;
|
53 |
+
}
|
54 |
+
|
55 |
+
/*
|
56 |
+
Inline editor
|
57 |
+
*/
|
58 |
+
|
59 |
+
#ame-plugin-visibility-editor .inline-edit-row {
|
60 |
+
.ame-pv-inline-edit-left {
|
61 |
+
width: 30%;
|
62 |
+
}
|
63 |
+
.ame-pv-inline-edit-right {
|
64 |
+
width: 70%;
|
65 |
+
}
|
66 |
+
|
67 |
+
span.title {
|
68 |
+
width: auto;
|
69 |
+
}
|
70 |
+
input[type="text"] {
|
71 |
+
width: 100%;
|
72 |
+
}
|
73 |
+
|
74 |
+
.ame-pv-inline-reset {
|
75 |
+
line-height: 28px;
|
76 |
+
margin-left: 1em;
|
77 |
+
}
|
78 |
+
|
79 |
+
td {
|
80 |
+
box-shadow: inset 0 -1px 0 rgba(0,0,0,0.1);
|
81 |
+
}
|
82 |
+
|
83 |
+
p.submit {
|
84 |
+
margin-bottom: 0.2em;
|
85 |
+
}
|
86 |
+
}
|
modules/plugin-visibility/plugin-visibility.ts
CHANGED
@@ -3,9 +3,10 @@
|
|
3 |
/// <reference path="../../js/jqueryui.d.ts" />
|
4 |
/// <reference path="../../js/lodash-3.10.d.ts" />
|
5 |
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
|
|
|
6 |
|
7 |
-
declare
|
8 |
-
declare
|
9 |
|
10 |
interface PluginVisibilityScriptData {
|
11 |
isMultisite: boolean,
|
@@ -13,10 +14,7 @@ interface PluginVisibilityScriptData {
|
|
13 |
selectedActor: string,
|
14 |
installedPlugins: Array<PvPluginInfo>,
|
15 |
settings: PluginVisibilitySettings,
|
16 |
-
isProVersion: boolean
|
17 |
-
|
18 |
-
adminAjaxUrl: string,
|
19 |
-
dismissNoticeNonce: string
|
20 |
}
|
21 |
|
22 |
interface PluginVisibilitySettings {
|
@@ -24,7 +22,9 @@ interface PluginVisibilitySettings {
|
|
24 |
plugins: {
|
25 |
[fileName : string] : {
|
26 |
isVisibleByDefault: boolean,
|
27 |
-
grantAccess: GrantAccessMap
|
|
|
|
|
28 |
}
|
29 |
}
|
30 |
}
|
@@ -37,7 +37,10 @@ interface PvPluginInfo {
|
|
37 |
name: string,
|
38 |
fileName: string,
|
39 |
description: string,
|
40 |
-
isActive: boolean
|
|
|
|
|
|
|
41 |
}
|
42 |
|
43 |
class AmePluginVisibilityModule {
|
@@ -66,7 +69,7 @@ class AmePluginVisibilityModule {
|
|
66 |
this.actorSelector = new AmeActorSelector(AmeActors, scriptData.isProVersion);
|
67 |
|
68 |
//Wrap the selected actor in a computed observable so that it can be used with Knockout.
|
69 |
-
|
70 |
this.selectedActor = ko.computed<string>({
|
71 |
read: function () {
|
72 |
return _selectedActor();
|
@@ -95,6 +98,10 @@ class AmePluginVisibilityModule {
|
|
95 |
this.plugins = _.map(scriptData.installedPlugins, (plugin) => {
|
96 |
return new AmePlugin(plugin, _.get(scriptData.settings.plugins, plugin.fileName, {}), this);
|
97 |
});
|
|
|
|
|
|
|
|
|
98 |
|
99 |
this.privilegedActors = [this.actorSelector.getCurrentUserActor()];
|
100 |
if (this.isMultisite) {
|
@@ -202,13 +209,16 @@ class AmePluginVisibilityModule {
|
|
202 |
isVisibleByDefault: plugin.isVisibleByDefault(),
|
203 |
grantAccess: _.mapValues(plugin.grantAccess, (allow): boolean => {
|
204 |
return allow();
|
205 |
-
})
|
|
|
|
|
206 |
};
|
207 |
});
|
208 |
|
209 |
return result;
|
210 |
}
|
211 |
|
|
|
212 |
saveChanges() {
|
213 |
const settings = this.getSettings();
|
214 |
|
@@ -226,28 +236,60 @@ class AmePluginVisibilityModule {
|
|
226 |
}
|
227 |
}
|
228 |
|
229 |
-
class AmePlugin
|
230 |
-
name: string
|
231 |
fileName: string;
|
232 |
-
description: string
|
233 |
isActive: boolean;
|
234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
isChecked: KnockoutComputed<boolean>;
|
236 |
|
237 |
isVisibleByDefault: KnockoutObservable<boolean>;
|
238 |
grantAccess: {[actorId : string] : KnockoutObservable<boolean>};
|
239 |
|
240 |
-
constructor(details: PvPluginInfo,
|
241 |
-
|
242 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
this.fileName = details.fileName;
|
244 |
this.isActive = details.isActive;
|
245 |
|
246 |
-
|
247 |
-
this.
|
|
|
|
|
|
|
248 |
|
249 |
const emptyGrant: {[actorId : string] : boolean} = {};
|
250 |
-
this.grantAccess = _.mapValues(_.get(
|
251 |
return ko.observable<boolean>(hasAccess);
|
252 |
});
|
253 |
|
@@ -268,9 +310,43 @@ class AmePlugin implements PvPluginInfo {
|
|
268 |
return this.grantAccess[actorId];
|
269 |
}
|
270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
static stripAllTags(input): string {
|
272 |
//Based on: http://phpjs.org/functions/strip_tags/
|
273 |
-
|
274 |
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
275 |
return input.replace(commentsAndPhpTags, '').replace(tags, '');
|
276 |
}
|
@@ -282,12 +358,6 @@ jQuery(function ($) {
|
|
282 |
|
283 |
//Permanently dismiss the usage hint via AJAX.
|
284 |
$('#ame-pv-usage-notice').on('click', '.notice-dismiss', function() {
|
285 |
-
|
286 |
-
wsPluginVisibilityData.adminAjaxUrl,
|
287 |
-
{
|
288 |
-
'action' : 'ws_ame_dismiss_pv_usage_notice',
|
289 |
-
'_ajax_nonce' : wsPluginVisibilityData.dismissNoticeNonce
|
290 |
-
}
|
291 |
-
);
|
292 |
});
|
293 |
});
|
3 |
/// <reference path="../../js/jqueryui.d.ts" />
|
4 |
/// <reference path="../../js/lodash-3.10.d.ts" />
|
5 |
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
|
6 |
+
/// <reference path="../../ajax-wrapper/ajax-action-wrapper.d.ts" />
|
7 |
|
8 |
+
declare let amePluginVisibility: AmePluginVisibilityModule;
|
9 |
+
declare const wsPluginVisibilityData: PluginVisibilityScriptData;
|
10 |
|
11 |
interface PluginVisibilityScriptData {
|
12 |
isMultisite: boolean,
|
14 |
selectedActor: string,
|
15 |
installedPlugins: Array<PvPluginInfo>,
|
16 |
settings: PluginVisibilitySettings,
|
17 |
+
isProVersion: boolean
|
|
|
|
|
|
|
18 |
}
|
19 |
|
20 |
interface PluginVisibilitySettings {
|
22 |
plugins: {
|
23 |
[fileName : string] : {
|
24 |
isVisibleByDefault: boolean,
|
25 |
+
grantAccess: GrantAccessMap,
|
26 |
+
customName: string,
|
27 |
+
customDescription: string
|
28 |
}
|
29 |
}
|
30 |
}
|
37 |
name: string,
|
38 |
fileName: string,
|
39 |
description: string,
|
40 |
+
isActive: boolean,
|
41 |
+
|
42 |
+
customName: string,
|
43 |
+
customDescription: string
|
44 |
}
|
45 |
|
46 |
class AmePluginVisibilityModule {
|
69 |
this.actorSelector = new AmeActorSelector(AmeActors, scriptData.isProVersion);
|
70 |
|
71 |
//Wrap the selected actor in a computed observable so that it can be used with Knockout.
|
72 |
+
let _selectedActor = ko.observable(this.actorSelector.selectedActor);
|
73 |
this.selectedActor = ko.computed<string>({
|
74 |
read: function () {
|
75 |
return _selectedActor();
|
98 |
this.plugins = _.map(scriptData.installedPlugins, (plugin) => {
|
99 |
return new AmePlugin(plugin, _.get(scriptData.settings.plugins, plugin.fileName, {}), this);
|
100 |
});
|
101 |
+
//Normally, the plugin list is sorted by the (real) plugin name. Re-sort taking custom names into account.
|
102 |
+
this.plugins.sort(function(a, b) {
|
103 |
+
return a.name().localeCompare(b.name());
|
104 |
+
});
|
105 |
|
106 |
this.privilegedActors = [this.actorSelector.getCurrentUserActor()];
|
107 |
if (this.isMultisite) {
|
209 |
isVisibleByDefault: plugin.isVisibleByDefault(),
|
210 |
grantAccess: _.mapValues(plugin.grantAccess, (allow): boolean => {
|
211 |
return allow();
|
212 |
+
}),
|
213 |
+
customName: plugin.customName(),
|
214 |
+
customDescription: plugin.customDescription()
|
215 |
};
|
216 |
});
|
217 |
|
218 |
return result;
|
219 |
}
|
220 |
|
221 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
222 |
saveChanges() {
|
223 |
const settings = this.getSettings();
|
224 |
|
236 |
}
|
237 |
}
|
238 |
|
239 |
+
class AmePlugin {
|
240 |
+
name: KnockoutComputed<string>;
|
241 |
fileName: string;
|
242 |
+
description: KnockoutComputed<string>;
|
243 |
isActive: boolean;
|
244 |
|
245 |
+
defaultName: KnockoutObservable<string>;
|
246 |
+
defaultDescription: KnockoutObservable<string>;
|
247 |
+
|
248 |
+
isBeingEdited: KnockoutObservable<boolean>;
|
249 |
+
customName: KnockoutObservable<string>;
|
250 |
+
customDescription: KnockoutObservable<string>;
|
251 |
+
editableName: KnockoutObservable<string>;
|
252 |
+
editableDescription: KnockoutObservable<string>;
|
253 |
+
|
254 |
isChecked: KnockoutComputed<boolean>;
|
255 |
|
256 |
isVisibleByDefault: KnockoutObservable<boolean>;
|
257 |
grantAccess: {[actorId : string] : KnockoutObservable<boolean>};
|
258 |
|
259 |
+
constructor(details: PvPluginInfo, settings: Object, module: AmePluginVisibilityModule) {
|
260 |
+
const _ = AmePluginVisibilityModule._;
|
261 |
+
|
262 |
+
this.defaultName = ko.observable(details.name);
|
263 |
+
this.defaultDescription = ko.observable(details.description);
|
264 |
+
this.customName = ko.observable(_.get(settings, 'customName', ''));
|
265 |
+
this.customDescription = ko.observable(_.get(settings, 'customDescription', ''));
|
266 |
+
|
267 |
+
this.name = ko.computed(() => {
|
268 |
+
let value = this.customName();
|
269 |
+
if (value === '') {
|
270 |
+
value = this.defaultName();
|
271 |
+
}
|
272 |
+
return AmePlugin.stripAllTags(value);
|
273 |
+
});
|
274 |
+
this.description = ko.computed(() => {
|
275 |
+
let value = this.customDescription();
|
276 |
+
if (value === '') {
|
277 |
+
value = this.defaultDescription();
|
278 |
+
}
|
279 |
+
return AmePlugin.stripAllTags(value);
|
280 |
+
});
|
281 |
+
|
282 |
this.fileName = details.fileName;
|
283 |
this.isActive = details.isActive;
|
284 |
|
285 |
+
this.isBeingEdited = ko.observable(false);
|
286 |
+
this.editableName = ko.observable(this.defaultName());
|
287 |
+
this.editableDescription = ko.observable(this.defaultDescription());
|
288 |
+
|
289 |
+
this.isVisibleByDefault = ko.observable(_.get(settings, 'isVisibleByDefault', true));
|
290 |
|
291 |
const emptyGrant: {[actorId : string] : boolean} = {};
|
292 |
+
this.grantAccess = _.mapValues(_.get(settings, 'grantAccess', emptyGrant), (hasAccess) => {
|
293 |
return ko.observable<boolean>(hasAccess);
|
294 |
});
|
295 |
|
310 |
return this.grantAccess[actorId];
|
311 |
}
|
312 |
|
313 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
314 |
+
openInlineEditor() {
|
315 |
+
this.editableName(this.customName() === '' ? this.defaultName() : this.customName());
|
316 |
+
this.editableDescription(this.customDescription() === '' ? this.defaultDescription() : this.customDescription());
|
317 |
+
this.isBeingEdited(true);
|
318 |
+
}
|
319 |
+
|
320 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
321 |
+
cancelEdit() {
|
322 |
+
this.isBeingEdited(false);
|
323 |
+
}
|
324 |
+
|
325 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
326 |
+
confirmEdit() {
|
327 |
+
this.customName(this.editableName());
|
328 |
+
this.customDescription(this.editableDescription());
|
329 |
+
|
330 |
+
if (this.customName() === this.defaultName()) {
|
331 |
+
this.customName('');
|
332 |
+
}
|
333 |
+
if (this.customDescription() === this.defaultDescription()) {
|
334 |
+
this.customDescription('');
|
335 |
+
}
|
336 |
+
|
337 |
+
this.isBeingEdited(false);
|
338 |
+
}
|
339 |
+
|
340 |
+
//noinspection JSUnusedGlobalSymbols Used in KO template.
|
341 |
+
resetNameAndDescription() {
|
342 |
+
this.customName('');
|
343 |
+
this.customDescription('');
|
344 |
+
this.isBeingEdited(false);
|
345 |
+
}
|
346 |
+
|
347 |
static stripAllTags(input): string {
|
348 |
//Based on: http://phpjs.org/functions/strip_tags/
|
349 |
+
const tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
|
350 |
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
351 |
return input.replace(commentsAndPhpTags, '').replace(tags, '');
|
352 |
}
|
358 |
|
359 |
//Permanently dismiss the usage hint via AJAX.
|
360 |
$('#ame-pv-usage-notice').on('click', '.notice-dismiss', function() {
|
361 |
+
AjawV1.getAction('ws_ame_dismiss_pv_usage_notice').request();
|
|
|
|
|
|
|
|
|
|
|
|
|
362 |
});
|
363 |
});
|
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.
|
7 |
-
Stable tag: 1.
|
8 |
|
9 |
Lets you edit the WordPress admin menu. You can re-order, hide or rename menus, add custom menus and more.
|
10 |
|
@@ -63,6 +63,20 @@ Plugins installed in the `mu-plugins` directory are treated as "always on", so y
|
|
63 |
|
64 |
== Changelog ==
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
= 1.7.3 =
|
67 |
* Fixed a bug where closing the menu properties of a custom menu item could set "extra capability" to "read".
|
68 |
* Added a workaround for WooCommerce 2.6.8 to display the number of new orders in the "Orders" menu title.
|
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.8
|
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 |
|
64 |
== Changelog ==
|
65 |
|
66 |
+
= 1.8 =
|
67 |
+
* You can edit plugin names and descriptions through the "Plugins" tab. This only changes how plugins are displayed on the "Plugins" page. It doesn't affect plugin files on disk.
|
68 |
+
* Added an option to highlight new menu items. This feature is off by default. You can enable it in the "Settings" tab.
|
69 |
+
* Added an option to compress menu data that the plugin stores in the database.
|
70 |
+
* Added a compatibility workaround for the Divi Training plugin. The hidden menu items that it adds to the "Dashboard" menu should no longer show up when you activate AME.
|
71 |
+
* Added a workaround that improves compatibility with plugins that set their menu icons using CSS.
|
72 |
+
* Fixed an old bug where sorting menu items would put all separators at the top. Now they'll stay near their preceding menu item.
|
73 |
+
* Fixed incorrect shadows on custom screen options links.
|
74 |
+
* Fixed a couple of UI layout issues that were caused by bugs in other plugins.
|
75 |
+
* Fixed a rare issue where hiding the admin bar would leave behind empty space.
|
76 |
+
* When you use the "A-Z" button to sort top level menus, it also sorts submenu items. To avoid compatibility issues, the first item of each submenu stays in its original position.
|
77 |
+
* Automatically reset plugin access if the only allowed user no longer exists. This should cut down on the number of users who accidentally lock themselves out by setting "Who can access the plugin" to "Only the current user" and then later deleting that user account.
|
78 |
+
* Minor performance optimizations.
|
79 |
+
|
80 |
= 1.7.3 =
|
81 |
* Fixed a bug where closing the menu properties of a custom menu item could set "extra capability" to "read".
|
82 |
* Added a workaround for WooCommerce 2.6.8 to display the number of new orders in the "Orders" menu title.
|