Custom Menu Wizard Widget - Version 1.1.0

Version Description

  • added 'Current Root Item' and 'Current Parent Item' to the Children of filter

  • added Fallback to Current Item option, with subsibiary options for overriding a couple of Output options, as a means to enable Current Root & Current Parent to match a Current Item at root level

  • added an Output option to include both the parent item and the parent's siblings (for a successful Children of filter)

  • added max-width style (100%) to the Children of SELECT in the widget options

  • added widget version to the admin js enqueuer

  • ignore/disable Hide Empty option for WP >

Download this release

Release Info

Developer wizzud
Plugin Icon 128x128 Custom Menu Wizard Widget
Version 1.1.0
Comparing to
See all releases

Code changes from version 1.0.0 to 1.1.0

Files changed (4) hide show
  1. custom-menu-wizard.js +45 -21
  2. custom-menu-wizard.php +304 -94
  3. demo.html +418 -0
  4. readme.txt +86 -14
custom-menu-wizard.js CHANGED
@@ -1,28 +1,52 @@
1
  /* Plugin Name: Custom Menu Wizard
2
- * Version: 1.0.0
3
  * Author: Roger Barrett
4
  *
5
  * Script for controlling this widget's options (in Admin -> Widgets)
6
  */
7
  jQuery(function($){
8
- var dotPrefix = '.widget-custom-menu-wizard'
9
- $(document).on('click', dotPrefix + '-collapsible-fieldset', function(){
10
- var chkbox = $('input', this).eq(0),
11
- collapse = !chkbox.prop('checked');
12
- if(chkbox.length){
13
- chkbox.prop('checked', collapse);
14
- $('div', this).css({backgroundPosition:collapse?'0 0':'0 -36px'});
15
- $(this).next('div')[collapse?'slideUp':'slideDown']();
16
- }
17
- this.blur();
18
- return false;
19
- });
20
- $(document).on('change', dotPrefix + '-filter-radio', function(){
21
- $(dotPrefix + '-filter-radio-dep', this.form).prop('disabled', $(dotPrefix + '-filter-radio', this.form).eq(0).prop('checked'));
22
- });
23
- $(document).on('change', dotPrefix + '-select-menu', function(){
24
- var optgroups = $('select' + dotPrefix + '-filter-radio-dep', this.form).val(0).find('optgroup');
25
- optgroups.filter(':visible').hide();
26
- optgroups.eq( this.selectedIndex ).show();
27
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  });
1
  /* Plugin Name: Custom Menu Wizard
2
+ * Version: 1.1.0
3
  * Author: Roger Barrett
4
  *
5
  * Script for controlling this widget's options (in Admin -> Widgets)
6
  */
7
  jQuery(function($){
8
+ var dotPrefix = '.widget-custom-menu-wizard',
9
+ filterItems = $('select' + dotPrefix + '-listen');
10
+ $(document)
11
+ //fieldsets...
12
+ .on('click', dotPrefix + '-collapsible-fieldset', function(){
13
+ var chkbox = $('input', this).eq(0),
14
+ collapse = !chkbox.prop('checked');
15
+ if(chkbox.length){
16
+ chkbox.prop('checked', collapse);
17
+ $('div', this).css({backgroundPosition:collapse?'0 0':'0 -36px'});
18
+ $(this).next('div')[collapse?'slideUp':'slideDown']();
19
+ }
20
+ this.blur();
21
+ return false;
22
+ })
23
+ //change of menu...
24
+ .on('change', dotPrefix + '-selectmenu', function(){
25
+ var select = $('select' + dotPrefix + '-listen', this.form),
26
+ from = $('#' + select.attr('id') + '_ignore').find('optgroup'),
27
+ groupClone;
28
+ if(from.length > this.selectedIndex){
29
+ if(select.val() > 0){
30
+ select.val(0);
31
+ }
32
+ groupClone = from.eq( this.selectedIndex ).clone();
33
+ groupClone.find('option[selected]').removeAttr('selected').prop('selected', false);
34
+ select.find('optgroup').remove();
35
+ select.append(groupClone).trigger('change');
36
+ }
37
+ })
38
+ //enableif and disableif...
39
+ .on('change', dotPrefix + '-listen', function(){
40
+ var listeners = $(dotPrefix + '-listen', this.form),
41
+ showAll = listeners.eq(0).prop('checked'),
42
+ rootParent = !showAll && listeners.filter('select').val() < 0;
43
+ $(dotPrefix + '-disableif', this.form).css({color:showAll ? '#999999' : 'inherit'}).find('input,select').prop('disabled', showAll);
44
+ $(dotPrefix + '-enableif', this.form).css({color:!rootParent ? '#999999' : 'inherit'}).find('input,select').prop('disabled', !rootParent);
45
+ });
46
+ //remove non-active optgroups...
47
+ filterItems.find('optgroup').filter(function(){
48
+ return !$(this).data('cmwActiveMenu');
49
+ }).remove();
50
+ //trigger change...
51
+ filterItems.trigger('change');
52
  });
custom-menu-wizard.php CHANGED
@@ -3,12 +3,26 @@
3
  * Plugin Name: Custom Menu Wizard
4
  * Plugin URI: http://www.wizzud.com/
5
  * Description: Full control over the wp_nav_menu parameters for a custom menu, plus the ability to filter for specific level(s), or for children of a selected menu item or the current item
6
- * Version: 1.0.0
7
  * Author: Roger Barrett
8
  * Author URI: http://www.wizzud.com/
9
  * License: GPL2+
10
  */
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * registers the widget
14
  */
@@ -21,14 +35,16 @@ add_action('widgets_init', 'custom_menu_wizard_register_widget');
21
  * enqueues script file for the widget admin
22
  */
23
  function custom_menu_wizard_widget_admin_script(){
24
- wp_enqueue_script('custom-menu-wizard-plugin-script', plugins_url('/custom-menu-wizard.js', __FILE__), array('jquery'));
25
  }
26
  add_action('admin_print_scripts-widgets.php', 'custom_menu_wizard_widget_admin_script');
27
 
28
  /*
29
  * Custom Menu Wizard Walker class
 
 
30
  */
31
- class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
32
 
33
  /**
34
  * opens a sub-level with a UL or OL start-tag
@@ -70,51 +86,65 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
70
 
71
  $cmw =& $args->_custom_menu_wizard;
72
  //in $cmw (array) :
73
- // filter : 0 = none, 1 = kids of (current or specific item), 2 = current path
74
- // filter_item : current menu item if zero, else a menu item id
75
  // flat_output : true = equivalent of $max_depth == -1
76
  // include_parent : true = include the filter_item menu item
 
77
  // include_ancestors : true = include the filter_item menu item plus all it's ancestors
78
  // title_from_parent : true = widget wants parent's title as title
79
  // start_level : integer, 1+
80
  // depth : integer, replacement for max_depth and also applied to 'flat' output
 
 
 
81
  //$elements is an array of objects, indexed by position within the menu (menu_order),
82
  //starting at 1 and incrementing sequentially regardless of parentage (ie. first item is [1],
83
  //second item is [2] whether it's at root or subordinate to first item)
84
 
85
- $find_any = empty( $cmw['filter'] );
86
- $find_kids_of = $cmw['filter'] == 1;
87
  $find_current_item = $find_kids_of && empty( $cmw['filter_item'] );
88
- $find_current_path = $cmw['filter'] > 1; //ie. 2!
 
 
 
 
 
89
 
90
  //are we looking for something in particular?...
91
  if( $find_kids_of || $cmw['start_level'] > 1 ){
92
- $id_field = $this->db_fields['id'];
93
- $parent_field = $this->db_fields['parent'];
94
 
95
  //start level applies to the *kids* of a find_kids_of search, not to the parent, so while we
96
  //are still looking for the parent, the start_level for a find_kids_of search is actually one
97
- //up from mw['start_level']...
98
  $start_level = $find_kids_of ? $cmw['start_level'] - 1 : $cmw['start_level'];
99
 
100
  $keep_ids = array();
101
  $keep_items = array();
102
- $temp = array();
103
  foreach( $elements as $i=>$item ){
104
  if( empty( $item->$parent_field ) ){
105
  //set root level of menu, and no ancestors...
106
  $temp[ $item->$id_field ] = array(
107
  'level' => 1,
108
  //this is an array of indexes into $elements...
109
- 'breadcrumb' => array( $i )
 
 
110
  );
 
111
  }elseif( isset( $temp[ $item->$parent_field ] ) ){
112
  //set one greater than parent's level, and ancestors are parent's ancestors plus the parent...
113
  $temp[ $item->$id_field ] = array(
114
  'level' => $temp[ $item->$parent_field ]['level'] + 1,
115
- 'breadcrumb' => $temp[ $item->$parent_field ]['breadcrumb']
 
 
116
  );
117
  $temp[ $item->$id_field ]['breadcrumb'][] = $i;
 
118
  }
119
  //if $temp[] hasn't been set then it's an orphan; in order to keep orphans, max_depth must be 0 (ie. unlimited)
120
  //note that if a child is an orphan then all descendants of that child are also considered to be orphans!
@@ -126,19 +156,28 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
126
  //are we still looking for a starting point?...
127
  if( empty( $keep_ids ) ){
128
  if( //...we're looking for unspecific items starting at this level...
129
- $find_any ||
130
  //...we're looking for current item, and this is it...
131
  ( $find_current_item && $item->current ) ||
 
 
 
 
 
 
132
  //...we're looking for a particular menu item, and this is it...
133
- ( $find_kids_of && $cmw['filter_item'] == $item->$id_field ) ||
134
- //...we're looking for current path, and this is on it...
135
- ( $find_current_path && ( $item->current || $item->current_item_parent || $item->current_item_ancestor ) )
136
  ){
137
  //NOTE : at this point I'm *keeping* the id of the parent of a find_kids_of search, but not the actual item!
138
  $keep_ids[] = $item->$id_field;
139
  if( !$find_kids_of ){
140
  $keep_items[] = $item;
141
  }
 
 
 
 
 
142
  //depth, if set, kicks in at this point :
143
  // if doing a find_kids_of search then this level counts as 0, and the next level (the kids) counts as 1
144
  // otherwise, the current level counts as 1
@@ -154,7 +193,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
154
  //having found at least one, any more have to be:
155
  // - within max_depth of the first one found, and
156
  // - either it's an unspecific search, or we have the parent already
157
- }elseif( $temp[ $item->$id_field ]['level'] <= $max_level && ($find_any || in_array( $item->$parent_field, $keep_ids ) ) ){
158
  $keep_ids[] = $item->$id_field;
159
  $keep_items[] = $item;
160
  }
@@ -166,28 +205,65 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
166
  if( !empty( $keep_items) ){
167
 
168
  //do we need to prepend parent or ancestors?...
169
- $temp = $temp[ $keep_items[0]->$id_field ]['breadcrumb'];
170
- //remove the last element, which is the item's own index...
171
- array_pop( $temp );
172
- $i = $j = count( $temp );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  if( $find_kids_of && $i > 0 ){
174
  if( $cmw['include_ancestors'] ){
175
  $j = 0;
176
- }elseif( $cmw['include_parent'] ){
177
  --$j;
178
  }
179
  while( $i > $j ){
180
- array_unshift( $keep_items, $elements[ $temp[ --$i ] ]);
181
  }
182
  }
183
- //do we want the parent's title as the widget title?...
184
- if( $find_kids_of && $cmw['title_from_parent'] && count( $temp ) > 0){
185
- $cmw['parent_title'] = apply_filters(
186
- 'the_title',
187
- $elements[ $temp[ count( $temp ) - 1 ] ]->title,
188
- $elements[ $temp[ count( $temp ) - 1 ] ]->ID
189
- );
190
- }
191
  }
192
 
193
  //for each item we're keeping, use the temp array to hold:
@@ -244,10 +320,15 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
244
 
245
  var $_cmw_switches = array(
246
  'hide_title',
 
 
 
 
247
  'flat_output',
248
  'include_parent',
 
249
  'include_ancestors',
250
- 'hide_empty',
251
  'title_from_parent',
252
  'ol_root',
253
  'ol_sub',
@@ -274,8 +355,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
274
  );
275
  var $_cmw_integers = array(
276
  'depth' => 0,
277
- 'filter' => 0,
278
- 'filter_item' => 0,
279
  'menu' => 0,
280
  'start_level' => 1
281
  );
@@ -313,10 +393,14 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
313
  }
314
 
315
  /**
316
- * this merely removes itself from the filters and returns an empty string
317
- * it gets added by the cmw_filter_wp_nav_menu_SLUG_items method below, and only
318
  * ever gets run when hide_empty is set on the widget instance
319
  *
 
 
 
 
320
  * @param string $nav_menu HTML for the menu
321
  * @param object $args
322
  * @return string HTML for the menu
@@ -327,11 +411,15 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
327
  }
328
 
329
  /**
330
- * this gets run if hide_empty is set
331
  * if $items is empty then add a wp_nav_menu filter to do the actual return of an empty string
332
  * it gets run before the wp_nav_menu filter, but it gets the $items array whereas the wp_nav_menu filter does not
333
  * it gets added by $this->widget() before wp_nav_menu() is called, and removed immediately after wp_nav_menu() returns
334
  *
 
 
 
 
335
  * @param array $items Menu items
336
  * @param object $args
337
  * @return array Menu items
@@ -369,6 +457,9 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
369
  $instance[ $k ] = empty( $instance[ $k ] ) ? $v : trim( $instance[ $k ] );
370
  }
371
 
 
 
 
372
  $this->cmw_title_from_parent = '';
373
 
374
  //fetch menu...
@@ -418,7 +509,11 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
418
  '_custom_menu_wizard' => array(
419
  'filter' => $instance['filter'],
420
  'filter_item' => $instance['filter_item'],
 
 
 
421
  'include_parent' => $instance['include_parent'],
 
422
  'include_ancestors' => $instance['include_ancestors'],
423
  'title_from_parent' => $instance['title_from_parent'],
424
  'ol_root' => $instance['ol_root'],
@@ -434,6 +529,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
434
  if( !empty( $instance['container_class'] ) ){
435
  $params['container_class'] = $instance['container_class'];
436
  }
 
437
  $out = wp_nav_menu( $params );
438
 
439
  if( $instance['hide_empty'] ){
@@ -497,7 +593,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
497
  }
498
  //integers...
499
  foreach( $this->_cmw_integers as $k=>$v ){
500
- $instance[ $k ] = isset( $instance[ $k ]) ? max( $v, intval( $instance[ $k ] ) ) : $v;
501
  }
502
  //strings...
503
  foreach( $this->_cmw_strings as $k=>$v ){
@@ -516,66 +612,113 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
516
  echo '<p>'. sprintf( __('No menus have been created yet. <a href="%s">Create one</a>.'), admin_url('nav-menus.php') ) .'</p>';
517
  return;
518
  }
 
 
 
 
519
  ?>
520
  <p>
521
  <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:') ?></label>
522
  <label for="<?php echo $this->get_field_id('hide_title'); ?>" class="alignright">
523
- <input id="<?php echo $this->get_field_id('hide_title'); ?>" name="<?php echo $this->get_field_name('hide_title'); ?>" type="checkbox" value="1" <?php checked( $instance['hide_title'] ); ?> />
 
524
  <?php _e('Hide'); ?></label>
525
- <input id="<?php echo $this->get_field_id('title'); ?>" class="widefat" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $instance['title']; ?>" />
 
526
  <small><em><?php _e('Title can be set, but need not be displayed'); ?></em></small>
527
  </p>
528
 
529
  <p>
530
  <label for="<?php echo $this->get_field_id('menu'); ?>"><?php _e('Select Menu:'); ?></label>
531
- <select id="<?php echo $this->get_field_id('menu'); ?>" class="widget-<?php echo $this->id_base; ?>-select-menu" name="<?php echo $this->get_field_name('menu'); ?>">
 
532
  <?php
533
  foreach( $menus as $i=>$menu ){
534
  $menus[ $i ]->_items = wp_get_nav_menu_items( $menu->term_id );
535
  ?>
536
  <option <?php selected($instance['menu'], $menu->term_id); ?> value="<?php echo $menu->term_id; ?>"><?php echo $menu->name; ?></option>
537
  <?php
538
- }
539
- ?>
540
  </select>
541
  </p>
542
 
543
- <?php $this->_open_a_field_section($instance, 'Filter', 'fs_filter'); ?>
 
 
 
 
 
 
544
  <p>
545
  <label for="<?php echo $this->get_field_id('filter'); ?>_0">
546
- <input id="<?php echo $this->get_field_id('filter'); ?>_0" class="widget-<?php echo $this->id_base; ?>-filter-radio" name="<?php echo $this->get_field_name('filter'); ?>" type="radio" value="0" <?php checked($instance['filter'], 0); ?> />
 
547
  <?php _e('Show all'); ?></label>
548
  <br /><label for="<?php echo $this->get_field_id('filter'); ?>_1">
549
- <input id="<?php echo $this->get_field_id('filter'); ?>_1" class="widget-<?php echo $this->id_base; ?>-filter-radio" name="<?php echo $this->get_field_name('filter'); ?>" type="radio" value="1" <?php checked($instance['filter'], 1); ?> />
 
550
  <?php _e('Children of:'); ?></label>
551
- <select id="<?php echo $this->get_field_id('filter_item'); ?>" class="widget-<?php echo $this->id_base; ?>-filter-radio-dep" name="<?php echo $this->get_field_name('filter_item'); ?>" <?php disabled($instance['filter'] == 0); ?>>
 
552
  <option value="0" <?php selected( $instance['filter_item'], 0 ); ?>><?php _e('Current Item'); ?></option>
 
 
553
  <?php
 
 
 
 
 
554
  $maxlevel = 1;
555
  foreach( $menus as $i=>$menu ){
556
- $itemindents = array('0' => 3);
557
- $style = ( $i == 0 && empty($instance['menu']) ) || $instance['menu'] == $menu->term_id ? '' : ' style="display:none;"';
558
- ?>
559
- <optgroup label="<?php echo $menu->name; ?>"<?php echo $style; ?>>
560
- <?php
561
  if( !empty( $menu->_items ) ){
562
  foreach( $menu->_items as $item ){
563
  //exclude orpans!
564
  if( isset($itemindents[ $item->menu_item_parent ])){
565
- $maxlevel = max( $maxlevel, ceil( $itemindents[ $item->menu_item_parent ] / 10 ) );
566
- $itemindents[ $item->ID ] = $itemindents[ $item->menu_item_parent ] + 10;
567
- ?>
568
- <option style="padding-left:<?php echo $itemindents[ $item->menu_item_parent ] ?>px;" value="<?php echo $item->ID; ?>" <?php selected( $instance['filter_item'], $item->ID ); ?>><?php echo $item->title; ?></option>
569
- <?php
570
  }
571
  }
572
  }
573
- ?>
574
- </optgroup>
575
- <?php
576
  }
577
- ?>
 
 
578
  </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  </p>
580
 
581
  <p>
@@ -610,25 +753,44 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
610
  </p>
611
  <?php $this->_close_a_field_section(); ?>
612
 
613
- <?php $this->_open_a_field_section($instance, 'Output', 'fs_output'); ?>
 
 
 
 
 
 
614
  <p>
615
  <label for="<?php echo $this->get_field_id('flat_output'); ?>_0">
616
- <input id="<?php echo $this->get_field_id('flat_output'); ?>_0" name="<?php echo $this->get_field_name('flat_output'); ?>" type="radio" value="0" <?php checked(!$instance['flat_output']); ?> />
 
617
  <?php _e('Hierarchical'); ?></label>
618
  &nbsp;<label for="<?php echo $this->get_field_id('flat_output'); ?>_1">
619
- <input id="<?php echo $this->get_field_id('flat_output'); ?>_1" name="<?php echo $this->get_field_name('flat_output'); ?>" type="radio" value="1" <?php checked($instance['flat_output']); ?> />
 
620
  <?php _e('Flat'); ?></label>
621
  </p>
622
 
623
- <p>
624
  <label for="<?php echo $this->get_field_id('include_parent'); ?>">
625
- <input id="<?php echo $this->get_field_id('include_parent'); ?>" class="widget-<?php echo $this->id_base; ?>-filter-radio-dep" name="<?php echo $this->get_field_name('include_parent'); ?>" type="checkbox" value="1" <?php checked($instance['include_parent']); ?> <?php disabled($instance['filter'] == 0); ?> />
626
- <?php _e('Include Parent'); ?></label>
 
 
 
 
 
 
 
627
  <br /><label for="<?php echo $this->get_field_id('include_ancestors'); ?>">
628
- <input id="<?php echo $this->get_field_id('include_ancestors'); ?>" class="widget-<?php echo $this->id_base; ?>-filter-radio-dep" name="<?php echo $this->get_field_name('include_ancestors'); ?>" type="checkbox" value="1" <?php checked($instance['include_ancestors']); ?> <?php disabled($instance['filter'] == 0); ?> />
 
 
629
  <?php _e('Include Ancestors'); ?></label>
630
  <br /><label for="<?php echo $this->get_field_id('title_from_parent'); ?>">
631
- <input id="<?php echo $this->get_field_id('title_from_parent'); ?>" class="widget-<?php echo $this->id_base; ?>-filter-radio-dep" name="<?php echo $this->get_field_name('title_from_parent'); ?>" type="checkbox" value="1" <?php checked($instance['title_from_parent']); ?> <?php disabled($instance['filter'] == 0); ?> />
 
 
632
  <?php _e('Title from Parent Item'); ?></label>
633
  <br /><small><em><?php _e('Only if the &quot;Children of:&quot; Filter returns items'); ?></em></small>
634
  </p>
@@ -636,71 +798,109 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
636
  <p>
637
  <?php _e('Change UL to OL:'); ?>
638
  <br /><label for="<?php echo $this->get_field_id('ol_root'); ?>">
639
- <input id="<?php echo $this->get_field_id('ol_root'); ?>" name="<?php echo $this->get_field_name('ol_root'); ?>" type="checkbox" value="1" <?php checked($instance['ol_root']); ?> />
 
640
  <?php _e('Top Level'); ?></label>
641
  &nbsp;<label for="<?php echo $this->get_field_id('ol_sub'); ?>">
642
- <input id="<?php echo $this->get_field_id('ol_sub'); ?>" name="<?php echo $this->get_field_name('ol_sub'); ?>" type="checkbox" value="1" <?php checked($instance['ol_sub']); ?> />
 
643
  <?php _e('Sub-Levels'); ?></label>
644
  </p>
645
 
 
 
 
 
 
 
646
  <p>
647
  <label for="<?php echo $this->get_field_id('hide_empty'); ?>">
648
- <input id="<?php echo $this->get_field_id('hide_empty'); ?>" name="<?php echo $this->get_field_name('hide_empty'); ?>" type="checkbox" value="1" <?php checked($instance['hide_empty']); ?> />
 
649
  <?php _e('Hide Widget if Empty'); ?></label>
650
  <br /><small><em><?php _e('Prevents any output when no items are found'); ?></em></small>
651
  </p>
 
 
 
 
 
652
  <?php $this->_close_a_field_section(); ?>
653
 
654
- <?php $this->_open_a_field_section($instance, 'Container', 'fs_container'); ?>
 
 
 
 
 
655
  <p>
656
  <label for="<?php echo $this->get_field_id('container'); ?>"><?php _e('Element:') ?></label>
657
- <input id="<?php echo $this->get_field_id('container'); ?>" name="<?php echo $this->get_field_name('container'); ?>" type="text" value="<?php echo $instance['container']; ?>" />
658
- <br /><small><em><?php _e( 'Eg. div or nav; leave empty for no container' ); ?></em></small></p>
 
659
  </p>
660
  <p>
661
  <label for="<?php echo $this->get_field_id('container_id'); ?>"><?php _e('Unique ID:') ?></label>
662
- <input id="<?php echo $this->get_field_id('container_id'); ?>" name="<?php echo $this->get_field_name('container_id'); ?>" type="text" value="<?php echo $instance['container_id']; ?>" />
663
- <br /><small><em><?php _e( 'An optional ID for the container' ); ?></em></small></p>
 
664
  </p>
665
  <p>
666
  <label for="<?php echo $this->get_field_id('container_class'); ?>"><?php _e('Class:') ?></label>
667
- <input id="<?php echo $this->get_field_id('container_class'); ?>" name="<?php echo $this->get_field_name('container_class'); ?>" type="text" value="<?php echo $instance['container_class']; ?>" />
668
- <br /><small><em><?php _e( 'Extra class for the container' ); ?></em></small></p>
 
669
  </p>
670
  <?php $this->_close_a_field_section(); ?>
671
 
672
- <?php $this->_open_a_field_section($instance, 'Classes', 'fs_classes'); ?>
 
 
 
 
 
673
  <p>
674
  <label for="<?php echo $this->get_field_id('menu_class'); ?>"><?php _e('Menu Class:') ?></label>
675
- <input id="<?php echo $this->get_field_id('menu_class'); ?>" name="<?php echo $this->get_field_name('menu_class'); ?>" type="text" value="<?php echo $instance['menu_class']; ?>" />
676
- <br /><small><em><?php _e( 'Class for the list element forming the menu' ); ?></em></small></p>
 
677
  </p>
678
  <p>
679
  <label for="<?php echo $this->get_field_id('widget_class'); ?>"><?php _e('Widget Class:') ?></label>
680
- <input id="<?php echo $this->get_field_id('widget_class'); ?>" name="<?php echo $this->get_field_name('widget_class'); ?>" type="text" value="<?php echo $instance['widget_class']; ?>" />
681
- <br /><small><em><?php _e( 'Extra class for the widget itself' ); ?></em></small></p>
 
682
  </p>
683
  <?php $this->_close_a_field_section(); ?>
684
 
685
- <?php $this->_open_a_field_section($instance, 'Links', 'fs_links'); ?>
 
 
 
 
 
686
  <p>
687
  <label for="<?php echo $this->get_field_id('before'); ?>"><?php _e('Before the Link:') ?></label>
688
- <input id="<?php echo $this->get_field_id('before'); ?>" class="widefat" name="<?php echo $this->get_field_name('before'); ?>" type="text" value="<?php echo $instance['before']; ?>" />
 
689
  <small><em><?php _e( htmlspecialchars('Text/HTML to go before the <a> of the link') ); ?></em></small>
690
  </p>
691
  <p>
692
  <label for="<?php echo $this->get_field_id('after'); ?>"><?php _e('After the Link:') ?></label>
693
- <input id="<?php echo $this->get_field_id('after'); ?>" class="widefat" name="<?php echo $this->get_field_name('after'); ?>" type="text" value="<?php echo $instance['after']; ?>" />
 
694
  <small><em><?php _e( htmlspecialchars('Text/HTML to go after the </a> of the link') ); ?></em></small>
695
  </p>
696
  <p>
697
  <label for="<?php echo $this->get_field_id('link_before'); ?>"><?php _e('Before the Link Text:') ?></label>
698
- <input id="<?php echo $this->get_field_id('link_before'); ?>" class="widefat" name="<?php echo $this->get_field_name('link_before'); ?>" type="text" value="<?php echo $instance['link_before']; ?>" />
 
699
  <small><em><?php _e( 'Text/HTML to go before the link text' ); ?></em></small>
700
  </p>
701
  <p>
702
  <label for="<?php echo $this->get_field_id('link_after'); ?>"><?php _e('After the Link Text:') ?></label>
703
- <input id="<?php echo $this->get_field_id('link_after'); ?>" class="widefat" name="<?php echo $this->get_field_name('link_after'); ?>" type="text" value="<?php echo $instance['link_after']; ?>" />
 
704
  <small><em><?php _e( 'Text/HTML to go after the link text' ); ?></em></small>
705
  </p>
706
  <?php $this->_close_a_field_section(); ?>
@@ -719,8 +919,9 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
719
  // the default is *not* collapsed (field $fname == 0)
720
  $collapsed = !empty($instance[$fname]);
721
  ?>
722
- <div class="stuffbox widget-<?php echo $this->id_base; ?>-collapsible-fieldset" style="margin:0 0 0.5em;cursor:pointer;">
723
- <input id="<?php echo $this->get_field_id($fname); ?>" class="hidden-field" name="<?php echo $this->get_field_name($fname); ?>" type="checkbox" value="1" <?php checked($collapsed); ?> />
 
724
  <div style="background:transparent url(images/arrows.png) no-repeat 0 <?php echo $collapsed ? '0' : '-36px'; ?>;height:16px; width:16px;float:right;outline:0 none;"></div>
725
  <h3 style="font-size:1em;margin:0;padding:2px 0.5em;"><?php echo $text; ?></h3>
726
  </div>
@@ -736,5 +937,14 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_menu{
736
  </div>
737
  <?php
738
  } //end _close_a_field_section()
 
 
 
 
 
 
 
 
 
739
 
740
- }
3
  * Plugin Name: Custom Menu Wizard
4
  * Plugin URI: http://www.wizzud.com/
5
  * Description: Full control over the wp_nav_menu parameters for a custom menu, plus the ability to filter for specific level(s), or for children of a selected menu item or the current item
6
+ * Version: 1.1.0
7
  * Author: Roger Barrett
8
  * Author URI: http://www.wizzud.com/
9
  * License: GPL2+
10
  */
11
 
12
+ /*
13
+ * v1.1.0 change log:
14
+ * - added 'Current Root Item' and 'Current Parent Item' to the 'Children of' filter
15
+ * - added an Output option to include both the parent item and the parent's siblings (for a successful 'Children of' filter)
16
+ * - added Fallback to Current Item option, and subsidiary Output option overrides, to enable Current Root & Current Parent to match a Current Item at root level
17
+ * - added max-width style (100%) to the 'Children of' SELECT in the widget options
18
+ * - added widget version to the admin js enqueuer
19
+ * - ignore/disable hide_empty for WP >= v3.6 (wp_nav_menu() does it automatically)
20
+ * - rebuilt 'Children of' SELECT to account for IE's lack of OPTGROUP/OPTION styling
21
+ * - moved the setting of 'disabled' attributes on INPUTs/SELECTs from PHP into javascript
22
+ */
23
+
24
+ $Custom_Menu_Wizard_Widget_Version = '1.1.0';
25
+
26
  /**
27
  * registers the widget
28
  */
35
  * enqueues script file for the widget admin
36
  */
37
  function custom_menu_wizard_widget_admin_script(){
38
+ wp_enqueue_script('custom-menu-wizard-plugin-script', plugins_url('/custom-menu-wizard.js', __FILE__), array('jquery'), $Custom_Menu_Wizard_Widget_Version);
39
  }
40
  add_action('admin_print_scripts-widgets.php', 'custom_menu_wizard_widget_admin_script');
41
 
42
  /*
43
  * Custom Menu Wizard Walker class
44
+ * NB: Walker_Nav_Menu class is in wp-includes/nav-menu-template.php, and is itself an
45
+ * extension of the Walker class (wp-includes/class-wp-walker.php)
46
  */
47
+ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
48
 
49
  /**
50
  * opens a sub-level with a UL or OL start-tag
86
 
87
  $cmw =& $args->_custom_menu_wizard;
88
  //in $cmw (array) :
89
+ // filter : true = kids of (current [root|parent] item or specific item)
90
+ // filter_item : 0 = current item, -1 = parent of current (v1.1.0), -2 = root ancestor of current (v1.1.0); else a menu item id
91
  // flat_output : true = equivalent of $max_depth == -1
92
  // include_parent : true = include the filter_item menu item
93
+ // include_parent_siblings : true = include the siblings (& parent) of the filter_item menu item
94
  // include_ancestors : true = include the filter_item menu item plus all it's ancestors
95
  // title_from_parent : true = widget wants parent's title as title
96
  // start_level : integer, 1+
97
  // depth : integer, replacement for max_depth and also applied to 'flat' output
98
+ // fallback_no_ancestor : true = if looking for an ancestor (root or parent) of a top-level current item, fallback to current item (v1.1.0)
99
+ // fallback_include_parent : true = if fallback_no_ancestor comes into play then force include_parent to true (v1.1.0)
100
+ // fallback_include_parent_siblings : true = if fallback_no_ancestor comes into play then force include_parent_siblings to true (v1.1.0)
101
  //$elements is an array of objects, indexed by position within the menu (menu_order),
102
  //starting at 1 and incrementing sequentially regardless of parentage (ie. first item is [1],
103
  //second item is [2] whether it's at root or subordinate to first item)
104
 
105
+ $find_kids_of = $cmw['filter'];
 
106
  $find_current_item = $find_kids_of && empty( $cmw['filter_item'] );
107
+ $find_current_parent = $find_kids_of && $cmw['filter_item'] == -1; //v1.1.0
108
+ $find_current_root = $find_kids_of && $cmw['filter_item'] == -2; //v1.1.0
109
+ $fallback_current_item = $cmw['fallback_no_ancestor'] && ( $find_current_parent || $find_current_root ); //v1.1.0
110
+ //these could change depending on whether a fallback comes into play (v1.1.0)
111
+ $include_parent = $cmw['include_parent'];
112
+ $include_parent_siblings = $cmw['include_parent_siblings'];
113
 
114
  //are we looking for something in particular?...
115
  if( $find_kids_of || $cmw['start_level'] > 1 ){
116
+ $id_field = $this->db_fields['id']; //eg. = 'db_id'
117
+ $parent_field = $this->db_fields['parent']; //eg. = 'menu_item_parent'
118
 
119
  //start level applies to the *kids* of a find_kids_of search, not to the parent, so while we
120
  //are still looking for the parent, the start_level for a find_kids_of search is actually one
121
+ //up from cmw['start_level']...
122
  $start_level = $find_kids_of ? $cmw['start_level'] - 1 : $cmw['start_level'];
123
 
124
  $keep_ids = array();
125
  $keep_items = array();
126
+ $temp = array(0 => array('kids' => array()));
127
  foreach( $elements as $i=>$item ){
128
  if( empty( $item->$parent_field ) ){
129
  //set root level of menu, and no ancestors...
130
  $temp[ $item->$id_field ] = array(
131
  'level' => 1,
132
  //this is an array of indexes into $elements...
133
+ 'breadcrumb' => array( $i ),
134
+ 'parent' => 0,
135
+ 'kids' => array()
136
  );
137
+ $temp[0]['kids'][] = $i;
138
  }elseif( isset( $temp[ $item->$parent_field ] ) ){
139
  //set one greater than parent's level, and ancestors are parent's ancestors plus the parent...
140
  $temp[ $item->$id_field ] = array(
141
  'level' => $temp[ $item->$parent_field ]['level'] + 1,
142
+ 'breadcrumb' => $temp[ $item->$parent_field ]['breadcrumb'],
143
+ 'parent' => $item->$parent_field,
144
+ 'kids' => array()
145
  );
146
  $temp[ $item->$id_field ]['breadcrumb'][] = $i;
147
+ $temp[ $item->$parent_field ]['kids'][] = $i;
148
  }
149
  //if $temp[] hasn't been set then it's an orphan; in order to keep orphans, max_depth must be 0 (ie. unlimited)
150
  //note that if a child is an orphan then all descendants of that child are also considered to be orphans!
156
  //are we still looking for a starting point?...
157
  if( empty( $keep_ids ) ){
158
  if( //...we're looking for unspecific items starting at this level...
159
+ !$find_kids_of ||
160
  //...we're looking for current item, and this is it...
161
  ( $find_current_item && $item->current ) ||
162
+ //...we're looking for current parent, and this is it...
163
+ ( $find_current_parent && $item->current_item_parent ) ||
164
+ //...we're looking for a current root ancestor, and this is one...
165
+ ( $find_current_root && $item->current_item_ancestor ) ||
166
+ //...we've got a fallback for a top-level current item with no ancestor...
167
+ ( $fallback_current_item && $item->current && $temp[ $item->$id_field ]['level'] == 1 ) ||
168
  //...we're looking for a particular menu item, and this is it...
169
+ ( $cmw['filter_item'] == $item->$id_field )
 
 
170
  ){
171
  //NOTE : at this point I'm *keeping* the id of the parent of a find_kids_of search, but not the actual item!
172
  $keep_ids[] = $item->$id_field;
173
  if( !$find_kids_of ){
174
  $keep_items[] = $item;
175
  }
176
+ //v1.1.0 if this was the fallback option, we may need to update $include_parent[_siblings]...
177
+ if( $fallback_current_item && $item->current && $temp[ $item->$id_field ]['level'] == 1 ){
178
+ $include_parent = $include_parent || $cmw['fallback_include_parent'];
179
+ $include_parent_siblings = $include_parent_siblings || $cmw['fallback_include_parent_siblings'];
180
+ }
181
  //depth, if set, kicks in at this point :
182
  // if doing a find_kids_of search then this level counts as 0, and the next level (the kids) counts as 1
183
  // otherwise, the current level counts as 1
193
  //having found at least one, any more have to be:
194
  // - within max_depth of the first one found, and
195
  // - either it's an unspecific search, or we have the parent already
196
+ }elseif( $temp[ $item->$id_field ]['level'] <= $max_level && (!$find_kids_of || in_array( $item->$parent_field, $keep_ids ) ) ){
197
  $keep_ids[] = $item->$id_field;
198
  $keep_items[] = $item;
199
  }
205
  if( !empty( $keep_items) ){
206
 
207
  //do we need to prepend parent or ancestors?...
208
+ $breadcrumb = $temp[ $keep_items[0]->$id_field ]['breadcrumb'];
209
+ //remove the last breadcrumb element, which is the item's own index...
210
+ array_pop( $breadcrumb );
211
+ //last element is now the parent (if there is one)
212
+ $i = $j = count( $breadcrumb );
213
+
214
+ //do we want the parent's title as the widget title?...
215
+ if( $find_kids_of && $cmw['title_from_parent'] && $i > 0 ){
216
+ $cmw['parent_title'] = apply_filters(
217
+ 'the_title',
218
+ $elements[ $breadcrumb[ $i - 1 ] ]->title,
219
+ $elements[ $breadcrumb[ $i - 1 ] ]->ID
220
+ );
221
+ }
222
+
223
+ //if we have a parent and we also want all the parent siblings, then we need
224
+ //to pop the parent off the bottom of temp and either append or prepend the
225
+ //kids of the parent's parent onto keep_items...
226
+ if( $find_kids_of && $i > 0 && $include_parent_siblings ){
227
+ $siblings = $temp[ $keep_items[0]->$id_field ]['parent'];
228
+ if( !empty( $siblings ) ){
229
+ $siblings = $temp[ $temp[ $siblings ]['parent'] ]['kids'];
230
+ }
231
+ if( !empty( $siblings ) ){
232
+ //remove (and store) parent...
233
+ $j = array_pop( $breadcrumb );
234
+ $parentAt = -1;
235
+ //going backwards thru the array, prepend the parent and anything higher in the array than it...
236
+ for($i = count($siblings) - 1; $i > -1; $i--){
237
+ if( $parentAt < 0 && $siblings[ $i ] == $j ){
238
+ $parentAt = $i;
239
+ }
240
+ if( $parentAt > -1 ){
241
+ array_unshift( $keep_items, $elements[ $siblings[ $i ] ]);
242
+ }
243
+ }
244
+ //going forwards thru the array, append anything lower in the array than the parent...
245
+ for($i = $parentAt + 1; $i < count($siblings); $i++){
246
+ //anything after parent gets appended; parent and before get prepended...
247
+ array_push( $keep_items, $elements[ $siblings[ $i ] ]);
248
+ }
249
+ $i = $j = count( $breadcrumb );
250
+ //don't include_parent now because we just have...
251
+ $include_parent = false;
252
+ }
253
+ unset( $siblings );
254
+ }
255
+
256
  if( $find_kids_of && $i > 0 ){
257
  if( $cmw['include_ancestors'] ){
258
  $j = 0;
259
+ }elseif( $include_parent ){
260
  --$j;
261
  }
262
  while( $i > $j ){
263
+ array_unshift( $keep_items, $elements[ $breadcrumb[ --$i ] ]);
264
  }
265
  }
266
+ unset( $breadcrumb );
 
 
 
 
 
 
 
267
  }
268
 
269
  //for each item we're keeping, use the temp array to hold:
320
 
321
  var $_cmw_switches = array(
322
  'hide_title',
323
+ 'filter', //v1.1.0 changed from integer
324
+ 'fallback_no_ancestor', //v1.1.0 added
325
+ 'fallback_include_parent', //v1.1.0 added
326
+ 'fallback_include_parent_siblings', //v1.1.0 added
327
  'flat_output',
328
  'include_parent',
329
+ 'include_parent_siblings', //v1.1.0 added
330
  'include_ancestors',
331
+ 'hide_empty', //v1.1.0: this now only has relevance prior to WP v3.6
332
  'title_from_parent',
333
  'ol_root',
334
  'ol_sub',
355
  );
356
  var $_cmw_integers = array(
357
  'depth' => 0,
358
+ 'filter_item' => -2, //v1.1.0 changed from 0
 
359
  'menu' => 0,
360
  'start_level' => 1
361
  );
393
  }
394
 
395
  /**
396
+ * this (filter: wp_nav_menu) merely removes itself from the filters and returns an empty string
397
+ * it gets added by the cmw_filter_check_for_no_items method below, and only
398
  * ever gets run when hide_empty is set on the widget instance
399
  *
400
+ * v1.1.0 As of WP v3.6 this method becomes superfluous because wp_nav_menu() has had code added to immediately
401
+ * cop out (return false) if the output from wp_nav_menu_{$menu->slug}_items filter(s) is empty.
402
+ * However, it stays in so as to cope with versions < 3.6
403
+ *
404
  * @param string $nav_menu HTML for the menu
405
  * @param object $args
406
  * @return string HTML for the menu
411
  }
412
 
413
  /**
414
+ * this gets run (filter: wp_nav_menu_{$menu->slug}_items) if hide_empty is set
415
  * if $items is empty then add a wp_nav_menu filter to do the actual return of an empty string
416
  * it gets run before the wp_nav_menu filter, but it gets the $items array whereas the wp_nav_menu filter does not
417
  * it gets added by $this->widget() before wp_nav_menu() is called, and removed immediately after wp_nav_menu() returns
418
  *
419
+ * v1.1.0 As of WP v3.6 this method becomes superfluous because wp_nav_menu() has had code added to immediately
420
+ * cop out (return false) if the output from wp_nav_menu_{$menu->slug}_items filter(s) is empty.
421
+ * However, it stays in so as to cope with versions < 3.6
422
+ *
423
  * @param array $items Menu items
424
  * @param object $args
425
  * @return array Menu items
457
  $instance[ $k ] = empty( $instance[ $k ] ) ? $v : trim( $instance[ $k ] );
458
  }
459
 
460
+ //v1.1.0 As of WP v3.6, wp_nav_menu() automatically prevents any HTML output if there are no items...
461
+ $instance['hide_empty'] = $instance['hide_empty'] && $this->_pre_3point6();
462
+
463
  $this->cmw_title_from_parent = '';
464
 
465
  //fetch menu...
509
  '_custom_menu_wizard' => array(
510
  'filter' => $instance['filter'],
511
  'filter_item' => $instance['filter_item'],
512
+ 'fallback_no_ancestor' => $instance['fallback_no_ancestor'], //v1.1.0
513
+ 'fallback_include_parent' => $instance['fallback_include_parent'], //v1.1.0
514
+ 'fallback_include_parent_siblings' => $instance['fallback_include_parent_siblings'], //v1.1.0
515
  'include_parent' => $instance['include_parent'],
516
+ 'include_parent_siblings' => $instance['include_parent_siblings'], //v1.1.0
517
  'include_ancestors' => $instance['include_ancestors'],
518
  'title_from_parent' => $instance['title_from_parent'],
519
  'ol_root' => $instance['ol_root'],
529
  if( !empty( $instance['container_class'] ) ){
530
  $params['container_class'] = $instance['container_class'];
531
  }
532
+ //NB: wp_nav_menu() is in wp-includes/nav-menu-template.php
533
  $out = wp_nav_menu( $params );
534
 
535
  if( $instance['hide_empty'] ){
593
  }
594
  //integers...
595
  foreach( $this->_cmw_integers as $k=>$v ){
596
+ $instance[ $k ] = isset( $instance[ $k ]) ? max( $v, intval( $instance[ $k ] ) ) : max($v, 0);
597
  }
598
  //strings...
599
  foreach( $this->_cmw_strings as $k=>$v ){
612
  echo '<p>'. sprintf( __('No menus have been created yet. <a href="%s">Create one</a>.'), admin_url('nav-menus.php') ) .'</p>';
613
  return;
614
  }
615
+
616
+ /**
617
+ * permanently visible section : Title (with Hide) and Menu
618
+ */
619
  ?>
620
  <p>
621
  <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:') ?></label>
622
  <label for="<?php echo $this->get_field_id('hide_title'); ?>" class="alignright">
623
+ <input id="<?php echo $this->get_field_id('hide_title'); ?>" name="<?php echo $this->get_field_name('hide_title'); ?>"
624
+ type="checkbox" value="1" <?php checked( $instance['hide_title'] ); ?> />
625
  <?php _e('Hide'); ?></label>
626
+ <input id="<?php echo $this->get_field_id('title'); ?>" class="widefat" name="<?php echo $this->get_field_name('title'); ?>"
627
+ type="text" value="<?php echo $instance['title']; ?>" />
628
  <small><em><?php _e('Title can be set, but need not be displayed'); ?></em></small>
629
  </p>
630
 
631
  <p>
632
  <label for="<?php echo $this->get_field_id('menu'); ?>"><?php _e('Select Menu:'); ?></label>
633
+ <select id="<?php echo $this->get_field_id('menu'); ?>" class="widget-<?php echo $this->id_base; ?>-selectmenu"
634
+ name="<?php echo $this->get_field_name('menu'); ?>">
635
  <?php
636
  foreach( $menus as $i=>$menu ){
637
  $menus[ $i ]->_items = wp_get_nav_menu_items( $menu->term_id );
638
  ?>
639
  <option <?php selected($instance['menu'], $menu->term_id); ?> value="<?php echo $menu->term_id; ?>"><?php echo $menu->name; ?></option>
640
  <?php
641
+ }
642
+ ?>
643
  </select>
644
  </p>
645
 
646
+ <?php
647
+ /**
648
+ * start collapsible section : 'Filter'
649
+ */
650
+ $this->_open_a_field_section($instance, 'Filter', 'fs_filter');
651
+ ?>
652
+ <small class="alignright" style="line-height:1;"><a href="<?php echo plugins_url('/demo.html', __FILE__); ?>" target="_blank"><?php _e(' demo' ); ?></a></small>
653
  <p>
654
  <label for="<?php echo $this->get_field_id('filter'); ?>_0">
655
+ <input id="<?php echo $this->get_field_id('filter'); ?>_0" class="widget-<?php echo $this->id_base; ?>-listen"
656
+ name="<?php echo $this->get_field_name('filter'); ?>" type="radio" value="0" <?php checked(!$instance['filter']); ?> />
657
  <?php _e('Show all'); ?></label>
658
  <br /><label for="<?php echo $this->get_field_id('filter'); ?>_1">
659
+ <input id="<?php echo $this->get_field_id('filter'); ?>_1" class="widget-<?php echo $this->id_base; ?>-listen"
660
+ name="<?php echo $this->get_field_name('filter'); ?>" type="radio" value="1" <?php checked($instance['filter']); ?> />
661
  <?php _e('Children of:'); ?></label>
662
+ <select id="<?php echo $this->get_field_id('filter_item'); ?>" class="widget-<?php echo $this->id_base; ?>-listen"
663
+ style="max-width:100%;" name="<?php echo $this->get_field_name('filter_item'); ?>">
664
  <option value="0" <?php selected( $instance['filter_item'], 0 ); ?>><?php _e('Current Item'); ?></option>
665
+ <option value="-2" <?php selected( $instance['filter_item'], -2 ); ?>><?php _e('Current Root Item'); ?></option>
666
+ <option value="-1" <?php selected( $instance['filter_item'], -1 ); ?>><?php _e('Current Parent Item'); ?></option>
667
  <?php
668
+ //v1.1.0
669
+ // IE is a pita when it comes to SELECTs because it ignores any styling on OPTGROUPs and OPTIONs, so I'm changing the way
670
+ // that this SELECT works by introducing a copy from which the javascript can pick the relevant OPTGROUP
671
+ $menuOptions = array();
672
+
673
  $maxlevel = 1;
674
  foreach( $menus as $i=>$menu ){
675
+ //v1.1.0 changed the indents from padding to hyphen-space (for IE!!!! grrrr...)
676
+ $itemindents = array('0' => 0);
677
+ $activeOpts = ( $i == 0 && empty($instance['menu']) ) || $instance['menu'] == $menu->term_id;
678
+ $style = $activeOpts ? '' : ' style="display:none;"';
679
+ $menuOptions[] = '<optgroup label="' . $menu->name . '" data-cmw-active-menu="' . ($activeOpts ? 'true' : 'false') .'">';
680
  if( !empty( $menu->_items ) ){
681
  foreach( $menu->_items as $item ){
682
  //exclude orpans!
683
  if( isset($itemindents[ $item->menu_item_parent ])){
684
+ $itemindents[ $item->ID ] = $itemindents[ $item->menu_item_parent ] + 1;
685
+ $maxlevel = max( $maxlevel, $itemindents[ $item->ID ] );
686
+ $menuOptions[] = '<option style="padding-left:0.75em;" value="' . $item->ID . '" ' .
687
+ selected( $instance['filter_item'], $item->ID, false ) . '>' .
688
+ str_repeat('- ', $itemindents[ $item->menu_item_parent ]) . $item->title . '</option>';
689
  }
690
  }
691
  }
692
+ $menuOptions[] = '</optgroup>';
 
 
693
  }
694
+ $menuOptions = implode("\n", $menuOptions);
695
+ echo $menuOptions;
696
+ ?>
697
  </select>
698
+ <select id="<?php echo $this->get_field_id('filter_item_ignore'); ?>" disabled="disabled"
699
+ style="display:none;position:absolute;left:-5000px;top:-5000px;"
700
+ name="<?php echo $this->get_field_name('filter_item_ignore'); ?>">
701
+ <?php echo $menuOptions; ?>
702
+ </select>
703
+ </p>
704
+
705
+ <p class="widget-<?php echo $this->id_base; ?>-enableif">
706
+ <label for="<?php echo $this->get_field_id('fallback_no_ancestor'); ?>">
707
+ <input id="<?php echo $this->get_field_id('fallback_no_ancestor'); ?>"
708
+ name="<?php echo $this->get_field_name('fallback_no_ancestor'); ?>" type="checkbox" value="1"
709
+ <?php checked($instance['fallback_no_ancestor']); ?> />
710
+ <?php _e('Fallback to Current Item, and'); ?></label>
711
+ <br /><label for="<?php echo $this->get_field_id('fallback_include_parent'); ?>" style="padding-left:1em;">
712
+ <input id="<?php echo $this->get_field_id('fallback_include_parent'); ?>"
713
+ name="<?php echo $this->get_field_name('fallback_include_parent'); ?>" type="checkbox" value="1"
714
+ <?php checked($instance['fallback_include_parent']); ?> />
715
+ <?php _e('Include Parent...'); ?> </label>
716
+ <label for="<?php echo $this->get_field_id('fallback_include_parent_siblings'); ?>">
717
+ <input id="<?php echo $this->get_field_id('fallback_include_parent_siblings'); ?>"
718
+ name="<?php echo $this->get_field_name('fallback_include_parent_siblings'); ?>" type="checkbox" value="1"
719
+ <?php checked($instance['fallback_include_parent_siblings']); ?> />
720
+ <?php _e('&amp; its Siblings'); ?></label>
721
+ <br /><small><em><?php _e('If Current Root/Parent and no ancestor exists'); ?></em></small>
722
  </p>
723
 
724
  <p>
753
  </p>
754
  <?php $this->_close_a_field_section(); ?>
755
 
756
+ <?php
757
+ /**
758
+ * start collapsible section : 'Output'
759
+ */
760
+ $this->_open_a_field_section($instance, 'Output', 'fs_output');
761
+ ?>
762
+ <small class="alignright" style="line-height:1;"><a href="<?php echo plugins_url('/demo.html', __FILE__); ?>" target="_blank"><?php _e(' demo' ); ?></a></small>
763
  <p>
764
  <label for="<?php echo $this->get_field_id('flat_output'); ?>_0">
765
+ <input id="<?php echo $this->get_field_id('flat_output'); ?>_0" name="<?php echo $this->get_field_name('flat_output'); ?>"
766
+ type="radio" value="0" <?php checked(!$instance['flat_output']); ?> />
767
  <?php _e('Hierarchical'); ?></label>
768
  &nbsp;<label for="<?php echo $this->get_field_id('flat_output'); ?>_1">
769
+ <input id="<?php echo $this->get_field_id('flat_output'); ?>_1" name="<?php echo $this->get_field_name('flat_output'); ?>"
770
+ type="radio" value="1" <?php checked($instance['flat_output']); ?> />
771
  <?php _e('Flat'); ?></label>
772
  </p>
773
 
774
+ <p class="widget-<?php echo $this->id_base; ?>-disableif">
775
  <label for="<?php echo $this->get_field_id('include_parent'); ?>">
776
+ <input id="<?php echo $this->get_field_id('include_parent'); ?>"
777
+ name="<?php echo $this->get_field_name('include_parent'); ?>" type="checkbox"
778
+ value="1" <?php checked($instance['include_parent']); ?> />
779
+ <?php _e('Include Parent...'); ?> </label>
780
+ <label for="<?php echo $this->get_field_id('include_parent_siblings'); ?>">
781
+ <input id="<?php echo $this->get_field_id('include_parent_siblings'); ?>"
782
+ name="<?php echo $this->get_field_name('include_parent_siblings'); ?>" type="checkbox"
783
+ value="1" <?php checked($instance['include_parent_siblings']); ?> />
784
+ <?php _e('&amp; its Siblings'); ?></label>
785
  <br /><label for="<?php echo $this->get_field_id('include_ancestors'); ?>">
786
+ <input id="<?php echo $this->get_field_id('include_ancestors'); ?>"
787
+ name="<?php echo $this->get_field_name('include_ancestors'); ?>" type="checkbox"
788
+ value="1" <?php checked($instance['include_ancestors']); ?> />
789
  <?php _e('Include Ancestors'); ?></label>
790
  <br /><label for="<?php echo $this->get_field_id('title_from_parent'); ?>">
791
+ <input id="<?php echo $this->get_field_id('title_from_parent'); ?>"
792
+ name="<?php echo $this->get_field_name('title_from_parent'); ?>" type="checkbox"
793
+ value="1" <?php checked($instance['title_from_parent']); ?> />
794
  <?php _e('Title from Parent Item'); ?></label>
795
  <br /><small><em><?php _e('Only if the &quot;Children of:&quot; Filter returns items'); ?></em></small>
796
  </p>
798
  <p>
799
  <?php _e('Change UL to OL:'); ?>
800
  <br /><label for="<?php echo $this->get_field_id('ol_root'); ?>">
801
+ <input id="<?php echo $this->get_field_id('ol_root'); ?>" name="<?php echo $this->get_field_name('ol_root'); ?>"
802
+ type="checkbox" value="1" <?php checked($instance['ol_root']); ?> />
803
  <?php _e('Top Level'); ?></label>
804
  &nbsp;<label for="<?php echo $this->get_field_id('ol_sub'); ?>">
805
+ <input id="<?php echo $this->get_field_id('ol_sub'); ?>" name="<?php echo $this->get_field_name('ol_sub'); ?>"
806
+ type="checkbox" value="1" <?php checked($instance['ol_sub']); ?> />
807
  <?php _e('Sub-Levels'); ?></label>
808
  </p>
809
 
810
+ <?php
811
+ //v1.1.0 As of WP v3.6, wp_nav_menu() automatically cops out (without outputting any HTML) if there are no items,
812
+ // so the hide_empty option becomes superfluous; however, I'll keep the previous setting (if there was one)
813
+ // in case of reversion to an earlier version of WP...
814
+ if( $this->_pre_3point6() ){
815
+ ?>
816
  <p>
817
  <label for="<?php echo $this->get_field_id('hide_empty'); ?>">
818
+ <input id="<?php echo $this->get_field_id('hide_empty'); ?>" name="<?php echo $this->get_field_name('hide_empty'); ?>"
819
+ type="checkbox" value="1" <?php checked($instance['hide_empty']); ?> />
820
  <?php _e('Hide Widget if Empty'); ?></label>
821
  <br /><small><em><?php _e('Prevents any output when no items are found'); ?></em></small>
822
  </p>
823
+ <?php }else{ ?>
824
+ <input id="<?php echo $this->get_field_id('hide_empty'); ?>" name="<?php echo $this->get_field_name('hide_empty'); ?>"
825
+ type="hidden" value="<?php echo $instance['hide_empty'] ? '1' : ''; ?>" />
826
+ <?php } ?>
827
+
828
  <?php $this->_close_a_field_section(); ?>
829
 
830
+ <?php
831
+ /**
832
+ * start collapsible section : 'Container'
833
+ */
834
+ $this->_open_a_field_section($instance, 'Container', 'fs_container');
835
+ ?>
836
  <p>
837
  <label for="<?php echo $this->get_field_id('container'); ?>"><?php _e('Element:') ?></label>
838
+ <input id="<?php echo $this->get_field_id('container'); ?>" name="<?php echo $this->get_field_name('container'); ?>"
839
+ type="text" value="<?php echo $instance['container']; ?>" />
840
+ <br /><small><em><?php _e( 'Eg. div or nav; leave empty for no container' ); ?></em></small>
841
  </p>
842
  <p>
843
  <label for="<?php echo $this->get_field_id('container_id'); ?>"><?php _e('Unique ID:') ?></label>
844
+ <input id="<?php echo $this->get_field_id('container_id'); ?>" name="<?php echo $this->get_field_name('container_id'); ?>"
845
+ type="text" value="<?php echo $instance['container_id']; ?>" />
846
+ <br /><small><em><?php _e( 'An optional ID for the container' ); ?></em></small>
847
  </p>
848
  <p>
849
  <label for="<?php echo $this->get_field_id('container_class'); ?>"><?php _e('Class:') ?></label>
850
+ <input id="<?php echo $this->get_field_id('container_class'); ?>" name="<?php echo $this->get_field_name('container_class'); ?>"
851
+ type="text" value="<?php echo $instance['container_class']; ?>" />
852
+ <br /><small><em><?php _e( 'Extra class for the container' ); ?></em></small>
853
  </p>
854
  <?php $this->_close_a_field_section(); ?>
855
 
856
+ <?php
857
+ /**
858
+ * start collapsible section : 'Classes'
859
+ */
860
+ $this->_open_a_field_section($instance, 'Classes', 'fs_classes');
861
+ ?>
862
  <p>
863
  <label for="<?php echo $this->get_field_id('menu_class'); ?>"><?php _e('Menu Class:') ?></label>
864
+ <input id="<?php echo $this->get_field_id('menu_class'); ?>" name="<?php echo $this->get_field_name('menu_class'); ?>"
865
+ type="text" value="<?php echo $instance['menu_class']; ?>" />
866
+ <br /><small><em><?php _e( 'Class for the list element forming the menu' ); ?></em></small>
867
  </p>
868
  <p>
869
  <label for="<?php echo $this->get_field_id('widget_class'); ?>"><?php _e('Widget Class:') ?></label>
870
+ <input id="<?php echo $this->get_field_id('widget_class'); ?>" name="<?php echo $this->get_field_name('widget_class'); ?>"
871
+ type="text" value="<?php echo $instance['widget_class']; ?>" />
872
+ <br /><small><em><?php _e( 'Extra class for the widget itself' ); ?></em></small>
873
  </p>
874
  <?php $this->_close_a_field_section(); ?>
875
 
876
+ <?php
877
+ /**
878
+ * start collapsible section : 'Links'
879
+ */
880
+ $this->_open_a_field_section($instance, 'Links', 'fs_links');
881
+ ?>
882
  <p>
883
  <label for="<?php echo $this->get_field_id('before'); ?>"><?php _e('Before the Link:') ?></label>
884
+ <input id="<?php echo $this->get_field_id('before'); ?>" class="widefat" name="<?php echo $this->get_field_name('before'); ?>"
885
+ type="text" value="<?php echo $instance['before']; ?>" />
886
  <small><em><?php _e( htmlspecialchars('Text/HTML to go before the <a> of the link') ); ?></em></small>
887
  </p>
888
  <p>
889
  <label for="<?php echo $this->get_field_id('after'); ?>"><?php _e('After the Link:') ?></label>
890
+ <input id="<?php echo $this->get_field_id('after'); ?>" class="widefat" name="<?php echo $this->get_field_name('after'); ?>"
891
+ type="text" value="<?php echo $instance['after']; ?>" />
892
  <small><em><?php _e( htmlspecialchars('Text/HTML to go after the </a> of the link') ); ?></em></small>
893
  </p>
894
  <p>
895
  <label for="<?php echo $this->get_field_id('link_before'); ?>"><?php _e('Before the Link Text:') ?></label>
896
+ <input id="<?php echo $this->get_field_id('link_before'); ?>" class="widefat" name="<?php echo $this->get_field_name('link_before'); ?>"
897
+ type="text" value="<?php echo $instance['link_before']; ?>" />
898
  <small><em><?php _e( 'Text/HTML to go before the link text' ); ?></em></small>
899
  </p>
900
  <p>
901
  <label for="<?php echo $this->get_field_id('link_after'); ?>"><?php _e('After the Link Text:') ?></label>
902
+ <input id="<?php echo $this->get_field_id('link_after'); ?>" class="widefat" name="<?php echo $this->get_field_name('link_after'); ?>"
903
+ type="text" value="<?php echo $instance['link_after']; ?>" />
904
  <small><em><?php _e( 'Text/HTML to go after the link text' ); ?></em></small>
905
  </p>
906
  <?php $this->_close_a_field_section(); ?>
919
  // the default is *not* collapsed (field $fname == 0)
920
  $collapsed = !empty($instance[$fname]);
921
  ?>
922
+ <div class="stuffbox widget-<?php echo $this->id_base; ?>-collapsible-fieldset" title="<?php _e( 'Click to show/hide' ); ?>" style="margin:0 0 0.5em;cursor:pointer;">
923
+ <input id="<?php echo $this->get_field_id($fname); ?>" class="hidden-field" name="<?php echo $this->get_field_name($fname); ?>"
924
+ type="checkbox" value="1" <?php checked($collapsed); ?> />
925
  <div style="background:transparent url(images/arrows.png) no-repeat 0 <?php echo $collapsed ? '0' : '-36px'; ?>;height:16px; width:16px;float:right;outline:0 none;"></div>
926
  <h3 style="font-size:1em;margin:0;padding:2px 0.5em;"><?php echo $text; ?></h3>
927
  </div>
937
  </div>
938
  <?php
939
  } //end _close_a_field_section()
940
+
941
+ /**
942
+ * returns true if the version of WP is lower than 3.6 (ie. 3.5* or below)
943
+ */
944
+ function _pre_3point6(){
945
+ global $wp_version;
946
+
947
+ return version_compare( strtolower( $wp_version ), '3.6a', '<' );
948
+ } //end _pre_3point6()
949
 
950
+ } //end of class
demo.html ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en-GB">
3
+ <head>
4
+ <title>Custom Menu Wizard : Interactive Demo</title>
5
+ <script type='text/javascript' src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
6
+ <script type='text/javascript' src='custom-menu-wizard.js'></script>
7
+ <style type='text/css'>
8
+ html, body {width:100%; border:0 none; margin:0; padding:0;}
9
+ body {font-family:arial,sans-serif; font-size:14px; font-weight:normal; line-height:1.25; color:#333333; background-color:#ffffff;}
10
+ div, p, h3, ul, ol, li, form, input, select, label, a {position:relative;}
11
+ a {color:#333333; text-decoration:none;}
12
+ p {margin: 1em 0;}
13
+ input, select {font-family:inherit; font-size:inherit; font-weight:inherit; color:inherit;}
14
+ select {max-width:100%;}
15
+ label {vertical-align:middle;}
16
+ form {display:block; width:270px;}
17
+ h3 {border-bottom:1px solid #cccccc;margin:0 0 0.25em; padding: 0.5em 0 0.25em;}
18
+ button {background-color:#cccccc; border-color:#999999; border-radius:0.5em 0 0.5em 0; border-style:solid; border-width:1px 0 0 1px; bottom:-1em; cursor:pointer; font-size:inherit; margin:0; padding:0 0.2em; position:absolute; right:-1em;}
19
+ button:hover {background-color:#666666; color:#ffffff;}
20
+ optgroup option {padding-left:0.75em;}
21
+ #formheader {background-color:#666666; border-radius:0.4em 0.4em 0 0; color:#FFFFFF; margin:0 -1em -0.5em; padding:0.25em 1em; text-align:center;}
22
+ #theform {margin:1em; padding:0 1em; border:1px solid #999999; border-radius:0.5em;}
23
+ #theoutput {margin:1em;}
24
+ #theoutput div {margin:0.5em 0; padding:0 1em; border:1px solid #cccccc; border-radius:0.5em; min-height:2em; min-width:8em;}
25
+ #theoutput ul, #theoutput ol {margin:0.5em 0 0.5em 1.5em; padding:0;}
26
+ #theoutput li ul {margin:0 0 0 1em;}
27
+ #theoutput li ol {margin:0 0 0 1.5em;}
28
+ #theoutput ul {list-style-type:disc;}
29
+ #theoutput ul ul {list-style-type:circle;}
30
+ #theoutput ul ul ul {list-style-type:square;}
31
+ #theoutput ul ul ul ul {list-style-type:disc;}
32
+ #theoutput ul ul ul ul ul {list-style-type:circle;}
33
+ #theoutput ol {list-style-type:decimal;}
34
+ #theoutput ol ol {list-style-type:upper-alpha;}
35
+ #theoutput ol ol ol {list-style-type:lower-alpha;}
36
+ #theoutput ol ol ol ol {list-style-type:lower-roman;}
37
+ #theoutput ol ol ol ol ol {list-style-type:decimal;}
38
+ #themenu {margin:1em;}
39
+ #themenu ul {font-size:12px; list-style-type:none; margin:1em 0; padding:0;}
40
+ #themenu ul ul {margin:0 0 0 5em;}
41
+ #themenu li {display:block; margin:0; padding:0;}
42
+ #themenu a {display:inline-block; text-align:center; padding:0.3333em; margin:0.1667em; border-radius:0.3333em;}
43
+ #themenu span {display:block; width:6em; height:1.75em; line-height:1.75; border:1px solid #999999; border-radius:0.25em; box-shadow:2px 2px 2px 0px #666666;}
44
+ #thefooter {float:left; clear:left; margin:0 1em; color:#808080;}
45
+ #thefooter div {font-size:12px;}
46
+ .alignleft {float:left;}
47
+ .alignright {float:right;}
48
+ .current-ancestor {border-color:#cccc00 !important; background-image:-webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 153, 1)), to(rgba(255, 255, 153, 0.1))); background-image:-webkit-linear-gradient(top, rgba(255, 255, 153, 1), rgba(255, 255, 153, 0.1)); background-image:-moz--linear-gradient(top, rgba(255, 255, 153, 1), rgba(255, 255, 153, 0.1)); background-image:-ms-linear-gradient(top, rgba(255, 255, 153, 1), rgba(255, 255, 153, 0.1)); background-image:-o-linear-gradient(top, rgba(255, 255, 153, 1), rgba(255, 255, 153, 0.1)); background-image:linear-gradient(to bottom, rgba(255, 255, 153, 1), rgba(255, 255, 153, 0.1)); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff99, endColorstr=#1affff99); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff99, endColorstr=#1affff99)";}
49
+ .current-item {border-color:#cc0000 !important; background-image:-webkit-gradient(linear, left top, left bottom, from(rgba(255, 204, 204, 1)), to(rgba(255, 204, 204, 0.1))); background-image:-webkit-linear-gradient(top, rgba(255, 204, 204, 1), rgba(255, 204, 204, 0.1)); background-image:-moz--linear-gradient(top, rgba(255, 204, 204, 1), rgba(255, 204, 204, 0.1)); background-image:-ms-linear-gradient(top, rgba(255, 204, 204, 1), rgba(255, 204, 204, 0.1)); background-image:-o-linear-gradient(top, rgba(255, 204, 204, 1), rgba(255, 204, 204, 0.1)); background-image:linear-gradient(to bottom, rgba(255, 204, 204, 1), rgba(255, 204, 204, 0.1)); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffcccc, endColorstr=#1affcccc); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffcccc, endColorstr=#1affcccc)";}
50
+ .current-parent {border-color:#ff9900 !important; background-image:-webkit-gradient(linear, left top, left bottom, from(rgba(255, 204, 153, 1)), to(rgba(255, 204, 153, 0.1))); background-image:-webkit-linear-gradient(top, rgba(255, 204, 153, 1), rgba(255, 204, 153, 0.1)); background-image:-moz--linear-gradient(top, rgba(255, 204, 153, 1), rgba(255, 204, 153, 0.1)); background-image:-ms-linear-gradient(top, rgba(255, 204, 153, 1), rgba(255, 204, 153, 0.1)); background-image:-o-linear-gradient(top, rgba(255, 204, 153, 1), rgba(255, 204, 153, 0.1)); background-image:linear-gradient(to bottom, rgba(255, 204, 153, 1), rgba(255, 204, 153, 0.1)); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffcc99, endColorstr=#1affcc99); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffcc99, endColorstr=#1affcc99)";}
51
+ .grey {color:#999999;}
52
+ .picked > a {background-color:#000066; color:#ffffff; font-weight:bold;}
53
+ .tryit {margin-left:1em; text-shadow:1px 1px 1px #ff0000;}
54
+ .widefat {width:100%;}
55
+ </style>
56
+ </head>
57
+ <body>
58
+ <div>
59
+ <div id='theform' class='alignright'>
60
+ <form>
61
+ <div id="formheader">
62
+ <strong>Custom Menu Wizard</strong> Interactive Demo
63
+ <br /><small>v1.1.0 <em>(subset of admin options)</em></small><strong class="tryit"><em>Try it out&hellip;</em></strong>
64
+ </div>
65
+
66
+ <p>
67
+ <label for="widget-custom-menu-wizard-2-title">Title:</label>
68
+ <label class="alignright">
69
+ <input type="checkbox" value="1" name="hide_title" id="widget-custom-menu-wizard-2-hide_title">
70
+ Hide</label>
71
+ <input type="text" value="" name="title" class="widefat" id="widget-custom-menu-wizard-2-title">
72
+ <small><em>Title can be set, but need not be displayed</em></small>
73
+ </p>
74
+
75
+ <p>
76
+ <label>
77
+ <input type="radio" checked="checked" value="0" name="filter" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_0">
78
+ Show all</label>
79
+ <br /><label>
80
+ <input type="radio" value="1" name="filter" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_1">
81
+ Children of:</label>
82
+ <select name="filter_item" style="max-width:100%;" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_item">
83
+ <option selected="selected" value="0">Current Item</option>
84
+ <option value="-2">Current Root Item</option>
85
+ <option value="-1">Current Parent Item</option>
86
+ <optgroup label="the-menu" data-cmw-active-menu='true'></optgroup>
87
+ </select>
88
+ </p>
89
+
90
+ <p class="widget-custom-menu-wizard-enableif">
91
+ <label>
92
+ <input type="checkbox" value="1" name="fallback_no_ancestor" id="widget-custom-menu-wizard-2-fallback_no_ancestor">
93
+ Fallback to Current Item, and</label>
94
+ <br /><label style="padding-left:1em;">
95
+ <input type="checkbox" value="1" name="fallback_include_parent" id="widget-custom-menu-wizard-2-fallback_include_parent">
96
+ Include Parent... </label>
97
+ <label>
98
+ <input type="checkbox" value="1" name="fallback_include_parent_siblings" id="widget-custom-menu-wizard-2-fallback_include_parent_siblings">
99
+ &amp; its Siblings</label>
100
+ <br /><small><em>If Current Root/Parent and no ancestor exists</em></small>
101
+ </p>
102
+
103
+ <p>
104
+ <label for="widget-custom-menu-wizard-2-start_level">Starting Level:</label>
105
+ <select name="start_level" id="widget-custom-menu-wizard-2-start_level">
106
+ </select>
107
+ <br /><small><em>Level to start testing items for inclusion</em></small>
108
+ </p>
109
+
110
+ <p>
111
+ <label for="widget-custom-menu-wizard-2-depth">For Depth:</label>
112
+ <select name="depth" id="widget-custom-menu-wizard-2-depth">
113
+ <option selected="selected" value="0">unlimited</option>
114
+ </select>
115
+ <br /><small><em>Relative to the first Filtered item found</em></small>
116
+ </p>
117
+
118
+ <p>
119
+ <label>
120
+ <input type="radio" checked="checked" value="0" name="flat_output" id="widget-custom-menu-wizard-2-flat_output_0">
121
+ Hierarchical</label>
122
+ &nbsp;<label>
123
+ <input type="radio" value="1" name="flat_output" id="widget-custom-menu-wizard-2-flat_output_1">
124
+ Flat</label>
125
+ </p>
126
+
127
+ <p class="widget-custom-menu-wizard-disableif">
128
+ <label>
129
+ <input type="checkbox" value="1" name="include_parent" id="widget-custom-menu-wizard-2-include_parent">
130
+ Include Parent... </label>
131
+ <label>
132
+ <input type="checkbox" value="1" name="include_parent_siblings" id="widget-custom-menu-wizard-2-include_parent_siblings">
133
+ &amp; its Siblings</label>
134
+ <br /><label>
135
+ <input type="checkbox" value="1" name="include_ancestors" id="widget-custom-menu-wizard-2-include_ancestors">
136
+ Include Ancestors</label>
137
+ <br /><label>
138
+ <input type="checkbox" value="1" name="title_from_parent" id="widget-custom-menu-wizard-2-title_from_parent">
139
+ Title from Parent Item</label>
140
+ <br /><small><em>Only if the "Children of:" Filter returns items</em></small>
141
+ </p>
142
+
143
+ <p>
144
+ Change UL to OL:
145
+ <br /><label>
146
+ <input type="checkbox" value="1" name="ol_root" id="widget-custom-menu-wizard-2-ol_root">
147
+ Top Level</label>
148
+ &nbsp;<label>
149
+ <input type="checkbox" value="1" name="ol_sub" id="widget-custom-menu-wizard-2-ol_sub">
150
+ Sub-Levels</label>
151
+ </p>
152
+
153
+ <p class="grey">
154
+ <small><em>Note that since WP v3.6 does it automatically,
155
+ <br />&quot;Hide Widget if Empty&quot; is ON for this demo.</em></small>
156
+ </p>
157
+
158
+ <button title="Reset the form to its defaults...">reset</button>
159
+ </form>
160
+ </div>
161
+
162
+ <div id='theoutput' class='alignright'>
163
+ <strong>Basic Output</strong> &hellip;
164
+ <div id='widget-output'></div>
165
+ </div>
166
+
167
+ <div id='themenu' class='alignleft'>
168
+ <div>
169
+ <strong>&quot;Selected&quot; Menu</strong> <small class='grey'>(example)</small>
170
+ <small><em>Click an item to toggle &quot;Current Item&quot;</em></small>
171
+ </div>
172
+ <ul>
173
+ <li>
174
+ <a href='#'><span>alpha</span></a>
175
+ <ul>
176
+ <li>
177
+ <a href='#'><span>bravo</span></a>
178
+ </li>
179
+ <li>
180
+ <a href='#'><span>charlie</span></a>
181
+ <ul>
182
+ <li>
183
+ <a href='#'><span>delta</span></a>
184
+ <ul>
185
+ <li>
186
+ <a href='#'><span>echo</span></a>
187
+ <ul>
188
+ <li>
189
+ <a href='#'><span>foxtrot</span></a>
190
+ </li>
191
+ <li>
192
+ <a href='#'><span>golf</span></a>
193
+ </li>
194
+ </ul>
195
+ </li>
196
+ </ul>
197
+ </li>
198
+ <li>
199
+ <a href='#'><span>hotel</span></a>
200
+ <ul>
201
+ <li>
202
+ <a href='#'><span>india</span></a>
203
+ <ul>
204
+ <li>
205
+ <a href='#'><span>juliet</span></a>
206
+ </li>
207
+ </ul>
208
+ </li>
209
+ </ul>
210
+ </li>
211
+ </ul>
212
+ </li>
213
+ <li>
214
+ <a href='#'><span>kilo</span></a>
215
+ </li>
216
+ </ul>
217
+ </li>
218
+ <li>
219
+ <a href='#'><span>lima</span></a>
220
+ <ul>
221
+ <li>
222
+ <a href='#'><span>mike</span></a>
223
+ <ul>
224
+ <li>
225
+ <a href='#'><span>november</span></a>
226
+ </li>
227
+ </ul>
228
+ </li>
229
+ </ul>
230
+ </li>
231
+ </ul>
232
+ </div>
233
+
234
+ <div id='thefooter'>
235
+ <div>
236
+ Please note that this page is a simulator : it uses javascript to reproduce what the widget
237
+ would do, without interacting with WordPress in any way.
238
+ </div>
239
+ </div>
240
+
241
+ </div>
242
+ <script type='text/javascript'>
243
+ jQuery(function($){
244
+ var maxlevel = 0,
245
+ switches = {hide_title:1, filter:1, fallback_no_ancestor:1, fallback_include_parent:1, fallback_include_parent_siblings:1, flat_output:1, include_parent:1, include_parent_siblings:1, include_ancestors:1, title_from_parent:1, ol_root:1, ol_sub:1},
246
+ integers = {filter_item:1, start_level:1, depth:1},
247
+ getSettings = function(){
248
+ var settings = {};
249
+ $.each($('form').serializeArray(), function(i, v){
250
+ settings[v.name] = switches[v.name] ? v.value === '1' : (integers[v.name] ? parseInt(v.value, 10) : v.value);
251
+ });
252
+ return settings;
253
+ },
254
+ hyphenIndent = function(s, n){
255
+ while(--n){
256
+ s = '- ' + s;
257
+ }
258
+ return s;
259
+ },
260
+ show = function(e, settings){
261
+ //hide_empty is assumed to be on (WP < v3.6) or will automatically on (WP v3.6+)
262
+ var output = $('#widget-output').empty(),
263
+ items = $('.picked'),
264
+ html = '',
265
+ currLevel = 0,
266
+ startLevel, title;
267
+ settings = settings || getSettings();
268
+ if(items.length){
269
+ title = settings.hide_title ? '' : settings.title;
270
+ if(settings.filter && settings.title_from_parent){
271
+ title = $('.picked-parent').children('a').text() || '';
272
+ }
273
+ items.each(function(){
274
+ var level = settings.flat_output ? 1 : parseInt(this.className.match(/level-(\d+)/)[1], 10);
275
+ if(currLevel){
276
+ if(level === currLevel){
277
+ html += '</li>';
278
+ }else if(level > currLevel){
279
+ html += settings.ol_sub ? '<ol>' : '<ul>';
280
+ }else{
281
+ while(currLevel-- > level){
282
+ html += '</li>' + (settings.ol_sub ? '</ol>' : '</ul>');
283
+ }
284
+ }
285
+ }else{
286
+ startLevel = level;
287
+ }
288
+ html += '<li><a href="#">' + $(this).children('a').text() + '</a>';
289
+ currLevel = level;
290
+ });
291
+ while(currLevel-- > startLevel){
292
+ html += '</li>' + (settings.ol_sub ? '</ol>' : '</ul>');
293
+ }
294
+ html += '</li>';
295
+ output.html( (settings.ol_root ? '<ol>' : '<ul>') + html + (settings.ol_root ? '</ol>' : '</ul>') );
296
+ if(title){
297
+ output.prepend('<h3>' + title + '</h3>');
298
+ }
299
+ }
300
+ },
301
+ walk = function(e){
302
+ var settings = getSettings(),
303
+ includeParent = settings.include_parent,
304
+ includeParentSiblings = settings.include_parent_siblings,
305
+ items = $('#themenu li').removeClass('picked-parent'),
306
+ picked = items.filter('.picked'),
307
+ cls = [],
308
+ firstParent = true,
309
+ parent, i;
310
+ if(!settings.filter){
311
+ //show all...
312
+ for(i = 1; i < settings.start_level; i++){
313
+ items = items.not('.level-' + i);
314
+ }
315
+ if(settings.depth){
316
+ for(i = i + settings.depth; i < maxlevel + 1; i++){
317
+ items = items.not('.level-' + i);
318
+ }
319
+ }
320
+ }else{
321
+ //parent item...
322
+ if(settings.filter_item > 0){
323
+ parent = items.eq(settings.filter_item - 1);
324
+ }else if(!settings.filter_item){
325
+ parent = $('.current-item').closest('li');
326
+ }else{
327
+ if(settings.filter_item < -1){
328
+ //this could be more than one!...
329
+ parent = $('.current-ancestor').closest('li');
330
+ }else{
331
+ parent = $('.current-parent').closest('li');
332
+ }
333
+ if(!parent.length && settings.fallback_no_ancestor){
334
+ parent = $('.current-item').closest('li');
335
+ includeParent = includeParent || settings.fallback_include_parent;
336
+ includeParentSiblings = includeParentSiblings || settings.fallback_include_parent_siblings;
337
+ }
338
+ }
339
+ //could be multiple - only want first one that matches start_level...
340
+ parent = parent.filter(function(){
341
+ var level = parseInt(this.className.match(/level-(\d+)/)[1], 10),
342
+ rtn = firstParent && level > settings.start_level - 2,
343
+ i, j;
344
+ for(i = level + 1, j = 0; rtn && i <= maxlevel && (!settings.depth || j < settings.depth); i++, j++){
345
+ cls.push('.level-' + i);
346
+ }
347
+ if(rtn){
348
+ firstParent = false;
349
+ }
350
+ return rtn;
351
+ });
352
+ //kids...
353
+ items = parent.find('li').filter( cls.join(',') );
354
+ if(items.length){
355
+ if(includeParentSiblings){
356
+ items = items.add( parent.siblings('li') ).add( parent );
357
+ includeParent = false;
358
+ }
359
+ if(settings.include_ancestors){
360
+ items = items.add( parent.parentsUntil('#themenu', 'li') ).add( parent );
361
+ includeParent = false;
362
+ }
363
+ if(includeParent){
364
+ items = items.add( parent );
365
+ }
366
+ parent.addClass('picked-parent');
367
+ }
368
+ }
369
+ picked.not(items).removeClass('picked');
370
+ items.not('.picked').addClass('picked');
371
+ show.call(this, e, settings);
372
+ },
373
+ flds = $('input,select');
374
+ $('#widget-output').on('click', 'a', false);
375
+ $('#themenu a').on('click', function(){
376
+ //click on a #themenu item to [un]make it the current item...
377
+ var cls = ['current-item', 'current-parent', 'current-ancestor'],
378
+ inPath = $(this).find('span').not('.' + cls[0]).parentsUntil('#themenu', 'li'),
379
+ i, n;
380
+ $('.' + cls.join(',.')).removeClass().removeAttr('title');
381
+ for(i = 0; i < inPath.length; i++){
382
+ n = i === 1 ? cls.join(' ') : cls[0];
383
+ inPath.eq(i).children('a').find('span').addClass(n).attr({title:n.replace(' ', ' & ').replace(/-/g, ' ')});
384
+ if(cls.length > 1){
385
+ cls.shift();
386
+ }
387
+ }
388
+ flds.eq(0).trigger('change');
389
+ return false;
390
+ }).map(function(i){
391
+ //create filter_item's optgroup options...
392
+ var el = $(this),
393
+ level = el.parentsUntil('#themenu', 'li').length;
394
+ maxlevel = Math.max(maxlevel, level);
395
+ el.parent().addClass('level-' + level);
396
+ return $('<option/>', {value:i + 1}).text( hyphenIndent(el.text(), level) ).get(0);
397
+ }).appendTo('optgroup');
398
+ //populate starting-level and depth options...
399
+ for(i = 1; i < maxlevel + 1; i++){
400
+ var levels = i < 2 ? ' level' : ' levels',
401
+ att = {value:i};
402
+ $('<option/>', att).text(i + levels).appendTo('#widget-custom-menu-wizard-2-depth');
403
+ if(i < 2){
404
+ att.selected = 'selected';
405
+ }
406
+ $('<option/>', att).text(i).appendTo('#widget-custom-menu-wizard-2-start_level');
407
+ }
408
+ $('button').on('click', function(){
409
+ $(this).parent().get(0).reset();
410
+ $('#widget-custom-menu-wizard-2-filter_item').trigger('change');
411
+ return false;
412
+ });
413
+ flds.not( flds.filter('[type="text"]').on('blur', show) )
414
+ .on('change', walk).eq(0).trigger('change');
415
+ });
416
+ </script>
417
+ </body>
418
+ </html>
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: wizzud
3
  Tags: menu,widget,widgets,navigation,nav,custom menus,custom menu,partial menu,menu level,menu branch
4
  Requires at least: 3.0.1
5
- Tested up to: 3.5.1
6
- Stable tag: 1.0.0
7
  License: GPLv2 or Later
8
 
9
  Custom Menu Wizard Widget : Show branches or levels of your menu in a widget, with full customisation.
@@ -20,12 +20,13 @@ Features include:
20
  * Specify a level to start at, and the number of levels to output
21
  * Select hierarchicial or flat output, both options still abiding by the specified number of levels to output
22
  * Allow the widget title to be entered but not output, or even to be set from the parent item of a menu's sub-branch
23
- * Optionally disable widget output completely if there are no matching menu items found
24
  * Include a sub-branch's parent and/or ancestor item(s) in the output, over and above any start level setting
25
  * Automatically add cmw-level-N and cmw-has-submenu classes to output menu items
26
  * Add/specify custom class(es) for the widget block, the menu container, and the menu itself
27
  * Modify the link's output with additional HTML around the link's text and/or the link element itself
28
  * Use Ordered Lists (OL) for the top and/or sub levels instead of Unordered Lists (UL)
 
29
 
30
  **Widget Options**
31
 
@@ -57,21 +58,54 @@ logical sections and made each section collapsible (with remembered state, open
57
 
58
  * **Children of** *(radio & select)*
59
 
60
- The dropdown list will present a "Current Item" option, followed by all the available items from the menu chosen in `Select Menu`.
 
61
  The widget will output the *children* of the selected item, always assuming that they lie within the bounds of any other parameters set.
62
- If you change `Select Menu`, the options presented in this dropdown will change accordingly.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  * **Starting Level** *(select, default: "1")*
65
 
66
  This is the level within the chosen menu (from `Select Menu`) that the widget will start looking for items to keep. Obviously, level 1
67
  is the root level (ie. those items that have no parent item); level 2 is all the immediate children of the root level items, and so on.
 
68
 
69
  * **For Depth** *(select, default: "unlimited")*
70
 
71
  This is the maximum depth of the eventual output structure after filtering, and in the case of `Flat` output being requested it is
72
- still applied - as if the output were `Hierarchical` and then flattened at the very last moment. You need to be aware that the
 
 
73
  `For Depth` setting is applied relative to the level at which the first item to be kept is found. For example, say you were to set
74
- `Children of` to "Current Item", `Starting Level` to "2", and `For Depth` to "2 levels"; if the current item was found at level 3,
75
  then you would get the current item's immediate children (from level 4), plus *their* immediate children (from level 5).
76
 
77
  * **Output**
@@ -85,10 +119,14 @@ logical sections and made each section collapsible (with remembered state, open
85
  Output in a single list format, ignoring any parent-child relationship other than to maintain the same physical order as would be
86
  presented in a `Hierarchical` output.
87
 
88
- * **Include Parent** *(checkbox)*
89
 
90
  If checked, include the parent item in the output. Only applies to a successful `Children of` filter.
91
 
 
 
 
 
92
  * **Include Ancestors** *(checkbox)*
93
 
94
  Same as `Include Parent` except that all ancestors, right back to root level, are included. Only applies to a successful
@@ -115,6 +153,11 @@ logical sections and made each section collapsible (with remembered state, open
115
  * **Hide Widget if Empty** *(checkbox)*
116
 
117
  If checked, the widget will not output *any* HTML unless it finds at least one menu item that matches the Filter settings.
 
 
 
 
 
118
 
119
  * **Container**
120
 
@@ -126,7 +169,7 @@ logical sections and made each section collapsible (with remembered state, open
126
 
127
  * **Unique ID**
128
 
129
- This allows you to specify you own id (which should be unique) for the container.
130
 
131
  * **Class**
132
 
@@ -177,18 +220,47 @@ If you have a question or problem, please use the integrated Support forum.
177
 
178
  == Screenshots ==
179
 
180
- 1. Widget options (A).
 
 
181
 
182
- 2. Widget options (B).
183
 
184
- 3. Widget options (C).
185
 
186
  == Changelog ==
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  = 1.0.0 =
 
189
  Initial release
190
 
191
  == Upgrade Notice ==
192
 
193
- = 1.0.0 =
194
- Initial release
 
 
 
 
 
 
2
  Contributors: wizzud
3
  Tags: menu,widget,widgets,navigation,nav,custom menus,custom menu,partial menu,menu level,menu branch
4
  Requires at least: 3.0.1
5
+ Tested up to: 3.6
6
+ Stable tag: 1.1.0
7
  License: GPLv2 or Later
8
 
9
  Custom Menu Wizard Widget : Show branches or levels of your menu in a widget, with full customisation.
20
  * Specify a level to start at, and the number of levels to output
21
  * Select hierarchicial or flat output, both options still abiding by the specified number of levels to output
22
  * Allow the widget title to be entered but not output, or even to be set from the parent item of a menu's sub-branch
23
+ * Optionally disable widget output completely if there are no matching menu items found (WordPress < v3.6)
24
  * Include a sub-branch's parent and/or ancestor item(s) in the output, over and above any start level setting
25
  * Automatically add cmw-level-N and cmw-has-submenu classes to output menu items
26
  * Add/specify custom class(es) for the widget block, the menu container, and the menu itself
27
  * Modify the link's output with additional HTML around the link's text and/or the link element itself
28
  * Use Ordered Lists (OL) for the top and/or sub levels instead of Unordered Lists (UL)
29
+ * As of v1.1.0 : Select a branch based on the ultimate ancestor (root level) of the "current" item
30
 
31
  **Widget Options**
32
 
58
 
59
  * **Children of** *(radio & select)*
60
 
61
+ The dropdown list will present a "Current Item" option (default), a "Current Root Item" (v1.1.0)
62
+ and "Current Parent Item" (v1.1.0) option, followed by all the available items from the menu chosen in `Select Menu`.
63
  The widget will output the *children* of the selected item, always assuming that they lie within the bounds of any other parameters set.
64
+
65
+ "Current Item" is the menu item that WordPress recognises as being currently on display;
66
+ "Current Parent Item" (v1.1.0) is the *immediate* ancestor (within `Select Menu`) of that same menu item;
67
+ and "Current Root Item" (v1.1.0) is the *ultimate* ancestor (within `Select Menu`) of that same menu item.
68
+ Obviously, if the menu item currently on display (as determined by WordPress) does not
69
+ appear in the `Select Menu` then there is going to be no output for any of these options.
70
+
71
+ If you change `Select Menu`, the options presented in this dropdown will change accordingly and the selected option will revert to the default.
72
+
73
+ * **Fallback to Current Item** *(checkbox)* as of v1.1.0
74
+
75
+ This option is only applicable when `Children of` is set to either "Current Root Item" or "Current Parent Item". If enabled,
76
+ it provides a fallback of effectively switching the filter to "Current Item" **if, and only if**, the current menu item
77
+ (as determined by WordPress) is at Level 1
78
+ (top level) of the selected menu. For example, say you were to set `Children of` to "Current Parent Item", with `Starting Level`
79
+ at "1" and `For Depth` at "unlimited" : if the current menu item was found at level 1 (root level of the menu) then ordinarily
80
+ there would be no output because the current item has no parent! If you were to enable `Fallback to Current Item` then you
81
+ *would* have some output - the entire branch below the current item.
82
+
83
+ * **Include Parent...** *(checkbox)* as of v1.1.0
84
+
85
+ This option extends the `Fallback to Current Item` option (above). If the enabled fallback is actually used, this option can
86
+ temporarily override the equivalent **Output** option to ON. Note that if the **Output** options are already set to include
87
+ the parent item (with or without siblings), this option has absolutely no effect.
88
+
89
+ * **& its Siblings** *(checkbox)* as of v1.1.0
90
+
91
+ This option extends the `Fallback to Current Item` option (above). If the enabled fallback is actually used, this option can
92
+ temporarily override the equivalent **Output** option to ON. Note that if the equivalent **Output** option is already enabled,
93
+ this option has absolutely no effect.
94
 
95
  * **Starting Level** *(select, default: "1")*
96
 
97
  This is the level within the chosen menu (from `Select Menu`) that the widget will start looking for items to keep. Obviously, level 1
98
  is the root level (ie. those items that have no parent item); level 2 is all the immediate children of the root level items, and so on.
99
+ Note that for a `Children of` filter there is no difference between level 1 and level 2 (because there are no children at level 1).
100
 
101
  * **For Depth** *(select, default: "unlimited")*
102
 
103
  This is the maximum depth of the eventual output structure after filtering, and in the case of `Flat` output being requested it is
104
+ still applied - as if the output were `Hierarchical` and then flattened at the very last moment.
105
+
106
+ You need to be aware that the
107
  `For Depth` setting is applied relative to the level at which the first item to be kept is found. For example, say you were to set
108
+ `Children of` to "Current Item", `Starting Level` to "2", and `For Depth` to "2 levels" : if the current item was found at level 3,
109
  then you would get the current item's immediate children (from level 4), plus *their* immediate children (from level 5).
110
 
111
  * **Output**
119
  Output in a single list format, ignoring any parent-child relationship other than to maintain the same physical order as would be
120
  presented in a `Hierarchical` output.
121
 
122
+ * **Include Parent...** *(checkbox)*
123
 
124
  If checked, include the parent item in the output. Only applies to a successful `Children of` filter.
125
 
126
+ * **& its Siblings** *(checkbox)* as of v1.1.0
127
+
128
+ If checked, include the parent item **and** its siblings in the output. Only applies to a successful `Children of` filter.
129
+
130
  * **Include Ancestors** *(checkbox)*
131
 
132
  Same as `Include Parent` except that all ancestors, right back to root level, are included. Only applies to a successful
153
  * **Hide Widget if Empty** *(checkbox)*
154
 
155
  If checked, the widget will not output *any* HTML unless it finds at least one menu item that matches the Filter settings.
156
+
157
+ Please note that as of WordPress v3.6, this option becomes superfluous and will **not** be presented (the wp_nav_menu() function
158
+ has been modified to automatically suppress all HTML output if there are no items to be displayed). The widget will retain
159
+ the setting used on earlier WP versions (in case reversion from WP v3.6 might be required) but *will not present the option
160
+ for WP v3.6+*.
161
 
162
  * **Container**
163
 
169
 
170
  * **Unique ID**
171
 
172
+ This allows you to specify your own id (which should be unique) for the container.
173
 
174
  * **Class**
175
 
220
 
221
  == Screenshots ==
222
 
223
+ 1. Widget options
224
+
225
+ 2. More widget options
226
 
227
+ 3. Even more widget options
228
 
229
+ 4. Demo / Helper
230
 
231
  == Changelog ==
232
 
233
+ = 1.1.0 =
234
+
235
+ * added 'Current Root Item' and 'Current Parent Item' to the `Children of` filter
236
+
237
+ * added `Fallback to Current Item` option, with subsibiary options for overriding a couple of Output options, as a means to enable Current Root & Current Parent to match a Current Item at root level
238
+
239
+ * added an Output option to include both the parent item **and** the parent's siblings (for a successful `Children of` filter)
240
+
241
+ * added max-width style (100%) to the `Children of` SELECT in the widget options
242
+
243
+ * added widget version to the admin js enqueuer
244
+
245
+ * ignore/disable Hide Empty option for WP >= v3.6 (wp_nav_menu() now does it automatically)
246
+
247
+ * included a stand-alone helper/demo html page
248
+
249
+ * rebuilt the `Children of` SELECT in the widget options to cope with IE's lack of OPTGROUP/OPTION styling
250
+
251
+ * moved the setting of 'disabled' attributes on INPUTs/SELECTs from PHP into javascript
252
+
253
  = 1.0.0 =
254
+
255
  Initial release
256
 
257
  == Upgrade Notice ==
258
 
259
+ = 1.1.0 =
260
+
261
+ `Children of` has 2 extra options, for filtering using the Current Item's parent (immediate ancestor) or root (ultimate ancestor) item,
262
+ with fallbacks for when a Current Item has no ancestor. There is also an additional Output option which extends Include Parent to also
263
+ include the parent's siblings. An interactive helper/demo page is now available, which will hopefully assist in deciding which options
264
+ need setting for particular requirements. Other changes include tweaks to the management of the `Children of` SELECT (to allow for IE),
265
+ a few style enhancements to the presentation of the widget in admin, and removal of the `Hide Widget if Empty` option for WP v3.6 (still
266
+ presented for WP < 3.6 though!).