Completed
Pull Request — master (#422)
by
unknown
09:17
created

class-wp-bootstrap-navwalker.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
0 ignored issues
show
It is not recommended to output anything before PHP's opening tag in non-template files.
Loading history...
2
<?php
3
/**
4
 * WP Bootstrap Navwalker
5
 *
6
 * @package WP-Bootstrap-Navwalker
7
 */
8
/*
9
 * Class Name: WP_Bootstrap_Navwalker
10
 * Plugin Name: WP Bootstrap Navwalker
11
 * Plugin URI:  https://github.com/wp-bootstrap/wp-bootstrap-navwalker
12
 * Description: A custom WordPress nav walker class to implement the Bootstrap 4 navigation style in a custom theme using the WordPress built in menu manager.
13
 * Author: Edward McIntyre - @twittem, WP Bootstrap, William Patton - @pattonwebz
14
 * Version: 4.1.0
15
 * Author URI: https://github.com/wp-bootstrap
16
 * GitHub Plugin URI: https://github.com/wp-bootstrap/wp-bootstrap-navwalker
17
 * GitHub Branch: master
18
 * License: GPL-3.0+
19
 * License URI: http://www.gnu.org/licenses/gpl-3.0.txt
20
*/
21
/* Check if Class Exists. */
22
if ( ! class_exists( 'WP_Bootstrap_Navwalker' ) ) {
23
	/**
24
	 * WP_Bootstrap_Navwalker class.
25
	 *
26
	 * @extends Walker_Nav_Menu
27
	 */
28
	class WP_Bootstrap_Navwalker extends Walker_Nav_Menu {
29
		/**
30
		 * Starts the list before the elements are added.
31
		 *
32
		 * @since WP 3.0.0
33
		 *
34
		 * @see Walker_Nav_Menu::start_lvl()
35
		 *
36
		 * @param string   $output Used to append additional content (passed by reference).
37
		 * @param int      $depth  Depth of menu item. Used for padding.
38
		 * @param stdClass $args   An object of wp_nav_menu() arguments.
39
		 */
40
		public function start_lvl( &$output, $depth = 0, $args = array() ) {
41 View Code Duplication
			if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
42
				$t = '';
43
				$n = '';
44
			} else {
45
				$t = "\t";
46
				$n = "\n";
47
			}
48
			$indent = str_repeat( $t, $depth );
49
			// Default class to add to the file.
50
			$classes = array( 'dropdown-menu' );
51
			/**
52
			 * Filters the CSS class(es) applied to a menu list element.
53
			 *
54
			 * @since WP 4.8.0
55
			 *
56
			 * @param array    $classes The CSS classes that are applied to the menu `<ul>` element.
57
			 * @param stdClass $args    An object of `wp_nav_menu()` arguments.
58
			 * @param int      $depth   Depth of menu item. Used for padding.
59
			 */
60
			$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
61
			$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
62
			/**
63
			 * The `.dropdown-menu` container needs to have a labelledby
64
			 * attribute which points to it's trigger link.
65
			 *
66
			 * Form a string for the labelledby attribute from the the latest
67
			 * link with an id that was added to the $output.
68
			 */
69
			$labelledby = '';
70
			// find all links with an id in the output.
71
			preg_match_all( '/(<a.*?id=\"|\')(.*?)\"|\'.*?>/im', $output, $matches );
72
			// with pointer at end of array check if we got an ID match.
73
			if ( end( $matches[2] ) ) {
74
				// build a string to use as aria-labelledby.
75
				$labelledby = 'aria-labelledby="' . end( $matches[2] ) . '"';
76
			}
77
			$output .= "{$n}{$indent}<ul$class_names $labelledby role=\"menu\">{$n}";
78
		}
79
		/**
80
		 * Starts the element output.
81
		 *
82
		 * @since WP 3.0.0
83
		 * @since WP 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
84
		 *
85
		 * @see Walker_Nav_Menu::start_el()
86
		 *
87
		 * @param string   $output Used to append additional content (passed by reference).
88
		 * @param WP_Post  $item   Menu item data object.
89
		 * @param int      $depth  Depth of menu item. Used for padding.
90
		 * @param stdClass $args   An object of wp_nav_menu() arguments.
91
		 * @param int      $id     Current item ID.
92
		 */
93
		public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
94 View Code Duplication
			if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
95
				$t = '';
96
				$n = '';
97
			} else {
98
				$t = "\t";
99
				$n = "\n";
100
			}
101
			$indent = ( $depth ) ? str_repeat( $t, $depth ) : '';
102
			$classes = empty( $item->classes ) ? array() : (array) $item->classes;
103
			// Initialize some holder variables to store specially handled item
104
			// wrappers and icons.
105
			$linkmod_classes = array();
106
			$icon_classes    = array();
107
			/**
108
			 * Get an updated $classes array without linkmod or icon classes.
109
			 *
110
			 * NOTE: linkmod and icon class arrays are passed by reference and
111
			 * are maybe modified before being used later in this function.
112
			 */
113
			$classes = self::separate_linkmods_and_icons_from_classes( $classes, $linkmod_classes, $icon_classes, $depth );
114
			// Join any icon classes plucked from $classes into a string.
115
			$icon_class_string = join( ' ', $icon_classes );
116
			/**
117
			 * Filters the arguments for a single nav menu item.
118
			 *
119
			 *  WP 4.4.0
120
			 *
121
			 * @param stdClass $args  An object of wp_nav_menu() arguments.
122
			 * @param WP_Post  $item  Menu item data object.
123
			 * @param int      $depth Depth of menu item. Used for padding.
124
			 */
125
			$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
126
			// Add .dropdown or .active classes where they are needed.
127
			if ( isset( $args->has_children ) && $args->has_children ) {
128
				$classes[] = 'dropdown';
129
			}
130
			if ( in_array( 'current-menu-item', $classes, true ) || in_array( 'current-menu-parent', $classes, true ) ) {
131
				$classes[] = 'active';
132
			}
133
			// Add some additional default classes to the item.
134
			$classes[] = 'menu-item-' . $item->ID;
135
			$classes[] = 'nav-item';
136
			// Allow filtering the classes.
137
			$classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );
