Version Description
Initial release
=
Download this release
Release Info
Developer | wizzud |
Plugin | Custom Menu Wizard Widget |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- custom-menu-wizard.js +28 -0
- custom-menu-wizard.php +740 -0
- readme.txt +194 -0
custom-menu-wizard.js
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
});
|
custom-menu-wizard.php
ADDED
@@ -0,0 +1,740 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
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 |
+
*/
|
15 |
+
function custom_menu_wizard_register_widget() {
|
16 |
+
register_widget('Custom_Menu_Wizard_Widget');
|
17 |
+
}
|
18 |
+
add_action('widgets_init', 'custom_menu_wizard_register_widget');
|
19 |
+
|
20 |
+
/**
|
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
|
35 |
+
*
|
36 |
+
* @param string $output Passed by reference. Used to append additional content.
|
37 |
+
* @param int $depth Depth of page. Used for padding.
|
38 |
+
*/
|
39 |
+
function start_lvl( &$output, $depth = 0, $args = array() ) {
|
40 |
+
$indent = str_repeat("\t", $depth);
|
41 |
+
$listtag = empty( $args->_custom_menu_wizard['ol_sub'] ) ? 'ul' : 'ol';
|
42 |
+
$output .= "\n$indent<$listtag class=\"sub-menu\">\n";
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* closes a sub-level with a UL or OL end-tag
|
47 |
+
*
|
48 |
+
* @param string $output Passed by reference. Used to append additional content.
|
49 |
+
* @param int $depth Depth of page. Used for padding.
|
50 |
+
*/
|
51 |
+
function end_lvl( &$output, $depth = 0, $args = array() ) {
|
52 |
+
$indent = str_repeat("\t", $depth);
|
53 |
+
$listtag = empty( $args->_custom_menu_wizard['ol_sub'] ) ? 'ul' : 'ol';
|
54 |
+
$output .= "$indent</$listtag>\n";
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* pre-filters elements then calls parent::walk()
|
59 |
+
*
|
60 |
+
* @param array $elements Menu items
|
61 |
+
* @param integer $max_depth
|
62 |
+
* @return string
|
63 |
+
*/
|
64 |
+
function walk($elements, $max_depth){
|
65 |
+
|
66 |
+
$args = array_slice(func_get_args(), 2);
|
67 |
+
$args = $args[0];
|
68 |
+
|
69 |
+
if( $max_depth >= -1 && !empty( $elements ) && isset($args->_custom_menu_wizard) ){
|
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!
|
121 |
+
//also note that orphans (in the original menu) are ignored by this widget!
|
122 |
+
|
123 |
+
if( isset( $temp[ $item->$id_field ] ) ){
|
124 |
+
//are we at or below the start level?...
|
125 |
+
if( $temp[ $item->$id_field ]['level'] >= $start_level ){
|
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
|
145 |
+
if( $cmw['depth'] > 0 ){
|
146 |
+
$max_level = $temp[ $item->$id_field ]['level'] + $cmw['depth'] - ($find_kids_of ? 0 : 1);
|
147 |
+
}else{
|
148 |
+
//unlimited...
|
149 |
+
$max_level = 9999;
|
150 |
+
}
|
151 |
+
//...and reset start level...
|
152 |
+
$start_level = $cmw['start_level'];
|
153 |
+
}
|
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 |
+
}
|
161 |
+
}
|
162 |
+
}
|
163 |
+
} //end foreach
|
164 |
+
|
165 |
+
unset( $keep_ids );
|
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:
|
194 |
+
// [0] => the level within the new structure (starting at 1), and
|
195 |
+
// [1] => the number of kids each item has
|
196 |
+
$temp = array();
|
197 |
+
foreach( $keep_items as $item ){
|
198 |
+
if( isset( $temp[ $item->$parent_field ] ) ){
|
199 |
+
$temp[ $item->$id_field ] = array( $temp[ $item->$parent_field ][0] + 1, 0 );
|
200 |
+
$temp[ $item->$parent_field ][1] += 1;
|
201 |
+
}else{
|
202 |
+
$temp[ $item->$id_field ] = array( 1, 0 );
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
//transfer $keep back into $elements, resetting the index to increment from 1; also add
|
207 |
+
//new classes to indicate level (starting at 1) and whether any item has kids
|
208 |
+
//
|
209 |
+
//note that we have already filtered out real orphans, but we may have introduced top-level
|
210 |
+
//items that would appear to be orphans to the parent::walk() method, so we need to set all
|
211 |
+
//the top-level items to appear as if they are root-level items...
|
212 |
+
$elements = array();
|
213 |
+
$i = 1;
|
214 |
+
foreach( $keep_items as $item ){
|
215 |
+
$item->classes[] = 'cmw-level-' . $temp[ $item->$id_field ][0];
|
216 |
+
if( $temp[ $item->$id_field ][1] > 0 ){
|
217 |
+
$item->classes[] = 'cmw-has-submenu';
|
218 |
+
}
|
219 |
+
if( $temp[ $item->$id_field ][0] == 1 ){
|
220 |
+
//fake as root level item...
|
221 |
+
$item->$parent_field = 0;
|
222 |
+
}
|
223 |
+
$elements[ $i++ ] = $item;
|
224 |
+
}
|
225 |
+
unset( $keep_items, $temp );
|
226 |
+
|
227 |
+
//since we've done all the depth filtering, set max_depth to unlimited (unless 'flat' was requested!)...
|
228 |
+
if( !$cmw['flat_output'] ){
|
229 |
+
$max_depth = 0;
|
230 |
+
}
|
231 |
+
$elements = apply_filters( 'custom_menu_wizard_walker_items', $elements, $args );
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
return empty( $elements ) ? '' : parent::walk($elements, $max_depth, $args);
|
236 |
+
}
|
237 |
+
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Custom Menu Wizard Widget class
|
242 |
+
*/
|
243 |
+
class Custom_Menu_Wizard_Widget extends WP_Widget {
|
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',
|
254 |
+
//field section toggles...
|
255 |
+
'fs_filter',
|
256 |
+
'fs_output',
|
257 |
+
'fs_container',
|
258 |
+
'fs_classes',
|
259 |
+
'fs_links'
|
260 |
+
);
|
261 |
+
var $_cmw_strings = array(
|
262 |
+
'title' => '',
|
263 |
+
'container' => 'div',
|
264 |
+
'container_id' => '',
|
265 |
+
'container_class' => '',
|
266 |
+
'menu_class' => 'menu-widget',
|
267 |
+
'widget_class' => ''
|
268 |
+
);
|
269 |
+
var $_cmw_html = array(
|
270 |
+
'before' => '',
|
271 |
+
'after' => '',
|
272 |
+
'link_before' => '',
|
273 |
+
'link_after' => ''
|
274 |
+
);
|
275 |
+
var $_cmw_integers = array(
|
276 |
+
'depth' => 0,
|
277 |
+
'filter' => 0,
|
278 |
+
'filter_item' => 0,
|
279 |
+
'menu' => 0,
|
280 |
+
'start_level' => 1
|
281 |
+
);
|
282 |
+
|
283 |
+
/**
|
284 |
+
* class constructor
|
285 |
+
*/
|
286 |
+
function __construct() {
|
287 |
+
parent::__construct(
|
288 |
+
'custom-menu-wizard',
|
289 |
+
'Custom Menu Wizard',
|
290 |
+
array(
|
291 |
+
'classname' => 'widget_custom_menu_wizard',
|
292 |
+
'description' => __('Add a custom menu, or part of one, as a widget')
|
293 |
+
// ),
|
294 |
+
// array(
|
295 |
+
// 'width'=>560
|
296 |
+
)
|
297 |
+
);
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* removes itself from the filters and, if available and requested, stores parent_title in the instance for use as the widget title
|
302 |
+
*
|
303 |
+
* @param array $items Filtered menu items
|
304 |
+
* @param object $args
|
305 |
+
* @return array Menu items
|
306 |
+
*/
|
307 |
+
function cmw_filter_retain_parent_title($items, $args){
|
308 |
+
remove_filter('custom_menu_wizard_walker_items', array( $this, 'cmw_filter_retain_parent_title' ), 10, 2);
|
309 |
+
if( !empty( $args->_custom_menu_wizard['title_from_parent'] ) && !empty( $args->_custom_menu_wizard['parent_title'] ) ){
|
310 |
+
$this->cmw_title_from_parent = $args->_custom_menu_wizard['parent_title'];
|
311 |
+
}
|
312 |
+
return $items;
|
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
|
323 |
+
*/
|
324 |
+
function cmw_filter_no_output_when_empty($nav_menu, $args){
|
325 |
+
remove_filter( 'wp_nav_menu', array( $this, 'cmw_filter_no_output_when_empty' ), 65532, 2 );
|
326 |
+
return empty( $args->_custom_menu_wizard ) ? $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
|
338 |
+
*/
|
339 |
+
function cmw_filter_check_for_no_items($items, $args){
|
340 |
+
if( !empty( $args->_custom_menu_wizard ) && empty( $items ) ){
|
341 |
+
add_filter( 'wp_nav_menu', array( $this, 'cmw_filter_no_output_when_empty' ), 65532, 2 );
|
342 |
+
}
|
343 |
+
return $items;
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* produces the widget HTML at the front end
|
348 |
+
*
|
349 |
+
* @param object $args Widget arguments
|
350 |
+
* @param array $instance Configuration for this widget instance
|
351 |
+
*/
|
352 |
+
function widget($args, $instance) {
|
353 |
+
extract( $args, EXTR_SKIP );
|
354 |
+
|
355 |
+
//switches...
|
356 |
+
foreach( $this->_cmw_switches as $k=>$v ){
|
357 |
+
$instance[ $v ] = !empty( $instance[ $v ] );
|
358 |
+
}
|
359 |
+
//integers...
|
360 |
+
foreach( $this->_cmw_integers as $k=>$v ){
|
361 |
+
$instance[ $k ] = max( $v, intval( $instance[ $k ] ) );
|
362 |
+
}
|
363 |
+
//strings...
|
364 |
+
foreach( $this->_cmw_strings as $k=>$v ){
|
365 |
+
$instance[ $k ] = empty( $instance[ $k ] ) ? $v : trim( $instance[ $k ] );
|
366 |
+
}
|
367 |
+
//html strings...
|
368 |
+
foreach( $this->_cmw_html as $k=>$v ){
|
369 |
+
$instance[ $k ] = empty( $instance[ $k ] ) ? $v : trim( $instance[ $k ] );
|
370 |
+
}
|
371 |
+
|
372 |
+
$this->cmw_title_from_parent = '';
|
373 |
+
|
374 |
+
//fetch menu...
|
375 |
+
if( !empty($instance['menu'] ) ){
|
376 |
+
$menu = wp_get_nav_menu_object( $instance['menu'] );
|
377 |
+
|
378 |
+
//no menu, no output...
|
379 |
+
if ( !empty( $menu ) ){
|
380 |
+
|
381 |
+
if( !empty( $instance['widget_class'] ) ){
|
382 |
+
//$before_widget is usually just a DIV start-tag, with an id and a class; if it
|
383 |
+
//gets more complicated than that then this may not work as expected...
|
384 |
+
if( preg_match( '/^<[^>]+?class=["\']/', $before_widget ) > 0 ){
|
385 |
+
$before_widget = preg_replace( '/(class=["\'])/', '$1' . $instance['widget_class'] . ' ', $before_widget, 1 );
|
386 |
+
}else{
|
387 |
+
$before_widget = preg_replace( '/^(<\w+)(\s|>)/', '$1 class="' . $instance['widget_class'] . '"$2', $before_widget );
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
if( !empty( $instance['container_class'] ) ){
|
392 |
+
$instance['container_class'] = "menu-{$menu->slug}-container {$instance['container_class']}";
|
393 |
+
}
|
394 |
+
|
395 |
+
if( $instance['title_from_parent'] ){
|
396 |
+
add_filter('custom_menu_wizard_walker_items', array( $this, 'cmw_filter_retain_parent_title' ), 10, 2);
|
397 |
+
}
|
398 |
+
|
399 |
+
if( $instance['hide_empty'] ){
|
400 |
+
add_filter( "wp_nav_menu_{$menu->slug}_items", array( $this, 'cmw_filter_check_for_no_items' ), 65532, 2 );
|
401 |
+
}
|
402 |
+
|
403 |
+
$walker = new Custom_Menu_Wizard_Walker;
|
404 |
+
$params = array(
|
405 |
+
'menu' => $menu,
|
406 |
+
'container' => $instance['container'] == 'none' ? false : $instance['container'],
|
407 |
+
'container_id' => $instance['container_id'],
|
408 |
+
'menu_class' => $instance['menu_class'],
|
409 |
+
'echo' => false,
|
410 |
+
'fallback_cb' => false,
|
411 |
+
'before' => $instance['before'],
|
412 |
+
'after' => $instance['after'],
|
413 |
+
'link_before' => $instance['link_before'],
|
414 |
+
'link_after' => $instance['link_after'],
|
415 |
+
'depth' => empty( $instance['flat_output'] ) ? $instance['depth'] : -1,
|
416 |
+
'walker' =>$walker,
|
417 |
+
//widget specific stuff...
|
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'],
|
425 |
+
'ol_sub' => $instance['ol_sub'],
|
426 |
+
'flat_output' => $instance['flat_output'],
|
427 |
+
'start_level' => $instance['start_level'],
|
428 |
+
'depth' => $instance['depth']
|
429 |
+
)
|
430 |
+
);
|
431 |
+
if( $instance['ol_root'] ){
|
432 |
+
$params['items_wrap'] = '<ol id="%1$s" class="%2$s">%3$s</ol>';
|
433 |
+
}
|
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'] ){
|
440 |
+
remove_filter( "wp_nav_menu_{$menu->slug}_items", array( $this, 'cmw_filter_check_for_no_items' ), 65532, 2 );
|
441 |
+
}
|
442 |
+
|
443 |
+
//only put something out if there is something to put out...
|
444 |
+
if( !empty( $out ) ){
|
445 |
+
|
446 |
+
if( $instance['title_from_parent'] && isset( $this->cmw_title_from_parent ) ){
|
447 |
+
$title = $this->cmw_title_from_parent;
|
448 |
+
}
|
449 |
+
if( empty( $title ) ){
|
450 |
+
$title = $instance['hide_title'] ? '' : $instance['title'];
|
451 |
+
}
|
452 |
+
|
453 |
+
echo $before_widget;
|
454 |
+
if ( !empty($title) ){
|
455 |
+
echo $before_title . apply_filters('widget_title', $title, $instance, $this->id_base) . $after_title;
|
456 |
+
}
|
457 |
+
echo $out . $after_widget;
|
458 |
+
}
|
459 |
+
}
|
460 |
+
}
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* updates the widget settings sent from the backend admin
|
465 |
+
*/
|
466 |
+
function update( $new_instance, $old_instance ) {
|
467 |
+
$instance = $old_instance;
|
468 |
+
|
469 |
+
//switches...
|
470 |
+
foreach( $this->_cmw_switches as $k=>$v ){
|
471 |
+
$instance[ $v ] = empty( $new_instance[ $v ] ) ? 0 : 1;
|
472 |
+
}
|
473 |
+
//integers...
|
474 |
+
foreach( $this->_cmw_integers as $k=>$v ){
|
475 |
+
$instance[ $k ] = isset( $new_instance[ $k ]) ? max( $v, intval( $new_instance[ $k ] ) ) : $v;
|
476 |
+
}
|
477 |
+
//strings...
|
478 |
+
foreach( $this->_cmw_strings as $k=>$v ){
|
479 |
+
$instance[ $k ] = isset( $new_instance[ $k ] ) ? strip_tags( trim( $new_instance[ $k ] ) ) : $v;
|
480 |
+
}
|
481 |
+
//html strings...
|
482 |
+
foreach( $this->_cmw_html as $k=>$v ){
|
483 |
+
$instance[ $k ] = isset( $new_instance[ $k ] ) ? trim( $new_instance[ $k ] ) : $v;
|
484 |
+
}
|
485 |
+
|
486 |
+
return $instance;
|
487 |
+
}
|
488 |
+
|
489 |
+
/**
|
490 |
+
* produces the backend admin form(s)
|
491 |
+
*/
|
492 |
+
function form( $instance ) {
|
493 |
+
|
494 |
+
//switches...
|
495 |
+
foreach( $this->_cmw_switches as $k=>$v ){
|
496 |
+
$instance[ $v ] = !empty( $instance[ $v ] );
|
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 ){
|
504 |
+
$instance[ $k ] = isset( $instance[ $k ] ) ? esc_attr( trim( $instance[ $k ] ) ) : $v;
|
505 |
+
}
|
506 |
+
//html strings...
|
507 |
+
foreach( $this->_cmw_html as $k=>$v ){
|
508 |
+
$instance[ $k ] = isset( $instance[ $k ] ) ? esc_html( trim( $instance[ $k ] ) ) : $v;
|
509 |
+
}
|
510 |
+
|
511 |
+
//get menus...
|
512 |
+
$menus = get_terms( 'nav_menu', array( 'hide_empty' => false ) );
|
513 |
+
|
514 |
+
//if no menus exist, suggest the user go create one...
|
515 |
+
if( empty( $menus ) ){
|
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>
|
582 |
+
<label for="<?php echo $this->get_field_id('start_level'); ?>"><?php _e('Starting Level:'); ?></label>
|
583 |
+
<select id="<?php echo $this->get_field_id('start_level'); ?>" name="<?php echo $this->get_field_name('start_level'); ?>">
|
584 |
+
<?php
|
585 |
+
$j = max( $maxlevel, $instance['start_level'] );
|
586 |
+
for( $i = 1; $i <= $j; $i++ ){
|
587 |
+
?>
|
588 |
+
<option value="<?php echo $i; ?>" <?php selected($instance['start_level'], $i); ?>><?php echo $i; ?></option>
|
589 |
+
<?php
|
590 |
+
}
|
591 |
+
?>
|
592 |
+
</select>
|
593 |
+
<br /><small><em><?php _e('Level to start testing items for inclusion'); ?></em></small>
|
594 |
+
</p>
|
595 |
+
|
596 |
+
<p>
|
597 |
+
<label for="<?php echo $this->get_field_id('depth'); ?>"><?php _e('For Depth:'); ?></label>
|
598 |
+
<select id="<?php echo $this->get_field_id('depth'); ?>" name="<?php echo $this->get_field_name('depth'); ?>">
|
599 |
+
<option value="0" <?php selected( $instance['depth'], 0 ); ?>><?php _e('unlimited'); ?></option>
|
600 |
+
<?php
|
601 |
+
$j = max( $j, $instance['depth'] );
|
602 |
+
for( $i = 1; $i <= $j; $i++ ){
|
603 |
+
?>
|
604 |
+
<option value="<?php echo $i; ?>" <?php selected( $instance['depth'], $i ); ?>><?php echo $i; ?> <?php _e($i > 1 ? 'levels' : 'level'); ?></option>
|
605 |
+
<?php
|
606 |
+
}
|
607 |
+
?>
|
608 |
+
</select>
|
609 |
+
<br /><small><em><?php _e('Relative to the first Filtered item found'); ?></em></small>
|
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 |
+
<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 "Children of:" Filter returns items'); ?></em></small>
|
634 |
+
</p>
|
635 |
+
|
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 |
+
<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(); ?>
|
707 |
+
|
708 |
+
<?php
|
709 |
+
} //end form()
|
710 |
+
|
711 |
+
/**
|
712 |
+
* outputs the HTML to begin a collapsible/expandable group of settings
|
713 |
+
*
|
714 |
+
* @param array $instance
|
715 |
+
* @param string $text Label
|
716 |
+
* @param string $fname Field name
|
717 |
+
*/
|
718 |
+
function _open_a_field_section( &$instance, $text, $fname ){
|
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>
|
727 |
+
<div class="hide-if-js"<?php echo !$collapsed ? ' style="display:block;"' : ''; ?>>
|
728 |
+
<?php
|
729 |
+
} //end _open_a_field_section()
|
730 |
+
|
731 |
+
/**
|
732 |
+
* outputs the HTML to close off a collapsible/expandable group of settings
|
733 |
+
*/
|
734 |
+
function _close_a_field_section(){
|
735 |
+
?>
|
736 |
+
</div>
|
737 |
+
<?php
|
738 |
+
} //end _close_a_field_section()
|
739 |
+
|
740 |
+
}
|
readme.txt
ADDED
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Custom Menu Wizard Widget ===
|
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.
|
10 |
+
|
11 |
+
== Description ==
|
12 |
+
|
13 |
+
This plugin is a boosted version of the WordPress "Custom Menu" widget.
|
14 |
+
It provides full control over most of the parameters available when calling WP's [wp_nav_menu()](http://codex.wordpress.org/Function_Reference/wp_nav_menu) function, as well as providing pre-filtering of the menu items in order to be able to select a specific portion of the custom menu. It also automatically adds a couple of custom classes.
|
15 |
+
|
16 |
+
Features include:
|
17 |
+
|
18 |
+
* Display the entire menu, just a branch of it, or even just a specific level of it
|
19 |
+
* Select a branch based on a specific menu item, or the "current" item (currently displayed page)
|
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 |
+
|
32 |
+
There are quite a few options, which makes the widget settings box very long. I have therefore grouped most of the options into
|
33 |
+
logical sections and made each section collapsible (with remembered state, open by default).
|
34 |
+
|
35 |
+
* **Title**
|
36 |
+
|
37 |
+
Set the title for your widget.
|
38 |
+
|
39 |
+
* **Hide** *(checkbox)*
|
40 |
+
|
41 |
+
Prevents the entered `Title` being displayed in the front-end widget output.
|
42 |
+
|
43 |
+
In the Widgets admin page, I find it useful to still be able to see the `Title` in the sidebar when the widget is collapsed, but I
|
44 |
+
don't necessarily want that `Title` to actually be output when the widget is displayed at the front-end. Hence this checkbox.
|
45 |
+
|
46 |
+
* **Select Menu** *(select)*
|
47 |
+
|
48 |
+
Choose the appropriate menu from the dropdown list of Custom Menus currently defined in your WordPress application. The
|
49 |
+
first one available (alphabetically) is already selected for you by default.
|
50 |
+
|
51 |
+
* **Filter**
|
52 |
+
|
53 |
+
* **Show all** *(radio, default)*
|
54 |
+
|
55 |
+
Don't apply the `Children of` filter. If you check this option, the `Children of` select will be disabled, as will the `Include Parent`,
|
56 |
+
`Include Ancestors` and `Title from Parent Item` checkboxes, as they are only applicable to a `Children of` filter.
|
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**
|
78 |
+
|
79 |
+
* **Hierarchical** *(radio, default)*
|
80 |
+
|
81 |
+
Output in the standard nested list format.
|
82 |
+
|
83 |
+
* **Flat** *(radio)*
|
84 |
+
|
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
|
95 |
+
`Children of` filter.
|
96 |
+
|
97 |
+
* **Title from Parent Item** *(checkbox)*
|
98 |
+
|
99 |
+
Again, this only applies to a successful `Children of` filter. If checked, use the title of the parent item as the widget's
|
100 |
+
title when displaying the output. This will override (ie. ignore) the `Hide` checkbox setting!
|
101 |
+
|
102 |
+
* **Change UL to OL**
|
103 |
+
|
104 |
+
The standard for menus is to use UL (unordered list) elements to display the output. These settings give you the option to swap
|
105 |
+
the ULs out for OLs (ordered lists).
|
106 |
+
|
107 |
+
* **Top Level** *(checkbox)*
|
108 |
+
|
109 |
+
If checked, swap the outermost UL for an OL.
|
110 |
+
|
111 |
+
* **Sub-Levels** *(checkbox)*
|
112 |
+
|
113 |
+
If checked, swap any nested (ie. not the outermost) ULs for an OLs.
|
114 |
+
|
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 |
+
|
121 |
+
* **Element** *(default: "div")*
|
122 |
+
|
123 |
+
This menu list is usually wrapped in a "container" element, and this is the tag for that element. You may change it for another
|
124 |
+
tag, or you may clear it out and the container will be completely removed. Please note that WordPress is set by default to only
|
125 |
+
accept "div" or "nav", but that could be changed or extended by any template or plugin.
|
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 |
+
|
133 |
+
This allows you to add your own class to the container element.
|
134 |
+
|
135 |
+
* **Classes**
|
136 |
+
|
137 |
+
* **Menu Class** *(default: "menu-widget")
|
138 |
+
|
139 |
+
This is the class that will be applied to the list element that holds the entire menu.
|
140 |
+
|
141 |
+
* **Widget Class**
|
142 |
+
|
143 |
+
This allows you to add your own class to the outermost element of the widget, the one that wraps the entire widget output.
|
144 |
+
|
145 |
+
* **Links**
|
146 |
+
|
147 |
+
* **Before the Link**
|
148 |
+
|
149 |
+
Text or HTML that will be placed immediately before each menu item's link.
|
150 |
+
|
151 |
+
* **After the Link**
|
152 |
+
|
153 |
+
Text or HTML that will be placed immediately after each menu item's link.
|
154 |
+
|
155 |
+
* **Before the Link Text**
|
156 |
+
|
157 |
+
Text or HTML that will be placed immediately before each menu item's link text.
|
158 |
+
|
159 |
+
* **After the Link Text**
|
160 |
+
|
161 |
+
Text or HTML that will be placed immediately after each menu item's link text.
|
162 |
+
|
163 |
+
== Installation ==
|
164 |
+
|
165 |
+
1. EITHER Upload the zip package via 'Plugins > Add New > Upload' in your WP Admin
|
166 |
+
|
167 |
+
OR Extract the zip package and upload `custom-menu-wizard` folder to the `/wp-content/plugins/` directory
|
168 |
+
|
169 |
+
1. Activate the plugin through the 'Plugins' menu in your WP Admin
|
170 |
+
|
171 |
+
The widget will now be available in the 'Widgets' admin page.
|
172 |
+
As long as you already have at least one Menu defined, you can add the new widget to a sidebar and configure it however you want.
|
173 |
+
|
174 |
+
== Frequently Asked Questions ==
|
175 |
+
|
176 |
+
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
|