Admin Menu Editor - Version 0.2

Version Description

  • Provisional WPMU support.
  • Missing and unused menu items now get different icons in the menu editor.
  • Fixed some visual glitches.
  • Items that are not present in the default menu will only be included in the generated menu if their "Custom" flag is set. Makes perfect sense, eh? The takeaway is that you should tick the "Custom" checkbox for the menus you have created manually if you want them to show up.
  • You no longer need to manually reload the page to see the changes you made to the menu. Just clicking "Save Changes" is enough.
  • Added tooltips to the small flag icons that indicate that a particular menu item is hidden, user-created or otherwise special.
  • Updated the readme.txt
Download this release

Release Info

Developer whiteshadow
Plugin Icon 128x128 Admin Menu Editor
Version 0.2
Comparing to
See all releases

Code changes from version 0.1.6 to 0.2

admin-menu-editor-mu.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ To install Admin Menu Editor as a global plugin in WPMU :
5
+ 1) Place the "admin-menu-editor" directory into your "mu-plugins" directory.
6
+ 2) Move this file, admin-menu-editor-mu.php, from the "admin-menu-editor" directory
7
+ to your "mu-plugins" directory.
8
+
9
+ The resulting directory structure should look like this :
10
+
11
+ mu-plugins/
12
+ admin-menu-editor-mu.php
13
+ admin-menu-editor/
14
+ menu-editor.php
15
+ menu-editor-core.php
16
+ ...and other Admin Menu Editor files
17
+
18
+ **/
19
+
20
+ //Load the plugin
21
+ $ws_menu_editor_filename = dirname(__FILE__) . '/admin-menu-editor/menu-editor.php';
22
+ if ( file_exists($ws_menu_editor_filename) ) {
23
+ require $ws_menu_editor_filename;
24
+ } else {
25
+ add_action('admin_notices', 'ws_ame_installation_error');
26
+ }
27
+
28
+ function ws_ame_installation_error(){
29
+ if ( !is_site_admin() ) return;
30
+ ?>
31
+ <div class="error fade"><p>
32
+ <strong>Admin Menu Editor is installed incorrectly!</strong>
33
+ </p>
34
+ <p>
35
+ Please copy the entire <code>admin-menu-directory</code> directory to your <code>mu-plugins</code>
36
+ directory, then move only the admin-menu-editor-mu.php file from
37
+ <code>admin-menu-editor</code> to <code>mu-plugins</code>.
38
+ </p>
39
+ </div>
40
+ <?php
41
+ }
42
+
43
+ ?>
images/plugin_add.png ADDED
Binary file
images/plugin_error.png ADDED
Binary file
menu-editor-core.php CHANGED
@@ -12,20 +12,30 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
12
 
13
  protected $default_wp_menu = null; //Holds the default WP menu for later use in the editor
14
  protected $default_wp_submenu = null; //Holds the default WP menu for later use
 
 
 
15
 
16
  function __construct($plugin_file=''){
 
 
 
 
 
 
 
 
 
17
  //Set some plugin-specific options
18
  $this->option_name = 'ws_menu_editor';
19
- $this->defaults = array(
20
- );
21
 
22
  $this->settings_link = 'options-general.php?page=menu_editor';
23
-
24
  $this->magic_hooks = true;
25
  $this->magic_hook_priority = 99999;
26
-
27
  //Call the default constructor
28
- if ( empty($plugin_file) ) $plugin_file = __FILE__;
29
  parent::__construct($plugin_file);
30
 
31
  //Build some template arrays
@@ -38,6 +48,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
38
  'hookname' => null,
39
  'icon_url' => null,
40
  'position' => null,
 
 
 
41
  );
42
 
43
  $this->blank_item = array(
@@ -46,6 +59,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
46
  'file' => null,
47
  'page_title' => null,
48
  'position' => null,
 
49
  );
50
 
51
  }
@@ -100,10 +114,14 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
100
  function hook_admin_menu(){
101
  global $menu, $submenu;
102
 
103
- $page = add_options_page('Menu Editor', 'Menu Editor', 'manage_options', 'menu_editor', array(&$this, 'page_menu_editor'));
104
- //Output our JS & CSS on that page only
105
- add_action("admin_print_scripts-$page", array(&$this, 'enqueue_scripts'));
106
- add_action("admin_print_scripts-$page", array(&$this, 'print_editor_css'));
 
 
 
 
107
 
108
  $this->default_wp_menu = $menu;
109
  $this->default_wp_submenu = $submenu;
@@ -129,7 +147,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
129
  */
130
  function filter_menu(){
131
  global $menu, $submenu, $_wp_submenu_nopriv, $_wp_menu_nopriv;
132
-
133
  foreach ( array( 'submenu' ) as $sub_loop ) {
134
  foreach ($$sub_loop as $parent => $sub) {
135
  foreach ($sub as $index => $data) {
@@ -143,7 +161,6 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
143
  unset(${$sub_loop}[$parent]);
144
  }
145
  }
146
-
147
  }
148
 
149
  /**
@@ -158,10 +175,6 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
158
  die("Access denied");
159
  }
160
 
161
- ?>
162
- <div class="wrap">
163
- <h2>Menu Editor</h2>
164
- <?php
165
  //Handle form submissions
166
  if (isset($_POST['data'])){
167
  check_admin_referer('menu-editor-form');
@@ -169,17 +182,34 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
169
  //Try to decode a menu tree encoded as JSON
170
  $data = $this->json_decode($_POST['data'], true);
171
  if (!$data){
172
- echo "<!-- First decodind attempt failed, trying to fix with stripslashes() -->";
173
  $fixed = stripslashes($_POST['data']);
174
  $data = $this->json_decode( $fixed, true );
175
  }
 
 
176
 
177
  if ($data){
178
  //Save the custom menu
179
  $this->options['custom_menu'] = $data;
180
  $this->save_options();
181
- echo '<div id="message" class="updated fade"><p><strong>Settings saved. <a href="javascript:window.location.href=window.location.href">Reload the page</a> to see the modified menu.</strong></p></div>';
 
182
  } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  echo '<div id="message" class="error"><p><strong>Failed to decode input! The menu wasn\'t modified.</strong></p></div>';
184
  }
185
  }
@@ -196,7 +226,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
196
  //Start out with the default menu if there is no user-created one
197
  $custom_menu = $default_menu;
198
  }
199
-
200
  //Encode both menus as JSON
201
  $default_menu_js = $this->getMenuAsJS($default_menu);
202
  $custom_menu_js = $this->getMenuAsJS($custom_menu);
@@ -227,16 +257,16 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
227
  </div>
228
  </div>
229
 
230
- <div class="ws_main_container" style='width: 138px;'>
231
- <form method="post" action="<?php echo admin_url('options-general.php?page=menu_editor'); ?>" id='ws_main_form' name='ws_main_form'>
232
  <?php wp_nonce_field('menu-editor-form'); ?>
233
  <input type="button" id='ws_save_menu' class="button-primary ws_main_button" value="Save Changes"
234
  style="margin-bottom: 20px;" />
235
  <input type="button" id='ws_load_menu' value="Load default menu" class="button ws_main_button" />
236
  <input type="button" id='ws_reset_menu' value="Reset menu" class="button ws_main_button" />
237
  <input type="hidden" name="data" id="ws_data" value="">
238
- </form>
239
  </div>
 
240
 
241
  </div>
242
  <script type='text/javascript'>
@@ -357,7 +387,7 @@ var customMenu = <?php echo $custom_menu_js; ?>;
357
  $menu_defaults[$topfile]['used'] = true;
358
  } else {
359
  //Record the menu as missing, unless it's a menu separator
360
- if ( empty($topmenu['separator']) /*strpos($topfile, 'separator_') !== false*/ )
361
  $topmenu['missing'] = true;
362
  }
