PluginProbe
Hello Plus / 1.2.0
Hello Plus v1.2.0
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.6.0 1.6.1 1.6.2 1.7.0 1.7.1 1.7.2 1.7.3 All 30 releases
hello-plus / modules / template-parts / classes / render / widget-header-render.php

widget-header-render.php in Hello Plus 1.2.0, at modules/template-parts/classes/render/widget-header-render.php

577 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace HelloPlus\Modules\TemplateParts\Classes\Render;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit; // Exit if accessed directly.
7 }
8
9 use Elementor\{
10 Group_Control_Image_Size,
11 Icons_Manager,
12 Utils
13 };
14
15 use HelloPlus\Modules\TemplateParts\Widgets\Ehp_Header;
16 use HelloPlus\Classes\Ehp_Button;
17
18 /**
19 * class Widget_Header_Render
20 */
21 class Widget_Header_Render {
22
23 const LAYOUT_CLASSNAME = 'ehp-header';
24 const SITE_LINK_CLASSNAME = 'ehp-header__site-link';
25 const CTAS_CONTAINER_CLASSNAME = 'ehp-header__ctas-container';
26
27 protected Ehp_Header $widget;
28
29 protected array $settings;
30
31 public function render(): void {
32 $layout_classnames = [
33 self::LAYOUT_CLASSNAME,
34 ];
35 $navigation_breakpoint = $this->settings['navigation_breakpoint'] ?? '';
36 $box_border = $this->settings['show_box_border'] ?? '';
37 $behavior_float = $this->settings['behavior_float'];
38 $behavior_on_scroll = $this->settings['behavior_onscroll_select'];
39 $layout_preset = $this->settings['layout_preset_select'];
40 $behavior_scale_logo = $this->settings['behavior_sticky_scale_logo'];
41 $behavior_scale_title = $this->settings['behavior_sticky_scale_title'];
42 $behavior_float_shape = $this->settings['behavior_float_shape'];
43 $behavior_float_shape_tablet = $this->settings['behavior_float_shape_tablet'] ?? '';
44 $behavior_float_shape_mobile = $this->settings['behavior_float_shape_mobile'] ?? '';
45 $has_blur_background = $this->settings['blur_background'];
46
47 if ( ! empty( $navigation_breakpoint ) ) {
48 $layout_classnames[] = 'has-navigation-breakpoint-' . $navigation_breakpoint;
49 }
50
51 if ( 'yes' === $box_border ) {
52 $layout_classnames[] = 'has-box-border';
53 }
54
55 if ( 'yes' === $behavior_float ) {
56 $layout_classnames[] = 'has-behavior-float';
57 }
58
59 if ( 'yes' === $behavior_scale_logo ) {
60 $layout_classnames[] = 'has-behavior-sticky-scale-logo';
61 }
62
63 if ( 'yes' === $behavior_scale_title ) {
64 $layout_classnames[] = 'has-behavior-sticky-scale-title';
65 }
66
67 if ( ! empty( $behavior_float_shape ) ) {
68 $layout_classnames[] = 'has-shape-' . $behavior_float_shape;
69
70 if ( ! empty( $behavior_float_shape_mobile ) ) {
71 $layout_classnames[] = 'has-shape-sm-' . $behavior_float_shape_mobile;
72 }
73
74 if ( ! empty( $behavior_float_shape_tablet ) ) {
75 $layout_classnames[] = 'has-shape-md-' . $behavior_float_shape_tablet;
76 }
77 }
78
79 if ( ! empty( $behavior_on_scroll ) ) {
80 $layout_classnames[] = 'has-behavior-onscroll-' . $behavior_on_scroll;
81 }
82
83 if ( 'navigate' === $layout_preset ) {
84 $layout_classnames[] = 'has-align-link-start';
85 } elseif ( 'identity' === $layout_preset ) {
86 $layout_classnames[] = 'has-align-link-center';
87 } elseif ( 'connect' === $layout_preset ) {
88 $layout_classnames[] = 'has-align-link-connect';
89 }
90
91 if ( 'yes' === $has_blur_background ) {
92 $layout_classnames[] = 'has-blur-background';
93 }
94
95 $render_attributes = [
96 'class' => $layout_classnames,
97 'data-scroll-behavior' => $behavior_on_scroll,
98 'data-behavior-float' => $behavior_float,
99 ];
100
101 $this->widget->add_render_attribute( 'layout', $render_attributes );
102
103 $this->maybe_add_advanced_attributes();
104
105 ?>
106 <header <?php $this->widget->print_render_attribute_string( 'layout' ); ?>>
107 <div class="ehp-header__elements-container">
108 <?php
109 $this->render_site_link();
110 $this->render_navigation();
111 $this->render_ctas_container();
112 ?>
113 </div>
114 </header>
115 <?php
116 }
117
118 protected function maybe_add_advanced_attributes() {
119 $advanced_css_id = $this->settings['advanced_custom_css_id'];
120 $advanced_css_classes = $this->settings['advanced_custom_css_classes'];
121
122 $wrapper_render_attributes = [];
123 if ( ! empty( $advanced_css_classes ) ) {
124 $wrapper_render_attributes['class'] = $advanced_css_classes;
125 }
126
127 if ( ! empty( $advanced_css_id ) ) {
128 $wrapper_render_attributes['id'] = $advanced_css_id;
129 }
130 if ( empty( $wrapper_render_attributes ) ) {
131 return;
132 }
133 $this->widget->add_render_attribute( '_wrapper', $wrapper_render_attributes );
134 }
135
136 public function render_site_link(): void {
137 $site_logo_brand_select = $this->settings['site_logo_brand_select'];
138
139 $site_title_text = $this->widget->get_site_title();
140 $site_title_tag = $this->settings['site_logo_title_tag'] ?? 'h2';
141 $site_link_classnames = self::SITE_LINK_CLASSNAME;
142
143 $this->widget->add_render_attribute( 'site-link', [
144 'class' => $site_link_classnames,
145 ] );
146
147 $site_link = $this->get_link_url();
148
149 if ( $site_link ) {
150 $this->widget->add_link_attributes( 'site-link', $site_link );
151 }
152
153 if ( $this->settings['site_logo_image'] ) {
154 $this->settings['site_logo_image'] = $this->widget->add_site_logo_if_present( $this->settings['site_logo_image'] );
155 }
156
157 ?>
158 <a <?php $this->widget->print_render_attribute_string( 'site-link' ); ?>>
159 <?php if ( 'logo' === $site_logo_brand_select ) {
160 Group_Control_Image_Size::print_attachment_image_html( $this->settings, 'site_logo_image' );
161 } ?>
162 <?php if ( 'title' === $site_logo_brand_select ) {
163 $site_title_output = sprintf( '<%1$s %2$s %3$s>%4$s</%1$s>', Utils::validate_html_tag( $site_title_tag ), $this->widget->get_render_attribute_string( 'heading' ), 'class="ehp-header__site-title"', esc_html( $site_title_text ) );
164 // Escaped above
165 Utils::print_unescaped_internal_string( $site_title_output );
166 } ?>
167 </a>
168 <?php
169 }
170
171 public function render_navigation(): void {
172 $available_menus = $this->widget->get_available_menus();
173 $menu_classname = 'ehp-header__menu';
174
175 if ( ! $available_menus ) {
176 return;
177 }
178
179 $pointer_hover_type = $this->settings['style_navigation_pointer_hover'] ?? '';
180 $focus_active_type = $this->settings['style_navigation_focus_active'] ?? '';
181 $has_responsive_divider = $this->settings['style_responsive_menu_divider'];
182
183 if ( 'none' !== $pointer_hover_type ) {
184 $menu_classname .= ' has-pointer-hover-' . $pointer_hover_type;
185 }
186
187 if ( 'none' !== $focus_active_type ) {
188 $menu_classname .= ' has-focus-active-' . $focus_active_type;
189 }
190
191 if ( 'yes' === $has_responsive_divider ) {
192 $menu_classname .= ' has-responsive-divider';
193 }
194
195 $settings = $this->settings;
196 $submenu_layout = $this->settings['style_submenu_layout'] ?? 'horizontal';
197
198 $args = [
199 'echo' => false,
200 'menu' => $settings['navigation_menu'],
201 'menu_class' => $menu_classname,
202 'menu_id' => 'menu-' . $this->widget->get_and_advance_nav_menu_index() . '-' . $this->widget->get_id(),
203 'fallback_cb' => '__return_empty_string',
204 'container' => '',
205 ];
206
207 // Add custom filter to handle Nav Menu HTML output.
208 add_filter( 'nav_menu_link_attributes', [ $this, 'handle_link_classes' ], 10, 4 );
209 add_filter( 'nav_menu_submenu_css_class', [ $this, 'handle_sub_menu_classes' ] );
210 add_filter( 'walker_nav_menu_start_el', [ $this, 'handle_walker_menu_start_el' ], 10, 4 );
211 add_filter( 'nav_menu_item_id', '__return_empty_string' );
212
213 // General Menu.
214 $menu_html = wp_nav_menu( $args );
215
216 // Remove all our custom filters.
217 remove_filter( 'nav_menu_link_attributes', [ $this, 'handle_link_classes' ] );
218 remove_filter( 'nav_menu_submenu_css_class', [ $this, 'handle_sub_menu_classes' ] );
219 remove_filter( 'walker_nav_menu_start_el', [ $this, 'handle_walker_menu_start_el' ] );
220 remove_filter( 'nav_menu_item_id', '__return_empty_string' );
221
222 if ( empty( $menu_html ) ) {
223 return;
224 }
225
226 if ( $settings['navigation_menu_name'] ) {
227 $this->widget->add_render_attribute( 'main-menu', 'aria-label', $settings['navigation_menu_name'] );
228 }
229
230 $this->widget->add_render_attribute( 'main-menu', 'class', [
231 ' has-submenu-layout-' . $submenu_layout,
232 'ehp-header__navigation',
233 ] );
234 ?>
235
236 <nav <?php $this->widget->print_render_attribute_string( 'main-menu' ); ?>>
237 <?php
238 // Add custom filter to handle Nav Menu HTML output.
239 add_filter( 'nav_menu_link_attributes', [ $this, 'handle_link_classes' ], 10, 4 );
240 add_filter( 'nav_menu_submenu_css_class', [ $this, 'handle_sub_menu_classes' ] );
241 add_filter( 'walker_nav_menu_start_el', [ $this, 'handle_walker_menu_start_el' ], 10, 4 );
242 add_filter( 'nav_menu_item_id', '__return_empty_string' );
243
244 $args['echo'] = true;
245
246 wp_nav_menu( $args );
247
248 // Remove all our custom filters.
249 remove_filter( 'nav_menu_link_attributes', [ $this, 'handle_link_classes' ] );
250 remove_filter( 'nav_menu_submenu_css_class', [ $this, 'handle_sub_menu_classes' ] );
251 remove_filter( 'walker_nav_menu_start_el', [ $this, 'handle_walker_menu_start_el' ] );
252 remove_filter( 'nav_menu_item_id', '__return_empty_string' );
253
254 $this->render_ctas_container();
255 ?>
256 </nav>
257 <?php
258 $this->render_menu_toggle();
259 }
260
261 private function render_menu_toggle() {
262 $toggle_icon = $this->settings['navigation_menu_icon'];
263 $toggle_classname = 'ehp-header__button-toggle';
264
265 $this->widget->add_render_attribute( 'button-toggle', [
266 'class' => $toggle_classname,
267 'role' => 'button',
268 'tabindex' => '0',
269 'aria-label' => esc_html__( 'Menu Toggle', 'hello-plus' ),
270 'aria-expanded' => 'false',
271 ] );
272
273 ?>
274 <div class="ehp-header__side-toggle">
275 <?php if ( 'yes' === $this->settings['contact_buttons_show'] ) {
276 $this->render_contact_buttons();
277 } ?>
278 <button <?php $this->widget->print_render_attribute_string( 'button-toggle' ); ?>>
279 <span class="ehp-header__toggle-icon ehp-header__toggle-icon--open" aria-hidden="true">
280 <?php
281 Icons_Manager::render_icon( $toggle_icon,
282 [
283 'role' => 'presentation',
284 ]
285 );
286 ?>
287 </span>
288 <i class="eicon-close ehp-header__toggle-icon ehp-header__toggle-icon--close"></i>
289 <span class="elementor-screen-only"><?php esc_html_e( 'Menu', 'hello-plus' ); ?></span>
290 </button>
291 </div>
292 <?php
293 }
294
295 protected function render_ctas_container() {
296 $responsive_button_width = $this->settings['cta_responsive_width'] ?? '';
297 $ctas_container_classnames = self::CTAS_CONTAINER_CLASSNAME;
298
299 if ( '' !== $responsive_button_width ) {
300 $ctas_container_classnames .= ' has-responsive-width-' . $responsive_button_width;
301 }
302
303 $this->widget->add_render_attribute( 'ctas-container', [
304 'class' => $ctas_container_classnames,
305 ] );
306 ?>
307 <div <?php $this->widget->print_render_attribute_string( 'ctas-container' ); ?>>
308 <?php
309 if ( 'yes' === $this->settings['contact_buttons_show'] ) {
310 $this->render_contact_buttons();
311 }
312 ?>
313 <?php if ( ! empty( $this->settings['secondary_cta_button_text'] ) ) {
314 $this->render_button( 'secondary' );
315 } ?>
316 <?php if ( ! empty( $this->settings['primary_cta_button_text'] ) ) {
317 $this->render_button( 'primary' );
318 } ?>
319 </div>
320 <?php
321 }
322
323 protected function render_contact_buttons() {
324 $contact_buttons = $this->settings['contact_buttons_repeater'];
325 $link_type = $this->settings['contact_buttons_link_type'];
326 $responsive_display = $this->settings['contact_buttons_responsive_display'];
327 $hover_animation = $this->settings['contact_button_hover_animation'];
328
329 $contact_buttons_classnames = [
330 'ehp-header__contact-buttons',
331 'has-responsive-display-' . $responsive_display,
332 ];
333
334 $this->widget->add_render_attribute( 'contact-buttons', [
335 'class' => $contact_buttons_classnames,
336 ] );
337
338 ?>
339 <div <?php $this->widget->print_render_attribute_string( 'contact-buttons' ); ?>>
340 <?php
341 foreach ( $contact_buttons as $key => $contact_button ) {
342 // Ensure attributes are cleared for this key
343 $this->widget->remove_render_attribute( 'contact-button-' . $key );
344
345 $link = [
346 'platform' => $contact_button['contact_buttons_platform'],
347 'number' => $contact_button['contact_buttons_number'] ?? '',
348 'username' => $contact_button['contact_buttons_username'] ?? '',
349 'email_data' => [
350 'contact_buttons_mail' => $contact_button['contact_buttons_mail'] ?? '',
351 'contact_buttons_mail_subject' => $contact_button['contact_buttons_mail_subject'] ?? '',
352 'contact_buttons_mail_body' => $contact_button['contact_buttons_mail_body'] ?? '',
353 ],
354 'viber_action' => $contact_button['contact_buttons_viber_action'] ?? '',
355 'url' => $contact_button['contact_buttons_url'] ?? '',
356 'location' => $contact_button['contact_buttons_waze'] ?? '',
357 'map' => $contact_button['contact_buttons_map'] ?? '',
358 ];
359
360 $icon = $contact_button['contact_buttons_icon'];
361
362 $button_classnames = [ 'ehp-header__contact-button' ];
363
364 if ( ! empty( $hover_animation ) ) {
365 $button_classnames[] = 'elementor-animation-' . $hover_animation;
366 }
367
368 $this->widget->add_render_attribute( 'contact-button-' . $key, [
369 'aria-label' => esc_attr( $contact_button['contact_buttons_label'] ),
370 'class' => $button_classnames,
371 ] );
372
373 if ( $this->is_url_link( $contact_button['contact_buttons_platform'] ) ) {
374 $this->render_link_attributes( $link, 'contact-button-' . $key );
375 } else {
376 $formatted_link = $this->get_formatted_link( $link, 'contact_icon' );
377
378 $this->widget->add_render_attribute( 'contact-button-' . $key, [
379 'href' => $formatted_link,
380 'rel' => 'noopener noreferrer',
381 'target' => '_blank',
382 ] );
383 }
384 ?>
385
386 <a <?php $this->widget->print_render_attribute_string( 'contact-button-' . $key ); ?>>
387 <?php if ( 'icon' === $link_type ) {
388 Icons_Manager::render_icon( $icon,
389 [
390 'aria-hidden' => 'true',
391 'class' => 'ehp-header__contact-button-icon',
392 ]
393 );
394 } ?>
395 <?php if ( 'label' === $link_type ) { ?>
396 <span class="ehp-header__contact-button-label"><?php echo esc_html( $contact_button['contact_buttons_label'] ); ?></span>
397 <?php } ?>
398 </a>
399 <?php } ?>
400 </div>
401 <?php
402 }
403
404 protected function is_url_link( $platform ) {
405 return 'url' === $platform || 'waze' === $platform || 'map' === $platform;
406 }
407
408 protected function render_link_attributes( array $link, string $key ) {
409 switch ( $link['platform'] ) {
410 case 'waze':
411 if ( empty( $link['location']['url'] ) ) {
412 $link['location']['url'] = '#';
413 }
414
415 $this->widget->add_link_attributes( $key, $link['location'] );
416 break;
417 case 'url':
418 if ( empty( $link['url']['url'] ) ) {
419 $link['url']['url'] = '#';
420 }
421
422 $this->widget->add_link_attributes( $key, $link['url'] );
423 break;
424 case 'map':
425 if ( empty( $link['map']['url'] ) ) {
426 $link['map']['url'] = '#';
427 }
428
429 $this->widget->add_link_attributes( $key, $link['map'] );
430 break;
431 default:
432 break;
433 }
434 }
435
436 protected function get_formatted_link( array $link, string $prefix ): string {
437
438 // Ensure we clear the default link value if the matching type value is empty
439 switch ( $link['platform'] ) {
440 case 'email':
441 $formatted_link = $this->build_email_link( $link['email_data'], $prefix );
442 break;
443 case 'sms':
444 $formatted_link = ! empty( $link['number'] ) ? 'sms:' . $link['number'] : '';
445 break;
446 case 'messenger':
447 $formatted_link = ! empty( $link['username'] ) ?
448 $this->build_messenger_link( $link['username'] ) :
449 '';
450 break;
451 case 'whatsapp':
452 $formatted_link = ! empty( $link['number'] ) ? 'https://wa.me/' . $link['number'] : '';
453 break;
454 case 'viber':
455 $formatted_link = $this->build_viber_link( $link['viber_action'], $link['number'] );
456 break;
457 case 'skype':
458 $formatted_link = ! empty( $link['username'] ) ? 'skype:' . $link['username'] . '?chat' : '';
459 break;
460 case 'telephone':
461 $formatted_link = ! empty( $link['number'] ) ? 'tel:' . $link['number'] : '';
462 break;
463 default:
464 break;
465 }
466
467 return esc_html( $formatted_link );
468 }
469
470 public static function build_email_link( array $data, string $prefix ) {
471 $email = $data[ $prefix . '_mail' ] ?? '';
472 $subject = $data[ $prefix . '_mail_subject' ] ?? '';
473 $body = $data[ $prefix . '_mail_body' ] ?? '';
474
475 if ( ! $email ) {
476 return '';
477 }
478
479 $link = 'mailto:' . $email;
480
481 if ( $subject ) {
482 $link .= '?subject=' . $subject;
483 }
484
485 if ( $body ) {
486 $link .= $subject ? '&' : '?';
487 $link .= 'body=' . $body;
488 }
489
490 return $link;
491 }
492
493 public static function build_viber_link( string $action, string $number ) {
494 if ( empty( $number ) ) {
495 return '';
496 }
497
498 return add_query_arg( [
499 'number' => rawurlencode( $number ),
500 ], 'viber://' . $action );
501 }
502
503 public static function build_messenger_link( string $username ) {
504 return 'https://m.me/' . $username;
505 }
506
507 protected function render_button( $type ) {
508 $button = new Ehp_Button( $this->widget, [
509 'type' => $type,
510 'widget_name' => 'header',
511 ] );
512 $button->render();
513 }
514
515 public function get_link_url(): array {
516 return [ 'url' => $this->widget->get_site_url() ];
517 }
518
519 public function handle_link_classes( $atts, $item, $args, $depth ) {
520 $classes = $depth ? 'ehp-header__item ehp-header__item--sub-level' : 'ehp-header__item ehp-header__item--top-level';
521 $is_anchor = false !== strpos( $atts['href'], '#' );
522
523 if ( ! $is_anchor && in_array( 'current-menu-item', $item->classes, true ) ) {
524 $classes .= ' is-item-active';
525 }
526
527 if ( $is_anchor ) {
528 $classes .= ' is-item-anchor';
529 }
530
531 if ( empty( $atts['class'] ) ) {
532 $atts['class'] = $classes;
533 } else {
534 $atts['class'] .= ' ' . $classes;
535 }
536
537 return $atts;
538 }
539
540 public function handle_sub_menu_classes() {
541 $submenu_layout = $this->settings['style_submenu_layout'] ?? 'horizontal';
542 $submenu_shape = $this->settings['style_submenu_shape'];
543
544 $dropdown_classnames = [ 'ehp-header__dropdown' ];
545 $dropdown_classnames[] = 'has-layout-' . $submenu_layout;
546
547 if ( ! empty( $submenu_shape ) ) {
548 $dropdown_classnames[] = 'has-shape-' . $submenu_shape;
549 }
550
551 return $dropdown_classnames;
552 }
553
554 public function handle_walker_menu_start_el( $item_output, $item ) {
555
556 if ( in_array( 'menu-item-has-children', $item->classes, true ) ) {
557 $submenu_icon = $this->settings['navigation_menu_submenu_icon'];
558
559 $svg_icon = Icons_Manager::try_get_icon_html( $submenu_icon,
560 [
561 'aria-hidden' => 'true',
562 'class' => 'ehp-header__submenu-toggle-icon',
563 ]
564 );
565
566 $item_output = '<button type="button" class="ehp-header__item ehp-header__dropdown-toggle" aria-expanded="false">' . esc_html( $item->title ) . $svg_icon . '</button>';
567 }
568
569 return $item_output;
570 }
571
572 public function __construct( Ehp_Header $widget ) {
573 $this->widget = $widget;
574 $this->settings = $widget->get_settings_for_display();
575 }
576 }
577