138
			// Form a string of classes in format: class="class_names".
139
			$class_names = join( ' ', $classes );
140
			$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
141
			/**
142
			 * Filters the ID applied to a menu item's list item element.
143
			 *
144
			 * @since WP 3.0.1
145
			 * @since WP 4.1.0 The `$depth` parameter was added.
146
			 *
147
			 * @param string   $menu_id The ID that is applied to the menu item's `<li>` element.
148
			 * @param WP_Post  $item    The current menu item.
149
			 * @param stdClass $args    An object of wp_nav_menu() arguments.
150
			 * @param int      $depth   Depth of menu item. Used for padding.
151
			 */
152
			$id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth );
153
			$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
154
			$output .= $indent . '<li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement"' . $id . $class_names . '>';
155
			// initialize array for holding the $atts for the link item.
156
			$atts = array();
157
			// Set title from item to the $atts array - if title is empty then
158
			// default to item title.
159
			if ( empty( $item->attr_title ) ) {
160
				$atts['title'] = ! empty( $item->title ) ? strip_tags( $item->title ) : '';
161
			} else {
162
				$atts['title'] = $item->attr_title;
163
			}
164
			$atts['target'] = ! empty( $item->target ) ? $item->target : '';
165
			$atts['rel']    = ! empty( $item->xfn ) ? $item->xfn : '';
166
			// If item has_children add atts to <a>.