363
 
@@ -419,13 +449,7 @@ var customMenu = <?php echo $custom_menu_js; ?>;
419
  }
420
 
421
  //Resort the tree to ensure the found items are in the right spots
422
- uasort($tree, array(&$this, 'compare_position'));
423
- //Resort all submenus as well
424
- foreach ($tree as $topfile => &$topmenu){
425
- if (!empty($topmenu['items'])){
426
- uasort($topmenu['items'], array(&$this, 'compare_position'));
427
- }
428
- }
429
 
430
  return $tree;
431
  }
@@ -442,37 +466,18 @@ var customMenu = <?php echo $custom_menu_js; ?>;
442
  $tree = array();
443
  $separator_count = 0;
444
  foreach ($menu as $pos => $item){
445
- //Is this a separator?
446
- if ($item[2] == ''){
447
- //Yes. Most properties are unset for separators.
448
- $tree['separator_'.$separator_count.'_'] = array(
449
- 'page_title' => null,
450
- 'menu_title' => null,
451
- 'access_level' => null,
452
- 'file' => null,
453
- 'css_class' => null,
454
- 'hookname' => null,
455
- 'icon_url' => null,
456
- 'position' => null,
457
- 'defaults' => $this->menu2assoc($item, $pos),
458
- 'separator' => true,
459
- );
460
  $separator_count++;
461
- } else {
462
- //No, a normal menu item
463
- $tree[$item[2]] = array(
464
- 'page_title' => null,
465
- 'menu_title' => null,
466
- 'access_level' => null,
467
- 'file' => null,
468
- 'css_class' => null,
469
- 'hookname' => null,
470
- 'icon_url' => null,
471
- 'position' => null,
472
- 'items' => array(),
473
- 'defaults' => $this->menu2assoc($item, $pos),
474
- );
475
  }
 
 
476
  }
477
 
478
  //Attach all submenu items
@@ -493,6 +498,8 @@ var customMenu = <?php echo $custom_menu_js; ?>;
493
  );
494
  }
495
  }
 
 
496
 
497
  return $tree;
498
  }
@@ -548,6 +555,26 @@ var customMenu = <?php echo $custom_menu_js; ?>;
548
 
549
  return $p1 - $p2;
550
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
 
552
  /**
553
  * WPMenuEditor::tree2wp()
@@ -557,16 +584,20 @@ var customMenu = <?php echo $custom_menu_js; ?>;
557
  * @return array $menu and $submenu
558
  */
559
  function tree2wp($tree){
 
 
 
560
  //Sort the menu by position
561
  uasort($tree, array(&$this, 'compare_position'));
562
 
563
  //Prepare the top menu
564
- $menu = array();
565
  foreach ($tree as &$topmenu){
566
- //Skip missing entries -- disabled to allow user-created menus
567
- //if (isset($topmenu['missing']) && $topmenu['missing']) continue;
 
568
  //Skip hidden entries
569
  if (!empty($topmenu['hidden'])) continue;
 
570
  //Build the WP item structure, using defaults where necessary
571
  $topmenu = $this->apply_defaults($topmenu);
572
  $menu[] = array(
@@ -578,31 +609,32 @@ var customMenu = <?php echo $custom_menu_js; ?>;
578
  $topmenu['hookname'], //ID
579
  $topmenu['icon_url']
580
  );
581
- }
582
-
583
- //Prepare the submenu
584
- $submenu = array();
585
- foreach ($tree as $x){
586
- if (!isset($x['items'])) continue; //skip menus without items (usually separators)
587
- $items = $x['items'];
588
- //Sort by position
589
- uasort($items, array(&$this, 'compare_position'));
590
- foreach ($items as $item) {
591
- //Skip hidden items
592
- if (!empty($item['hidden'])) {
593
- continue;
 
 
 
 
 
 
 
 
 
594
  }
595
-
596
- $item = $this->apply_defaults($item);
597
- $submenu[$x['file']][] = array(
598
- $item['menu_title'],
599
- $item['access_level'],
600
- $item['file'],
601
- $item['page_title'],
602
- );
603
  }
604
  }
605
-
606
  return array($menu, $submenu);
607
  }
608
 
12
 
13
  protected $default_wp_menu = null; //Holds the default WP menu for later use in the editor
14
  protected $default_wp_submenu = null; //Holds the default WP menu for later use
15
+
16
+ private $blank_menu = null;
17
+ private $blank_item = null;
18
 
19
  function __construct($plugin_file=''){
20
+ if ( empty($plugin_file) ) $plugin_file = __FILE__;
21
+
22
+ //Determine if the plugin is installed in the mu-plugins directory
23
+ $this->is_mu_plugin = $this->is_in_wpmu_plugin_dir($plugin_file);
24
+ //If so, we'll store the custom menu in a site-wide option
25
+ if ( $this->is_mu_plugin ){
26
+ $this->sitewide_options = true;
27
+ }
28
+
29
  //Set some plugin-specific options
30
  $this->option_name = 'ws_menu_editor';
31
+ $this->defaults = array();
 
32
 
33
  $this->settings_link = 'options-general.php?page=menu_editor';
34
+
35
  $this->magic_hooks = true;
36
  $this->magic_hook_priority = 99999;
37
+
38
  //Call the default constructor
 
39
  parent::__construct($plugin_file);
40
 
41
  //Build some template arrays
48
  'hookname' => null,
49
  'icon_url' => null,
50
  'position' => null,
51
+ 'defaults' => null,
52
+ 'separator' => null,
53
+ 'custom' => null,
54
  );
55
 
