PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.2.3
Kirki – Freeform Page Builder, Website Builder & Customizer v6.2.3
6.2.4 6.2.3 6.2.2 6.2.1 6.2.0 6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / includes / Frontend / Preview / ExceptionalElements.php
kirki / includes / Frontend / Preview Last commit date
templates 3 months ago DataHelper.php 1 week ago ExceptionalElements.php 5 days ago Preview.php 5 days ago Utils.php 1 week ago
ExceptionalElements.php
1434 lines
1 <?php
2 /**
3 * Preview script helper class for handle exceptional element
4 *
5 * @package kirki
6 */
7
8 namespace Kirki\Frontend\Preview;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 use Kirki\Ajax\Symbol;
15 use Kirki\HelperFunctions;
16
17 /**
18 * ExceptionalElements Class
19 */
20 class ExceptionalElements {
21 /**
22 * Get this exceptional element
23 *
24 * @param array $this_data single element block.
25 * @param array $attributes single element all attributes.
26 * @param array $options single element all options.
27 * @return string HTML markup.
28 */
29 public function get_this_exceptional_element( $this_data, $attributes, $options ) {
30 switch ( $this_data['name'] ) {
31 case 'custom-code': {
32 return $this->custom_code( $this_data, $attributes );
33 }
34 case 'form': {
35 return $this->form_element( $this_data, $attributes, $options );
36 }
37 case 'map':
38 case 'google-map': {
39 return $this->map_element( $this_data, $attributes );
40 }
41 case 'svg':
42 case 'svg-icon':
43 {
44 return $this->svg_and_icon_element( $this_data, $attributes, $options );
45 }
46 case 'textarea': {
47 return '<textarea ' . $attributes . '></textarea>';
48 }
49 case 'select': {
50 return $this->select_element( $this_data, $attributes, $options );
51 }
52 case 'section': {
53 return $this->section_element( $this_data, $attributes, $options );
54 }
55 case 'video': {
56 return $this->video_element( $this_data, $attributes, $options );
57 }
58 case 'radio-group': {
59 return $this->radio_group( $this_data, $attributes );
60 }
61 case 'checkbox-element': {
62 return $this->checkbox_element( $this_data, $attributes, $options );
63 }
64 case 'radio-button': {
65 return '<input type="radio" ' . $attributes . ' />';
66 }
67 case 'image': {
68 return $this->image_element( $this_data, $attributes, $options );
69 }
70 case 'link-block': {
71 return $this->link_block_element( $this_data, $attributes, $options );
72 }
73 case 'slider':
74 case 'collection': {
75 $element_name = $this_data['name'];
76 $properties = $this_data['properties'];
77
78 $dynamic_content = $element_name === 'slider'
79 ? ( $properties['dynamicSliderContent'] ?? array() )
80 : ( $properties['dynamicContent'] ?? array() );
81
82 if ( ! empty( $dynamic_content['offset'] ) ) {
83 $options['offset'] = (int) $dynamic_content['offset'];
84 }
85
86 if ( $element_name === 'slider' ) {
87 $options['slider_mode'] = $properties['slider']['mode'] ?? 'manual'; // default manual
88 $options['element_name'] = $element_name;
89 $slider_mask_id = $this_data['children'][0];
90
91 if ( $slider_mask_id && isset( $this->data[ $slider_mask_id ] ) ) {
92 $slider_mask_data = $this->data[ $slider_mask_id ];
93 $options['slider_mask_children'] = $slider_mask_data['children'] ?? array();
94 }
95 }
96
97 $children = array();
98
99 if ( empty( $dynamic_content['collectionType'] ) ) {
100 $dynamic_content['collectionType'] = 'posts'; // default value
101 }
102
103 $children = $this->construct_items_collection_markup( $dynamic_content, $this_data, $options );
104
105 return $this->construct_collection_markup( $children, $this_data, $attributes, $element_name, $options );
106 }
107 case 'loading': {
108 return $this->collection_loading_element( $this_data, $attributes, $options );
109 }
110 case 'terms': // TODO: migrate and remove
111 case 'users': // TODO: migrate and remove
112 case 'collection-wrapper': // TODO: migrate and remove
113 case 'slider_mask':
114 case 'items': {
115 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
116 $collection = isset( $options['collection'] ) ? $options['collection'] : array();
117 $itemType = isset( $options['itemType'] ) ? $options['itemType'] : 'post';
118 $collection_item_id = $this_data['children'][0];
119 $slider_mask_children = $this_data['children'];
120 $slider_mode = $options['slider_mode'] ?? 'manual';
121 $is_slider = isset( $options['element_name'] ) && $options['element_name'] === 'slider';
122
123 $children = array();
124
125 if ( ! $options ) {
126 $options = array();
127 }
128
129 if ( $is_slider && $slider_mode === 'manual' ) {
130 foreach ( $slider_mask_children as $key => $child_id ) {
131 $children[] = $this->recGenHTML( $child_id, $options );
132 }
133 } else { // for collection and slider (dynamic)
134 foreach ( $collection as $key => $collection_item ) {
135 $item_index = HelperFunctions::get_current_item_index( $key + 1, $options );
136 $options = array_merge(
137 $options,
138 array(
139 'itemType' => $itemType,
140 $itemType => $collection_item,
141 'item_index' => $item_index,
142 )
143 );
144
145 $children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $collection_item_id, $options, ( $key === 0 ) );
146 };
147 }
148
149 return $this->get_template(
150 'items',
151 array(
152 'attributes' => $attributes,
153 'children' => $children,
154 'tag' => $tag,
155 )
156 );
157 }
158
159 case 'pagination': {
160 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
161 $markup = '';
162 $show_pagination = isset( $options['pagination'] ) ? $options['pagination'] : true;
163 $pagination_type = isset( $options['pagination_type'] ) ? $options['pagination_type'] : 'numeric';
164 $offset = isset( $options['offset'] ) ? (int) $options['offset'] : 0;
165
166 if ( $show_pagination ) {
167 $collection_count = 0;
168
169 if ( isset( $options['itemType'], $options['collection_count'] ) ) {
170 $collection_count = $options['collection_count'];
171 }
172
173 $current_page = isset( $options['page_no'] ) ? $options['page_no'] : 1;
174 $items_per_page = isset( $options['items_per_page'] ) ? $options['items_per_page'] : 3;
175 $total_pages = $collection_count ? (int) ceil( ( $collection_count - $offset ) / $items_per_page ) : 0;
176 // $pagination_item_id = $this_data['children'][0];
177 $pagination_item_id = isset( $this_data['children'][0] ) ? $this_data['children'][0] : '';
178
179 $children = array();
180
181 // pagination type: numeric or infinite_scroll
182 if ( $pagination_type === 'numeric' ) {
183 $start = 1;
184 $end = $total_pages;
185
186 /**
187 * custom for large pagination start
188 */
189 // Determine the range to display
190 $range = 10;
191 $half_range = floor( $range / 2 );
192
193 // Calculate new $start and $end
194 $start = max( 1, $current_page - $half_range );
195 $end = min( $total_pages, $current_page + $half_range );
196
197 // Adjust $start and $end if at the boundaries
198 if ( $end - $start < $range - 1 ) {
199 if ( $start == 1 ) {
200 $end = min( $start + $range - 1, $total_pages );
201 } else {
202 $start = max( $end - $range + 1, 1 );
203 }
204 }
205 /**
206 * custom for large pagination end
207 */
208
209 if ( $end > 1 ) {
210 for ( $i = $start; $i <= $end; $i++ ) {
211 $options = array(
212 'page_number' => $i,
213 'current_page' => $current_page === $i,
214 );
215 $children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $pagination_item_id, $options, ( $i === $start ) );
216 }
217 }
218
219 $markup = $this->get_template(
220 'pagination',
221 array(
222 'attributes' => $attributes,
223 'children' => $children,
224 'tag' => $tag,
225 )
226 );
227 } elseif ( $pagination_type === 'infinite_scroll' ) {
228 $markup = $this->get_template(
229 'pagination',
230 array(
231 'attributes' => $attributes . ' data-total-pages="' . $total_pages . '" data-current-page="' . $current_page . '"' . ' data-pagination-type="' . $pagination_type . '"' . 'style="height:1px "',
232 'children' => $children,
233 'tag' => $tag,
234 )
235 );
236 } elseif ( $pagination_type === 'load_more' && $current_page !== $total_pages ) {
237 $children = isset( $this_data['children'] ) ? $this_data['children'] : array();
238
239 $child_markup = $this->construct_children_markup( $children, $options );
240
241 $attr = $attributes . ' data-total-pages="' . $total_pages . '" data-current-page="' . $current_page . '"' . ' data-pagination-type="' . $pagination_type . '"';
242 return "<$tag $attr>
243 $child_markup
244 </$tag>";
245 }
246 }
247
248 return $markup;
249 }
250
251 case 'pagination-item': {
252 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
253 $current_page = isset( $options['current_page'] ) ? $options['current_page'] : false;
254 $page_number = isset( $options['page_number'] ) ? $options['page_number'] : false;
255
256 $children = array();
257
258 foreach ( $this_data['children'] as $child ) {
259 $children[] = $this->recGenHTML(
260 $child,
261 array(
262 'page_number' => $page_number,
263 )
264 );
265 }
266
267 return $this->get_template(
268 'pagination-item',
269 array(
270 'attributes' => $attributes,
271 'children' => $children,
272 'current_page' => $current_page,
273 'page_number' => $page_number,
274 'tag' => $tag,
275 )
276 );
277 }
278
279 case 'pagination-number': {
280 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'span';
281 $page_number = isset( $options['page_number'] ) ? $options['page_number'] : 1;
282
283 return $this->get_template(
284 'pagination-number',
285 array(
286 'attributes' => $attributes,
287 'page_number' => $page_number,
288 'tag' => $tag,
289 )
290 );
291 }
292
293 case 'common': {
294 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
295 $type = isset( $this_data['properties']['type'] ) ? $this_data['properties']['type'] : false;
296
297 if ( $type ) {
298 $attributes .= ' data-kirki-type="' . $type . '"';
299 }
300
301 $children = isset( $this_data['children'] ) ? $this_data['children'] : array();
302
303 $child_markup = $this->construct_children_markup( $children, $options );
304
305 return "<$tag $attributes>
306 $child_markup
307 </$tag>";
308 }
309
310 case 'symbol': {
311 return $this->generate_symbol_html( $this_data, $attributes, $options );
312 }
313 case 'popup-body': {
314 return $this->popup_element( $this_data, $attributes, $options );
315 }
316
317 case 'button': {
318 return $this->button_element( $this_data, $attributes, $options );
319 }
320
321 case 'navigation': {
322 return $this->navigation_element( $this_data, $attributes, $options );
323 }
324
325 case 'navigation-item': {
326 return $this->navigation_item_element($this_data, $attributes, $options);
327 }
328
329 case 'navigation-items': {
330 return $this->navigation_items_element( $this_data, $attributes, $options );
331 }
332
333 case 'slider_nav':{
334 return $this->slider_nav_element( $this_data, $attributes, $options );
335 }
336 case 'tabs':{
337 return $this->tabs_element( $this_data, $attributes, $options );
338 }
339 case 'tab':{
340 return $this->tab_element( $this_data, $attributes, $options );
341 }
342 case 'tab_pane':{
343 return $this->tab_pane_element( $this_data, $attributes, $options );
344 }
345 case 'tab_content':
346 case 'tab_menu':{
347 return $this->tab_menu_and_content_element( $this_data, $attributes, $options );
348 }
349 }
350 }
351
352 /**
353 * Generate collection loading element markup
354 *
355 * @param array $this_data single element block.
356 * @param array $attributes single element all attributes.
357 * @param array $options single element all options.
358 * @return string HTML markup.
359 */
360 private function collection_loading_element( $this_data, $attributes, $options ) {
361 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
362
363 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
364
365 return "<$tag $attributes kirki-collection=\"loading\" data-element_hide=\"true\">
366 $children_markup
367 </$tag>";
368 }
369
370 /**
371 * Generate section element markup
372 *
373 * @param array $this_data single element block.
374 * @param array $attributes single element all attributes.
375 * @param array $options single element all options.
376 * @return string HTML markup.
377 */
378 private function section_element( $this_data, $attributes, $options ) {
379 $id = isset( $this_data['id'] ) ? $this_data['id'] : '';
380 if ( $id ) {
381 $id = $this->get_unique_section_id_from_title( $id );
382 }
383
384 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'a';
385
386 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
387
388 return "<$tag $attributes id=\"$id\">
389 $children_markup
390 </$tag>";
391 }
392
393 private function navigation_element( $this_data, $attributes, $options ) {
394 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'a';
395
396 $hamburger = isset($this_data['properties']['navigation']['hamburger']) ? $this_data['properties']['navigation']['hamburger'] : false;
397
398 if ( ! is_array( $options ) ) {
399 $options = array();
400 }
401
402 if ( ! $options ) {
403 $options = array();
404 }
405 $options = array_merge(
406 $options,
407 array(
408 'navigation' => array(
409 'id' => $this_data['id'],
410 'hamburger' => $hamburger,
411 'showNavigationChildrenOn' => isset($this_data['properties']['navigation']['showNavigationChildrenOn']) ? $this_data['properties']['navigation']['showNavigationChildrenOn'] : 'hover',
412 ),
413 )
414 );
415
416 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
417
418 return "<$tag $attributes>
419 $children_markup
420 </$tag>";
421 }
422
423 private function navigation_item_element($this_data, $attributes, $options)
424 {
425 $tag = isset($this_data['properties'], $this_data['properties']['tag']) ? $this_data['properties']['tag'] : 'a';
426
427 $children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
428
429 $extra_attributes = '';
430
431 $show_on = 'hover';
432
433 // check showNavigationChildrenOn is hover or click or always then add kirki-navigation-item-trigger-on='hover'/'click'/'always'
434 if (isset($this_data['properties']['navigationItem']['showNavigationChildrenOn'])) {
435 $show_on = $this_data['properties']['navigationItem']['showNavigationChildrenOn'];
436 $extra_attributes .= ' kirki-navigation-item-trigger-on="' . $show_on . '"';
437 } else if (isset($options['navigation']['showNavigationChildrenOn'], $options['navigation']['hamburger']) && $options['navigation']['hamburger']) {
438 $show_on = $options['navigation']['showNavigationChildrenOn'];
439 $extra_attributes .= ' kirki-navigation-item-trigger-on="' . $show_on . '"';
440 } else {
441 $extra_attributes .= ' kirki-navigation-item-trigger-on="hover"';
442 }
443
444 if ('always' !== $show_on) {
445 $extra_attributes .= ' kirki-navigation-item-dismiss-on="' . ($this_data['properties']['navigationItem']['hideNavigationChildrenOn'] ?? 'mouseleave') . '"';
446 }
447
448 if (!$options) {
449 $options = array();
450 }
451
452 // add if kirki-navigation="nav-item" has in $this_data['properties']['attributes'] then set inside_nav_item = true
453 $options = array_merge(
454 $options,
455 array(
456 'inside_nav_item' => isset($this_data['properties']['attributes']['kirki-navigation']) && $this_data['properties']['attributes']['kirki-navigation'] === 'nav-item',
457 )
458 );
459
460 $children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
461
462 return "<$tag $attributes $extra_attributes>
463 $children_markup
464 </$tag>";
465 }
466
467 private function navigation_items_element($this_data, $attributes, $options)
468 {
469
470 $tag = isset($this_data['properties'], $this_data['properties']['tag']) ? $this_data['properties']['tag'] : 'a';
471
472 $extra_attr = isset($options['inside_navigation']) && $options['inside_navigation'] ? 'kirki-navigation-hide="true"' : '';
473
474 if (isset($options['navigation']['hamburger']) && $options['navigation']['hamburger']) {
475 $extra_attr .= ' kirki-navigation-type="close"';
476 }
477
478 if (!$options) {
479 $options = array();
480 }
481 $options = array_merge(
482 $options,
483 array(
484 'inside_navigation' => true,
485 )
486 );
487
488 $children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
489 // check it has kirki-menu-wrapper: true as attribute
490 // if (isset($this_data['properties']['attributes']['kirki-menu-wrapper']) && $this_data['properties']['attributes']['kirki-menu-wrapper'] === 'true') {
491 if (isset($options['inside_nav_item']) && $options['inside_nav_item'] === true) {
492 // Match the content inside class="..." and data-kirki="..."
493 preg_match('/class="([^"]+)"/', $attributes, $classMatch);
494 preg_match('/data-kirki="([^"]+)"/', $attributes, $dataMatch);
495
496 $class = $classMatch[1] ?? null;
497 $data_kirki = $dataMatch[1] ?? null;
498
499 return "
500 <div kirki-menu-wrapper-div='true'>
501 <$tag class='$class' data-kirki='$data_kirki'>
502 $children_markup
503 </$tag>
504 </div>
505 ";
506 } else {
507 return "<$tag $attributes $extra_attr>
508 $children_markup
509 </$tag>";
510 }
511
512 }
513
514 private function form_element( $this_data, $attributes, $options ) {
515 $properties = $this_data['properties'];
516 $post_id = HelperFunctions::get_post_id_if_possible_from_url();
517 $form_id = $this_data['id'];
518 $post_data = $form_id . '|' . $post_id;
519 $form_data = $post_data . '|' . wp_hash( $post_data );
520 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
521 $form_id_base64 = base64_encode( base64_encode( $form_data ) );
522
523 $form_nonce_field = wp_nonce_field( 'wp_rest', '_wpnonce', true, false );
524
525 if ( ! $options ) {
526 $options = array();
527 }
528
529 $options = array_merge(
530 $options,
531 array(
532 'form' => array(
533 'id' => $form_id,
534 ),
535 )
536 );
537
538 $form_children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
539
540 if ( isset( $properties['form']['type'] ) && $properties['form']['type'] !== 'external' ) {
541 $attributes = $this->getAllAttributes(
542 $this_data,
543 array(
544 'action' => false,
545 'method' => false,
546 'rest' => true,
547 ),
548 );
549 }
550
551 return "<form $attributes>
552 <input type=\"hidden\" name=\"_kirki_form\" value=\"$form_id_base64\" />
553 $form_nonce_field
554 $form_children_markup
555 </form>";
556 }
557
558 private function select_element( $this_data, $attributes, $options ) {
559 $properties = $this_data['properties'];
560 $select_options = isset( $properties['options']['list'] ) ? $properties['options']['list'] : array();
561 $selected = isset( $properties['options']['selectedOption'] ) ? $properties['options']['selectedOption'] : '';
562 $html = '<select ' . $attributes . '>';
563 foreach ( $select_options as $option ) {
564 $html .= "<option value='";
565 $html .= $option['value'] . "'";
566 $html .= $selected === $option['value'] ? ' selected' : '';
567 $html .= '>';
568 $html .= $option['contents'];
569 $html .= '</option>';
570 }
571 $html .= '</select>';
572
573 return $html;
574 }
575
576 /**
577 * Generate checkbox element markup
578 *
579 * @param array $this_data single element block.
580 * @param array $attributes single element all attributes.
581 * @param array $options single element all options.
582 * @return string HTML markup.
583 */
584 private function checkbox_element( $this_data, $attributes, $options ) {
585 $relation_type = isset( $options['relation_type'] ) ? $options['relation_type'] : 'posts';
586 if ( ! isset( $options['form'] ) ) {
587 // Start: Filter functionality
588 if ( $relation_type === 'posts' ) {
589 $checked_ids = isset( $options['selected_post_ids'] ) ? $options['selected_post_ids'] : array();
590 $checked = in_array( (string) $options['post']->ID, $checked_ids, true );
591
592 if ( $checked ) {
593 $attributes = 'checked ' . $attributes;
594 }
595
596 $attributes = "name='cm_post' value='" . $options['post']->ID . "' " . $attributes;
597 } elseif ( $relation_type === 'terms' ) {
598 $taxonomy = $options['term']['taxonomy'];
599 $term_id = $options['term']['term_id'];
600
601 $checked_ids = isset( $options['selected_taxonomies'] ) ? $options['selected_taxonomies'] : array();
602 $checked = in_array( (string) $term_id, $checked_ids, true );
603
604 if ( $checked ) {
605 $attributes = 'checked ' . $attributes;
606 }
607
608 $attributes = "name='$taxonomy' value='$term_id' " . $attributes;
609 }
610 }
611 // End: Filter functionality
612
613 return '<input type="checkbox" ' . $attributes . ' />';
614 }
615
616 private function link_block_element( $this_data, $attributes, $options ) {
617 $href = $this->get_href_value( $this_data, $options );
618
619 $preload_link = '';
620
621 if ( $href ) {
622 $attributes = preg_replace( '/href="([^"]+")/i', '', $attributes );
623
624 // check if this link is active
625 $attributes = $this->add_link_active_class( $href, $attributes, $this_data, $options );
626
627 $preload_link = $this->get_preload_link( $href, $this_data );
628 }
629
630 return '<a ' . $attributes . ' ' . ' href="' . $href . '" >' . $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options ) . '</a>' . $preload_link;
631 }
632
633 private function button_element( $this_data, $attributes, $options ) {
634 $href = $this->get_href_value( $this_data, $options );
635 $preload_link = '';
636
637 if ( $href ) {
638 $attributes = preg_replace( '/href="([^"]+")/i', '', $attributes );
639
640 // check if this link is active
641 $attributes = $this->add_link_active_class( $href, $attributes, $this_data, $options );
642
643 $preload_link = $this->get_preload_link( $href, $this_data );
644 }
645
646 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
647 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'button';
648 if ( $href ) {
649 $tag = 'a';
650 }
651
652 return "<$tag $attributes href=\"$href\">
653 $children_markup
654 </$tag>
655 $preload_link";
656 }
657
658 private function svg_and_icon_element( $this_data, $attributes, $options ) {
659 $properties = $this_data['properties'];
660 $svg = isset( $properties['svgOuterHtml'] ) ? $properties['svgOuterHtml'] : '';
661 return str_replace( '<svg', "<svg $attributes", $svg );
662 }
663
664 /**
665 * Construct children markup
666 *
667 * @param array $children single element all childrens.
668 * @param array $options single element all options.
669 * @return string HTML markup.
670 */
671 private function construct_children_markup( $children, $options ) {
672 $markup = '';
673 if ( isset( $children ) && is_array( $children ) ) {
674 foreach ( $children as $child ) {
675 $markup .= $this->recGenHTML( $child, $options );
676 }
677 }
678 return $markup;
679 }
680 private function construct_items_collection_markup( $dynamic_content, $this_data, $options ) {
681 $collection_type = isset( $dynamic_content['collectionType'] ) ? $dynamic_content['collectionType'] : 'posts';
682 $show_pagination = isset( $dynamic_content['pagination'] ) ? $dynamic_content['pagination'] : true;
683 $pagination_type = isset( $dynamic_content['pagination_type'] ) ? $dynamic_content['pagination_type'] : 'numeric';
684
685 if ( ! $options ) {
686 $options = array();
687 }
688
689 $items_data = Utils::get_items_data_from_dynamic_contents( $dynamic_content, $options );
690
691 $data = $items_data['data'];
692 $pagination = $items_data['pagination'];
693 $itemType = $items_data['itemType'];
694
695 $additional_options = array();
696
697 // START: Filter functionality
698 if ( $collection_type === 'posts' && isset( $dynamic_content['post_type'] ) && $dynamic_content['post_type'] ) {
699 if ( isset( $_GET['post'][ $dynamic_content['post_type'] ] ) && is_array( $_GET['post'][ $dynamic_content['post_type'] ] ) ) {
700 $additional_options['selected_post_ids'] = $_GET['post'][ $dynamic_content['post_type'] ];
701 }
702 } elseif ( $collection_type === 'terms' ) {
703 if ( isset( $_GET['taxonomy'][ $dynamic_content['taxonomy'] ] ) && is_array( $_GET['taxonomy'][ $dynamic_content['taxonomy'] ] ) ) {
704 $additional_options['selected_taxonomies'] = $_GET['taxonomy'][ $dynamic_content['taxonomy'] ];
705 }
706 }
707
708 $additional_options['relation_type'] = $collection_type;
709 // END: Filter functionality
710
711 $options = array_merge(
712 $options,
713 $additional_options
714 );
715
716 $children = array();
717
718 foreach ( $this_data['children'] as $child ) {
719
720 if ( count( $data ) > 0 ) {
721 if ( isset( $this->data[ $child ] ) && $this->data[ $child ]['name'] === 'empty' ) {
722 continue;
723 }
724 } elseif ( count( $data ) === 0 ) {
725 if ( isset( $this->data[ $child ] ) && ( $this->data[ $child ]['name'] === 'pagination' || $this->data[ $child ]['name'] === 'items' ) ) {
726 continue;
727 }
728 }
729
730 $children[] = $this->recGenHTML(
731 $child,
732 array_merge(
733 $options,
734 array(
735 'collection' => $data,
736 'collection_count' => $pagination['total_count'] ?? 0,
737 'items_per_page' => $pagination['per_page'] ?? 0,
738 'page_no' => $pagination['current_page'] ?? 1,
739 'pagination' => $show_pagination,
740 'itemType' => $itemType,
741 'pagination_type' => $pagination_type,
742 'inside_collection' => true
743 )
744 )
745 );
746 }
747
748 return $children;
749 }
750
751
752 /**
753 * Construct collection markup
754 *
755 * @param array $collection single element collection data.
756 * @param array $this_data single element.
757 * @param array $attributes single element all attributes.
758 * @return string HTML markup.
759 */
760 private function construct_collection_markup( $children, $this_data, $attributes, $element_name = 'collection', $options=[] ) {
761 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
762
763 $collection_info = $this->get_collection_info($options, $this_data);
764
765 if ( is_array( $children ) ) {
766 return $this->get_template(
767 'collection',
768 array(
769 'data' => $collection_info,
770 'attributes' => $attributes,
771 'children' => $children,
772 'tag' => $tag,
773 )
774 );
775 } else {
776 return '';
777 }
778 }
779
780 public function get_collection_info($options, $this_data) {
781 $collection_info = array(
782 'post_id' => isset($options['post']) ? $options['post']->ID : false,
783 'collection_data_id' => isset($this_data['original_id']) ? $this_data['original_id'] :$this_data['id']
784 );
785 if(isset($options['kirki_template_id']) && $options['kirki_template_id']) {
786 $collection_info['post_id'] = $options['kirki_template_id'];
787 }
788 if(isset($options['inside_symbol']) && $options['inside_symbol'] === true){
789 $collection_info['post_id'] = $options['symbol_id'];
790 }
791 return $collection_info;
792 }
793
794 /**
795 * Generate custom code markup
796 *
797 * @param array $this_data single element block.
798 * @param array $attributes single element all attributes.
799 * @return string HTML markup.
800 */
801 private function custom_code( $this_data, $attributes ) {
802 $properties = $this_data['properties'];
803 if ( isset( $properties['content'] ) ) {
804 if ( isset( $properties['data-type'] ) && $properties['data-type'] === 'url' ) {
805 return '<div ' . $attributes . '>
806 <iframe
807 src="' . $properties['content'] . '"
808 title="' . $this_data['id'] . '"
809 allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
810 style="width:100%;height:100%;"
811 ></iframe>
812 </div>';
813 } else {
814 return '<div ' . $attributes . '>' . $properties['content'] . '</div>';
815 }
816 }
817 return '';
818 }
819
820 /**
821 * Generate Map element markup
822 *
823 * @param array $this_data single element block.
824 * @param array $attributes single element all attributes.
825 * @return string HTML markup.
826 */
827 private function map_element( $this_data, $attributes ) {
828 $properties = isset( $this_data['properties']['map'] ) ? $this_data['properties']['map'] : false;
829 if ( ! $properties ) {
830 return '';
831 }
832 return '<div ' . $attributes . '></div>';
833 }
834
835 /**
836 * Generate Video element markup
837 *
838 * @param array $this_data single element block.
839 * @param array $attributes single element all attributes.
840 * @return string HTML markup.
841 */
842 private function video_element( $this_data, $attributes, $options ) {
843 $properties = $this_data['properties'];
844 $name = $properties['attributes']['name'];
845 $src = $properties['attributes']['src'];
846 $scale = isset( $properties['scale'] ) ? $properties['scale'] : 'cover';
847 $aspectRatio = isset( $properties['aspectRatio'] ) ? $properties['aspectRatio'] : '16 / 9';
848 $type = $properties['attributes']['type'];
849 $controls = $properties['attributes']['controls'];
850 $play_inline = isset( $properties['attributes']['playInline'] ) ? $properties['attributes']['playInline'] : true;
851 $duration = isset( $properties['attributes']['duration'] ) ? $properties['attributes']['duration'] : 0;
852 $start_time = $properties['attributes']['startTime'];
853 $end_time = isset( $properties['attributes']['endTime'] ) ? $properties['attributes']['endTime'] : $duration;
854 $span_attr_string = $this->getAllAttributes(
855 $this_data,
856 array(
857 'class' => true,
858 'data-kirki' => true,
859 'rest' => false,
860 ),
861 );
862 $dynamic_content = isset( $properties['dynamicContent'] ) ? $properties['dynamicContent'] : false;
863
864 if ( isset( $this_data['properties']['attributes']['muted'] ) && $this_data['properties']['attributes']['muted'] === false ) {
865 unset( $this_data['properties']['attributes']['muted'] );
866 }
867
868 $video_attr_string = $this->getAllAttributes(
869 $this_data,
870 array(
871 'class' => false,
872 'data-kirki' => false,
873 'src' => false,
874 'autoPlay' => false,
875 'controls' => false,
876 'dataVideoPlayListener' => false,
877 'rest' => true,
878 ),
879 );
880
881 if ( $play_inline ) {
882 $video_attr_string .= ' playsinline';
883 }
884
885 $poster = '';
886 if ( isset( $properties['thumbnail'], $properties['thumbnail']['status'] ) && $properties['thumbnail']['status'] ) {
887 $poster = isset( $properties['thumbnail'], $properties['thumbnail']['url'] ) ? $properties['thumbnail']['url'] : null;
888 }
889
890 $video_src = '';
891 if ( $dynamic_content ) {
892 // TODO: Need to get dynamic course video or image url for tutor lms using hook.
893 if ( isset( $options['itemType'] ) ) {
894 if ( $options['itemType'] === 'post' ) {
895 if ( $options['post']->{$dynamic_content['value']} ) {
896 $video_obj = $options['post']->{$dynamic_content['value']};
897
898 if ( isset( $video_obj['url'] ) ) {
899 $video_src = $video_obj['url'];
900 }
901 } else {
902 $video_obj = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
903
904 if ( isset( $video_obj['url'] ) ) {
905 $video_src = $video_obj['url'];
906 }
907 }
908 }
909 } else {
910 $video_obj = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
911
912 if ( isset( $video_obj['url'] ) ) {
913 $video_src = $video_obj['url'];
914 }
915 }
916 }
917
918 // if no dynamic video src then check original source for fallback video url
919 if ( ! $video_src && ! $src ) {
920 return '';
921 } else {
922 $src = $video_src ? $video_src : $src;
923 }
924
925 $video_url_type = $this->video_type( $src );
926
927 if ( $video_url_type === 'youtube' ) {
928 $video_src = $this->get_youtube_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
929 } elseif ( $video_url_type === 'vimeo' ) {
930 $video_src = $this->get_vimeo_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
931 } elseif ( $video_url_type === 'tiktok' ) {
932 $video_src = $this->get_tiktok_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
933 } else {
934 $video_src = $src . '#t=' . $start_time . ',' . $duration;
935 }
936
937 $html = '<span ' . $span_attr_string . '>';
938 if ( $video_url_type === 'youtube' || $video_url_type === 'vimeo' || $video_url_type === 'tiktok' ) {
939 $html .= '<iframe height="100%" width="100%" title="' . $name . '" src="' . $video_src . '" style="aspect-ratio: ' . $aspectRatio . ';" ></iframe>';
940 } else {
941 if ( isset( $properties['attributes']['lazy'] ) && $properties['attributes']['lazy'] ) {
942 // `data-src` is used in `source` tag to lazy load the video using JS. Check JS preview script for videos.
943 $html .= '<video' . $video_attr_string . ' style="object-fit: ' . $scale . '; aspect-ratio: ' . $aspectRatio . ';" poster="' . $poster . '">
944 <source data-src="' . $video_src . '" type="' . $type . '"></source></video>';
945 } else {
946 $html .= '<video' . $video_attr_string . ' style="object-fit: ' . $scale . '; aspect-ratio: ' . $aspectRatio . ';" poster="' . $poster . '">
947 <source src="' . $video_src . '" type="' . $type . '"></source></video>';
948 }
949 }
950 $html .= '</span>';
951 return $html;
952 }
953
954 /**
955 * Generate Video element markup
956 *
957 * @param array $this_data single element block.
958 * @param array $attributes single element all attributes.
959 * @return string HTML markup.
960 */
961 private function radio_group( $this_data, $attributes ) {
962 $properties = $this_data['properties'];
963 $data = $properties['data']['child'];
964 $name = $properties['attributes']['name'];
965
966 $str = '<div ' . $attributes . '>';
967
968 foreach ( $data as $key => $child ) {
969 $attrs = "type='radio' name='{$name}' value='{$child['value']}'";
970 $attrs .= $child['checked'] ? ' checked' : '';
971
972 $str .= '<label>
973 <input ' . $attrs . '/>
974 <span>' . $child['content'] . '</span>
975 </label>';
976 }
977 $str .= '</div>';
978 return $str;
979 }
980
981 /**
982 * Generate popup-body element markup
983 *
984 * @param array $this_data single element block.
985 * @param array $attributes single element all attributes.
986 * @return string HTML markup.
987 */
988 private function popup_element( $this_data, $attributes, $options ) {
989 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
990 return '<div class="kirki-popup-body-wrapper"><div ' . $attributes . '>' . $children_markup . '</div></div>';
991 }
992
993 /**
994 * Recursively Generate menu items element markup
995 *
996 * @param array $submenus all submenus.
997 * @param int $depth menu nesting info.
998 * @return string HTML markup.
999 */
1000 private function rec_gen_menu_items( $submenus, $depth ) {
1001 if ( count( $submenus ) === 0 ) {
1002 return '';
1003 }
1004 if ( $depth === 0 ) {
1005 $str = '<ul class="' . 'kirki-nav-menu">';
1006 } else {
1007 $str = '<ul class="' . 'kirki-element-submenu">';
1008 }
1009 $depth++;
1010 foreach ( $submenus as $key => $menu ) {
1011 $str .= '<li class="' . 'kirki-element-nav-item"><a class="' . 'kirki-link-element" href="' . $menu->url . '" target="' . $menu->target . '">' . $menu->title . '</a>' . $this->rec_gen_menu_items( $menu->submenus, $depth ) . '</li>';
1012 }
1013 $str .= '</ul>';
1014 return $str;
1015 }
1016
1017 /**
1018 * This method will add css value and unit
1019 *
1020 * @param array $value css value and unit pair.
1021 * @return string 5px | auto.
1022 */
1023 private function add_unit( $value ) {
1024 if ( isset( $value['unit'] ) && $value['unit'] !== 'auto' ) {
1025 return $value['value'] . $value['unit'];
1026 }
1027 return 'auto';
1028 }
1029
1030 /**
1031 * Generate Image element markup
1032 *
1033 * @param array $this_data single element block.
1034 * @param array $attributes single element all attributes.
1035 * @param array $options single element all options.
1036 * @return string HTML markup.
1037 */
1038 private function image_element( $this_data, $attributes, $options ) {
1039 $properties = $this_data['properties'];
1040 $svg_outer_html = isset( $properties['svgOuterHtml'] ) ? $properties['svgOuterHtml'] : false;
1041 $dynamic_content = isset( $properties['dynamicContent'] ) ? $properties['dynamicContent'] : false;
1042 $dynamic_alt = isset( $properties['dynamicAlt'] ) ? $properties['dynamicAlt'] : false;
1043
1044 $user_initials = false;
1045
1046 $src = '';
1047
1048 if ( $dynamic_content ) {
1049 $image_data = array();
1050
1051 if ( $dynamic_content['type'] === 'reference' && isset( $options['post'], $options['post']->ID ) ) {
1052 $content_info = array(
1053 'collectionItem' => array(
1054 'ID' => $options['post']->ID,
1055 ),
1056 'dynamicContent' => $dynamic_content,
1057 );
1058
1059 $content = apply_filters( 'kirki_dynamic_content', false, $content_info );
1060 $image_data = $content;
1061 } elseif ( $dynamic_content['type'] === 'gallery' ) {
1062 $content_info = array(
1063 'collectionItem' => array(
1064 'id' => $options['gallery']['id'],
1065 'url' => $options['gallery']['url'],
1066
1067 ),
1068 'dynamicContent' => $dynamic_content,
1069 );
1070
1071 $content = apply_filters( 'kirki_dynamic_content', false, $content_info );
1072
1073 $image_data = $content;
1074 } elseif ( $dynamic_content['type'] === 'user' ) {
1075 $user_id = isset( $options['user'], $options['user']['ID'] ) ? $options['user']['ID'] : null;
1076 $src = HelperFunctions::get_user_dynamic_content( $dynamic_content['value'], $user_id, $dynamic_content['meta'] ?? '' );
1077 $image_data = array(
1078 'src' => $src,
1079 );
1080 } elseif ( isset( $options['itemType'] ) ) {
1081 if ( $options['itemType'] === 'post' ) {
1082 if ( isset( $options['post']->{$dynamic_content['value']} ) && $options['post']->{$dynamic_content['value']} ) {
1083 $image_data = $options['post']->{$dynamic_content['value']};
1084 } else {
1085 $image_data = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
1086 }
1087 } elseif ( $options['itemType'] === 'comment' ) {
1088 if ( isset( $options['comment']->{$dynamic_content['value']} ) && $options['comment']->{$dynamic_content['value']} ) {
1089 $image_data = $options['comment']->{$dynamic_content['value']};
1090 }
1091 } elseif ( $options['itemType'] === 'user' ) {
1092 if ( isset( $options['user'], $options['user'][ $dynamic_content['value'] ] ) ) {
1093 $image_data = array(
1094 'src' => $options['user'][ $dynamic_content['value'] ],
1095 );
1096 }
1097 }
1098 } else {
1099 $post = isset( $options['post'] ) ? $options['post'] : get_post( HelperFunctions::get_post_id_if_possible_from_url() );
1100 $image_data = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], $post, isset( $dynamic_content['meta'] ) ? $dynamic_content['meta'] : null );
1101 if ( is_string( $image_data ) ) {
1102 $image_data = array(
1103 'src' => $image_data,
1104 );
1105 }
1106 }
1107
1108 if ( isset( $image_data['src'] ) ) {
1109 $src = $image_data['src'];
1110 }
1111
1112 if ( isset( $image_data['wp_attachment_id'] ) ) {
1113 $properties['wp_attachment_id'] = $image_data['wp_attachment_id'];
1114 }
1115 }
1116
1117 if ( $dynamic_content && $src ) {
1118 // replace src and alt.
1119 $attributes = preg_replace( array( '/src="([^"]+")/i' ), array( '' ), $attributes );
1120 } else {
1121 $src = isset( $properties['attributes']['src'] ) ? $properties['attributes']['src'] : '';
1122 }
1123
1124 // set dynamic alt here
1125 if ( $dynamic_alt ) {
1126 $new_alt = Utils::getDynamicRichTextValue( $dynamic_alt, $options );
1127
1128 // Update properties array for consistency
1129 $properties['attributes']['alt'] = $new_alt;
1130
1131 // Replace alt attribute inside the HTML string
1132 $attributes = preg_replace(
1133 '/alt="[^"]*"/i',
1134 'alt="' . esc_attr( $new_alt ) . '"',
1135 $attributes
1136 );
1137 } elseif ( empty( $properties['attributes']['alt'] ) ) {
1138 // get WordPress attachment alt text if alt is empty
1139 if ( isset( $properties['wp_attachment_id'] ) && $properties['wp_attachment_id'] ) {
1140 $alt_text = get_post_meta( $properties['wp_attachment_id'], '_wp_attachment_image_alt', true );
1141 $attributes = preg_replace( '/alt="([^"]*)"/i', 'alt="' . esc_attr( $alt_text ) . '"', $attributes );
1142 }
1143 }
1144
1145 $srcset = null;
1146 if ( ! $dynamic_content && isset( $properties['wp_attachment_id'] ) && $properties['wp_attachment_id'] ) {
1147 $srcset = wp_get_attachment_image_srcset( $properties['wp_attachment_id'] );
1148 $attributes .= $srcset ? ' srcset="' . $srcset . '"' : '';
1149
1150 $sizes = '';
1151 $a_meta_data = wp_get_attachment_metadata( $properties['wp_attachment_id'] );
1152 if ( $a_meta_data && isset( $a_meta_data['width'] ) ) {
1153 $width = $a_meta_data['width'];
1154 $sizes = '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
1155 $attributes .= $sizes ? ' sizes="' . $sizes . '"' : '';
1156 }
1157 }
1158
1159 if ( ( isset( $properties['load'] ) && $properties['load'] !== 'auto' ) || ! isset( $properties['load'] ) ) {
1160 $attributes .= isset( $properties['load'] ) ? ' loading="' . $properties['load'] . '"' : ' loading="lazy"';
1161 }
1162
1163 if ( isset( $properties['width'] ) ) {
1164 $attributes .= ' width="' . $this->add_unit( $properties['width'] ) . '"';
1165
1166 }
1167 if ( isset( $properties['height'] ) ) {
1168 $attributes .= ' height="' . $this->add_unit( $properties['height'] ) . '"';
1169 }
1170
1171 if ( ! $src ) {
1172 return '';
1173 }
1174
1175 $str = '';
1176
1177 if ( $svg_outer_html ) {
1178 $str .= '<img ' . $attributes . ' src="' . $src . '"/>
1179 <span>' . $svg_outer_html . '</span>';
1180 } else {
1181 $str .= '<img ' . $attributes . ' src="' . $src . '"/>';
1182 }
1183
1184 return $str;
1185 }
1186
1187 /**
1188 * Get video type from url
1189 *
1190 * @param string $url single element block.
1191 * @return string|bool video url type.
1192 */
1193 private function video_type( $url ) {
1194 if ( strpos( $url, 'youtube' ) > 0 || strpos( $url, 'youtu.be' ) > 0 ) {
1195 return 'youtube';
1196 } elseif ( strpos( $url, 'vimeo' ) > 0 ) {
1197 return 'vimeo';
1198 } elseif ( strpos( $url, 'tiktok' ) > 0 ) {
1199 return 'tiktok';
1200 } else {
1201 return false;
1202 }
1203 }
1204
1205 /**
1206 * Get video type from url
1207 *
1208 * @param string $url single element block.
1209 * @return string youtube url type.
1210 */
1211 private function get_youtube_embed_url( $url ) {
1212 preg_match( '%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match );
1213 return isset( $match[1] ) ? 'https://www.youtube.com/embed/' . $match[1] : '#';
1214 }
1215
1216 private function get_vimeo_embed_url( $url ) {
1217 preg_match( '/vimeo\.com\/(?:.*\/)?(\d+)/', $url, $matches );
1218 return isset( $matches[1] ) ? 'https://player.vimeo.com/video/' . $matches[1] : '#';
1219 }
1220
1221 private function get_tiktok_embed_url( $url ) {
1222 preg_match( '/tiktok\.com\/(?:@[\w.-]+\/)?video\/(\d+)/', $url, $matches );
1223 return isset( $matches[1] ) ? 'https://www.tiktok.com/embed/' . $matches[1] : '#';
1224 }
1225
1226 /**
1227 * Generate symbol markup
1228 *
1229 * @param array $this_data single element block.
1230 * @param array $attributes single element all attributes.
1231 * @return string HTML markup.
1232 */
1233 private function generate_symbol_html( $this_data, $attributes, $options = array() ) {
1234 $properties = $this_data['properties'];
1235 $symbol_id = $properties['symbolId'];
1236 $symbolElementProp = isset( $properties['symbolElProps'] ) ? $properties['symbolElProps'] : false;
1237 $symbol = Symbol::get_single_symbol( $symbol_id, true, false, $symbolElementProp );
1238
1239 if ( ! $symbol ) {
1240 return '';
1241 }
1242
1243 $symbol_data = $symbol['symbolData'];
1244 if ( ! $symbol_data || ! isset( $symbol_data['data'] ) ) {
1245 return '';
1246 }
1247 $options['symbol_id'] = $symbol_id;
1248 $options['inside_symbol'] = true;
1249
1250 $s = HelperFunctions::rec_update_data_id_then_return_new_html( $symbol_data['data'], $symbol_data['styleBlocks'], $symbol_data['root'], $options );
1251 $fonts_links = '';
1252 if ( isset( $symbol_data['customFonts'] ) ) {
1253 foreach ( $symbol_data['customFonts'] as $key => $f ) {
1254 if ( isset( $f['fontUrl'] ) ) {
1255 $fonts_links .= HelperFunctions::getFontsHTMLMarkup( $f );
1256 }
1257 }
1258 }
1259 return '<div ' . $attributes . '>' . $fonts_links . $s . '</div>';
1260 }
1261
1262 /**
1263 * Get html template.
1264 *
1265 * @param string $template template file name.
1266 * @param array $vars if extra variable needs inside template file.
1267 * @return string $message
1268 */
1269 private function get_template( $template, $vars ) {
1270 ob_start();
1271 include __DIR__ . "/templates/$template.view.php";
1272 $message = ob_get_contents();
1273 ob_end_clean();
1274 return $message;
1275 }
1276
1277 private function slider_nav_element( $this_data, $attributes, $options ) {
1278 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1279 $collection = isset( $options['collection'] ) ? $options['collection'] : array();
1280 $itemType = isset( $options['itemType'] ) ? $options['itemType'] : 'post';
1281 $slider_nav_item_id = isset( $this_data['children'][0] ) ? $this_data['children'][0] : '';
1282 $slider_nav_children = isset( $this_data['children'] ) ? $this_data['children'] : array();
1283 $slider_mode = $options['slider_mode'] ?? 'manual';
1284 $page_no = isset( $options['page_no'] ) ? (int) $options['page_no'] : 1;
1285
1286 $children = array();
1287
1288 if ( $slider_mode === 'manual' ) {
1289 foreach ( $slider_nav_children as $key => $child_id ) {
1290 $children[] = $this->recGenHTML( $child_id, $options );
1291 }
1292 } else { // dynamic
1293 if ( empty( $collection ) || ! $slider_nav_item_id ) {
1294 return '';
1295 }
1296
1297 $items_per_page = isset( $options['items_per_page'] ) ? (int) $options['items_per_page'] : count( $collection );
1298
1299 $start = ( $page_no - 1 ) * $items_per_page;
1300 $items_to_render = array_slice( $collection, $start, $items_per_page );
1301
1302 foreach ( $items_to_render as $key => $collection_item ) {
1303 $item_index = HelperFunctions::get_current_item_index( $key + 1, $options );
1304
1305 $merged_options = array_merge(
1306 $options,
1307 array(
1308 'itemType' => $itemType,
1309 $itemType => $collection_item,
1310 'item_index' => $item_index,
1311 'nav_index' => $start + $key,
1312 'is_active' => $key === 0,
1313 )
1314 );
1315
1316 $children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $slider_nav_item_id, $merged_options, ( $key === 0 ) );
1317 }
1318 }
1319
1320 return $this->get_template(
1321 'pagination-item',
1322 array(
1323 'attributes' => $attributes,
1324 'children' => $children,
1325 'current_page' => 1,
1326 'page_number' => $page_no,
1327 'tag' => $tag,
1328 )
1329 );
1330 }
1331
1332 private function tabs_element( $this_data, $attributes, $options ) {
1333 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1334 $children = $this_data['children'] ?? array();
1335 $markup = '';
1336
1337 foreach ( $children as $child ) {
1338 $merged_options = array_merge(
1339 $options,
1340 array(
1341 'active_tab_index' => isset($this_data['properties'],$this_data['properties']['active_tab']) ? $this_data['properties']['active_tab'] : 0,
1342 )
1343 );
1344
1345 $markup .= $this->recGenHTML( $child, $merged_options );
1346 }
1347
1348 return "<$tag $attributes>
1349 $markup
1350 </$tag>";
1351 }
1352
1353 private function tab_element( $this_data, $attributes, $options ) {
1354 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1355 $children = $this_data['children'] ?? array();
1356 $markup = '';
1357
1358 $active_tab_index = isset( $options['active_tab_index'] ) ? $options['active_tab_index'] : 0;
1359 $child_index = isset( $options['child_index'] ) ? $options['child_index'] : 0;
1360
1361 if ( $active_tab_index === $child_index ) {
1362 // Add kirki-current-tab class to attributes
1363 if ( preg_match( '/class="([^"]*)"/', $attributes, $matches ) ) {
1364 // Class attribute exists, append to it
1365 $existing_classes = $matches[1];
1366 $new_classes = trim( $existing_classes . ' kirki-current-tab' );
1367 $attributes = preg_replace(
1368 '/class="[^"]*"/',
1369 'class="' . esc_attr( $new_classes ) . '"',
1370 $attributes
1371 );
1372 } else {
1373 // No class attribute, add it
1374 $attributes .= ' class="kirki-current-tab"';
1375 }
1376 }
1377
1378 // foreach ( $children as $child ) {
1379 // $markup .= $this->recGenHTML( $child, $options );
1380 // }
1381 $markup = $this->get_child_content_or_childrens( $this_data, $options );
1382 return "<$tag $attributes>
1383 $markup
1384 </$tag>";
1385 }
1386
1387 private function tab_pane_element( $this_data, $attributes, $options ) {
1388 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1389 $children = $this_data['children'] ?? array();
1390 $markup = '';
1391
1392 $active_tab_index = isset( $options['active_tab_index'] ) ? $options['active_tab_index'] : 0;
1393 $child_index = isset( $options['child_index'] ) ? $options['child_index'] : 0;
1394
1395 if ( $active_tab_index === $child_index ) {
1396 // Add kirki-tab-active class to attributes
1397 if ( preg_match( '/class="([^"]*)"/', $attributes, $matches ) ) {
1398 // Class attribute exists, append to it
1399 $existing_classes = $matches[1];
1400 $new_classes = trim( $existing_classes . ' kirki-tab-active' );
1401 $attributes = preg_replace(
1402 '/class="[^"]*"/',
1403 'class="' . esc_attr( $new_classes ) . '"',
1404 $attributes
1405 );
1406 } else {
1407 // No class attribute, add it
1408 $attributes .= ' class="kirki-tab-active"';
1409 }
1410 }
1411
1412 $markup = $this->get_child_content_or_childrens( $this_data, $options );
1413 return "<$tag $attributes>
1414 $markup
1415 </$tag>";
1416 }
1417
1418 private function tab_menu_and_content_element( $this_data, $attributes, $options ) {
1419 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1420 $children = $this_data['children'] ?? array();
1421 $markup = '';
1422
1423 $markup = $this->get_child_content_or_childrens( $this_data, $options );
1424 if($this_data['name'] === 'tab_menu'){
1425 $attributes .= ' data-kirki_tab="tab_menu"';
1426 }else{
1427 $attributes .= ' data-kirki_tab="tab_content"';
1428 }
1429 return "<$tag $attributes>
1430 $markup
1431 </$tag>";
1432 }
1433
1434 }