167
			if ( isset( $args->has_children ) && $args->has_children && 0 === $depth && $args->depth > 1 ) {
168
				$atts['href']          = '#';
169
				$atts['data-toggle']   = 'dropdown';
170
				$atts['aria-haspopup'] = 'true';
171
				$atts['aria-expanded'] = 'false';
172
				$atts['class']         = 'dropdown-toggle nav-link';
173
				$atts['id']            = 'menu-item-dropdown-' . $item->ID;
174
			} else {
175
				$atts['href'] = ! empty( $item->url ) ? $item->url : '#';
176
				// Items in dropdowns use .dropdown-item instead of .nav-link.
177
				if ( $depth > 0 ) {
178
					$atts['class'] = 'dropdown-item';
179
				} else {
180
					$atts['class'] = 'nav-link';
181
				}
182
			}
183
184
185
			// update atts of this item based on any custom linkmod classes.
186
			$atts = self::update_atts_for_linkmod_type( $atts, $linkmod_classes );
187
			// Allow filtering of the $atts array before using it.
188
			$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
189
			// Build a string of html containing all the atts for the item.
190
			$attributes = '';
191
			foreach ( $atts as $attr => $value ) {
192
				if ( ! empty( $value ) ) {
193
					$value       = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
194
					$attributes .= ' ' . $attr . '="' . $value . '"';
195
				}
196
			}
197
			/**
198
			 * Set a typeflag to easily test if this is a linkmod or not.
199
			 */
200
			$linkmod_type = self::get_linkmod_type( $linkmod_classes );
201
			/**
202
			 * START appending the internal item contents to the output.
203
			 */
204
			$item_output = isset( $args->before ) ? $args->before : '';
205
			/**
206
			 * This is the start of the internal nav item. Depending on what
207
			 * kind of linkmod we have we may need different wrapper elements.
208
			 */
209
			if ( '' !== $linkmod_type ) {
210
				// is linkmod, output the required element opener.
211
				$item_output .= self::linkmod_element_open( $linkmod_type, $attributes );
212
			} else {
213
				// With no link mod type set this must be a standard <a> tag.
214
				$item_output .= '<a' . $attributes . '>';
215
			}
216
			/**
217
			 * Initiate empty icon var, then if we have a string containing any
218
			 * icon classes form the icon markup with an <i> element. This is
219
			 * output inside of the item before the $title (the link text).
220
			 */
221
			$icon_html = '';
222
			if ( ! empty( $icon_class_string ) ) {
223
				// append an <i> with the icon classes to what is output before links.
224
				$icon_html = '<i class="' . esc_attr( $icon_class_string ) . '" aria-hidden="true"></i> ';
225
			}
226
			/** This filter is documented in wp-includes/post-template.php */
227
			$title = apply_filters( 'the_title', $item->title, $item->ID );
228
			/**
229
			 * Filters a menu item's title.
230
			 *
231
			 * @since WP 4.4.0
232
			 *
233
			 * @param string   $title The menu item's title.
234
			 * @param WP_Post  $item  The current menu item.
235
			 * @param stdClass $args  An object of wp_nav_menu() arguments.
236
			 * @param int      $depth Depth of menu item. Used for padding.
237
			 */
238
			$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
239
			/**
240
			 * If the .sr-only class was set apply to the nav items text only.
241
			 */
242
			if ( in_array( 'sr-only', $linkmod_classes, true ) ) {
243
				$title         = self::wrap_for_screen_reader( $title );
244
				$keys_to_unset = array_keys( $linkmod_classes, 'sr-only' );
245
				foreach ( $keys_to_unset as $k ) {
246
					unset( $linkmod_classes[ $k ] );
247
				}
248
			}
249
			/** add description item */
250
			if (!empty($item->description)){
251
				$object = $item->object;
0 ignored issues
show
$object is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
252
				$type = $item->type;
0 ignored issues
show
$type is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
253
				$title = $item->title;
254
				$description = $item->description;
255
				$permalink = $item->url;
0 ignored issues
show
$permalink is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
256
257
258
				if( $description != '' && $depth == 0 ) {
259
					$output .= '<small class="nav-description">' . $description . '</small>';
260
				}
261
			}
262
			// Put the item contents into $output.