56
  $this->blank_item = array(
59
  'file' => null,
60
  'page_title' => null,
61
  'position' => null,
62
+ 'custom' => null,
63
  );
64
 
65
  }
114
  function hook_admin_menu(){
115
  global $menu, $submenu;
116
 
117
+ //The menu editor is only visible to users with the manage_options privilege.
118
+ //Or, if the plugin is installed in mu-plugins, only to the site administrator(s).
119
+ if ( !$this->is_mu_plugin || ( function_exists('is_site_admin') && is_site_admin() ) ){
120
+ $page = add_options_page('Menu Editor', 'Menu Editor', 'manage_options', 'menu_editor', array(&$this, 'page_menu_editor'));
121
+ //Output our JS & CSS on that page only
122
+ add_action("admin_print_scripts-$page", array(&$this, 'enqueue_scripts'));
123
+ add_action("admin_print_scripts-$page", array(&$this, 'print_editor_css'));
124
+ }
125
 
126
  $this->default_wp_menu = $menu;
127
  $this->default_wp_submenu = $submenu;
147
  */
148
  function filter_menu(){
149
  global $menu, $submenu, $_wp_submenu_nopriv, $_wp_menu_nopriv;
150
+
151
  foreach ( array( 'submenu' ) as $sub_loop ) {
152
  foreach ($$sub_loop as $parent => $sub) {
153
  foreach ($sub as $index => $data) {
161
  unset(${$sub_loop}[$parent]);
162
  }
163
  }
 
164
  }
165
 
166
  /**
175
  die("Access denied");
176
  }
177
 
 
 
 
 
178
  //Handle form submissions
179
  if (isset($_POST['data'])){
180
  check_admin_referer('menu-editor-form');
182
  //Try to decode a menu tree encoded as JSON
183
  $data = $this->json_decode($_POST['data'], true);
184
  if (!$data){
 
185
  $fixed = stripslashes($_POST['data']);
186
  $data = $this->json_decode( $fixed, true );
187
  }
188
+
189
+ $url = remove_query_arg('noheader');
190
 
191
  if ($data){
192
  //Save the custom menu
193
  $this->options['custom_menu'] = $data;
194
  $this->save_options();
195
+ //Redirect back to the editor and display the success message
196
+ wp_redirect( add_query_arg('message', 1, $url) );
197
  } else {
198
+ //Or redirect & display the error message
199
+ wp_redirect( add_query_arg('message', 2, $url) );
200
+ }
201
+ die();
202
+ }
203
+
204
+ ?>
205
+ <div class="wrap">
206
+ <h2>Menu Editor</h2>
207
+ <?php
208
+
209
+ if ( !empty($_GET['message']) ){
210
+ if ( intval($_GET['message']) == 1 ){
211
+ echo '<div id="message" class="updated fade"><p><strong>Settings saved.</strong></p></div>';
212
+ } elseif ( intval($_GET['message']) == 2 ) {
213
  echo '<div id="message" class="error"><p><strong>Failed to decode input! The menu wasn\'t modified.</strong></p></div>';
214
  }
215
  }
226
  //Start out with the default menu if there is no user-created one
227
  $custom_menu = $default_menu;
228
  }
229
+
230
  //Encode both menus as JSON
231
  $default_menu_js = $this->getMenuAsJS($default_menu);
232
  $custom_menu_js = $this->getMenuAsJS($custom_menu);
257
  </div>
258
  </div>
259
 
260
+ <form method="post" action="<?php echo admin_url('options-general.php?page=menu_editor&noheader=1'); ?>" id='ws_main_form' name='ws_main_form'>
261
+ <div class="ws_main_container" style="width: 138px;">
262
  <?php wp_nonce_field('menu-editor-form'); ?>
263
  <input type="button" id='ws_save_menu' class="button-primary ws_main_button" value="Save Changes"
264
  style="margin-bottom: 20px;" />
265
  <input type="button" id='ws_load_menu' value="Load default menu" class="button ws_main_button" />
266
  <input type="button" id='ws_reset_menu' value="Reset menu" class="button ws_main_button" />
267
  <input type="hidden" name="data" id="ws_data" value="">
 
268
  </div>
269
+ </form>
270
 
271
  </div>
272
  <script type='text/javascript'>
387
  $menu_defaults[$topfile]['used'] = true;
388
  } else {
389
  //Record the menu as missing, unless it's a menu separator
390
+ if ( empty($topmenu['separator']) )
391
  $topmenu['missing'] = true;
392
  }
393
 
449
  }
450
 
451
  //Resort the tree to ensure the found items are in the right spots
452
+ $tree = $this->sort_menu_tree($tree);
 
 
 
 
 
 
453
 
454
  return $tree;
455
  }
466
  $tree = array();
467
  $separator_count = 0;
468
  foreach ($menu as $pos => $item){
469
+
470
+ $tree_item = $this->blank_menu;
471
+ $tree_item['defaults'] = $this->menu2assoc($item, $pos);
472
+ $tree_item['separator'] = empty($item[2]) || empty($item[0]);
473
+
474
+ $item_file = $tree_item['defaults']['file'];
475
+ if ( empty($item_file) ){
476
+ $item_file = 'separator_'.$separator_count.'_';
 
 
 
 
 
 
 
477
  $separator_count++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  }
479
+
480
+ $tree[$item_file] = $tree_item;
481
  }
482
 
483
  //Attach all submenu items
498
  );
499
  }
500
  }
501
+
502
+ $tree = $this->sort_menu_tree($tree);
503
 
504
  return $tree;
505
  }
555
 
556
  return $p1 - $p2;
557
  }
558
+
559
+ /**
560
+ * WPMenuEditor::sort_menu_tree()
561
+ * Sort the menus and menu items of a given menu according to their positions
562
+ *
563
+ * @param array $tree A menu structure in the internal format
564
+ * @return array Sorted menu in the internal format
565
+ */
566
+ function sort_menu_tree($tree){
567
+ //Resort the tree to ensure the found items are in the right spots
568
+ uasort($tree, array(&$this, 'compare_position'));
569
+ //Resort all submenus as well
570
+ foreach ($tree as $topfile => &$topmenu){
571
+ if (!empty($topmenu['items'])){
572
+ uasort($topmenu['items'], array(&$this, 'compare_position'));
573
+ }
574
+ }
575
+
576
+ return $tree;
577
+ }
578
 
579
  /**
580
  * WPMenuEditor::tree2wp()
584
  * @return array $menu and $submenu
585
  */
586
  function tree2wp($tree){
587
+ $menu = array();
588
+ $submenu = array();
589
+
590
  //Sort the menu by position
591
  uasort($tree, array(&$this, 'compare_position'));
592
 
593
  //Prepare the top menu
 
594
  foreach ($tree as &$topmenu){
595
+
596
+ //Skip missing menus, unless they're user-created and thus might point to a non-standard file
597
+ if ( !empty($topmenu['missing']) && empty($topmenu['custom']) ) continue;
598
  //Skip hidden entries
599
  if (!empty($topmenu['hidden'])) continue;
600
+
601
  //Build the WP item structure, using defaults where necessary
602
  $topmenu = $this->apply_defaults($topmenu);
603
  $menu[] = array(
609
  $topmenu['hookname'], //ID
610
  $topmenu['icon_url']
611
  );
612
+
613
+ //Prepare the submenu of this menu
614
+ if( !empty($topmenu['items']) ){
615
+ $items = $topmenu['items'];
616
+ //Sort by position
617
+ uasort($items, array(&$this, 'compare_position'));
618
+ foreach ($items as $item) {
619
+
620
+ //Skip missing items, unless they're user-created
621
+ if ( !empty($item['missing']) && empty($item['custom']) ) continue;
622
+ //Skip hidden items
623
+ if (!empty($item['hidden'])) {
624
+ continue;
625
+ }
626
+
627
+ $item = $this->apply_defaults($item);
628
+ $submenu[$topmenu['file']][] = array(
629
+ $item['menu_title'],
630
+ $item['access_level'],
631
+ $item['file'],
632
+ $item['page_title'],
633
+ );
634
  }
 
 
 
 
 
 
 
 
635
  }
636
  }
637
+
638
  return array($menu, $submenu);
639
  }
640
 
menu-editor.css CHANGED
@@ -12,10 +12,12 @@
12
 
13
  .ws_main_button {
14
  clear: both;
15
- display:block;
16
- width: 120px;
17
  margin: 4px;
18
- padding: 4px;
 
 
 
19
  }
20
 
21
  .ws_container {
@@ -87,30 +89,50 @@ a.ws_edit_link:hover {
87
  background-position: center;
88
  }
89
 
90
- /* style for items not present in the default menu - these are usually user-created items */
91
- .ws_missing {
92
- background-image: url('images/page_white_add.png');
93
- background-repeat: no-repeat;
94
- background-position: 232px 5px;
95
  }
96
 
97
- /* style for hidden items */
98
- .ws_hidden {
99
- background-image: url('images/plugin_disabled.png');
 
 
 
100
  background-repeat: no-repeat;
101
- background-position: 232px 5px;
102
  }
103
 
104
- /* style for unused items - those that are in the default menu but not in the custom one */
105
- .ws_unused {
106
- background-image: url('images/bullet_error.png');
107
- background-repeat: no-repeat;
108
- background-position: 232px 5px;
 
 
 
 
 
 
 
 
109
  }
110
 
111
- .ws_item {
 
 
112
  }
113
 
 
 
 
 
 
 
 
 
 
114
  .ws_editbox {
115
  display: block;
116
  background-color: #ffffd0;
@@ -124,7 +146,7 @@ a.ws_edit_link:hover {
124
  cursor: pointer;
125
  }
126
 
127
- .ws_editbox input {
128
  width: 220px;
129
  }
130
 
12
 
13
  .ws_main_button {
14
  clear: both;
15
+ display: block;
 
16
  margin: 4px;
17
+ margin-left: auto;
18
+ margin-right: auto;
19
+ width: 120px;
20
+ padding: 4px !important;
21
  }
22
 
23
  .ws_container {
89
  background-position: center;
90
  }
91
 
92
+ /* Menu/menu item flags */
93
+ .ws_flag_container {
94
+ float: right;
95
+ margin-right: 4px;
 
96
  }
97
 
98
+ .ws_flag {
99
+ display: block;
100
+ float: right;
101
+ width: 16px;
102
+ height: 16px;
103
+ margin-left: 4px;
104
  background-repeat: no-repeat;
 
105
  }
106
 
107
+ /* user-created items */
108
+ .ws_custom_item_flag {
109
+ background-image: url('images/page_white_add.png');
110
+ }
111
+
112
+ /* items not present in the default menu */
113
+ .ws_missing_flag {
114
+ background-image: url('images/plugin_error.png');
115
+ }
116
+
117
+ /* unused items - those that are in the default menu but not in the custom one */
118
+ .ws_unused_flag {
119
+ background-image: url('images/plugin_add.png');
120
  }
121
 
122
+ /* hidden items */
123
+ .ws_hidden_flag {
124
+ background-image: url('images/plugin_disabled.png');
125
  }
126
 
127
+ /* These classes could be used to apply different styles to items depending on their flags */
128
+ .ws_missing { }
129
+ .ws_custom_item { }
130
+ .ws_hidden { }
131
+ .ws_unused { }
132
+
133
+
134
+ .ws_item { }
135
+
136
  .ws_editbox {
137
  display: block;
138
  background-color: #ffffd0;
146
  cursor: pointer;
147
  }
148
 
149
+ .ws_editbox input[type="text"] {
150
  width: 220px;
151
  }
152
 
menu-editor.js CHANGED
@@ -54,8 +54,6 @@ function outputWpMenu(menu){
54
  }
55
  });
56
 
57
-
58
-
59
  //The "Default" button : Reset to default value when clicked
60
  $('.ws_reset_button').click(function () {
61
  //Find the related input field
@@ -80,32 +78,34 @@ function outputWpMenu(menu){
80
  $(this).parent().parent().parent().find('.ws_item_title').html($(this).val()+'&nbsp;');
81
  }
82
  });
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
 
85
  function outputTopMenu(menu, filename, ind){
86
  id = 'topmenu-'+ind;
87
  submenu_id = 'submenu-'+ind;
88
 
89
- //menu = menu_obj[filename];
90
-
91
  var subclass = '';
92
- //Apply subclasses based on the item's state
93
- if ( menu.separator /*(!menu.defaults.menu_title) && (!menu.menu_title)*/ ) {
94
  subclass = subclass + ' ws_menu_separator';
95
  }
96
- if (menu.missing) {
97
- subclass = subclass + ' ws_missing';
98
- }
99
- if (menu.hidden) {
100
- subclass = subclass + ' ws_hidden';
101
- }
102
- if (menu.unused) {
103
- subclass = subclass + ' ws_unused';
104
- }
105
 
 
106
  var s = '<div id="'+id+'" class="ws_container ws_menu '+subclass+'" submenu_id="'+submenu_id+'">'+
107
  '<div class="ws_item_head">'+
108
  '<a class="ws_edit_link"> </a>'+
 
109
  '<span class="ws_item_title">'+
110
  ((menu.menu_title!=null)?menu.menu_title:menu.defaults.menu_title)+
111
  '&nbsp;</span>'+
@@ -113,7 +113,22 @@ function outputTopMenu(menu, filename, ind){
113
  '<div class="ws_editbox" style="display: none;">'+buildEditboxFields(menu)+'</div>'+
114
  '</div>';
115
 
116
- $('#ws_menu_box').append(s);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  //Create a container for menu items, even if there are none
118
  $('#ws_submenu_box').append('<div class="ws_submenu" id="'+submenu_id+'" style="display:none;"></div>');
119
 
@@ -131,27 +146,32 @@ function outputTopMenu(menu, filename, ind){
131
  function outputMenuEntry(entry, ind, parent){
132
  if (!entry.defaults) return;
133
 
134
- var subclass = '';
135
- //Apply subclasses based on the item's state
136
- if (entry.missing) {
137
- subclass = subclass + ' ws_missing';
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
139
  if (entry.hidden) {
140
- subclass = subclass + ' ws_hidden';
141
  }
142
  if (entry.unused) {
143
- subclass = subclass + ' ws_unused';
 
 
 
144
  }
145
-
146
- var item = $('#'+parent).append('<div class="ws_container ws_item '+subclass+'">'+
147
- '<div class="ws_item_head">'+
148
- '<a class="ws_edit_link"> </a>'+
149
- '<span class="ws_item_title">'+
150
- ((entry.menu_title!=null)?entry.menu_title:entry.defaults.menu_title)+
151
- '&nbsp;</span>'+
152
- '</div>'+
153
- '<div class="ws_editbox" style="display:none;">'+buildEditboxFields(entry)+'</div>'+
154
- '<div>');
155
  }
156
 
157
  function buildEditboxField(entry, field_name, field_caption){
@@ -181,6 +201,19 @@ function buildEditboxFields(entry){
181
  for (var field_name in fields){
182
  s = s + buildEditboxField(entry, field_name, fields[field_name]);
183
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  return s;
185
  }
186
 
@@ -202,9 +235,11 @@ function encodeMenuAsJSON(){
202
 
203
  var filename = $(this).find('.ws_edit_field[field_name="file"] input').val();
204
  //Check if this is a separator
205
- if (filename==''){
206
- filename = 'separator_'+separator_count+'_';
207
  menu_obj.separator = true;
 
 
 
208
  separator_count++;
209
  }
210
 
@@ -226,10 +261,10 @@ function encodeMenuAsJSON(){
226
 
227
  });
228
  //Check if the menu is hidden
229
- if ($(this).hasClass('ws_hidden')){
230
- menu_obj['hidden'] = true;
231
- }
232
-
233
  menu_obj.items = {};
234
 
235
  var item_position = 0;
@@ -267,6 +302,9 @@ function encodeMenuAsJSON(){
267
  if ($(this).hasClass('ws_hidden')){
268
  item.hidden = true;
269
  }
 
 
 
270
  //Save the item in the parent menu
271
  menu_obj.items[filename] = item;
272
  });
@@ -280,6 +318,58 @@ function encodeMenuAsJSON(){
280
  return $.toJSON(data);
281
  }
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  var menu_in_clipboard = null;
284
  var submenu_in_clipboard = null;
285
  var item_in_clipboard = null;
@@ -304,13 +394,19 @@ $(document).ready(function(){
304
  var selection = $('#ws_menu_box .ws_active');
305
  if (!selection.length) return;
306
 
307
- //Mark the menu as hidden
308
- selection.toggleClass('ws_hidden');
 
 
309
  //Also mark all of it's submenus as hidden/visible
310
- if (selection.hasClass('ws_hidden')){
311
- $('#' + selection.attr('submenu_id') + ' .ws_item').addClass('ws_hidden');
 
 
312
  } else {
313
- $('#' + selection.attr('submenu_id') + ' .ws_item').removeClass('ws_hidden');
 
 
314
  }
315
  });
316
 
@@ -422,9 +518,13 @@ $(document).ready(function(){
422
  dropOnEmpty: true,
423
  });
424
 
425
- //Cleanup the menu's classes
426
- menu.attr('class','ws_container ws_menu ws_missing');
 
 
427
 
 
 
428
 
429
  var temp_id = 'custom_menu_'+ws_paste_count;
430
  //Assign a stub title
@@ -459,7 +559,7 @@ $(document).ready(function(){
459
  if (!selection.length) return;
460
 
461
  //Mark the item as hidden
462
- selection.toggleClass('ws_hidden');
463
  });
464
 
465
  //Delete menu
@@ -532,8 +632,13 @@ $(document).ready(function(){
532
  //Clone another item to use as a template (hack)
533
  var menu = $('#ws_submenu_box .ws_item:first').clone(true);
534
 
535
- //Cleanup the items's classes
536
- menu.attr('class','ws_container ws_item ws_missing');
 
 
 
 
 
537
 
538
  var temp_id = 'custom_item_'+ws_paste_count;
539
  //Assign a stub title
@@ -581,6 +686,5 @@ $(document).ready(function(){
581
  });
582
 
583
  });
584
-
585
 
586
  })(jQuery);
54
  }
55
  });
56
 
 
 
57
  //The "Default" button : Reset to default value when clicked
58
  $('.ws_reset_button').click(function () {
59
  //Find the related input field
78
  $(this).parent().parent().parent().find('.ws_item_title').html($(this).val()+'&nbsp;');
79
  }
80
  });
81
+
82
+ //When the "Custom" checkbox is clicked, add/remove the ws_custom_item class to
83
+ //the menu (or menu item) in question.
84
+ $('.ws_custom_toggle').change(function(){
85
+ //Find the container
86
+ var my_container = $(this).parents('.ws_container:first');
87
+ if ( $(this).is(':checked') ){
88
+ addMenuFlag(my_container, 'custom_item');
89
+ } else {
90
+ removeMenuFlag(my_container, 'custom_item');
91
+ }
92
+ });
93
  }
