PluginProbe
Responsive Menu – Mobile Menu & Hamburger Menu Builder / 4.7.4
Responsive Menu – Mobile Menu & Hamburger Menu Builder v4.7.4
4.7.4 4.7.3 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.10 4.1.11 4.1.12 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 All 91 releases
responsive-menu / v4.0.0 / inc / classes / class-walker.php

class-walker.php in Responsive Menu – Mobile Menu & Hamburger Menu Builder 4.7.4, at v4.0.0/inc/classes/class-walker.php

404 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This is core class file for responsive menu pro to design the menu
4 * with custom walker with saved settings.
5 *
6 * @since 4.0.0
7 *
8 * @package responsive_menu_pro
9 */
10
11 namespace RMP\Features\Inc;
12
13 /** Disable the direct access to this class */
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Class Walker prepare the menu as per loction and menu id.
20 *
21 * @since 4.0.0
22 * @package responsive_menu_pro
23 *
24 * @author Expresstech System
25 */
26 class Walker extends \Walker_Nav_Menu {
27
28
29 /**
30 * Hold the current menu item.
31 *
32 * @since 4.0.0
33 * @access protected
34 * @var string $current_item
35 */
36 private $current_item;
37
38 /**
39 * Hold the top most item id
40 *
41 * @since 4.0.0
42 * @access protected
43 * @var object
44 */
45 protected $root_item_id;
46
47 /**
48 * This is Walker class constructor function.
49 *
50 * @access public
51 * @param array $option
52 */
53 public function __construct( $options ) {
54 $this->options = $options;
55 }
56
57 /**
58 * Drop the "has children" class from items whose children are not in the list.
59 *
60 * WordPress stamps `menu-item-has-children` on before `wp_nav_menu_objects` runs, so
61 * anything that removes items on that filter - the plugin's own logged-in/logged-out
62 * visibility settings among them - can leave a parent claiming children it no longer
63 * has. The walker would then emit a submenu toggle whose aria-controls points at a
64 * <ul> that is never rendered: a control that announces a collapsed submenu, resolves
65 * to nothing, and does nothing when activated.
66 *
67 * @since 4.7.4
68 * @access public
69 *
70 * @param array $elements Menu item objects.
71 * @param int $max_depth Maximum depth to walk.
72 * @param mixed ...$args Arguments passed through to the parent walker.
73 * @return string
74 */
75 public function walk( $elements, $max_depth, ...$args ) {
76 $has_children = array();
77
78 foreach ( (array) $elements as $element ) {
79 if ( ! empty( $element->menu_item_parent ) ) {
80 $has_children[ intval( $element->menu_item_parent ) ] = true;
81 }
82 }
83
84 foreach ( (array) $elements as $element ) {
85 if ( empty( $element->classes ) || ! empty( $has_children[ intval( $element->ID ) ] ) ) {
86 continue;
87 }
88
89 $element->classes = array_diff( (array) $element->classes, array( 'menu-item-has-children' ) );
90 }
91
92 return parent::walk( $elements, $max_depth, ...$args );
93 }
94
95 /**
96 * Function to create element for menu items.
97 *
98 * @access public
99 * @version 4.0.0
100 *
101 * @param string/HTML $output
102 * @param object $item
103 * @param int $depth
104 * @param array $args
105 * @param int $id
106 */
107 public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
108 $this->set_current_item( $item );
109
110 $classes = array();
111 if ( ! empty( $item->classes ) ) {
112 $classes = (array) $item->classes;
113 }
114
115 $rmp_menu_classes = $classes;
116
117 /** Add rmp menu classes as per item */
118 foreach ( $classes as $class ) {
119 switch ( $class ) {
120 case 'menu-item':
121 $rmp_menu_classes[] = 'rmp-menu-item';
122 break;
123 case 'current-menu-item':
124 $rmp_menu_classes[] = 'rmp-menu-current-item';
125 break;
126 case 'menu-item-has-children':
127 $rmp_menu_classes[] = 'rmp-menu-item-has-children';
128 break;
129 case 'current-menu-parent':
130 $rmp_menu_classes[] = 'rmp-menu-item-current-parent';
131 break;
132 case 'current-menu-ancestor':
133 $rmp_menu_classes[] = 'rmp-menu-item-current-ancestor';
134 break;
135 }
136 }
137
138 // Add top/sub level class as per item.
139 if ( 0 === intval( $item->menu_item_parent ) ) {
140 $rmp_menu_classes[] = 'rmp-menu-top-level-item';
141 $this->root_item_id = $item->ID;
142 } else {
143 $rmp_menu_classes[] = 'rmp-menu-sub-level-item';
144 }
145
146 /* Clear child class if we are at the final depth level */
147 if ( isset( $rmp_menu_classes ) ) {
148 $has_child = array_search( 'rmp-menu-item-has-children', $rmp_menu_classes, true );
149 if ( ( intval( $depth ) + 1 ) === intval( $this->options['menu_depth'] ) && false !== $has_child ) {
150 unset( $rmp_menu_classes[ $has_child ] );
151 }
152 }
153
154 $class_names = join( ' ', array_unique( $rmp_menu_classes ) );
155
156 /** Prepare classes for menu item. */
157 if ( ! empty( $class_names ) ) {
158 $class_names = sprintf( 'class="%s"', esc_attr( $class_names ) );
159 } else {
160 $class_names = '';
161 }
162
163 $class_names = apply_filters( 'rmp_nav_item_class', $class_names, $item );
164
165 // Start menu item and set classes & ID.
166 $output .= sprintf(
167 '<li id="rmp-menu-item-%s" %s>',
168 esc_attr( $item->ID ),
169 $class_names
170 );
171
172 // Set attributes on menu item link.
173 $atts = array();
174 $atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
175 $atts['target'] = ! empty( $item->target ) ? $item->target : '';
176 $atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
177 $atts['href'] = ! empty( $item->url ) ? $item->url : '';
178 $atts['class'] = 'rmp-menu-item-link';
179 $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
180
181 $attributes = '';
182 foreach ( $atts as $key => $value ) {
183 if ( ! empty( $value ) ) {
184 $value = ( 'href' === $key ) ? esc_url( $value ) : esc_attr( $value );
185 $attributes .= sprintf( ' %s="%s" ', $key, $value );
186 }
187 }
188
189 $title = apply_filters( 'the_title', $item->title, $item->ID );
190 $title = apply_filters( 'rmp_menu_item_title', $title, $item, $args, $depth );
191
192 /*
193 * Build the submenu toggle. It is a real <button> that sits beside the link rather
194 * than a <div> inside it: a control nested in an anchor is neither valid HTML nor
195 * reachable by keyboard, so the submenu could only ever be opened with a mouse.
196 */
197 $sub_menu_arrow = '';
198 $has_children = in_array( 'rmp-menu-item-has-children', $rmp_menu_classes, true );
199
200 /* No toggle if we are at the final depth level - there is nothing left to reveal. */
201 if ( intval( $depth ) + 1 === intval( $this->options['menu_depth'] ) ) {
202 $has_children = false;
203 }
204
205 if ( $has_children ) {
206 $is_expanded = ( 'on' === $this->options['auto_expand_all_submenus'] )
207 || (
208 'on' === $this->options['auto_expand_current_submenus'] &&
209 (
210 in_array( 'rmp-menu-item-current-parent', $rmp_menu_classes, true ) ||
211 in_array( 'rmp-menu-item-current-ancestor', $rmp_menu_classes, true )
212 )
213 );
214
215 $arrow_classes = 'rmp-menu-subarrow';
216 if ( $is_expanded ) {
217 $arrow_classes .= ' rmp-menu-subarrow-active';
218 }
219
220 /* translators: %s: Title of the menu item the submenu belongs to. */
221 $toggle_label = sprintf( __( 'Toggle submenu of %s', 'responsive-menu' ), wp_strip_all_tags( $title ) );
222
223 /**
224 * Filters the accessible name of a submenu toggle button.
225 *
226 * @since 4.7.4
227 *
228 * @param string $toggle_label Accessible name announced by screen readers.
229 * @param object $item Menu item object.
230 * @param int $depth Depth of the menu item.
231 */
232 $toggle_label = apply_filters( 'rmp_submenu_toggle_label', $toggle_label, $item, $depth );
233
234 $sub_menu_arrow = sprintf(
235 '<button type="button" class="%1$s" aria-expanded="%2$s" aria-controls="rmp-submenu-%3$s" aria-label="%4$s">%5$s</button>',
236 esc_attr( $arrow_classes ),
237 $is_expanded ? 'true' : 'false',
238 esc_attr( $item->ID ),
239 esc_attr( $toggle_label ),
240 rm_sanitize_html_tags( $is_expanded ? $this->get_active_arrow() : $this->get_inactive_arrow() )
241 );
242 }
243
244 $item_output = '';
245 $item_output .= sprintf( '<a %s >', $attributes );
246 $item_output .= $title;
247 $item_output .= '</a>';
248 $item_output .= $sub_menu_arrow;
249
250 // If description is enable then add it below of menu item.
251 if ( ! empty( $item->description ) && 'on' === $this->options['submenu_descriptions_on'] ) {
252 $item_output .= sprintf( '<p class="rmp-menu-item-description"> %s </p>', esc_html( $item->description ) );
253 }
254
255 // Theme support for twenty twenty one.
256 if ( function_exists( 'twenty_twenty_one_add_sub_menu_toggle' ) ) {
257 remove_filter( 'walker_nav_menu_start_el', 'twenty_twenty_one_add_sub_menu_toggle', 10 );
258 remove_filter( 'walker_nav_menu_start_el', 'twenty_twenty_one_nav_menu_social_icons', 10 );
259 }
260
261 /* End Add Desktop Menu Widgets to Sub Items */
262 $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
263 }
264
265 /**
266 * Function to build the sub-menu items.
267 *
268 * @since 4.0.0
269 * @access public
270 *
271 * @param string|HTML $output
272 * @param int $depth
273 * @param array $args
274 */
275 public function start_lvl( &$output, $depth = 0, $args = array() ) {
276
277 /*
278 * Add sub-menu item wrap. The id is what the parent item's toggle button points at
279 * with aria-controls, and role="menu" is deliberately absent: this is site
280 * navigation, not an application menu with roving-tabindex semantics.
281 */
282 $output .= sprintf(
283 '<ul id="rmp-submenu-%1$s" aria-label="%2$s" data-depth="%3$s" class="rmp-submenu rmp-submenu-depth-%4$s">',
284 esc_attr( $this->current_item->ID ),
285 esc_attr( $this->current_item->title ),
286 ( $depth + 2 ),
287 ( $depth + 1 ) . $this->get_submenu_class_open_or_not()
288 );
289 }
290
291 /**
292 * Function to close the menu item.
293 *
294 * @access public
295 * @version 4.0.0
296 *
297 * @param string/HTML $output
298 * @param object $item
299 * @param int $depth
300 * @param array $args
301 */
302 public function end_el( &$output, $item, $depth = 0, $args = array() ) {
303 $output .= '</li>';
304 }
305
306 /**
307 * Function to close the sub-menu items.
308 *
309 * @since 4.0.0
310 * @access public
311 *
312 * @param string|HTML $output
313 * @param int $depth
314 * @param array $args
315 */
316 public function end_lvl( &$output, $depth = 0, $args = array() ) {
317 $output .= '</ul>';
318 }
319
320 /**
321 * Function get the active item toggle icon.
322 *
323 * @return HTML
324 */
325 public function get_active_arrow() {
326 if ( ! empty( $this->options['active_arrow_font_icon'] ) ) {
327 return $this->options['active_arrow_font_icon'];
328 } elseif ( ! empty( $this->options['active_arrow_image'] ) ) {
329 return sprintf(
330 '<img alt="%s" src="%s" />',
331 rmp_image_alt_by_url( $this->options['active_arrow_image'] ),
332 esc_url( $this->options['active_arrow_image'] )
333 );
334 } else {
335 return $this->options['active_arrow_shape'];
336 }
337 }
338
339 /**
340 * Function get the inactive item toggle icon.
341 *
342 * @return HTML
343 */
344 public function get_inactive_arrow() {
345 if ( ! empty( $this->options['inactive_arrow_font_icon'] ) ) {
346 return $this->options['inactive_arrow_font_icon'];
347 } elseif ( ! empty( $this->options['inactive_arrow_image'] ) ) {
348 return sprintf(
349 '<img alt="%s" src="%s" />',
350 rmp_image_alt_by_url( $this->options['inactive_arrow_image'] ),
351 esc_url( $this->options['inactive_arrow_image'] )
352 );
353 } else {
354 return $this->options['inactive_arrow_shape'];
355 }
356 }
357
358 /**
359 * Function to set the current item object.
360 *
361 * @param object $item Menu item object.
362 */
363 public function set_current_item( $item ) {
364 $this->current_item = $item;
365 }
366
367 /**
368 * Function to return the current item object.
369 *
370 * @return object $item Menu item object.
371 */
372 public function get_current_item() {
373 return $this->current_item;
374 }
375
376 /**
377 * Check submenu need to open or not.
378 *
379 * @return boolean
380 */
381 public function get_submenu_class_open_or_not() {
382 return $this->expand_all_submenu_options_is_on() || $this->expand_current_submenu_on_and_item_is_parent() ? ' rmp-submenu-open' : '';
383 }
384
385 /**
386 * Check all submenu need to open or not.
387 *
388 * @return boolean
389 */
390 public function expand_all_submenu_options_is_on() {
391 return 'on' === $this->options['auto_expand_all_submenus'];
392 }
393
394 /**
395 * Check current submenu need to open or not.
396 *
397 * @return boolean
398 */
399 public function expand_current_submenu_on_and_item_is_parent() {
400 return ( 'on' === $this->options['auto_expand_current_submenus'] )
401 && ( $this->get_current_item()->current_item_ancestor || $this->get_current_item()->current_item_parent );
402 }
403 }
404