263
			$item_output .= isset( $args->link_before ) ? $args->link_before . $icon_html . $title . $args->link_after : '';
264
			/**
265
			 * This is the end of the internal nav item. We need to close the
266
			 * correct element depending on the type of link or link mod.
267
			 */
268
			if ( '' !== $linkmod_type ) {
269
				// is linkmod, output the required element opener.
270
				$item_output .= self::linkmod_element_close( $linkmod_type, $attributes );
271
			} else {
272
				// With no link mod type set this must be a standard <a> tag.
273
				$item_output .= '</a>';
274
			}
275
			$item_output .= isset( $args->after ) ? $args->after : '';
276
			/**
277
			 * END appending the internal item contents to the output.
278
			 */
279
			$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
280
		}
281
282
		/**
283
		 * Traverse elements to create list from elements.
284
		 *
285
		 * Display one element if the element doesn't have any children otherwise,
286
		 * display the element and its children. Will only traverse up to the max
287
		 * depth and no ignore elements under that depth. It is possible to set the
288
		 * max depth to include all depths, see walk() method.
289
		 *
290
		 * This method should not be called directly, use the walk() method instead.
291
		 *
292
		 * @since WP 2.5.0
293
		 *
294
		 * @see Walker::start_lvl()
295
		 *
296
		 * @param object $element           Data object.
297
		 * @param array  $children_elements List of elements to continue traversing (passed by reference).
298
		 * @param int    $max_depth         Max depth to traverse.
299
		 * @param int    $depth             Depth of current element.
300
		 * @param array  $args              An array of arguments.
301
		 * @param string $output            Used to append additional content (passed by reference).
302
		 */
303
		public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
304
			if ( ! $element ) {
305
				return; }
306
			$id_field = $this->db_fields['id'];
307
			// Display this element.
308
			if ( is_object( $args[0] ) ) {
309
				$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] ); }
310
			parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
311
		}
312
		/**
313
		 * Menu Fallback
314
		 * =============
315
		 * If this function is assigned to the wp_nav_menu's fallback_cb variable
316
		 * and a menu has not been assigned to the theme location in the WordPress
317
		 * menu manager the function with display nothing to a non-logged in user,
318
		 * and will add a link to the WordPress menu manager if logged in as an admin.
319
		 *
320
		 * @param array $args passed from the wp_nav_menu function.
321
		 */
322
		public static function fallback( $args ) {
323
			if ( current_user_can( 'edit_theme_options' ) ) {
324
				/* Get Arguments. */
325
				$container       = $args['container'];
326
				$container_id    = $args['container_id'];
327
				$container_class = $args['container_class'];
328
				$menu_class      = $args['menu_class'];
329
				$menu_id         = $args['menu_id'];
330
				// initialize var to store fallback html.
331
				$fallback_output = '';
332
				if ( $container ) {
333
					$fallback_output .= '<' . esc_attr( $container );
334
					if ( $container_id ) {
335
						$fallback_output .= ' id="' . esc_attr( $container_id ) . '"';
336
					}
337
					if ( $container_class ) {
338
						$fallback_output .= ' class="' . esc_attr( $container_class ) . '"';
339
					}
340
					$fallback_output .= '>';
341
				}
342
				$fallback_output .= '<ul';
343
				if ( $menu_id ) {
344
					$fallback_output .= ' id="' . esc_attr( $menu_id ) . '"'; }
345
				if ( $menu_class ) {
346
					$fallback_output .= ' class="' . esc_attr( $menu_class ) . '"'; }
347
				$fallback_output .= '>';
348
				$fallback_output .= '<li><a href="' . esc_url( admin_url( 'nav-menus.php' ) ) . '" title="' . esc_attr__( 'Add a menu', 'wp-bootstrap-navwalker' ) . '">' . esc_html__( 'Add a menu', 'wp-bootstrap-navwalker' ) . '</a></li>';
349
				$fallback_output .= '</ul>';
350
				if ( $container ) {
351
					$fallback_output .= '</' . esc_attr( $container ) . '>';
352
				}
353
				// if $args has 'echo' key and it's true echo, otherwise return.
354
				if ( array_key_exists( 'echo', $args ) && $args['echo'] ) {
355
					echo $fallback_output; // WPCS: XSS OK.
356
				} else {
357
					return $fallback_output;
358
				}
359
			}
360
		}