94
 
95
  function outputTopMenu(menu, filename, ind){
96
  id = 'topmenu-'+ind;
97
  submenu_id = 'submenu-'+ind;
98
 
 
 
99
  var subclass = '';
100
+ if ( menu.separator ) {
 
101
  subclass = subclass + ' ws_menu_separator';
102
  }
 
 
 
 
 
 
 
 
 
103
 
104
+ //Create the menu HTML
105
  var s = '<div id="'+id+'" class="ws_container ws_menu '+subclass+'" submenu_id="'+submenu_id+'">'+
106
  '<div class="ws_item_head">'+
107
  '<a class="ws_edit_link"> </a>'+
108
+ '<div class="ws_flag_container"> </div>'+
109
  '<span class="ws_item_title">'+
110
  ((menu.menu_title!=null)?menu.menu_title:menu.defaults.menu_title)+
111
  '&nbsp;</span>'+
113
  '<div class="ws_editbox" style="display: none;">'+buildEditboxFields(menu)+'</div>'+
114
  '</div>';
115
 
116
+ var menu_obj = $(s).appendTo('#ws_menu_box');
117
+
118
+ //Apply flags based on the item's state
119
+ if (menu.missing && !menu.custom) {
120
+ addMenuFlag(menu_obj, 'missing');
121
+ }
122
+ if (menu.hidden) {
123
+ addMenuFlag(menu_obj, 'hidden');
124
+ }
125
+ if (menu.unused) {
126
+ addMenuFlag(menu_obj, 'unused');
127
+ }
128
+ if (menu.custom) {
129
+ addMenuFlag(menu_obj, 'custom_item');
130
+ }
131
+
132
  //Create a container for menu items, even if there are none
133
  $('#ws_submenu_box').append('<div class="ws_submenu" id="'+submenu_id+'" style="display:none;"></div>');
134
 
146
  function outputMenuEntry(entry, ind, parent){
147
  if (!entry.defaults) return;
148
 
149
+ var item = $(
150
+ '<div class="ws_container ws_item">'+
151
+ '<div class="ws_item_head">'+
152
+ '<a class="ws_edit_link"> </a>'+
153
+ '<div class="ws_flag_container"> </div>'+
154
+ '<span class="ws_item_title">'+
155
+ ((entry.menu_title!=null)?entry.menu_title:entry.defaults.menu_title)+
156
+ '&nbsp;</span>'+
157
+ '</div>'+
158
+ '<div class="ws_editbox" style="display:none;">'+buildEditboxFields(entry)+'</div>'+
159
+ '<div>'
160
+ ).appendTo('#'+parent)
161
+
162
+ //Apply flags based on the item's state
163
+ if (entry.missing && !entry.custom) {
164
+ addMenuFlag(item, 'missing');
165
  }
166
  if (entry.hidden) {
167
+ addMenuFlag(item, 'hidden');
168
  }
169
  if (entry.unused) {
170
+ addMenuFlag(item, 'unused');
171
+ }
172
+ if (entry.custom) {
173
+ addMenuFlag(item, 'custom_item');
174
  }
 
 
 
 
 
 
 
 
 
 
175
  }
176
 
177
  function buildEditboxField(entry, field_name, field_caption){
201
  for (var field_name in fields){
202
  s = s + buildEditboxField(entry, field_name, fields[field_name]);
203
  }
204
+
205
+ //Add the "Custom item" checkbox
206
+ var is_custom = false;
207
+ if ( typeof(entry['custom']) != 'undefined' ){
208
+ is_custom = entry['custom'];
209
+ }
210
+ s = s +
211
+ '<div class="ws_edit_field">'+
212
+ '<label title="Custom items are visible even if they\'re not present in the default WordPress menu">'+
213
+ '<input type="checkbox" class="ws_custom_toggle"'+
214
+ (is_custom?' checked="checked"':'')+ '> Custom</label>'+
215
+ '</div>';
216
+
217
  return s;
218
  }
219
 
235
 
236
  var filename = $(this).find('.ws_edit_field[field_name="file"] input').val();
237
  //Check if this is a separator
238
+ if ( $(this).hasClass('ws_menu_separator') ){
 
239
  menu_obj.separator = true;
240
+ if ( filename=='' ) {
241
+ filename = 'separator_'+separator_count+'_';
242
+ }
243
  separator_count++;
244
  }
245
 
261
 
262
  });
