PluginProbe
Menu Icons by Themeisle – Add Icons to Navigation Menus / 0.13.13
Menu Icons by Themeisle – Add Icons to Navigation Menus v0.13.13
0.13.24 trunk 0.1.0 0.1.1 0.1.2 0.1.3 0.1.4 0.1.5 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.11.2 0.11.3 0.11.4 0.11.5 0.12.0 0.12.1 0.12.10 0.12.11 0.12.12 0.12.2 0.12.3 0.12.4 All 70 releases
menu-icons / includes / front.php
front.php
517 lines 13.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Front end functionalities
5 *
6 * @package Menu_Icons
7 * @author Dzikri Aziz <kvcrvt@gmail.com>
8 */
9 final class Menu_Icons_Front_End {
10
11 /**
12 * Icon types
13 *
14 * @since 0.9.0
15 * @access protected
16 * @var array
17 */
18 protected static $icon_types = array();
19
20 /**
21 * Default icon style
22 *
23 * @since 0.9.0
24 * @access protected
25 * @var array
26 */
27 protected static $default_style = array(
28 'font_size' => array(
29 'property' => 'font-size',
30 'value' => '1.2',
31 'unit' => 'em',
32 ),
33 'vertical_align' => array(
34 'property' => 'vertical-align',
35 'value' => 'middle',
36 'unit' => null,
37 ),
38 'svg_width' => array(
39 'property' => 'width',
40 'value' => '1',
41 'unit' => 'em',
42 ),
43 );
44
45 /**
46 * Hidden label class
47 *
48 * @since 0.9.0
49 * @access protected
50 * @var string
51 */
52 protected static $hidden_label_class = 'visuallyhidden';
53
54
55 /**
56 * Add hooks for front-end functionalities
57 *
58 * @since 0.9.0
59 */
60 public static function init() {
61 $active_types = Menu_Icons_Settings::get( 'global', 'icon_types' );
62
63 if ( empty( $active_types ) ) {
64 return;
65 }
66
67 foreach ( Menu_Icons::get( 'types' ) as $type ) {
68 if ( in_array( $type->id, $active_types, true ) ) {
69 self::$icon_types[ $type->id ] = $type;
70 }
71 }
72
73 /**
74 * Allow themes/plugins to override the hidden label class
75 *
76 * @since 0.8.0
77 * @param string $hidden_label_class Hidden label class.
78 * @return string
79 */
80 self::$hidden_label_class = apply_filters( 'menu_icons_hidden_label_class', self::$hidden_label_class );
81
82 /**
83 * Allow themes/plugins to override default inline style
84 *
85 * @since 0.9.0
86 * @param array $default_style Default inline style.
87 * @return array
88 */
89 self::$default_style = apply_filters( 'menu_icons_default_style', self::$default_style );
90
91 add_action( 'wp_enqueue_scripts', array( __CLASS__, '_enqueue_styles' ), 4 );
92 add_filter( 'wp_nav_menu_args', array( __CLASS__, '_add_menu_item_title_filter' ) );
93 add_filter( 'wp_nav_menu', array( __CLASS__, '_remove_menu_item_title_filter' ) );
94 }
95
96
97 /**
98 * Get nav menu ID based on arguments passed to wp_nav_menu()
99 *
100 * @since 0.3.0
101 * @param array $args wp_nav_menu() Arguments
102 * @return mixed Nav menu ID or FALSE on failure
103 */
104 public static function get_nav_menu_id( $args ) {
105 $args = (object) $args;
106 $menu = wp_get_nav_menu_object( $args->menu );
107
108 // Get the nav menu based on the theme_location
109 if ( ! $menu
110 && $args->theme_location
111 && ( $locations = get_nav_menu_locations() )
112 && isset( $locations[ $args->theme_location ] )
113 ) {
114 $menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
115 }
116
117 // get the first menu that has items if we still can't find a menu
118 if ( ! $menu && ! $args->theme_location ) {
119 $menus = wp_get_nav_menus();
120 foreach ( $menus as $menu_maybe ) {
121 if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
122 $menu = $menu_maybe;
123 break;
124 }
125 }
126 }
127
128 if ( is_object( $menu ) && ! is_wp_error( $menu ) ) {
129 return $menu->term_id;
130 } else {
131 return false;
132 }
133 }
134
135
136 /**
137 * Enqueue stylesheets
138 *
139 * @since 0.1.0
140 * @wp_hook action wp_enqueue_scripts
141 * @link http://codex.wordpress.org/Plugin_API/Action_Reference/wp_enqueue_scripts
142 */
143 public static function _enqueue_styles() {
144 // Deregister icon picker plugin font-awesome style and re-register with the new handler to avoid other plugin/theme style handler conflict.
145 $wp_styles = wp_styles();
146 if ( $wp_styles && isset( $wp_styles->registered['font-awesome'] ) ) {
147 $registered = $wp_styles->registered['font-awesome'];
148 if ( strpos( $registered->src, Menu_Icons::get( 'url' ) ) !== false ) {
149 $wp_styles->remove( 'font-awesome' );
150 $registered->ver = Menu_Icons_Font_Awesome::$version;
151 $wp_styles->add( 'menu-icon-' . $registered->handle, $registered->src, $registered->deps, $registered->ver, $registered->args );
152 }
153 }
154
155 foreach ( self::$icon_types as $type ) {
156 $stylesheet_id = $type->stylesheet_id;
157 if ( 'font-awesome' === $stylesheet_id ) {
158 $stylesheet_id = 'menu-icon-' . $stylesheet_id;
159 }
160 if ( wp_style_is( $stylesheet_id, 'registered' ) ) {
161 wp_enqueue_style( $stylesheet_id );
162 }
163 }
164
165 /**
166 * Allow plugins/themes to override the extra stylesheet location
167 *
168 * @since 0.9.0
169 * @param string $extra_stylesheet_uri Extra stylesheet URI.
170 */
171 $extra_stylesheet_uri = apply_filters(
172 'menu_icons_extra_stylesheet_uri',
173 sprintf( '%scss/extra%s.css', Menu_Icons::get( 'url' ), kucrut_get_script_suffix() )
174 );
175
176 wp_enqueue_style(
177 'menu-icons-extra',
178 $extra_stylesheet_uri,
179 false,
180 Menu_Icons::VERSION
181 );
182 }
183
184
185 /**
186 * Add filter to 'the_title' hook
187 *
188 * We need to filter the menu item title but **not** regular post titles.
189 * Thus, we're adding the filter when `wp_nav_menu()` is called.
190 *
191 * @since 0.1.0
192 * @wp_hook filter wp_nav_menu_args
193 * @param array $args Not used.
194 *
195 * @return array
196 */
197 public static function _add_menu_item_title_filter( $args ) {
198 add_filter( 'the_title', array( __CLASS__, '_add_icon' ), 999, 2 );
199 add_filter( 'megamenu_the_title', array( __CLASS__, '_add_icon' ), 999, 2 );
200 add_filter( 'megamenu_nav_menu_css_class', array( __CLASS__, '_add_menu_item_class' ), 10, 3 );
201
202 return $args;
203 }
204
205
206 /**
207 * Remove filter from 'the_title' hook
208 *
209 * Because we don't want to filter post titles, we need to remove our
210 * filter when `wp_nav_menu()` exits.
211 *
212 * @since 0.1.0
213 * @wp_hook filter wp_nav_menu
214 * @param array $nav_menu Not used.
215 * @return array
216 */
217 public static function _remove_menu_item_title_filter( $nav_menu ) {
218 remove_filter( 'the_title', array( __CLASS__, '_add_icon' ), 999, 2 );
219 remove_filter( 'megamenu_the_title', array( __CLASS__, '_add_icon' ), 999, 2 );
220 remove_filter( 'megamenu_nav_menu_css_class', array( __CLASS__, '_add_menu_item_class' ), 10, 3 );
221 return $nav_menu;
222 }
223
224
225 /**
226 * Add icon to menu item title
227 *
228 * @since 0.1.0
229 * @since 0.9.0 Renamed the method to `add_icon()`.
230 * @wp_hook filter the_title
231 * @param string $title Menu item title.
232 * @param int $id Menu item ID.
233 *
234 * @return string
235 */
236 public static function _add_icon( $title, $id ) {
237 $meta = Menu_Icons_Meta::get( $id );
238 $icon = self::get_icon( $meta );
239
240 if ( empty( $icon ) ) {
241 return $title;
242 }
243 $menu_id = Menu_Icons_Settings::get_current_menu_id();
244 $menu_key = sprintf( 'menu_%d', $menu_id );
245 $global_hide_label = Menu_Icons_Settings::get( $menu_key, 'hide_label' );
246 $title_class = ! empty( $global_hide_label ) || ! empty( $meta['hide_label'] ) ? self::$hidden_label_class : '';
247 $title_wrapped = sprintf(
248 '<span%s>%s</span>',
249 ( ! empty( $title_class ) ) ? sprintf( ' class="%s"', esc_attr( $title_class ) ) : '',
250 $title
251 );
252
253 if ( 'after' === $meta['position'] ) {
254 $title_with_icon = "{$title_wrapped}{$icon}";
255 } else {
256 $title_with_icon = "{$icon}{$title_wrapped}";
257 }
258
259 /**
260 * Allow plugins/themes to override menu item markup
261 *
262 * @since 0.8.0
263 *
264 * @param string $title_with_icon Menu item markup after the icon is added.
265 * @param integer $id Menu item ID.
266 * @param array $meta Menu item metadata values.
267 * @param string $title Original menu item title.
268 *
269 * @return string
270 */
271 $title_with_icon = apply_filters( 'menu_icons_item_title', $title_with_icon, $id, $meta, $title );
272
273 return $title_with_icon;
274 }
275
276
277 /**
278 * Get icon
279 *
280 * @since 0.9.0
281 * @param array $meta Menu item meta value.
282 * @return string
283 */
284 public static function get_icon( $meta ) {
285 $icon = '';
286
287 // Icon type is not set.
288 if ( empty( $meta['type'] ) ) {
289 return $icon;
290 }
291
292 // Icon is not set.
293 if ( empty( $meta['icon'] ) ) {
294 return $icon;
295 }
296
297 // Icon type is not registered/enabled.
298 if ( ! isset( self::$icon_types[ $meta['type'] ] ) ) {
299 return $icon;
300 }
301
302 $type = self::$icon_types[ $meta['type'] ];
303
304 $callbacks = array(
305 array( $type, 'get_icon' ),
306 array( __CLASS__, "get_{$type->id}_icon" ),
307 array( __CLASS__, "get_{$type->template_id}_icon" ),
308 );
309
310 foreach ( $callbacks as $callback ) {
311 if ( is_callable( $callback ) ) {
312 $icon = call_user_func( $callback, $meta );
313 break;
314 }
315 }
316
317 return $icon;
318 }
319
320
321 /**
322 * Get icon style
323 *
324 * @since 0.9.0
325 * @param array $meta Menu item meta value.
326 * @param array $keys Style properties.
327 * @param bool $as_attribute Optional. Whether to output the style as HTML attribute or value only.
328 * Defaults to TRUE.
329 * @return string
330 */
331 public static function get_icon_style( $meta, $keys, $as_attribute = true ) {
332 $style_a = array();
333 $style_s = '';
334
335 foreach ( $keys as $key ) {
336 if ( ! isset( self::$default_style[ $key ] ) ) {
337 continue;
338 }
339
340 $rule = self::$default_style[ $key ];
341
342 if ( ! isset( $meta[ $key ] ) || $meta[ $key ] === $rule['value'] ) {
343 continue;
344 }
345
346 $value = $meta[ $key ];
347 if ( ! empty( $rule['unit'] ) ) {
348 $value .= $rule['unit'];
349 }
350
351 $style_a[ $rule['property'] ] = $value;
352 }
353
354 if ( empty( $style_a ) ) {
355 return $style_s;
356 }
357
358 foreach ( $style_a as $key => $value ) {
359 $style_s .= "{$key}:{$value};";
360 }
361
362 $style_s = esc_attr( $style_s );
363
364 if ( $as_attribute ) {
365 $style_s = sprintf( ' style="%s"', $style_s );
366 }
367
368 return $style_s;
369 }
370
371
372 /**
373 * Get icon classes
374 *
375 * @since 0.9.0
376 * @param array $meta Menu item meta value.
377 * @param string $output Whether to output the classes as string or array. Defaults to string.
378 * @return string|array
379 */
380 public static function get_icon_classes( $meta, $output = 'string' ) {
381 $classes = array( '_mi' );
382
383 if ( empty( $meta['hide_label'] ) ) {
384 $classes[] = "_{$meta['position']}";
385 }
386
387 if ( 'string' === $output ) {
388 $classes = implode( ' ', $classes );
389 }
390
391 return $classes;
392 }
393
394
395 /**
396 * Get font icon
397 *
398 * @since 0.9.0
399 * @param array $meta Menu item meta value.
400 * @return string
401 */
402 public static function get_font_icon( $meta ) {
403 $type = $meta['type'];
404 $icon = $meta['icon'];
405
406 $font_awesome5 = font_awesome_backward_compatible();
407 if ( ! empty( $type ) && 'fa' === $type ) {
408 $icon = explode( ' ', $icon );
409 $type = reset( $icon );
410 $icon = end( $icon );
411 $fa_icon = sprintf( '%s-%s', $type, $icon );
412 if ( array_key_exists( $fa_icon, $font_awesome5 ) ) {
413 $fa5_icon = $font_awesome5[ $fa_icon ];
414 $fa5_class = explode( ' ', $fa5_icon );
415 $type = reset( $fa5_class );
416 $icon = end( $fa5_class );
417 }
418 }
419 $classes = sprintf( '%s %s %s', self::get_icon_classes( $meta ), $type, $icon );
420 $style = self::get_icon_style( $meta, array( 'font_size', 'vertical_align' ) );
421 return sprintf( '<i class="%s" aria-hidden="true"%s></i>', esc_attr( $classes ), $style );
422 }
423
424
425 /**
426 * Get image icon
427 *
428 * @since 0.9.0
429 * @param array $meta Menu item meta value.
430 * @return string
431 */
432 public static function get_image_icon( $meta ) {
433 $args = array(
434 'class' => sprintf( '%s _image', self::get_icon_classes( $meta ) ),
435 'aria-hidden' => 'true',
436 );
437
438 $style = self::get_icon_style( $meta, array( 'vertical_align' ), false );
439 if ( ! empty( $style ) ) {
440 $args['style'] = $style;
441 }
442
443 return wp_get_attachment_image( $meta['icon'], $meta['image_size'], false, $args );
444 }
445
446
447 /**
448 * Get SVG icon
449 *
450 * @since 0.9.0
451 * @param array $meta Menu item meta value.
452 * @return string
453 */
454 public static function get_svg_icon( $meta ) {
455 $classes = sprintf( '%s _svg', self::get_icon_classes( $meta ) );
456 $style = self::get_icon_style( $meta, array( 'svg_width', 'vertical_align' ) );
457
458 $svg_icon = esc_url( wp_get_attachment_url( $meta['icon'] ) );
459 $width = '';
460 $height = '';
461 if ( 'image/svg+xml' === get_post_mime_type( $meta['icon'] ) ) {
462
463 // Check `WP_Filesystem` function exists OR not.
464 require_once ABSPATH . '/wp-admin/includes/file.php';
465 \WP_Filesystem();
466 global $wp_filesystem;
467
468 $svg_icon = get_attached_file( $meta['icon'] );
469 $svg_icon_content = $wp_filesystem->get_contents( $svg_icon );
470 if ( $svg_icon_content ) {
471 $xmlget = simplexml_load_string( $svg_icon_content );
472 $xmlattributes = $xmlget->attributes();
473 $width = (string) $xmlattributes->width;
474 $width = (int) filter_var( $xmlattributes->width, FILTER_SANITIZE_NUMBER_INT );
475 $height = (string) $xmlattributes->height;
476 $height = (int) filter_var( $xmlattributes->height, FILTER_SANITIZE_NUMBER_INT );
477 }
478 } else {
479 $attachment_meta = wp_get_attachment_metadata( $meta['icon'] );
480 if ( $attachment_meta ) {
481 $width = isset( $attachment_meta['width'] ) ? $attachment_meta['width'] : $width;
482 $height = isset( $attachment_meta['height'] ) ? $attachment_meta['height'] : $height;
483 }
484 }
485 if ( ! empty( $width ) ) {
486 $width = sprintf( ' width="%d"', $width );
487 }
488 if ( ! empty( $height ) ) {
489 $height = sprintf( ' height="%d"', $height );
490 }
491 $image_alt = get_post_meta( $meta['icon'], '_wp_attachment_image_alt', true );
492 $image_alt = $image_alt ? wp_strip_all_tags( $image_alt ) : '';
493 return sprintf(
494 '<img src="%s" class="%s" aria-hidden="true" alt="%s"%s%s%s/>',
495 esc_url( wp_get_attachment_url( $meta['icon'] ) ),
496 esc_attr( $classes ),
497 $image_alt,
498 $width,
499 $height,
500 $style
501 );
502 }
503
504 /**
505 * Add menu item class in `Max Mega Menu` item.
506 *
507 * @param array $classes Item classes.
508 * @param array $item WP menu item.
509 * @param object $args Menu object.
510 * @return array
511 */
512 public static function _add_menu_item_class( $classes, $item, $args ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
513 $classes[] = 'menu-item';
514 return $classes;
515 }
516 }
517