361
		/**
362
		 * Find any custom linkmod or icon classes and store in their holder
363
		 * arrays then remove them from the main classes array.
364
		 *
365
		 * Supported linkmods: .disabled, .dropdown-header, .dropdown-divider, .sr-only
366
		 * Supported iconsets: Font Awesome 4/5, Glypicons
367
		 *
368
		 * NOTE: This accepts the linkmod and icon arrays by reference.
369
		 *
370
		 * @since 4.0.0
371
		 *
372
		 * @param array   $classes         an array of classes currently assigned to the item.
373
		 * @param array   $linkmod_classes an array to hold linkmod classes.
374
		 * @param array   $icon_classes    an array to hold icon classes.
375
		 * @param integer $depth           an integer holding current depth level.
376
		 *
377
		 * @return array  $classes         a maybe modified array of classnames.
378
		 */
379
		private function separate_linkmods_and_icons_from_classes( $classes, &$linkmod_classes, &$icon_classes, $depth ) {
380
			// Loop through $classes array to find linkmod or icon classes.
381
			foreach ( $classes as $key => $class ) {
382
				// If any special classes are found, store the class in it's
383
				// holder array and and unset the item from $classes.
384
				if ( preg_match( '/^disabled|^sr-only/i', $class ) ) {
385
					// Test for .disabled or .sr-only classes.
386
					$linkmod_classes[] = $class;
387
					unset( $classes[ $key ] );
388
				} elseif ( preg_match( '/^dropdown-header|^dropdown-divider|^dropdown-item-text/i', $class ) && $depth > 0 ) {
389
					// Test for .dropdown-header or .dropdown-divider and a
390
					// depth greater than 0 - IE inside a dropdown.
391
					$linkmod_classes[] = $class;
392
					unset( $classes[ $key ] );
393
				} elseif ( preg_match( '/^fa-(\S*)?|^fa(s|r|l|b)?(\s?)?$/i', $class ) ) {
394
					// Font Awesome.
395
					$icon_classes[] = $class;
396
					unset( $classes[ $key ] );
397
				} elseif ( preg_match( '/^glyphicon-(\S*)?|^glyphicon(\s?)$/i', $class ) ) {
398
					// Glyphicons.
399
					$icon_classes[] = $class;
400
					unset( $classes[ $key ] );
401
				}
402
			}
403
			return $classes;
404
		}
405
		/**
406
		 * Return a string containing a linkmod type and update $atts array
407
		 * accordingly depending on the decided.
408
		 *
409
		 * @since 4.0.0
410
		 *
411
		 * @param array $linkmod_classes array of any link modifier classes.
412
		 *
413
		 * @return string                empty for default, a linkmod type string otherwise.
414
		 */
415
		private function get_linkmod_type( $linkmod_classes = array() ) {
416
			$linkmod_type = '';
417
			// Loop through array of linkmod classes to handle their $atts.
418
			if ( ! empty( $linkmod_classes ) ) {
419
				foreach ( $linkmod_classes as $link_class ) {
420
					if ( ! empty( $link_class ) ) {
421
						// check for special class types and set a flag for them.
422
						if ( 'dropdown-header' === $link_class ) {
423
							$linkmod_type = 'dropdown-header';
424
						} elseif ( 'dropdown-divider' === $link_class ) {
425
							$linkmod_type = 'dropdown-divider';
426
						} elseif ( 'dropdown-item-text' === $link_class ) {
427
							$linkmod_type = 'dropdown-item-text';
428
						}
429
					}
430
				}
431
			}
432
			return $linkmod_type;
433
		}