263
  //Check if the menu is hidden
264
+ menu_obj.hidden = $(this).hasClass('ws_hidden');
265
+ //Check if this is a custom menu
266
+ menu_obj.custom = $(this).hasClass('ws_custom_item');
267
+
268
  menu_obj.items = {};
269
 
270
  var item_position = 0;
302
  if ($(this).hasClass('ws_hidden')){
303
  item.hidden = true;
304
  }
305
+ //Check if this is a custom item
306
+ item.custom = $(this).hasClass('ws_custom_item');
307
+
308
  //Save the item in the parent menu
309
  menu_obj.items[filename] = item;
310
  });
318
  return $.toJSON(data);
319
  }
320
 
321
+ var item_flags = {
322
+ 'custom_item' : 'This is a custom menu item',
323
+ 'unused' : 'This item was automatically (re)inserted into your custom menu because it is present in the default WordPress menu',
324
+ 'missing' : 'This item is not present in the default WordPress menu. Tick the &quot;Custom&quot; checkbox if you want it to be visible anyway.',
325
+ 'hidden' : 'This item is hidden'
326
+ }
327
+
328
+ //These function manipulate the menu flags (e.g. hidden, custom, etc)
329
+ function addMenuFlag(item, flag){
330
+ item = $(item);
331
+
332
+ var item_class = 'ws_' + flag;
333
+ var img_class = 'ws_' + flag + '_flag';
334
+
335
+ item.addClass(item_class);
336
+ //Add the flag image
337
+ var flag_container = item.find('.ws_flag_container');
338
+ if ( flag_container.find('.' + img_class).length == 0 ){
339
+ flag_container.append('<div class="ws_flag '+img_class+'" title="'+item_flags[flag]+'"></div>');
340
+ }
341
+ }
342
+
343
+ function removeMenuFlag(item, flag){
344
+ item = $(item);
345
+ var item_class = 'ws_' + flag;
346
+ var img_class = 'ws_' + flag + '_flag';
347
+
348
+ item.removeClass('ws_' + flag);
349
+ item.find('.' + img_class).remove();
350
+ }
351
+
352
+ function toggleMenuFlag(item, flag){
353
+ if (menuHasFlag(item, flag)){
354
+ removeMenuFlag(item, flag);
355
+ } else {
356
+ addMenuFlag(item, flag);
357
+ }
358
+ }
359
+
360
+ function menuHasFlag(item, flag){
361
+ return $(item).hasClass('ws_'+flag);
362
+ }
363
+
364
+ function clearMenuFlags(item){
365
+ item = $(item);
366
+ item.find('.ws_flag').remove();
367
+ for(var flag in item_flags){
368
+ item.removeClass('ws_'+flag);
369
+ }
370
+ }
371
+
372
+ //Cut & paste stuff
373
  var menu_in_clipboard = null;
