Custom Menu Wizard Widget - Version 1.2.1

Version Description

  • added some extra custom classes, when applicable : cmw-fellback-to-current & cmw-fellback-to-parent (on outer UL/OL) and cmw-the-included-parent, cmw-an-included-parent-sibling & cmw-an-included-ancestor (on relevant LIs)

  • corrected 'show all from start level 1' processing so that custom classes get applied and 'Title from "Current" Item' works (regardless of filter settings)

  • changed the defaults for new widgets such that only the Filter section is open by default; all the others are collapsed

  • in demo.html, added output of the shortcode applicable to the selections made

  • in demo.html, added a link to the documentation page

  • corrected 2 of the shortcode examples in the readme.txt, and made emulator (dem) available from the readme

Download this release

Release Info

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

Code changes from version 1.2.0 to 1.2.1

Files changed (4) hide show
  1. custom-menu-wizard.js +1 -1
  2. custom-menu-wizard.php +285 -261
  3. demo.html +248 -148
  4. readme.txt +34 -15
custom-menu-wizard.js CHANGED
@@ -1,5 +1,5 @@
1
  /* Plugin Name: Custom Menu Wizard
2
- * Version: 1.2.0
3
  * Author: Roger Barrett
4
  *
5
  * Script for controlling this widget's options (in Admin -> Widgets)
1
  /* Plugin Name: Custom Menu Wizard
2
+ * Version: 1.2.1
3
  * Author: Roger Barrett
4
  *
5
  * Script for controlling this widget's options (in Admin -> Widgets)
custom-menu-wizard.php CHANGED
@@ -2,14 +2,20 @@
2
  /*
3
  * Plugin Name: Custom Menu Wizard
4
  * Plugin URI: http://wordpress.org/plugins/custom-menu-wizard/
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.2.0
7
  * Author: Roger Barrett
8
  * Author URI: http://www.wizzud.com/
9
  * License: GPL2+
10
  */
11
 
12
  /*
 
 
 
 
 
 
13
  * v1.2.0 change log:
14
  * - added custom_menu_wizard shortcode, to run the widget from within content
15
  * - moved the 'no ancestor' fallback into new Fallback collapsible section, and added a fallback for Current Item with no children
@@ -28,7 +34,7 @@
28
  * - moved the setting of 'disabled' attributes on INPUTs/SELECTs from PHP into javascript
29
  */
30
 
31
- $Custom_Menu_Wizard_Widget_Version = '1.2.0';
32
 
33
  /**
34
  * registers the widget and adds the shortcode
@@ -112,10 +118,13 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
112
  // fallback_no_children : true = if looking for a current item, and that item turns out to have no children, fallback to current parent (v1.2.0)
113
  // fallback_nc_include_parent : true = if fallback_no_children comes into play then force include_parent to true (v1.2.0)
114
  // fallback_nc_include_parent_siblings : true = if fallback_no_children comes into play then force include_parent_siblings to true (v1.2.0)
 
 
 
115
  //$elements is an array of objects, indexed by position within the menu (menu_order),
116
  //starting at 1 and incrementing sequentially regardless of parentage (ie. first item is [1],
117
  //second item is [2] whether it's at root or subordinate to first item)
118
- $cmw['_titles'] = array();
119
 
120
  $find_kids_of = $cmw['filter'];
121
  $find_current_item = $find_kids_of && empty( $cmw['filter_item'] );
@@ -126,235 +135,238 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
126
  $include_parent = $cmw['include_parent'];
127
  $include_parent_siblings = $cmw['include_parent_siblings'];
128
 
129
- //are we looking for something in particular?...
130
- if( $find_kids_of || $cmw['start_level'] > 1 ){
131
-
132
- $id_field = $this->db_fields['id']; //eg. = 'db_id'
133
- $parent_field = $this->db_fields['parent']; //eg. = 'menu_item_parent'
134
-
135
- //start level applies to the *kids* of a find_kids_of search, not to the parent, so while we
136
- //are still looking for the parent, the start_level for a find_kids_of search is actually one
137
- //up from cmw['start_level']...
138
- $start_level = $find_kids_of ? $cmw['start_level'] - 1 : $cmw['start_level'];
139
-
140
- $keep_ids = array();
141
- $keep_items = array();
142
- $temp = array(0 => array('kids' => array()));
143
- foreach( $elements as $i=>$item ){
144
- if( empty( $item->$parent_field ) ){
145
- //set root level of menu, and no ancestors...
146
- $temp[ $item->$id_field ] = array(
147
- 'level' => 1,
148
- //this is an array of indexes into $elements...
149
- 'breadcrumb' => array( $i ),
150
- 'parent' => 0,
151
- 'kids' => array()
152
- );
153
- $temp[0]['kids'][] = $i;
154
- }elseif( isset( $temp[ $item->$parent_field ] ) ){
155
- //set one greater than parent's level, and ancestors are parent's ancestors plus the parent...
156
- $temp[ $item->$id_field ] = array(
157
- 'level' => $temp[ $item->$parent_field ]['level'] + 1,
158
- 'breadcrumb' => $temp[ $item->$parent_field ]['breadcrumb'],
159
- 'parent' => $item->$parent_field,
160
- 'kids' => array()
161
- );
162
- $temp[ $item->$id_field ]['breadcrumb'][] = $i;
163
- $temp[ $item->$parent_field ]['kids'][] = $i;
 
 
 
 
 
 
164
  }
165
- //if $temp[] hasn't been set then it's an orphan; in order to keep orphans, max_depth must be 0 (ie. unlimited)
166
- //note that if a child is an orphan then all descendants of that child are also considered to be orphans!
167
- //also note that orphans (in the original menu) are ignored by this widget!
168
-
169
- if( isset( $temp[ $item->$id_field ] ) ){
170
- //let's keep track of current menu item (as index into $elements)...
171
- if( $item->current ){
172
- $ci_index = $i;
173
- }
174
- //are we at or below the start level?...
175
- if( $temp[ $item->$id_field ]['level'] >= $start_level ){
176
- //are we still looking for a starting point?...
177
- if( empty( $keep_ids ) ){
178
- if( //...we're looking for unspecific items starting at this level...
179
- !$find_kids_of ||
180
- //...we're looking for current item, and this is it...
181
- ( $find_current_item && $item->current ) ||
182
- //...we're looking for current parent, and this is it...
183
- ( $find_current_parent && $item->current_item_parent ) ||
184
- //...we're looking for a current root ancestor, and this is one...
185
- ( $find_current_root && $item->current_item_ancestor ) ||
186
- //...we've got a fallback for a top-level current item with no ancestor...
187
- ( $fallback_to_current_item && $item->current && $temp[ $item->$id_field ]['level'] == 1 ) ||
188
- //...we're looking for a particular menu item, and this is it...
189
- ( $cmw['filter_item'] == $item->$id_field )
190
- ){
191
- //NOTE : at this point I'm *keeping* the id of the parent of a find_kids_of search, but not the actual item!
192
- $keep_ids[] = $item->$id_field;
193
- if( !$find_kids_of ){
194
- $keep_items[] = $item;
195
- }
196
- //v1.1.0 if this was the fallback_no_ancestor option, we may need to update $include_parent[_siblings]...
197
- if( $fallback_to_current_item && $item->current && $temp[ $item->$id_field ]['level'] == 1 ){
198
- $include_parent = $include_parent || $cmw['fallback_include_parent'];
199
- $include_parent_siblings = $include_parent_siblings || $cmw['fallback_include_parent_siblings'];
200
- }
201
- //depth, if set, kicks in at this point :
202
- // if doing a find_kids_of search then this level counts as 0, and the next level (the kids) counts as 1
203
- // otherwise, the current level counts as 1
204
- if( $cmw['depth'] > 0 ){
205
- $max_level = $temp[ $item->$id_field ]['level'] + $cmw['depth'] - ($find_kids_of ? 0 : 1);
206
- }else{
207
- //unlimited...
208
- $max_level = 9999;
209
- }
210
- //...and reset start level...
211
- $start_level = $cmw['start_level'];
212
- }
213
- //having found at least one, any more have to be:
214
- // - within max_depth of the first one found, and
215
- // - either it's an unspecific search, or we have the parent already
216
- }elseif( $temp[ $item->$id_field ]['level'] <= $max_level && ( !$find_kids_of || in_array( $item->$parent_field, $keep_ids ) ) ){
217
  $keep_ids[] = $item->$id_field;
218
- $keep_items[] = $item;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  }
 
 
 
 
 
 
220
  }
221
  }
222
- } //end foreach
223
-
224
- //v1.2.0 do we need to invoke the fallback for a childless 'children of current item'?...
225
- //note that this is slightly different to the no_ancestor fallback, in that we are treating it like a switch from current item
226
- //to current parent, *except* that here the fallback for not having an ancestor is to pretend there's a level-0 ancestor (above
227
- //root); obviously it (the level-0 ancestor) will no item of its own, which means the kids now have no (real) parent
228
- if( $find_current_item && $cmw['fallback_no_children'] && empty( $keep_items ) && !empty( $keep_ids ) ){
229
- //what are the options?
230
- // - the current item & its siblings
231
- // - ... optionally plus its parent (if there is one)
232
- // - ... optionally plus its parent (if there is one) and the parent's siblings
233
- //keep_ids[0] is the id of the current item; put the parent's kids into keep_items...
234
- foreach( $temp[ $temp[ $keep_ids[0] ]['parent'] ]['kids'] as $item ){
235
- $keep_items[] = $item;
236
- }
237
- $include_parent = $include_parent || $cmw['fallback_nc_include_parent'];
238
- $include_parent_siblings = $include_parent_siblings || $cmw['fallback_nc_include_parent_siblings'];
239
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
- unset( $keep_ids );
242
- if( !empty( $keep_items) ){
243
-
244
- //do we need to prepend parent or ancestors?...
245
- $breadcrumb = $temp[ $keep_items[0]->$id_field ]['breadcrumb'];
246
- //remove the last breadcrumb element, which is the item's own index...
247
- array_pop( $breadcrumb );
248
- //last element is now the parent (if there is one)
249
- $i = $j = count( $breadcrumb );
250
 
 
 
 
 
 
 
251
  //might we want the parent's title as the widget title?...
252
- if( $find_kids_of && $cmw['title_from_parent'] && $i > 0 ){
253
- $cmw['_titles']['parent'] = apply_filters(
254
- 'the_title',
255
- $elements[ $breadcrumb[ $i - 1 ] ]->title,
256
- $elements[ $breadcrumb[ $i - 1 ] ]->ID
257
- );
258
- }
259
- //v1.2.0 might we want the current item's title as the widget title?...
260
- //NB: using $ci_index because it's quite possible that the current menu item is not in $keep_items
261
- if( !empty( $ci_index ) && $cmw['title_from_current'] ){
262
- $cmw['_titles']['current'] = apply_filters(
263
- 'the_title',
264
- $elements[ $ci_index ]->title,
265
- $elements[ $ci_index ]->ID
266
- );
267
- }
268
 
269
- //if we have a parent and we also want all the parent siblings, then we need
270
- //to pop the parent off the bottom of temp and either append or prepend the
271
- //kids of the parent's parent onto keep_items...
272
- if( $find_kids_of && $i > 0 && $include_parent_siblings ){
273
- $siblings = $temp[ $keep_items[0]->$id_field ]['parent'];
274
- if( !empty( $siblings ) ){
275
- $siblings = $temp[ $temp[ $siblings ]['parent'] ]['kids'];
276
- }
277
- if( !empty( $siblings ) ){
278
- //remove (and store) parent...
279
- $j = array_pop( $breadcrumb );
280
- $parentAt = -1;
281
- //going backwards thru the array, prepend the parent and anything higher in the array than it...
282
- for($i = count($siblings) - 1; $i > -1; $i--){
283
- if( $parentAt < 0 && $siblings[ $i ] == $j ){
284
- $parentAt = $i;
285
- }
286
- if( $parentAt > -1 ){
287
- array_unshift( $keep_items, $elements[ $siblings[ $i ] ]);
288
- }
289
  }
290
- //going forwards thru the array, append anything lower in the array than the parent...
291
- for($i = $parentAt + 1; $i < count($siblings); $i++){
292
- //anything after parent gets appended; parent and before get prepended...
293
- array_push( $keep_items, $elements[ $siblings[ $i ] ]);
294
  }
295
- $i = $j = count( $breadcrumb );
296
- //don't include_parent now because we just have...
297
- $include_parent = false;
298
  }
299
- unset( $siblings );
300
- }
301
-
302
- if( $find_kids_of && $i > 0 ){
303
- if( $cmw['include_ancestors'] ){
304
- $j = 0;
305
- }elseif( $include_parent ){
306
- --$j;
307
- }
308
- while( $i > $j ){
309
- array_unshift( $keep_items, $elements[ $breadcrumb[ --$i ] ]);
310
  }
 
 
 
 
311
  }
312
- unset( $breadcrumb );
313
  }
314
 
315
- //for each item we're keeping, use the temp array to hold:
316
- // [0] => the level within the new structure (starting at 1), and
317
- // [1] => the number of kids each item has
318
- $temp = array();
319
- foreach( $keep_items as $item ){
320
- if( isset( $temp[ $item->$parent_field ] ) ){
321
- $temp[ $item->$id_field ] = array( $temp[ $item->$parent_field ][0] + 1, 0 );
322
- $temp[ $item->$parent_field ][1] += 1;
323
- }else{
324
- $temp[ $item->$id_field ] = array( 1, 0 );
325
  }
326
  }
 
 
327
 
328
- //transfer $keep back into $elements, resetting the index to increment from 1; also add
329
- //new classes to indicate level (starting at 1) and whether any item has kids
330
- //
331
- //note that we have already filtered out real orphans, but we may have introduced top-level
332
- //items that would appear to be orphans to the parent::walk() method, so we need to set all
333
- //the top-level items to appear as if they are root-level items...
334
- $elements = array();
335
- $i = 1;
336
- foreach( $keep_items as $item ){
337
- $item->classes[] = 'cmw-level-' . $temp[ $item->$id_field ][0];
338
- if( $temp[ $item->$id_field ][1] > 0 ){
339
- $item->classes[] = 'cmw-has-submenu';
340
- }
341
- if( $temp[ $item->$id_field ][0] == 1 ){
342
- //fake as root level item...
343
- $item->$parent_field = 0;
344
- }
345
- $elements[ $i++ ] = $item;
346
  }
347
- unset( $keep_items, $temp );
348
-
349
- //since we've done all the depth filtering, set max_depth to unlimited (unless 'flat' was requested!)...
350
- if( !$cmw['flat_output'] ){
351
- $max_depth = 0;
 
 
 
 
 
 
 
 
 
352
  }
353
- $elements = apply_filters( 'custom_menu_wizard_walker_items', $elements, $args );
 
 
 
 
354
  }
355
- }
 
 
 
 
 
 
356
 
357
- return empty( $elements ) ? '' : parent::walk($elements, $max_depth, $args);
358
  }
359
 
360
  }
@@ -365,30 +377,30 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
365
  class Custom_Menu_Wizard_Widget extends WP_Widget {
366
 
367
  var $_cmw_switches = array(
368
- 'hide_title',
369
- 'filter', //v1.1.0 changed from integer
370
- 'fallback_no_ancestor', //v1.1.0 added
371
- 'fallback_include_parent', //v1.1.0 added
372
- 'fallback_include_parent_siblings', //v1.1.0 added
373
- 'fallback_no_children', //v1.2.0 added
374
- 'fallback_nc_include_parent', //v1.2.0 added
375
- 'fallback_nc_include_parent_siblings', //v1.2.0 added
376
- 'flat_output',
377
- 'include_parent',
378
- 'include_parent_siblings', //v1.1.0 added
379
- 'include_ancestors',
380
- 'hide_empty', //v1.1.0: this now only has relevance prior to WP v3.6
381
- 'title_from_parent',
382
- 'title_from_current', //v1.2.0 added
383
- 'ol_root',
384
- 'ol_sub',
385
  //field section toggles...
386
- 'fs_filter',
387
- 'fs_fallbacks', //v1.2.0 added
388
- 'fs_output',
389
- 'fs_container',
390
- 'fs_classes',
391
- 'fs_links'
392
  );
393
  var $_cmw_strings = array(
394
  'title' => '',
@@ -411,6 +423,9 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
411
  'start_level' => 1
412
  );
413
 
 
 
 
414
  /**
415
  * class constructor
416
  */