434
		/**
435
		 * Update the attributes of a nav item depending on the limkmod classes.
436
		 *
437
		 * @since 4.0.0
438
		 *
439
		 * @param array $atts            array of atts for the current link in nav item.
440
		 * @param array $linkmod_classes an array of classes that modify link or nav item behaviors or displays.
441
		 *
442
		 * @return array                 maybe updated array of attributes for item.
443
		 */
444
		private function update_atts_for_linkmod_type( $atts = array(), $linkmod_classes = array() ) {
445
			if ( ! empty( $linkmod_classes ) ) {
446
				foreach ( $linkmod_classes as $link_class ) {
447
					if ( ! empty( $link_class ) ) {
448
						// update $atts with a space and the extra classname...
449
						// so long as it's not a sr-only class.
450
						if ( 'sr-only' !== $link_class ) {
451
							$atts['class'] .= ' ' . esc_attr( $link_class );
452
						}
453
						// check for special class types we need additional handling for.
454
						if ( 'disabled' === $link_class ) {
455
							// Convert link to '#' and unset open targets.
456
							$atts['href'] = '#';
457
							unset( $atts['target'] );
458
						} elseif ( 'dropdown-header' === $link_class || 'dropdown-divider' === $link_class || 'dropdown-item-text' === $link_class ) {
459
							// Store a type flag and unset href and target.
460
							unset( $atts['href'] );
461
							unset( $atts['target'] );
462
						}
463
					}
464
				}
465
			}
466
			return $atts;
467
		}
468
		/**
469
		 * Wraps the passed text in a screen reader only class.
470
		 *
471
		 * @since 4.0.0
472
		 *
473
		 * @param string $text the string of text to be wrapped in a screen reader class.
474
		 * @return string      the string wrapped in a span with the class.
475
		 */
476
		private function wrap_for_screen_reader( $text = '' ) {
477
			if ( $text ) {
478
				$text = '<span class="sr-only">' . $text . '</span>';
479
			}
480
			return $text;
481
		}
482
		/**
483
		 * Returns the correct opening element and attributes for a linkmod.
484
		 *
485
		 * @since 4.0.0
486
		 *
487
		 * @param string $linkmod_type a sting containing a linkmod type flag.
488
		 * @param string $attributes   a string of attributes to add to the element.
489
		 *
490
		 * @return string              a string with the openign tag for the element with attribibutes added.
491
		 */
492
		private function linkmod_element_open( $linkmod_type, $attributes = '' ) {
493
			$output = '';
494
			if ( 'dropdown-item-text' === $linkmod_type ) {
495
				$output .= '<span class="dropdown-item-text"' . $attributes . '>';
496
			} elseif ( 'dropdown-header' === $linkmod_type ) {
497
				// For a header use a span with the .h6 class instead of a real
498
				// header tag so that it doesn't confuse screen readers.
499
				$output .= '<span class="dropdown-header h6"' . $attributes . '>';
500
			} elseif ( 'dropdown-divider' === $linkmod_type ) {
501
				// this is a divider.
502
				$output .= '<div class="dropdown-divider"' . $attributes . '>';
503
			}
504
			return $output;
505
		}
506
		/**
507
		 * Return the correct closing tag for the linkmod element.
508
		 *
509
		 * @since 4.0.0
510
		 *
511
		 * @param string $linkmod_type a string containing a special linkmod type.
512
		 *
513
		 * @return string              a string with the closing tag for this linkmod type.
514
		 */
515
		private function linkmod_element_close( $linkmod_type ) {
516
			$output = '';
517
			if ( 'dropdown-header' === $linkmod_type || 'dropdown-item-text' === $linkmod_type ) {
518
				// For a header use a span with the .h6 class instead of a real
519
				// header tag so that it doesn't confuse screen readers.
520
				$output .= '</span>';
521
			} elseif ( 'dropdown-divider' === $linkmod_type ) {
522
				// this is a divider.
523
				$output .= '</div>';
524
			}
525
			return $output;
526
		}
527
	}
528
}
529