374
  var submenu_in_clipboard = null;
375
  var item_in_clipboard = null;
394
  var selection = $('#ws_menu_box .ws_active');
395
  if (!selection.length) return;
396
 
397
+ //Mark the menu as hidden/visible
398
+ //selection.toggleClass('ws_hidden');
399
+ toggleMenuFlag(selection, 'hidden');
400
+
401
  //Also mark all of it's submenus as hidden/visible
402
+ if ( menuHasFlag(selection,'hidden') ){
403
+ $('#' + selection.attr('submenu_id') + ' .ws_item').each(function(){
404
+ addMenuFlag(this, 'hidden');
405
+ });
406
  } else {
407
+ $('#' + selection.attr('submenu_id') + ' .ws_item').each(function(){
408
+ removeMenuFlag(this, 'hidden');
409
+ });
410
  }
411
  });
412
 
518
  dropOnEmpty: true,
519
  });
520
 
521
+ //Clean up the menu's flags & classes
522
+ menu.attr('class','ws_container ws_menu');
523
+ clearMenuFlags(menu);
524
+ addMenuFlag(menu, 'custom_item');
525
 
526
+ //Check the "Custom" checkbox
527
+ menu.find('.ws_custom_toggle').attr('checked', 'checked');
528
 
529
  var temp_id = 'custom_menu_'+ws_paste_count;
