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