@@ -426,18 +441,17 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
426
  }
427
 
428
  /**
429
- * removes itself from the filters and, if available, stores current|parent title in the widget instance
 
 
430
  *
431
  * @param array $items Filtered menu items
432
  * @param object $args
433
  * @return array Menu items
434
  */
435
- function cmw_filter_retain_possible_titles($items, $args){
436
- remove_filter('custom_menu_wizard_walker_items', array( $this, 'cmw_filter_retain_parent_title' ), 10, 2);
437
- foreach(array('parent', 'current') as $n){
438
- if( !empty( $args->_custom_menu_wizard['_titles'][ $n ] ) ){
439
- $this->cmw_titles[ $n ] = $args->_custom_menu_wizard['_titles'][ $n ];
440
- }
441
  }
442
  return $items;
443
  }
@@ -494,7 +508,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
494
 
495
  //switches...
496
  foreach( $this->_cmw_switches as $k=>$v ){
497
- $instance[ $v ] = !empty( $instance[ $v ] );
498
  }
499
  //integers...
500
  foreach( $this->_cmw_integers as $k=>$v ){
@@ -512,8 +526,6 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
512
  //v1.1.0 As of WP v3.6, wp_nav_menu() automatically prevents any HTML output if there are no items...
513
  $instance['hide_empty'] = $instance['hide_empty'] && $this->_pre_3point6();
514
 
515
- $this->cmw_titles = array();
516
-
517
  //fetch menu...
518
  if( !empty($instance['menu'] ) ){
519
  $menu = wp_get_nav_menu_object( $instance['menu'] );
@@ -534,14 +546,13 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
534
  if( !empty( $instance['container_class'] ) ){
535
  $instance['container_class'] = "menu-{$menu->slug}-container {$instance['container_class']}";
536
  }
537
-
538
- if( $instance['title_from_parent'] || $instance['title_from_current'] ){
539
- add_filter('custom_menu_wizard_walker_items', array( $this, 'cmw_filter_retain_possible_titles' ), 10, 2);
540
- }
541
-
542
- if( $instance['hide_empty'] ){
543
- add_filter( "wp_nav_menu_{$menu->slug}_items", array( $this, 'cmw_filter_check_for_no_items' ), 65532, 2 );
544
  }
 
545
 
546
  $walker = new Custom_Menu_Wizard_Walker;
547
  $params = array(
@@ -576,7 +587,9 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
576
  'ol_sub' => $instance['ol_sub'],
577
  'flat_output' => $instance['flat_output'],
578
  'start_level' => $instance['start_level'],
579
- 'depth' => $instance['depth']
 
 
580
  )
581
  );
582
  if( $instance['ol_root'] ){
@@ -585,9 +598,16 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
585
  if( !empty( $instance['container_class'] ) ){
586
  $params['container_class'] = $instance['container_class'];
587
  }
 
 
 
 
 
 
588
  //NB: wp_nav_menu() is in wp-includes/nav-menu-template.php
589
  $out = wp_nav_menu( apply_filters( 'custom_menu_wizard_nav_params', $params ) );
590
 
 
591
  if( $instance['hide_empty'] ){
592
  remove_filter( "wp_nav_menu_{$menu->slug}_items", array( $this, 'cmw_filter_check_for_no_items' ), 65532, 2 );
593
  }
@@ -599,16 +619,22 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
599
  //note that 'parent' is whatever you are getting the children of and therefore doesn't apply to a ShowAll, whereas
600
  //'current' is the current menu item (as determined by WP); also note that neither parent nor current actually has
601
  //to be present in the results
602
- if( $instance['title_from_parent'] && !empty( $this->cmw_titles['parent'] ) ){
603
- $title = $this->cmw_titles['parent'];
604
  }
605
- if( empty( $title ) && $instance['title_from_current'] && !empty( $this->cmw_titles['current'] ) ){
606
- $title = $this->cmw_titles['current'];
607
  }
608
  if( empty( $title ) ){
609
  $title = $instance['hide_title'] ? '' : $instance['title'];
610
  }
611
 
 
 
 
 
 
 
612
  echo $before_widget;
613
  if ( !empty($title) ){
614
  echo $before_title . apply_filters('widget_title', $title, $instance, $this->id_base) . $after_title;
@@ -627,7 +653,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
627
 
628
  //switches...
629
  foreach( $this->_cmw_switches as $k=>$v ){
630
- $instance[ $v ] = empty( $new_instance[ $v ] ) ? 0 : 1;
631
  }
632
  //integers...
633
  foreach( $this->_cmw_integers as $k=>$v ){
@@ -652,7 +678,7 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
652
 
653
  //switches...
654
  foreach( $this->_cmw_switches as $k=>$v ){
655
- $instance[ $v ] = !empty( $instance[ $v ] );
656
  }
657
  //integers...
658
  foreach( $this->_cmw_integers as $k=>$v ){
@@ -1027,16 +1053,14 @@ class Custom_Menu_Wizard_Walker extends Walker_Nav_Menu {
1027
  * @param string $fname Field name
1028
  */
1029
  function _open_a_field_section( &$instance, $text, $fname ){
1030
- // the default is *not* collapsed (field $fname == 0)
1031
- $collapsed = !empty($instance[$fname]);
1032
  ?>
1033
  <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;">
1034
  <input id="<?php echo $this->get_field_id($fname); ?>" class="hidden-field" name="<?php echo $this->get_field_name($fname); ?>"
1035
- type="checkbox" value="1" <?php checked($collapsed); ?> />
1036
- <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>
1037
  <h3 style="font-size:1em;margin:0;padding:2px 0.5em;"><?php _e( $text ); ?></h3>
1038
  </div>
1039
- <div class="hide-if-js"<?php echo !$collapsed ? ' style="display:block;"' : ''; ?>>
1040
  <?php
1041
  } //end _open_a_field_section()
1042
 
2
  /*
3
  * Plugin Name: Custom Menu Wizard
4
  * Plugin URI: http://wordpress.org/plugins/custom-menu-wizard/
5
+ * Description: Full control over the wp_nav_menu parameters for a custom menu; filter for specific level(s), for children of a selected menu item, the current menu item, or its parent or root item
6
+ * Version: 1.2.1
7
  * Author: Roger Barrett
8
  * Author URI: http://www.wizzud.com/
9
  * License: GPL2+
10
  */
11
 
12
  /*
13
+ * v1.2.1 change log:
14
+ * - added some extra custom classes, when applicable : cmw-fellback-to-current & cmw-fellback-to-parent (on outer UL/OL) and cmw-the-included-parent, cmw-an-included-parent-sibling & cmw-an-included-ancestor (on relevant LIs)
15
+ * - corrected 'show all from start level 1' processing so that custom classes get applied and 'Title from "Current" Item' works (regardless of filter settings)
16
+ * - changed the defaults for new widgets such that only the Filter section is open by default; all the others are collapsed
17
+ * - updated demo.html and readme.txt, and made demo available from readme
18
+ *
19
  * v1.2.0 change log:
20
  * - added custom_menu_wizard shortcode, to run the widget from within content
21
  * - moved the 'no ancestor' fallback into new Fallback collapsible section, and added a fallback for Current Item with no children
34
  * - moved the setting of 'disabled' attributes on INPUTs/SELECTs from PHP into javascript
35
  */
36
 
37
+ $Custom_Menu_Wizard_Widget_Version = '1.2.1';
38
 
39
  /**
40
  * registers the widget and adds the shortcode
118
  // fallback_no_children : true = if looking for a current item, and that item turns out to have no children, fallback to current parent (v1.2.0)
119
  // fallback_nc_include_parent : true = if fallback_no_children comes into play then force include_parent to true (v1.2.0)
120
  // fallback_nc_include_parent_siblings : true = if fallback_no_children comes into play then force include_parent_siblings to true (v1.2.0)
121
+ //
122
+ // _walker (array) : for anything that only the walker can determine and that needs to be communicated back to the widget instance
123
+ //
124
  //$elements is an array of objects, indexed by position within the menu (menu_order),
125
  //starting at 1 and incrementing sequentially regardless of parentage (ie. first item is [1],
126
  //second item is [2] whether it's at root or subordinate to first item)
127
+ $cmw['_walker']['fellback'] = false;
128
 
129
  $find_kids_of = $cmw['filter'];
130
  $find_current_item = $find_kids_of && empty( $cmw['filter_item'] );
135
  $include_parent = $cmw['include_parent'];
136
  $include_parent_siblings = $cmw['include_parent_siblings'];
137
 
138
+ $id_field = $this->db_fields['id']; //eg. = 'db_id'
139
+ $parent_field = $this->db_fields['parent']; //eg. = 'menu_item_parent'
140
+
141
+ //start level applies to the *kids* of a find_kids_of search, not to the parent, so while we
142
+ //are still looking for the parent, the start_level for a find_kids_of search is actually one
143
+ //up from cmw['start_level']...
144
+ $start_level = $find_kids_of ? $cmw['start_level'] - 1 : $cmw['start_level'];
145
+
146
+ $keep_ids = array();
147
+ $keep_items = array();
148
+ $temp = array(0 => array('kids' => array()));
149
+ foreach( $elements as $i=>$item ){
150
+ if( empty( $item->$parent_field ) ){
151
+ //set root level of menu, and no ancestors...
152
+ $temp[ $item->$id_field ] = array(
153
+ 'level' => 1,
154
+ //this is an array of indexes into $elements...
155
+ 'breadcrumb' => array( $i ),
156
+ 'parent' => 0,
157
+ 'kids' => array()
158
+ );
159
+ $temp[0]['kids'][] = $i;
160
+ }elseif( isset( $temp[ $item->$parent_field ] ) ){
161
+ //set one greater than parent's level, and ancestors are parent's ancestors plus the parent...
162
+ $temp[ $item->$id_field ] = array(
163
+ 'level' => $temp[ $item->$parent_field ]['level'] + 1,
164
+ 'breadcrumb' => $temp[ $item->$parent_field ]['breadcrumb'],
165
+ 'parent' => $item->$parent_field,
166
+ 'kids' => array()
167
+ );
168
+ $temp[ $item->$id_field ]['breadcrumb'][] = $i;
169
+ $temp[ $item->$parent_field ]['kids'][] = $i;
170
+ }
171
+ //if $temp[] hasn't been set then it's an orphan; in order to keep orphans, max_depth must be 0 (ie. unlimited)
172
+ //note that if a child is an orphan then all descendants of that child are also considered to be orphans!
173
+ //also note that orphans (in the original menu) are ignored by this widget!
174
+
175
+ if( isset( $temp[ $item->$id_field ] ) ){
176
+ //let's keep track of current menu item (as index into $elements)...
177
+ if( $item->current ){
178
+ $ci_index = $i;
179
  }
180
+ //are we at or below the start level?...
181
+ if( $temp[ $item->$id_field ]['level'] >= $start_level ){
182
+ //are we still looking for a starting point?...
183
+ if( empty( $keep_ids ) ){
184
+ if( //...we're looking for unspecific items starting at this level...
185
+ !$find_kids_of ||
186
+ //...we're looking for current item, and this is it...
187
+ ( $find_current_item && $item->current ) ||
188
+ //...we're looking for current parent, and this is it...
189
+ ( $find_current_parent && $item->current_item_parent ) ||
190
+ //...we're looking for a current root ancestor, and this is one...
191
+ ( $find_current_root && $item->current_item_ancestor ) ||
192
+ //...we've got a fallback for a top-level current item with no ancestor...
193
+ ( $fallback_to_current_item && $item->current && $temp[ $item->$id_field ]['level'] == 1 ) ||
194
+ //...we're looking for a particular menu item, and this is it...
195
+ ( $cmw['filter_item'] == $item->$id_field )
196
+ ){
197
+ //NOTE : at this point I'm *keeping* the id of the parent of a find_kids_of search, but not the actual item!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  $keep_ids[] = $item->$id_field;
199
+ if( !$find_kids_of ){
200
+ $keep_items[] = $item;
201
+ }
202
+ //v1.1.0 if this was the fallback_no_ancestor option, we may need to update $include_parent[_siblings]...
203
+ if( $fallback_to_current_item && $item->current && $temp[ $item->$id_field ]['level'] == 1 ){
204
+ $include_parent = $include_parent || $cmw['fallback_include_parent'];
205
+ $include_parent_siblings = $include_parent_siblings || $cmw['fallback_include_parent_siblings'];
206
+ $cmw['_walker']['fellback'] = 'to-current'; //v1.2.1
207
+ }
208
+ //depth, if set, kicks in at this point :
209
+ // if doing a find_kids_of search then this level counts as 0, and the next level (the kids) counts as 1
210
+ // otherwise, the current level counts as 1
211
+ if( $cmw['depth'] > 0 ){
212
+ $max_level = $temp[ $item->$id_field ]['level'] + $cmw['depth'] - ($find_kids_of ? 0 : 1);
213
+ }else{
214
+ //unlimited...
215
+ $max_level = 9999;
216
+ }
217
+ //...and reset start level...
218
+ $start_level = $cmw['start_level'];
219
  }
220
+ //having found at least one, any more have to be:
221
+ // - within max_depth of the first one found, and
222
+ // - either it's an unspecific search, or we have the parent already
223
+ }elseif( $temp[ $item->$id_field ]['level'] <= $max_level && ( !$find_kids_of || in_array( $item->$parent_field, $keep_ids ) ) ){
224
+ $keep_ids[] = $item->$id_field;
225
+ $keep_items[] = $item;
226
  }
227
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  }
229
+ } //end foreach
230
+
231
+ //v1.2.0 do we need to invoke the fallback for a childless 'children of current item'?...
232
+ //note that this is slightly different to the no_ancestor fallback, in that we are treating it like a switch from current item
233
+ //to current parent, *except* that here the fallback for not having an ancestor is to pretend there's a level-0 ancestor (above
234
+ //root); obviously it (the level-0 ancestor) will no item of its own, which means the kids now have no (real) parent
235
+ if( $find_current_item && $cmw['fallback_no_children'] && empty( $keep_items ) && !empty( $keep_ids ) ){
236
+ //what are the options?
237
+ // - the current item & its siblings
238
+ // - ... optionally plus its parent (if there is one)
239
+ // - ... optionally plus its parent (if there is one) and the parent's siblings
240
+ //keep_ids[0] is the id of the current item; put the parent's kids into keep_items...
241
+ foreach( $temp[ $temp[ $keep_ids[0] ]['parent'] ]['kids'] as $item ){
242
+ $keep_items[] = $item;
243
+ }
244
+ $include_parent = $include_parent || $cmw['fallback_nc_include_parent'];
245
+ $include_parent_siblings = $include_parent_siblings || $cmw['fallback_nc_include_parent_siblings'];
246
+ $cmw['_walker']['fellback'] = 'to-parent'; //v1.2.1
247
+ }
248
 
249
+ unset( $keep_ids );
250
+ if( !empty( $keep_items) ){
 
 
 
 
 
 
 
251
 
252
+ //do we need to prepend parent or ancestors?...
253
+ $breadcrumb = $temp[ $keep_items[0]->$id_field ]['breadcrumb'];
254
+ //remove the last breadcrumb element, which is the item's own index...
255
+ array_pop( $breadcrumb );
256
+ //last element is now the parent (if there is one)
257
+ $i = $j = count( $breadcrumb );
258
  //might we want the parent's title as the widget title?...
259
+ if( $find_kids_of && $cmw['title_from_parent'] && $i > 0 ){
260
+ $cmw['_walker']['parent_title'] = apply_filters(
261
+ 'the_title',
262
+ $elements[ $breadcrumb[ $i - 1 ] ]->title,
263
+ $elements[ $breadcrumb[ $i - 1 ] ]->ID
264
+ );
265
+ }
266
+ //v1.2.0 might we want the current item's title as the widget title?...
267
+ //NB: using $ci_index because it's quite possible that the current menu item is not in $keep_items
268
+ if( !empty( $ci_index ) && $cmw['title_from_current'] ){
269
+ $cmw['_walker']['current_title'] = apply_filters(
270
+ 'the_title',
271
+ $elements[ $ci_index ]->title,
272
+ $elements[ $ci_index ]->ID
273
+ );
274
+ }
275
 
276
+ //if we have a parent and we also want all the parent siblings, then we need
277
+ //to pop the parent off the bottom of temp and either append or prepend the
278
+ //kids of the parent's parent onto keep_items...
279
+ $paClass = 'cmw-the-included-parent';
280
+ if( $find_kids_of && $i > 0 && $include_parent_siblings ){
281
+ $siblings = $temp[ $keep_items[0]->$id_field ]['parent'];
282
+ if( !empty( $siblings ) ){
283
+ $siblings = $temp[ $temp[ $siblings ]['parent'] ]['kids'];
284
+ }
285
+ if( !empty( $siblings ) ){
286
+ //remove (and store) parent...
287
+ $j = array_pop( $breadcrumb );
288
+ $parentAt = -1;
289
+ //going backwards thru the array, prepend the parent and anything higher in the array than it...
290
+ for($i = count($siblings) - 1; $i > -1; $i--){
291
+ if( $parentAt < 0 && $siblings[ $i ] == $j ){
292
+ $parentAt = $i;
 
 
 
293
  }
294
+ if( $parentAt > -1 ){
295
+ array_unshift( $keep_items, $elements[ $siblings[ $i ] ]);
296
+ $keep_items[0]->classes[] = $parentAt == $i ? 'cmw-the-included-parent' : 'cmw-an-included-parent-sibling';
 
297
  }
 
 
 
298
  }
299
+ //going forwards thru the array, append anything lower in the array than the parent...
300
+ for($i = $parentAt + 1; $i < count($siblings); $i++){
301
+ //anything after parent gets appended; parent and before get prepended...
302
+ $j = count( $keep_items );
303
+ array_push( $keep_items, $elements[ $siblings[ $i ] ]);
304
+ $keep_items[$j]->classes[] = 'cmw-an-included-parent-sibling';
 
 
 
 
 
305
  }
306
+ $i = $j = count( $breadcrumb );
307
+ //don't include_parent now because we just have...
308
+ $include_parent = false;
309
+ $paClass = 'cmw-an-included-ancestor';
310
  }
311
+ unset( $siblings );
312
  }
313
 
314
+ if( $find_kids_of && $i > 0 ){
315
+ if( $cmw['include_ancestors'] ){
316
+ $j = 0; //everything in breadcrumb, from bottom to top
317
+ }elseif( $include_parent ){
318
+ --$j; //just the last item from breadcrumb
319
+ }
320
+ while( $i > $j ){
321
+ array_unshift( $keep_items, $elements[ $breadcrumb[ --$i ] ]);
322
+ $keep_items[0]->classes[] = $paClass;
323
+ $paClass = 'cmw-an-included-ancestor';
324
  }
325
  }
326
+ unset( $breadcrumb );
327
+ }
328
 
329
+ //for each item we're keeping, use the temp array to hold:
330
+ // [0] => the level within the new structure (starting at 1), and
331
+ // [1] => the number of kids each item has
332
+ $temp = array();
333
+ foreach( $keep_items as $item ){
334
+ if( isset( $temp[ $item->$parent_field ] ) ){
335
+ $temp[ $item->$id_field ] = array( $temp[ $item->$parent_field ][0] + 1, 0 );
336
+ $temp[ $item->$parent_field ][1] += 1;
337
+ }else{
338
+ $temp[ $item->$id_field ] = array( 1, 0 );
 
 
 
 
 
 
 
 
339
  }
340
+ }
341
+
342
+ //transfer $keep back into $elements, resetting the index to increment from 1; also add
343
+ //new classes to indicate level (starting at 1) and whether any item has kids
344
+ //
345
+ //note that we have already filtered out real orphans, but we may have introduced top-level
346
+ //items that would appear to be orphans to the parent::walk() method, so we need to set all
347
+ //the top-level items to appear as if they are root-level items...
348
+ $elements = array();
349
+ $i = 1;
350
+ foreach( $keep_items as $item ){
351
+ $item->classes[] = 'cmw-level-' . $temp[ $item->$id_field ][0];
352
+ if( $temp[ $item->$id_field ][1] > 0 ){
353
+ $item->classes[] = 'cmw-has-submenu';
354
  }
355
+ if( $temp[ $item->$id_field ][0] == 1 ){
356
+ //fake as root level item...
357
+ $item->$parent_field = 0;
358
+ }
359
+ $elements[ $i++ ] = $item;
360
  }
361
+ unset( $keep_items, $temp );
362
+
363
+ //since we've done all the depth filtering, set max_depth to unlimited (unless 'flat' was requested!)...
364
+ if( !$cmw['flat_output'] ){
365
+ $max_depth = 0;
366
+ }
367
+ } //ends the check for bad max depth, empty elements, or empty cmw args
368
 
369
+ return empty( $elements ) ? '' : parent::walk( apply_filters( 'custom_menu_wizard_walker_items', $elements, $args ), $max_depth, $args );
370
  }
371
 
372
  }
377
  class Custom_Menu_Wizard_Widget extends WP_Widget {
378
 
379
  var $_cmw_switches = array(
380
+ 'hide_title' => 0,
381
+ 'filter' => 0, //v1.1.0 changed from integer
382
+ 'fallback_no_ancestor' => 0, //v1.1.0 added
383
+ 'fallback_include_parent' => 0, //v1.1.0 added
384
+ 'fallback_include_parent_siblings' => 0, //v1.1.0 added
385
+ 'fallback_no_children' => 0, //v1.2.0 added
386
+ 'fallback_nc_include_parent' => 0, //v1.2.0 added
387
+ 'fallback_nc_include_parent_siblings' => 0, //v1.2.0 added
388
+ 'flat_output' => 0,
389
+ 'include_parent' => 0,
390
+ 'include_parent_siblings' => 0, //v1.1.0 added
391
+ 'include_ancestors' => 0,
392
+ 'hide_empty' => 0, //v1.1.0: this now only has relevance prior to WP v3.6
393
+ 'title_from_parent' => 0,
394
+ 'title_from_current' => 0, //v1.2.0 added
395
+ 'ol_root' => 0,
396
+ 'ol_sub' => 0,
397
  //field section toggles...
398
+ 'fs_filter' => 0,
399
+ 'fs_fallbacks' => 1, //v1.2.0 added
400
+ 'fs_output' => 1,
401
+ 'fs_container' => 1,
402
+ 'fs_classes' => 1,
403
+ 'fs_links' => 1
404
  );
405
  var $_cmw_strings = array(
406
  'title' => '',
423
  'start_level' => 1
424
  );
425
 
426
+ //v1.2.1 holds information determined by the walker...
427
+ var $_cmw_walker = array();
428
+
429
  /**
430
  * class constructor
431
  */
441
  }
442
 
443
  /**
444
+ * v1.2.1 stores any walker-determined information back into the widget instance
445
+ * gets run by the walker, on the filtered array of menu items, just before running parent::walk()
446
+ * only gets run *if* there are menu items found
447
  *
448
  * @param array $items Filtered menu items
449
  * @param object $args
450
  * @return array Menu items
451
  */
452
+ function cmw_filter_walker_items($items, $args){
453
+ if( !empty( $args->_custom_menu_wizard['_walker'] ) ){
454
+ $this->_cmw_walker = $args->_custom_menu_wizard['_walker'];
 
 
 
455
  }
456
  return $items;
457
  }
508
 
509
  //switches...
510
  foreach( $this->_cmw_switches as $k=>$v ){
511
+ $instance[ $k ] = !empty( $instance[ $k ] );
512
  }
513
  //integers...
514
  foreach( $this->_cmw_integers as $k=>$v ){
526
  //v1.1.0 As of WP v3.6, wp_nav_menu() automatically prevents any HTML output if there are no items...
527
  $instance['hide_empty'] = $instance['hide_empty'] && $this->_pre_3point6();
528
 
 
 
529
  //fetch menu...
530
  if( !empty($instance['menu'] ) ){
531
  $menu = wp_get_nav_menu_object( $instance['menu'] );
546
  if( !empty( $instance['container_class'] ) ){
547
  $instance['container_class'] = "menu-{$menu->slug}-container {$instance['container_class']}";
548
  }
549
+
550
+ $instance['menu_class'] = preg_split( '/\s+/', $instance['menu_class'], -1, PREG_SPLIT_NO_EMPTY );
551
+ if( $instance['fallback_no_ancestor'] || $instance['fallback_no_children'] ){
552
+ //v1.2.1 add a cmw-fellback-maybe class to the menu and we'll remove or replace it later...
553
+ $instance['menu_class'][] = 'cmw-fellback-maybe';
 
 
554
  }
555
+ $instance['menu_class'] = implode( ' ', $instance['menu_class'] );
556
 
557
  $walker = new Custom_Menu_Wizard_Walker;
558
  $params = array(
587
  'ol_sub' => $instance['ol_sub'],
588
  'flat_output' => $instance['flat_output'],
589
  'start_level' => $instance['start_level'],
590
+ 'depth' => $instance['depth'],
591
+ //v1.2.1 this is for the walker's use...
592
+ '_walker' => array()
593
  )
594
  );
595
  if( $instance['ol_root'] ){
598
  if( !empty( $instance['container_class'] ) ){
599
  $params['container_class'] = $instance['container_class'];
600
  }
601
+
602
+ add_filter('custom_menu_wizard_walker_items', array( $this, 'cmw_filter_walker_items' ), 10, 2);
603
+ if( $instance['hide_empty'] ){
604
+ add_filter( "wp_nav_menu_{$menu->slug}_items", array( $this, 'cmw_filter_check_for_no_items' ), 65532, 2 );
605
+ }
606
+
607
  //NB: wp_nav_menu() is in wp-includes/nav-menu-template.php
608
  $out = wp_nav_menu( apply_filters( 'custom_menu_wizard_nav_params', $params ) );
609
 
610
+ remove_filter('custom_menu_wizard_walker_items', array( $this, 'cmw_filter_walker_items' ), 10, 2);
611
  if( $instance['hide_empty'] ){
612
  remove_filter( "wp_nav_menu_{$menu->slug}_items", array( $this, 'cmw_filter_check_for_no_items' ), 65532, 2 );
613
  }
619
  //note that 'parent' is whatever you are getting the children of and therefore doesn't apply to a ShowAll, whereas
620
  //'current' is the current menu item (as determined by WP); also note that neither parent nor current actually has
621
  //to be present in the results
622
+ if( $instance['title_from_parent'] && !empty( $this->_cmw_walker['parent_title'] ) ){
623
+ $title = $this->_cmw_walker['parent_title'];
624
  }
625
+ if( empty( $title ) && $instance['title_from_current'] && !empty( $this->_cmw_walker['current_title'] ) ){
626
+ $title = $this->_cmw_walker['current_title'];
627
  }
628
  if( empty( $title ) ){
629
  $title = $instance['hide_title'] ? '' : $instance['title'];
630
  }
631
 
632
+ //remove/replace the cmw-fellback-maybe class...
633
+ $out = str_replace(
634
+ 'cmw-fellback-maybe',
635
+ empty( $this->_cmw_walker['fellback'] ) ? '' : 'cmw-fellback-' . $this->_cmw_walker['fellback'],
636
+ $out );
637
+
638
  echo $before_widget;
639
  if ( !empty($title) ){
640
  echo $before_title . apply_filters('widget_title', $title, $instance, $this->id_base) . $after_title;
653
 
654
  //switches...
655
  foreach( $this->_cmw_switches as $k=>$v ){
656
+ $instance[ $k ] = empty( $new_instance[ $k ] ) ? 0 : 1;
657
  }
658
  //integers...
659
  foreach( $this->_cmw_integers as $k=>$v ){
678
 
679
  //switches...
680
  foreach( $this->_cmw_switches as $k=>$v ){
681
+ $instance[ $k ] = isset( $instance[ $k ] ) ? !empty( $instance[ $k ] ) : !empty( $v );
682
  }
683
  //integers...
684
  foreach( $this->_cmw_integers as $k=>$v ){
1053
  * @param string $fname Field name
1054
  */
1055
  function _open_a_field_section( &$instance, $text, $fname ){
 
 
1056
  ?>
1057
  <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;">
1058
  <input id="<?php echo $this->get_field_id($fname); ?>" class="hidden-field" name="<?php echo $this->get_field_name($fname); ?>"
1059
+ type="checkbox" value="1" <?php checked( $instance[$fname] ); ?> />
1060
+ <div style="background:transparent url(images/arrows.png) no-repeat 0 <?php echo $instance[$fname] ? '0' : '-36px'; ?>;height:16px; width:16px;float:right;outline:0 none;"></div>
1061
  <h3 style="font-size:1em;margin:0;padding:2px 0.5em;"><?php _e( $text ); ?></h3>
1062
  </div>
1063
+ <div class="hide-if-js"<?php echo $instance[$fname] ? '' : ' style="display:block;"'; ?>>
1064
  <?php
1065
  } //end _open_a_field_section()
1066
 
demo.html CHANGED
@@ -7,19 +7,23 @@
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
  #widget-output {margin:0.5em 0; padding:0 1em; border:1px solid #cccccc; border-radius:0.5em; min-height:2em; min-width:9em;}
25
  #widget-output ul, #widget-output ol {margin:0.5em 0 0.5em 1.5em; padding:0;}
@@ -36,6 +40,7 @@
36
  #widget-output ol ol ol ol {list-style-type:lower-roman;}
37
  #widget-output ol ol ol ol ol {list-style-type:decimal;}
38
  #fallback {display:none; text-align:right; color:#006600;}
 
39
  #themenu {margin:1em;}
40
  #themenu ul {font-size:12px; list-style-type:none; margin:1em 0; padding:0;}
41
  #themenu ul ul {margin:0 0 0 5em;}
@@ -44,6 +49,7 @@
44
  #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;}
45
  #thefooter {float:left; clear:left; margin:0 1em; color:#808080;}
46
  #thefooter div {font-size:12px;}
 
47
  .alignleft {float:left;}
48
  .alignright {float:right;}
49
  .collapsible {background-color:#ffffff; background-image:-webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#e0e0e0)); background-image:-webkit-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:-moz-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:-ms-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:-o-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:linear-gradient(to bottom, #FFFFFF, #E0E0E0); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff, endColorstr=#e0e0e0); -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff, endColorstr=#e0e0e0)";border:1px solid #CCCCCC; border-radius:0.3333em; cursor:pointer; font-size:12px; line-height:1.75; padding:0 0.5em;}
@@ -51,9 +57,9 @@
51
  .collapsible:hover span {color:#333333;}
52
  .collapsible span:first-child, .collapsible.closed span:last-child {display:inline;}
53
  .collapsible.closed span:first-child {display:none;}
54
- .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)";}
55
- .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)";}
56
- .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)";}
57
  .grey {color:#999999;}
58
  .picked > a {background-color:#000066; color:#ffffff; font-weight:bold;}
59
  .tryit {margin-left:1em; text-shadow:1px 1px 1px #ff0000;}
@@ -64,132 +70,141 @@
64
  <div>
65
  <div id='theform' class='alignright'>
66
  <form>
67
- <div id="formheader">
68
  <strong>Custom Menu Wizard</strong> Interactive Demo
69
- <br /><small>v1.2.0 <em>(subset of admin options)</em></small><strong class="tryit"><em>Try it out&hellip;</em></strong>
70
  </div>
 
71
 
72
- <p>
73
- <label for="widget-custom-menu-wizard-2-title">Title:</label>
74
- <label class="alignright">
75
- <input type="checkbox" value="1" name="hide_title" id="widget-custom-menu-wizard-2-hide_title">
76
- Hide</label>
77
- <input type="text" value="" name="title" class="widefat" id="widget-custom-menu-wizard-2-title">
78
- <small><em>Title can be set, but need not be displayed</em></small>
79
- </p>
80
 
81
- <p class='collapsible'>Filter<span>&#9650;</span><span>&#9660;</span></p>
82
 
83
- <p>
84
- <label>
85
- <input type="radio" checked="checked" value="0" name="filter" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_0">
86
- Show all</label>
87
- <br /><label>
88
- <input type="radio" value="1" name="filter" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_1">
89
- Children of:</label>
90
- <select name="filter_item" style="max-width:100%;" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_item">
91
- <option selected="selected" value="0">Current Item</option>
92
- <option value="-2">Current Root Item</option>
93
- <option value="-1">Current Parent Item</option>
94
- <optgroup label="the-menu"></optgroup>
95
- </select>
96
- </p>
97
 
98
- <p>
99
- <label for="widget-custom-menu-wizard-2-start_level">Starting Level:</label>
100
- <select name="start_level" id="widget-custom-menu-wizard-2-start_level">
101
- </select>
102
- <br /><small><em>Level to start testing items for inclusion</em></small>
103
- </p>
104
 
105
- <p>
106
- <label for="widget-custom-menu-wizard-2-depth">For Depth:</label>
107
- <select name="depth" id="widget-custom-menu-wizard-2-depth">
108
- <option selected="selected" value="0">unlimited</option>
109
- </select>
110
- <br /><small><em>Relative to the first Filtered item found</em></small>
111
- </p>
112
 
113
- <p class='collapsible end-collapsible'>Fallbacks<span>&#9650;</span><span>&#9660;</span></p>
114
 
115
- <p class="widget-custom-menu-wizard-disableifnot-rp">
116
- <small><strong>If &quot;Children of&quot; is <em>Current Root / Parent Item</em>, and no ancestor exists :</strong></small>
117
- <br /><label>
118
- <input type="checkbox" value="1" name="fallback_no_ancestor" id="widget-custom-menu-wizard-2-fallback_no_ancestor">
119
- Switch to Current Item, and</label>
120
- <br /><label style="padding-left:1em;">
121
- <input type="checkbox" value="1" name="fallback_include_parent" id="widget-custom-menu-wizard-2-fallback_include_parent">
122
- Include Parent... </label>
123
- <label>
124
- <input type="checkbox" value="1" name="fallback_include_parent_siblings" id="widget-custom-menu-wizard-2-fallback_include_parent_siblings">
125
- &amp; its Siblings</label>
126
- <br /><small><em>If Current Root/Parent and no ancestor exists</em></small>
127
- </p>
128
 
129
- <p class="widget-custom-menu-wizard-disableifnot-ci">
130
- <small><strong>If &quot;Children of&quot; is <em>Current Item</em>, and current item has no children :</strong></small>
131
- <br /><label>
132
- <input type="checkbox" value="1" name="fallback_no_children" id="widget-custom-menu-wizard-2-fallback_no_children">
133
- Switch to Current Parent Item, and</label>
134
- <br /><label style="padding-left:1em;">
135
- <input type="checkbox" value="1" name="fallback_nc_include_parent" id="widget-custom-menu-wizard-2-fallback_nc_include_parent">
136
- Include Parent... </label>
137
- <label>
138
- <input type="checkbox" value="1" name="fallback_nc_include_parent_siblings" id="widget-custom-menu-wizard-2-fallback_nc_include_parent_siblings">
139
- &amp; its Siblings</label>
140
- </p>
141
 
142
- <p class='collapsible end-collapsible'>Output<span>&#9650;</span><span>&#9660;</span></p>
143
 
144
- <p>
145
- <label>
146
- <input type="radio" checked="checked" value="0" name="flat_output" id="widget-custom-menu-wizard-2-flat_output_0">
147
- Hierarchical</label>
148
- &nbsp;<label>
149
- <input type="radio" value="1" name="flat_output" id="widget-custom-menu-wizard-2-flat_output_1">
150
- Flat</label>
151
- </p>
152
 
153
- <p class="widget-custom-menu-wizard-disableif">
154
- <label>
155
- <input type="checkbox" value="1" name="include_parent" id="widget-custom-menu-wizard-2-include_parent">
156
- Include Parent... </label>
157
- <label>
158
- <input type="checkbox" value="1" name="include_parent_siblings" id="widget-custom-menu-wizard-2-include_parent_siblings">
159
- &amp; its Siblings</label>
160
- <br /><label>
161
- <input type="checkbox" value="1" name="include_ancestors" id="widget-custom-menu-wizard-2-include_ancestors">
162
- Include Ancestors</label>
163
- <br /><label>
164
- <input type="checkbox" value="1" name="title_from_parent" id="widget-custom-menu-wizard-2-title_from_parent">
165
- Title from Parent</label>
166
- <br /><small><em>Only if the "Children of" Filter returns items</em></small>
167
- </p>
168
 
169
- <p>
170
- <label>
171
- <input type="checkbox" value="1" name="title_from_current" id="widget-custom-menu-wizard-2-title_from_current">
172
- Title from &quot;Current&quot; Item</label>
173
- <br /><small><em>Lower priority than "Title from Parent"</em></small>
174
- </p>
175
 
176
- <p>
177
- Change UL to OL:
178
- <br /><label>
179
- <input type="checkbox" value="1" name="ol_root" id="widget-custom-menu-wizard-2-ol_root">
180
- Top Level</label>
181
- &nbsp;<label>
182
- <input type="checkbox" value="1" name="ol_sub" id="widget-custom-menu-wizard-2-ol_sub">
183
- Sub-Levels</label>
184
- </p>
185
 
186
- <p class="grey end-collapsible">
187
- <small><em>Note that since WP v3.6 does it automatically,
188
- <br />&quot;Hide Widget if Empty&quot; is ON for this demo.</em></small>
189
- </p>
190
 
 
191
  <button title="Reset the form to its defaults...">reset</button>
192
  </form>
 
 
 
 
 
 
 
193
  </div>
194
 
195
  <div id='theoutput' class='alignright'>
@@ -267,8 +282,9 @@
267
  </li>
268
  </ul>
269
  </div>
270
-
271
  <div id='thefooter'>
 
272
  <div>
273
  Please note that this page is a simulator : it uses javascript to reproduce what the widget
274
  would do, without interacting with WordPress in any way.
@@ -279,7 +295,7 @@
279
  <script type='text/javascript'>
280
  jQuery(function($){
281
  var maxlevel = 0,
282
- switches = {hide_title:1, filter:1, fallback_no_ancestor:1, fallback_include_parent:1, fallback_include_parent_siblings:1, fallback_no_children:1, fallback_nc_include_parent:1, fallback_nc_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},
283
  integers = {filter_item:1, start_level:1, depth:1},
284
  getSettings = function(){
285
  var settings = {};
@@ -294,6 +310,82 @@ jQuery(function($){
294
  }
295
  return s;
296
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  show = function(e, settings){
298
  //hide_empty is assumed to be on (WP < v3.6) or will automatically on (WP v3.6+)
299
  var output = $('#widget-output').empty(),
@@ -305,10 +397,10 @@ jQuery(function($){
305
  settings = settings || getSettings();
306
  if(items.length){
307
  if(settings.filter && settings.title_from_parent){
308
- title = $('.picked-parent').children('a').text() || '';
309
  }
310
  if(!title && settings.title_from_current){
311
- title = $('.current-item').text() || '';
312
  }
313
  if(!title && !settings.hide_title){
314
  title = settings.title || '';
@@ -317,44 +409,45 @@ jQuery(function($){
317
  var level = settings.flat_output ? 1 : parseInt(this.className.match(/level-(\d+)/)[1], 10),
318
  anchor = $(this).children('a');
319
  if(currLevel){
320
- if(level === currLevel){
321
- html += '</li>';
322
- }else if(level > currLevel){
323
  html += settings.ol_sub ? '<ol>' : '<ul>';
324
  }else{
325
- while(currLevel-- > level){
 
326
  html += '</li>' + (settings.ol_sub ? '</ol>' : '</ul>');
327
  }
 
328
  }
329
  }else{
330
  startLevel = level;
331
  }
332
- html += '<li class="cmw-level-' + level + '"><a href="#' + anchor.data('indx') + '">' + anchor.text() + '</a>';
333
  currLevel = level;
334
  });
335
- while(currLevel-- > startLevel){
 
336
  html += '</li>' + (settings.ol_sub ? '</ol>' : '</ul>');
337
  }
338
  html += '</li>';
339
- output.html( (settings.ol_root ? '<ol>' : '<ul>') + html + (settings.ol_root ? '</ol>' : '</ul>') );
340
  if(title){
341
  output.prepend('<h3>' + title + '</h3>');
342
  }
343
  output.find('li').filter(function(){
344
- return !!$(this).children('ul').length;
345
  }).addClass('cmw-has-submenu');
346
  }
 
347
  },
348
  walk = function(e){
349
  var settings = getSettings(),
350
  includeParent = settings.include_parent,
351
  includeParentSiblings = settings.include_parent_siblings,
352
- items = $('#themenu li').removeClass('picked-parent'),
353
  picked = items.filter('.picked'),
354
  cls = [],
355
  firstParent = true,
356
- fallback = false,
357
- parent, i;
358
  if(!settings.filter){
359
  //show all...
360
  for(i = 1; i < settings.start_level; i++){
@@ -370,19 +463,21 @@ jQuery(function($){
370
  if(settings.filter_item > 0){
371
  parent = items.eq(settings.filter_item - 1);
372
  }else if(!settings.filter_item){
373
- parent = $('.current-item').closest('li');
374
  }else{
375
  if(settings.filter_item < -1){
376
  //this could be more than one!...
377
- parent = $('.current-ancestor').closest('li');
378
  }else{
379
- parent = $('.current-parent').closest('li');
380
  }
381
  if(!parent.length && settings.fallback_no_ancestor){
382
- parent = $('.current-item').closest('li');
383
  includeParent = includeParent || settings.fallback_include_parent;
384
  includeParentSiblings = includeParentSiblings || settings.fallback_include_parent_siblings;
385
- fallback = !!parent.length;
 
 
386
  }
387
  }
388
  //could be multiple - only want first one that matches start_level...
@@ -406,32 +501,37 @@ jQuery(function($){
406
  includeParent = includeParent || settings.fallback_nc_include_parent;
407
  includeParentSiblings = includeParentSiblings || settings.fallback_nc_include_parent_siblings;
408
  parent = parent.parents('li').eq(0);
409
- fallback = !!parent.length;
 
 
410
  }
411
  if(items.length){
412
  if(includeParentSiblings){
413
- items = items.add( parent.siblings('li') ).add( parent );
414
- includeParent = false;
415
  }
416
  if(settings.include_ancestors){
417
- items = items.add( parent.parentsUntil('#themenu', 'li') ).add( parent );
418
- includeParent = false;
419
  }
420
  if(includeParent){
421
- items = items.add( parent );
422
  }
423
- parent.addClass('picked-parent');
424
  }
425
  }
426
- $('#fallback')[fallback && items.length ? 'show' : 'hide']();
 
 
 
427
  picked.not(items).removeClass('picked');
428
- items.not('.picked').addClass('picked');
429
  show.call(this, e, settings);
430
  },
431
  flds = $('input,select');
432
  $('#themenu a').on('click', function(){
433
  //click on a #themenu item to [un]make it the current item...
434
- var cls = ['current-item', 'current-parent', 'current-ancestor'],
435
  inPath = $(this).find('span').not('.' + cls[0]).parentsUntil('#themenu', 'li'),
436
  i, n;
437
  $('.' + cls.join(',.')).removeClass().removeAttr('title');
@@ -455,7 +555,7 @@ jQuery(function($){
455
  //allow setting current from widget output (only setting, not un-setting!)...
456
  $('#widget-output').on('click', 'a', function(){
457
  var indx = this.href.split('#')[1];
458
- $('#themenu a').eq(indx).not(':has(.current-item)').trigger('click');
459
  return false;
460
  });
461
  //populate starting-level and depth options...
@@ -473,7 +573,7 @@ jQuery(function($){
473
  $(document).on('change', '.demo-change', walk);
474
  //reset...
475
  $('button').on('click', function(){
476
- $(this).parent().get(0).reset();
477
  $('#widget-custom-menu-wizard-2-filter_item').trigger('change');
478
  return false;
479
  }).trigger('click');
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, code {position:relative;}
11
  a {color:#333333; text-decoration:none;}
12
+ code {color:#000099;}
13
  p {margin: 1em 0;}
14
+ input, select, button {font-family:inherit; font-size:inherit; font-weight:inherit; color:inherit; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box;}
15
  select {max-width:100%;}
16
  label {vertical-align:middle;}
17
+ form {display:block; border:1px solid #999999; border-radius:0.5em; margin:0; padding:0;}
18
  h3 {border-bottom:1px solid #cccccc;margin:0 0 0.25em; padding: 0.5em 0 0.25em;}
19
+ button {background-color:#cccccc; border-color:#999999; border-radius:0.4em 0 0.4em 0; border-style:solid; border-width:1px 0 0 1px; bottom:0; color:#000000; cursor:pointer; margin:0; padding:0 0.2em; position:absolute; right:0;}
20
  button:hover {background-color:#666666; color:#ffffff;}
21
  optgroup option {padding-left:0.75em;}
22
+ #theform {margin:1em; width:300px;}
23
+ #formheader {background-color:#666666; border-radius:0.4em 0.4em 0 0; color:#FFFFFF; margin:0 0 -0.5em; padding:0.25em 0; text-align:center;}
24
+ #formfields {padding:0 1em;}
25
+ #moreinfo {padding:0.5em 0; text-align:center;}
26
+ #moreinfo a {color:#0000ee;}
27
  #theoutput {margin:1em;}
28
  #widget-output {margin:0.5em 0; padding:0 1em; border:1px solid #cccccc; border-radius:0.5em; min-height:2em; min-width:9em;}
29
  #widget-output ul, #widget-output ol {margin:0.5em 0 0.5em 1.5em; padding:0;}
40
  #widget-output ol ol ol ol {list-style-type:lower-roman;}
41
  #widget-output ol ol ol ol ol {list-style-type:decimal;}
42
  #fallback {display:none; text-align:right; color:#006600;}
43
+ #fallback.cmw-fellback-to-current, #fallback.cmw-fellback-to-parent {display:block;}
44
  #themenu {margin:1em;}
45
  #themenu ul {font-size:12px; list-style-type:none; margin:1em 0; padding:0;}
46
  #themenu ul ul {margin:0 0 0 5em;}
49
  #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;}
50
  #thefooter {float:left; clear:left; margin:0 1em; color:#808080;}
51
  #thefooter div {font-size:12px;}
52
+ #theshortcode {color:#333333;}
53
  .alignleft {float:left;}
54
  .alignright {float:right;}
55
  .collapsible {background-color:#ffffff; background-image:-webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#e0e0e0)); background-image:-webkit-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:-moz-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:-ms-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:-o-linear-gradient(top, #FFFFFF, #E0E0E0); background-image:linear-gradient(to bottom, #FFFFFF, #E0E0E0); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff, endColorstr=#e0e0e0); -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff, endColorstr=#e0e0e0)";border:1px solid #CCCCCC; border-radius:0.3333em; cursor:pointer; font-size:12px; line-height:1.75; padding:0 0.5em;}
57
  .collapsible:hover span {color:#333333;}
58
  .collapsible span:first-child, .collapsible.closed span:last-child {display:inline;}
59
  .collapsible.closed span:first-child {display:none;}
60
+ .current-menu-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)";}
61
+ .current-menu-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)";}
62
+ .current-menu-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)";}
63
  .grey {color:#999999;}
64
  .picked > a {background-color:#000066; color:#ffffff; font-weight:bold;}
65
  .tryit {margin-left:1em; text-shadow:1px 1px 1px #ff0000;}
70
  <div>
71
  <div id='theform' class='alignright'>
72
  <form>
73
+ <div id='formheader'>
74
  <strong>Custom Menu Wizard</strong> Interactive Demo
75
+ <br /><small>v1.2.1 <em>(subset of admin options)</em></small><strong class="tryit"><em>Try it out&hellip;</em></strong>
76
  </div>
77
+ <div id='formfields'>
78
 
79
+ <p>
80
+ <label for="widget-custom-menu-wizard-2-title">Title:</label>
81
+ <label class="alignright">
82
+ <input type="checkbox" value="1" name="hide_title" id="widget-custom-menu-wizard-2-hide_title">
83
+ Hide</label>
84
+ <input type="text" value="" name="title" class="widefat" id="widget-custom-menu-wizard-2-title">
85
+ <small><em>Title can be set, but need not be displayed</em></small>
86
+ </p>
87
 
88
+ <p class='collapsible'>Filter<span>&#9650;</span><span>&#9660;</span></p>
89
 
90
+ <p>
91
+ <label>
92
+ <input type="radio" checked="checked" value="0" name="filter" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_0">
93
+ Show all</label>
94
+ <br /><label>
95
+ <input type="radio" value="1" name="filter" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_1">
96
+ Children of:</label>
97
+ <select name="filter_item" style="max-width:100%;" class="widget-custom-menu-wizard-listen" id="widget-custom-menu-wizard-2-filter_item">
98
+ <option selected="selected" value="0">Current Item</option>
99
+ <option value="-2">Current Root Item</option>
100
+ <option value="-1">Current Parent Item</option>
101
+ <optgroup label="the-menu"></optgroup>
102
+ </select>
103
+ </p>
104
 
105
+ <p>
106
+ <label for="widget-custom-menu-wizard-2-start_level">Starting Level:</label>
107
+ <select name="start_level" id="widget-custom-menu-wizard-2-start_level">
108
+ </select>
109
+ <br /><small><em>Level to start testing items for inclusion</em></small>
110
+ </p>
111
 
112
+ <p>
113
+ <label for="widget-custom-menu-wizard-2-depth">For Depth:</label>
114
+ <select name="depth" id="widget-custom-menu-wizard-2-depth">
115
+ <option selected="selected" value="0">unlimited</option>
116
+ </select>
117
+ <br /><small><em>Relative to the first Filtered item found</em></small>
118
+ </p>
119
 
120
+ <p class='collapsible end-collapsible'>Fallbacks<span>&#9650;</span><span>&#9660;</span></p>
121
 
122
+ <p class="widget-custom-menu-wizard-disableifnot-rp">
123
+ <small><strong>If &quot;Children of&quot; is <em>Current Root / Parent Item</em>, and no ancestor exists :</strong></small>
124
+ <br /><label>
125
+ <input type="checkbox" value="1" name="fallback_no_ancestor" id="widget-custom-menu-wizard-2-fallback_no_ancestor">
126
+ Switch to Current Item, and</label>
127
+ <br /><label style="padding-left:1em;">
128
+ <input type="checkbox" value="1" name="fallback_include_parent" id="widget-custom-menu-wizard-2-fallback_include_parent">
129
+ Include Parent... </label>
130
+ <label>
131
+ <input type="checkbox" value="1" name="fallback_include_parent_siblings" id="widget-custom-menu-wizard-2-fallback_include_parent_siblings">
132
+ &amp; its Siblings</label>
133
+ <br /><small><em>If Current Root/Parent and no ancestor exists</em></small>
134
+ </p>
135
 
136
+ <p class="widget-custom-menu-wizard-disableifnot-ci">
137
+ <small><strong>If &quot;Children of&quot; is <em>Current Item</em>, and current item has no children :</strong></small>
138
+ <br /><label>
139
+ <input type="checkbox" value="1" name="fallback_no_children" id="widget-custom-menu-wizard-2-fallback_no_children">
140
+ Switch to Current Parent Item, and</label>
141
+ <br /><label style="padding-left:1em;">
142
+ <input type="checkbox" value="1" name="fallback_nc_include_parent" id="widget-custom-menu-wizard-2-fallback_nc_include_parent">
143
+ Include Parent... </label>
144
+ <label>
145
+ <input type="checkbox" value="1" name="fallback_nc_include_parent_siblings" id="widget-custom-menu-wizard-2-fallback_nc_include_parent_siblings">
146
+ &amp; its Siblings</label>
147
+ </p>
148
 
149
+ <p class='collapsible end-collapsible'>Output<span>&#9650;</span><span>&#9660;</span></p>
150
 
151
+ <p>
152
+ <label>
153
+ <input type="radio" checked="checked" value="0" name="flat_output" id="widget-custom-menu-wizard-2-flat_output_0">
154
+ Hierarchical</label>
155
+ &nbsp;<label>
156
+ <input type="radio" value="1" name="flat_output" id="widget-custom-menu-wizard-2-flat_output_1">
157
+ Flat</label>
158
+ </p>
159
 
160
+ <p class="widget-custom-menu-wizard-disableif">
161
+ <label>
162
+ <input type="checkbox" value="1" name="include_parent" id="widget-custom-menu-wizard-2-include_parent">
163
+ Include Parent... </label>
164
+ <label>
165
+ <input type="checkbox" value="1" name="include_parent_siblings" id="widget-custom-menu-wizard-2-include_parent_siblings">
166
+ &amp; its Siblings</label>
167
+ <br /><label>
168
+ <input type="checkbox" value="1" name="include_ancestors" id="widget-custom-menu-wizard-2-include_ancestors">
169
+ Include Ancestors</label>
170
+ <br /><label>
171
+ <input type="checkbox" value="1" name="title_from_parent" id="widget-custom-menu-wizard-2-title_from_parent">
172
+ Title from Parent</label>
173
+ <br /><small><em>Only if the "Children of" Filter returns items</em></small>
174
+ </p>
175
 
176
+ <p>
177
+ <label>
178
+ <input type="checkbox" value="1" name="title_from_current" id="widget-custom-menu-wizard-2-title_from_current">
179
+ Title from &quot;Current&quot; Item</label>
180
+ <br /><small><em>Lower priority than "Title from Parent"</em></small>
181
+ </p>
182
 
183
+ <p>
184
+ Change UL to OL:
185
+ <br /><label>
186
+ <input type="checkbox" value="1" name="ol_root" id="widget-custom-menu-wizard-2-ol_root">
187
+ Top Level</label>
188
+ &nbsp;<label>
189
+ <input type="checkbox" value="1" name="ol_sub" id="widget-custom-menu-wizard-2-ol_sub">
190
+ Sub-Levels</label>
191
+ </p>
192
 
193
+ <p class="grey end-collapsible">
194
+ <small><em>Note that since WP v3.6 does it automatically,
195
+ <br />&quot;Hide Widget if Empty&quot; is ON for this demo.</em></small>
196
+ </p>
197
 
198
+ </div>
199
  <button title="Reset the form to its defaults...">reset</button>
200
  </form>
201
+
202
+ <div id="moreinfo">
203
+ <small>Doc.:
204
+ <a href="http://wordpress.org/plugins/custom-menu-wizard/" target='_blank'>wordpress.org/plugins/custom-menu-wizard/</a>
205
+ </small>
206
+ </div>
207
+
208
  </div>
209
 
210
  <div id='theoutput' class='alignright'>
282
  </li>
283
  </ul>
284
  </div>
285
+
286
  <div id='thefooter'>
287
+ <div id='theshortcode'>Shortcode : <code id='shortcode'></code></div>
288
  <div>
289
  Please note that this page is a simulator : it uses javascript to reproduce what the widget
290
  would do, without interacting with WordPress in any way.
295
  <script type='text/javascript'>
296
  jQuery(function($){
297
  var maxlevel = 0,
298
+ switches = {hide_title:1, filter:1, fallback_no_ancestor:1, fallback_include_parent:1, fallback_include_parent_siblings:1, fallback_no_children:1, fallback_nc_include_parent:1, fallback_nc_include_parent_siblings:1, flat_output:1, include_parent:1, include_parent_siblings:1, include_ancestors:1, title_from_parent:1, title_from_current:1, ol_root:1, ol_sub:1},
299
  integers = {filter_item:1, start_level:1, depth:1},
300
  getSettings = function(){
301
  var settings = {};
310
  }
311
  return s;
312
  },
313
+ shortcode = function(settings){
314
+ var args = {
315
+ 'menu' : 'example',
316
+ },
317
+ v, n;
318
+ if(settings.title){
319
+ args.title = settings.title;
320
+ }
321
+ if(settings.filter){
322
+ switch(settings.filter_item){
323
+ case 0: args.children_of = 'current'; break;
324
+ case -1: args.children_of = 'parent'; break;
325
+ case -2: args.children_of = 'root'; break;
326
+ default:
327
+ args.children_of = $('#themenu a').eq(settings.filter_item - 1).text();
328
+ }
329
+ }
330
+ if(settings.filter && settings.filter_item < 0 && settings.fallback_no_ancestor){
331
+ if(settings.fallback_include_parent_siblings){
332
+ args.fallback_parent = 'siblings';
333
+ }else if(settings.fallback_include_parent){
334
+ args.fallback_parent = 'parent';
335
+ }else{
336
+ args.fallback_parent = [1];
337
+ }
338
+ }
339
+ if(settings.filter && !settings.filter_item && settings.fallback_no_children){
340
+ if(settings.fallback_nc_include_parent_siblings){
341
+ args.fallback_current = 'siblings';
342
+ }else if(settings.fallback_nc_include_parent){
343
+ args.fallback_current = 'parent';
344
+ }else{
345
+ args.fallback_current = [1];
346
+ }
347
+ }
348
+ if(settings.start_level > 1){
349
+ args.start_level = [settings.start_level];
350
+ }
351
+ if(settings.depth > 0){
352
+ args.depth = [settings.depth];
353
+ }
354
+ n = [];
355
+ if(settings.filter){
356
+ if(settings.include_parent_siblings){
357
+ n.push('siblings');
358
+ }else if(settings.include_parent){
359
+ n.push('parent')
360
+ }
361
+ if(settings.include_ancestors){
362
+ n.push('ancestors');
363
+ }
364
+ if(n.length){
365
+ args.include = n.join(' ');
366
+ }
367
+ }
368
+ n = [];
369
+ if(settings.filter && settings.title_from_parent){
370
+ n.push('parent');
371
+ }
372
+ if(settings.title_from_current){
373
+ n.push('current');
374
+ }
375
+ if(n.length){
376
+ args.title_from = n.join(' ');
377
+ }
378
+ for(n in {flat_output:1, ol_root:1, ol_sub:1}){
379
+ if(settings[n]){
380
+ args[n] = [1];
381
+ }
382
+ }
383
+ v = [];
384
+ for(n in args){
385
+ v.push( $.isArray(args[n]) ? n + '=' + args[n][0] : n + '="' + args[n] + '"' );
386
+ }
387
+ $('code').text('[custom_menu_wizard ' + v.join(' ') + ']');
388
+ },
389
  show = function(e, settings){
390
  //hide_empty is assumed to be on (WP < v3.6) or will automatically on (WP v3.6+)
391
  var output = $('#widget-output').empty(),
397
  settings = settings || getSettings();
398
  if(items.length){
399
  if(settings.filter && settings.title_from_parent){
400
+ title = $('.the-parent').children('a').text() || '';
401
  }
402
  if(!title && settings.title_from_current){
403
+ title = $('.current-menu-item').text() || '';
404
  }
405
  if(!title && !settings.hide_title){
406
  title = settings.title || '';
409
  var level = settings.flat_output ? 1 : parseInt(this.className.match(/level-(\d+)/)[1], 10),
410
  anchor = $(this).children('a');
411
  if(currLevel){
412
+ if(level > currLevel){
 
 
413
  html += settings.ol_sub ? '<ol>' : '<ul>';
414
  }else{
415
+ while(currLevel > level){
416
+ --currLevel;
417
  html += '</li>' + (settings.ol_sub ? '</ol>' : '</ul>');
418
  }
419
+ html += '</li>';
420
  }
421
  }else{
422
  startLevel = level;
423
  }
424
+ html += '<li class="cmw-level-' + (level - startLevel + 1) + ($(this).data().included || '') + '"><a href="#' + anchor.data('indx') + '">' + anchor.text() + '</a>';
425
  currLevel = level;
426
  });
427
+ while(currLevel > startLevel){
428
+ --currLevel;
429
  html += '</li>' + (settings.ol_sub ? '</ol>' : '</ul>');
430
  }
431
  html += '</li>';
432
+ output.html( (settings.ol_root ? '<ol' : '<ul') + ' class="' + $.trim( 'menu-widget ' + ($('#fallback').get(0).className || '') ) + '">' + html + (settings.ol_root ? '</ol>' : '</ul>') );
433
  if(title){
434
  output.prepend('<h3>' + title + '</h3>');
435
  }
436
  output.find('li').filter(function(){
437
+ return !!$(this).children('ul, ol').length;
438
  }).addClass('cmw-has-submenu');
439
  }
440
+ shortcode(settings);
441
  },
442
  walk = function(e){
443
  var settings = getSettings(),
444
  includeParent = settings.include_parent,
445
  includeParentSiblings = settings.include_parent_siblings,
446
+ items = $('#themenu li').removeData('included').removeClass('the-parent'),
447
  picked = items.filter('.picked'),
448
  cls = [],
449
  firstParent = true,
450
+ fallback, parent, i;
 
451
  if(!settings.filter){
452
  //show all...
453
  for(i = 1; i < settings.start_level; i++){
463
  if(settings.filter_item > 0){
464
  parent = items.eq(settings.filter_item - 1);
465
  }else if(!settings.filter_item){
466
+ parent = $('.current-menu-item').closest('li');
467
  }else{
468
  if(settings.filter_item < -1){
469
  //this could be more than one!...
470
+ parent = $('.current-menu-ancestor').closest('li');
471
  }else{
472
+ parent = $('.current-menu-parent').closest('li');
473
  }
474
  if(!parent.length && settings.fallback_no_ancestor){
475
+ parent = $('.current-menu-item').closest('li');
476
  includeParent = includeParent || settings.fallback_include_parent;
477
  includeParentSiblings = includeParentSiblings || settings.fallback_include_parent_siblings;
478
+ if(parent.length){
479
+ fallback = 'cmw-fellback-to-current';
480
+ }
481
  }
482
  }
483
  //could be multiple - only want first one that matches start_level...
501
  includeParent = includeParent || settings.fallback_nc_include_parent;
502
  includeParentSiblings = includeParentSiblings || settings.fallback_nc_include_parent_siblings;
503
  parent = parent.parents('li').eq(0);
504
+ if(parent.length){
505
+ fallback = 'cmw-fellback-to-parent';
506
+ }
507
  }
508
  if(items.length){
509
  if(includeParentSiblings){
510
+ items = items.add( parent.siblings('li').data('included', ' cmw-an-included-parent-sibling') ).add( parent );
511
+ includeParent = true;
512
  }
513
  if(settings.include_ancestors){
514
+ items = items.add( parent.parentsUntil('#themenu', 'li').data('included', ' cmw-an-included-ancestor') ).add( parent );
515
+ includeParent = true;
516
  }
517
  if(includeParent){
518
+ items = items.add( parent.data('included', ' cmw-the-included-parent') );
519
  }
520
+ parent.addClass('the-parent');
521
  }
522
  }
523
+ $('#fallback').removeClass();
524
+ if(items.length && fallback){
525
+ $('#fallback').addClass(fallback);
526
+ }
527
  picked.not(items).removeClass('picked');
528
+ items.addClass('picked');
529
  show.call(this, e, settings);
530
  },
531
  flds = $('input,select');
532
  $('#themenu a').on('click', function(){
533
  //click on a #themenu item to [un]make it the current item...
534
+ var cls = ['current-menu-item', 'current-menu-parent', 'current-menu-ancestor'],
535
  inPath = $(this).find('span').not('.' + cls[0]).parentsUntil('#themenu', 'li'),
536
  i, n;
537
  $('.' + cls.join(',.')).removeClass().removeAttr('title');
555
  //allow setting current from widget output (only setting, not un-setting!)...
556
  $('#widget-output').on('click', 'a', function(){
557
  var indx = this.href.split('#')[1];
558
+ $('#themenu a').eq(indx).not(':has(.current-menu-item)').trigger('click');
559
  return false;
560
  });
561
  //populate starting-level and depth options...
573
  $(document).on('change', '.demo-change', walk);
574
  //reset...
575
  $('button').on('click', function(){
576
+ $('form').get(0).reset();
577
  $('#widget-custom-menu-wizard-2-filter_item').trigger('change');
578
  return false;
579
  }).trigger('click');
readme.txt CHANGED
@@ -3,7 +3,7 @@ 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.2.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.
@@ -29,10 +29,14 @@ Features include:
29
  * *As of v1.1.0* : Select a branch based on the ultimate ancestor (root level) of the "current" item
30
  * *As of v1.2.0* : Shortcode, [custom_menu_wizard], available to run the widget from within content
31
 
32
- **Widget Options**
 
 
 
33
 
34
  There are quite a few options, which makes the widget settings box very long. I have therefore grouped most of the options into
35
- logical sections and made each section collapsible (with remembered state, open by default).
 
36
 
37
  * **Title**
38
 
@@ -169,6 +173,8 @@ logical sections and made each section collapsible (with remembered state, open
169
 
170
  Again, this only applies to a successful `Children of` filter. If checked, use the title of the parent item as the widget's
171
  title when displaying the output. This will override (ie. ignore) the `Hide` checkbox setting!
 
 
172
 
173
  * **Title from "Current" Item** *(checkbox)*
174
 
@@ -244,7 +250,7 @@ logical sections and made each section collapsible (with remembered state, open
244
 
245
  Text or HTML that will be placed immediately after each menu item's link text.
246
 
247
- **Shortcode**
248
 
249
  The shortcode is **`[custom_menu_wizard]`**. Most of the attributes reflect the options available to the widget, but some have been simplified for
250
  easier use in the shortcode format.
@@ -359,11 +365,11 @@ found then there will be no output from the shortcode.
359
 
360
  * Show the children of the Current Item within the "main" menu, for unlimited depth, and include the Current Item's parent :
361
 
362
- `[custom_menu_wizard menu=main children_of=current include_parent=1]`
363
 
364
  * From the "animals" menu, show all the items *immediately* below (depth=1) "Small Dogs", plus "Small Dogs" and its sibling items, as ordered lists :
365
 
366
- `[custom_menu_wizard menu="animals" children_of="small dogs" depth=1 include_parent_siblings=1 ol_root=1 ol_sub=1]`
367
 
368
  == Installation ==
369
 
@@ -392,12 +398,28 @@ If you have a question or problem, please use the integrated Support forum.
392
 
393
  == Changelog ==
394
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  = 1.2.0 =
396
 
397
  * added custom_menu_wizard shortcode, to run the widget from within content
398
 
399
  * moved the 'no ancestor' fallback into new Fallback collapsible section, and added a fallback for Current Item with no children
400
 
 
 
401
  * fixed a bug with optgroups/options made available for the 'Children of' selector after the widget has been saved (also affected disabled fields and styling)
402
 
403
  * don't include menus with no items
@@ -430,17 +452,14 @@ Initial release
430
 
431
  == Upgrade Notice ==
432
 
 
 
 
 
 
 
433
  = 1.2.0 =
434
 
435
  Added custom_menu_wizard shortcode, to run the widget from within content. Also added a new fallback for Current Item having no children, and
436
  moved all fallbacks into a collapsible Fallbacks section. Fixed a bug with optgroups/options made available for the 'Children of' selector
437
  after the widget has been saved (also affected disabled fields and styling).
438
-
439
- = 1.1.0 =
440
-
441
- `Children of` has 2 extra options, for filtering using the Current Item's parent (immediate ancestor) or root (ultimate ancestor) item,
442
- with fallbacks for when a Current Item has no ancestor. There is also an additional Output option which extends Include Parent to also
443
- include the parent's siblings. An interactive helper/demo page is now available, which will hopefully assist in deciding which options
444
- need setting for particular requirements. Other changes include tweaks to the management of the `Children of` SELECT (to allow for IE),
445
- 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
446
- presented for WP < 3.6 though!).
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.2.1
7
  License: GPLv2 or Later
8
 
9
  Custom Menu Wizard Widget : Show branches or levels of your menu in a widget, with full customisation.
29
  * *As of v1.1.0* : Select a branch based on the ultimate ancestor (root level) of the "current" item
30
  * *As of v1.2.0* : Shortcode, [custom_menu_wizard], available to run the widget from within content
31
 
32
+ Demo Emulator : [www.wizzud.com/custom-menu-wizard](http://www.wizzud.com/custom-menu-wizard/) -
33
+ even shows the shortcode for the options that have been set. (This emulator is also provided as part of the plugin)
34
+
35
+ **WIDGET OPTIONS**
36
 
37
  There are quite a few options, which makes the widget settings box very long. I have therefore grouped most of the options into
38
+ logical sections and made each section collapsible (with remembered state once saved). As of v1.2.1, only the Filter section is
39
+ open by default; all sections below that start off collapsed.
40
 
41
  * **Title**
42
 
173
 
174
  Again, this only applies to a successful `Children of` filter. If checked, use the title of the parent item as the widget's
175
  title when displaying the output. This will override (ie. ignore) the `Hide` checkbox setting!
176
+
177
+ Please note that this is **not** the same as asking for the title from "the parent of the current menu item"!
178
 
179
  * **Title from "Current" Item** *(checkbox)*
180
 
250
 
251
  Text or HTML that will be placed immediately after each menu item's link text.
252
 
253
+ **SHORTCODE**
254
 
255
  The shortcode is **`[custom_menu_wizard]`**. Most of the attributes reflect the options available to the widget, but some have been simplified for
256
  easier use in the shortcode format.
365
 
366
  * Show the children of the Current Item within the "main" menu, for unlimited depth, and include the Current Item's parent :
367
 
368
+ `[custom_menu_wizard menu=main children_of=current include=parent]`
369
 
370
  * From the "animals" menu, show all the items *immediately* below (depth=1) "Small Dogs", plus "Small Dogs" and its sibling items, as ordered lists :
371
 
372
+ `[custom_menu_wizard menu="animals" children_of="small dogs" depth=1 include="siblings" ol_root=1 ol_sub=1]`
373
 
374
  == Installation ==
375
 
398
 
399
  == Changelog ==
400
 
401
+ = 1.2.1 =
402
+
403
+ * added some extra custom classes, when applicable : cmw-fellback-to-current & cmw-fellback-to-parent (on outer UL/OL) and cmw-the-included-parent, cmw-an-included-parent-sibling & cmw-an-included-ancestor (on relevant LIs)
404
+
405
+ * corrected 'show all from start level 1' processing so that custom classes get applied and 'Title from "Current" Item' works (regardless of filter settings)
406
+
407
+ * changed the defaults for new widgets such that only the Filter section is open by default; all the others are collapsed
408
+
409
+ * in demo.html, added output of the shortcode applicable to the selections made
410
+
411
+ * in demo.html, added a link to the documentation page
412
+
413
+ * corrected 2 of the shortcode examples in the readme.txt, and made emulator (dem) available from the readme
414
+
415
  = 1.2.0 =
416
 
417
  * added custom_menu_wizard shortcode, to run the widget from within content
418
 
419
  * moved the 'no ancestor' fallback into new Fallback collapsible section, and added a fallback for Current Item with no children
420
 
421
+ * added an option allowing setting of title from current menu item's title
422
+
423
  * fixed a bug with optgroups/options made available for the 'Children of' selector after the widget has been saved (also affected disabled fields and styling)
424
 
425
  * don't include menus with no items
452
 
453
  == Upgrade Notice ==
454
 
455
+ = 1.2.1 =
456
+
457
+ Added a few extra custom classes, and changed the defaults for new widgets such that only the Filter section is open by default.
458
+ Fixed Show All processing so that custom classes always get applied, and 'Title from "Current" Item' works regardless of filter settings.
459
+ Fixed a couple of the shortcode examples in the readme.txt, and added display of the applicable shortcode settings to the demo.html.
460
+
461
  = 1.2.0 =
462
 
463
  Added custom_menu_wizard shortcode, to run the widget from within content. Also added a new fallback for Current Item having no children, and
464
  moved all fallbacks into a collapsible Fallbacks section. Fixed a bug with optgroups/options made available for the 'Children of' selector
465
  after the widget has been saved (also affected disabled fields and styling).