530
  //Assign a stub title
559
  if (!selection.length) return;
560
 
561
  //Mark the item as hidden
562
+ toggleMenuFlag(selection, 'hidden');
563
  });
564
 
565
  //Delete menu
632
  //Clone another item to use as a template (hack)
633
  var menu = $('#ws_submenu_box .ws_item:first').clone(true);
634
 
635
+ //Cleanup the items's flags & classes
636
+ menu.attr('class','ws_container ws_item');
637
+ clearMenuFlags(menu);
638
+ addMenuFlag(menu, 'custom_item');
639
+
640
+ //Check the "Custom" checkbox
641
+ menu.find('.ws_custom_toggle').attr('checked', 'checked');
642
 
643
  var temp_id = 'custom_item_'+ws_paste_count;
644
  //Assign a stub title
686
  });
687
 
688
  });
 
689
 
690
  })(jQuery);
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: 0.1.6
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: 0.2
7
  Author: Janis Elsts
8
  Author URI: http://w-shadow.com/blog/
9
  */
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Admin Menu Editor ===
2
  Contributors: whiteshadow
3
  Donate link: http://w-shadow.com/
4
- Tags: admin, dashboard, menu, security
5
  Requires at least: 2.7.0
6
- Tested up to: 2.9
7
- Stable tag: 0.1.6
8
 
9
  Lets you directly edit the WordPress admin menu. You can re-order, hide or rename existing menus, add custom menus and more.
10
 
@@ -19,35 +19,51 @@ Admin Menu Editor lets you manually edit the Dashboard menu. You can reorder the
19
  * Hide/show any menu or menu item. A hidden menu is invisible to all users, including administrators.
20
  * Create custom menus that point to any part of the Dashboard. For example, you could create a new menu leading directly to the "Pending comments" page.
21
 
 
 
22
  **Known Issues**
23
 
24
- * If you delete any of the default menus they will reappear after saving. This is by design.
25
- * You can't use arbitrary URLs as menu targets because WordPress will automatically strip off the "http:/".
26
- * A plugin's menu that is moved to a different submenu will not work unless you also include the parent file in the "File" field.
27
 
28
  == Installation ==
29
 
30
- To do a new installation of the plugin, please follow these steps
31
 
32
  1. Download the admin-menu-editor.zip file to your local machine.
33
- 1. Unzip the file
34
- 1. Upload `admin-menu-editor` folder to the `/wp-content/plugins/` directory
35
  1. Activate the plugin through the 'Plugins' menu in WordPress.
36
 
37
  That's it. You can access the the menu editor by going to *Settings -> Menu Editor*. The plugin will automatically load your current menu configuration the first time you run it.
38
 
39
- To upgrade your installation
 
 
40
 
41
- 1. De-activate the plugin
42
- 1. Get and upload the new files (do steps 1. - 3. from "new installation" instructions)
43
- 1. Reactivate the plugin. Your settings should have been retained from the previous version.
 
 
 
44
 
45
  == Changelog ==
46
 
 
 
 
 
 
 
 
 
 
47
  = 0.1.6 =
48
  * Fixed a conflict with All In One SEO Pack 1.6.10. It was caused by that plugin adding invisible sub-menus to a non-existent top-level menu.
49
 
50
  = 0.1.5 =
51
  * First release on wordpress.org
52
  * Moved all images into a separate directory.
53
- * Added a readme.txt
1
  === Admin Menu Editor ===
2
  Contributors: whiteshadow
3
  Donate link: http://w-shadow.com/
4
+ Tags: admin, dashboard, menu, security, wpmu
5
  Requires at least: 2.7.0
6
+ Tested up to: 2.9.2
7
+ Stable tag: 0.2
8
 
9
  Lets you directly edit the WordPress admin menu. You can re-order, hide or rename existing menus, add custom menus and more.
10
 
19
  * Hide/show any menu or menu item. A hidden menu is invisible to all users, including administrators.
20
  * Create custom menus that point to any part of the Dashboard. For example, you could create a new menu leading directly to the "Pending comments" page.
21
 
22
+ [Suggest new features and improvements here](http://feedback.w-shadow.com/forums/58572-admin-menu-editor)
23
+
24
  **Known Issues**
25
 
26
+ * If you delete any of the default menus they will reappear after saving. This is by design. To get rid of a menu for good, either hide it or set it's access rights to a higher level.
27
+ * Custom menus will only show up in the final menu if the "Custom" box is checked. If some of your menu items are only visible in the editor but not the Dashboard menu itself, this is probably the reason.
28
+ * A plugin's menu that is moved to a different submenu will not work unless you also include the parent file in the "File" field. For example, if the plugin's page was originally in the "Settings" menu and had the "File" field set to "my_plugin", you'll need to change it to "options-general.php?page=my_plugin" and tick the "Custom" checkbox after moving it to a different menu.
29
 
30
  == Installation ==
31
 
32
+ **Normal installation**
33
 
34
  1. Download the admin-menu-editor.zip file to your local machine.
35
+ 1. Unzip the file.
36
+ 1. Upload the `admin-menu-editor` directory to your `/wp-content/plugins/` directory.
37
  1. Activate the plugin through the 'Plugins' menu in WordPress.
38
 
39
  That's it. You can access the the menu editor by going to *Settings -> Menu Editor*. The plugin will automatically load your current menu configuration the first time you run it.
40
 
41
+ **WPMU/Multi-user installation**
42
+
43
+ If you have a WPMU site, you can also install Admin Menu Editor as a global plugin. This will enable you to edit the Dashboard menu for all blogs and users at once.
44
 
45
+ 1. Download the admin-menu-editor.zip file to your local machine.
46
+ 1. Unzip the file.
47
+ 1. Upload the `admin-menu-editor` directory to your `/wp-content/mu-plugins/` directory.
48
+ 1. Move the `admin-menu-editor-mu.php` file from `admin-menu-editor` to `/wp-content/mu-plugins/`.
49
+
50
+ *Note : It is currently not possible to install this plugin both as a normal plugin and as a mu-plugin on the same site.*
51
 
52
  == Changelog ==
53
 
54
+ = 0.2 =
55
+ * Provisional WPMU support.
56
+ * Missing and unused menu items now get different icons in the menu editor.
57
+ * Fixed some visual glitches.
58
+ * Items that are not present in the default menu will only be included in the generated menu if their "Custom" flag is set. Makes perfect sense, eh? The takeaway is that you should tick the "Custom" checkbox for the menus you have created manually if you want them to show up.
59
+ * You no longer need to manually reload the page to see the changes you made to the menu. Just clicking "Save Changes" is enough.
60
+ * Added tooltips to the small flag icons that indicate that a particular menu item is hidden, user-created or otherwise special.
61
+ * Updated the readme.txt
62
+
63
  = 0.1.6 =
64
  * Fixed a conflict with All In One SEO Pack 1.6.10. It was caused by that plugin adding invisible sub-menus to a non-existent top-level menu.
65
 
66
  = 0.1.5 =
67
  * First release on wordpress.org
68
  * Moved all images into a separate directory.
69
+ * Added a readme.txt
shadow_plugin_framework.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  /**
4
  * @author W-Shadow
5
- * @copyright 2008
6
  */
7
 
8
  //Make sure the needed constants are defined
@@ -16,11 +16,14 @@ if ( ! defined( 'WP_PLUGIN_DIR' ) )
16
  define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );
17
 
18
  class MenuEd_ShadowPluginFramework {
19
- public static $framework_version = '0.1.2';
 
 
20
 
21
  protected $options = array();
22
  public $option_name = ''; //should be set or overriden by the plugin
23
  protected $defaults = array(); //should be set or overriden by the plugin
 
24
 
25
  public $plugin_file = ''; //Filename of the plugin.
26
  public $plugin_basename = ''; //Basename of the plugin, as returned by plugin_basename().
@@ -41,11 +44,20 @@ class MenuEd_ShadowPluginFramework {
41
  protected function __construct( $plugin_file = ''){
42
  if ($plugin_file == ''){
43
  //Try to guess the name of the file that included this file.
44
- //XXXXXX - not implemented yet.
45
  }
 
 
 
 
46
  $this->plugin_file = $plugin_file;
47
  $this->plugin_basename = plugin_basename($this->plugin_file);
48
- $this->plugin_dir_url = WP_PLUGIN_URL . '/' . dirname($this->plugin_basename);
 
 
 
 
 
49
 
50
  /************************************
51
  Load settings
@@ -81,7 +93,12 @@ class MenuEd_ShadowPluginFramework {
81
  * @return boolean TRUE if options were loaded okay and FALSE otherwise.
82
  */
83
  function load_options(){
84
- $this->options = get_option($this->option_name);
 
 
 
 
 
85
  if(!is_array($this->options)){
86
  $this->options = $this->defaults;
87
  return false;
@@ -122,8 +139,13 @@ class MenuEd_ShadowPluginFramework {
122
  * @return void
123
  */
124
  function save_options(){
125
- if ($this->option_name)
126
- update_option($this->option_name, $this->options);
 
 
 
 
 
127
  }
128
 
129
  /**
@@ -171,6 +193,23 @@ class MenuEd_ShadowPluginFramework {
171
  delete_option($this->option_name);
172
  }
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  }
175
 
176
  ?>
2
 
3
  /**
4
  * @author W-Shadow
5
+ * @copyright 2008-2010
6
  */
7
 
8
  //Make sure the needed constants are defined
16
  define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );
17
 
18
  class MenuEd_ShadowPluginFramework {
19
+ public static $framework_version = '0.2';
20
+
21
+ public $is_mu_plugin = null; //True if installed in the mu-plugins directory, false otherwise
22
 
23
  protected $options = array();
24
  public $option_name = ''; //should be set or overriden by the plugin
25
  protected $defaults = array(); //should be set or overriden by the plugin
26
+ protected $sitewide_options = false; //WPMU only : save the setting in a site-wide option
27
 
28
  public $plugin_file = ''; //Filename of the plugin.
29
  public $plugin_basename = ''; //Basename of the plugin, as returned by plugin_basename().
44
  protected function __construct( $plugin_file = ''){
45
  if ($plugin_file == ''){
46
  //Try to guess the name of the file that included this file.
47
+ //Not implemented yet.
48
  }
49
+
50
+ if ( is_null($this->is_mu_plugin) )
51
+ $this->is_mu_plugin = $this->is_in_wpmu_plugin_dir($plugin_file);
52
+
53
  $this->plugin_file = $plugin_file;
54
  $this->plugin_basename = plugin_basename($this->plugin_file);
55
+
56
+ if ( $this->is_mu_plugin ){
57
+ $this->plugin_dir_url = WPMU_PLUGIN_URL . '/' . dirname($this->plugin_basename);
58
+ } else {
59
+ $this->plugin_dir_url = WP_PLUGIN_URL . '/' . dirname($this->plugin_basename);
60
+ }
61
 
62
  /************************************
63
  Load settings
93
  * @return boolean TRUE if options were loaded okay and FALSE otherwise.
94
  */
95
  function load_options(){
96
+ if ( $this->sitewide_options ) {
97
+ $this->options = get_site_option($this->option_name);
98
+ } else {
99
+ $this->options = get_option($this->option_name);
100
+ }
101
+
102
  if(!is_array($this->options)){
103
  $this->options = $this->defaults;
104
  return false;
139
  * @return void
140
  */
141
  function save_options(){
142
+ if ($this->option_name) {
143
+ if ( $this->sitewide_options ) {
144
+ update_site_option($this->option_name, $this->options);
145
+ } else {
146
+ update_option($this->option_name, $this->options);
147
+ }
148
+ }
149
  }
150
 
151
  /**
193
  delete_option($this->option_name);
194
  }
195
 
196
+ /**
197
+ * MenuEd_ShadowPluginFramework::is_in_wpmu_plugin_dir()
198
+ * Checks if the specified file is inside the mu-plugins directory.
199
+ *
200
+ * @param string $filename The filename to check. Leave blank to use the current plugin's filename.
201
+ * @return bool
202
+ */
203
+ function is_in_wpmu_plugin_dir( $filename = '' ){
204
+ if ( !defined('WPMU_PLUGIN_DIR') ) return false;
205
+
206
+ if ( empty($filename) ){
207
+ $filename = $this->plugin_file;
208
+ }
209
+
210
+ return (strpos( realpath($filename), realpath(WPMU_PLUGIN_DIR) ) !== false);
211
+ }
212
+
213
  }
214
 
215
  ?>