PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.0.13
Kirki – Freeform Page Builder, Website Builder & Customizer v6.0.13
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 2 months ago DataHelper.php 2 months ago ExceptionalElements.php 1 month ago Preview.php 1 month ago Utils.php 1 month ago
ExceptionalElements.php
1411 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\Ajax\Users;
16 use Kirki\HelperFunctions;
17 use Kirki\Ajax\WordpressData;
18
19 /**
20 * ExceptionalElements Class
21 */
22 class ExceptionalElements {
23 /**
24 * Get this exceptional element
25 *
26 * @param array $this_data single element block.
27 * @param array $attributes single element all attributes.
28 * @param array $options single element all options.
29 * @return string HTML markup.
30 */
31 public function get_this_exceptional_element( $this_data, $attributes, $options ) {
32 switch ( $this_data['name'] ) {
33 case 'custom-code': {
34 return $this->custom_code( $this_data, $attributes );
35 }
36 case 'form': {
37 return $this->form_element( $this_data, $attributes, $options );
38 }
39 case 'map':
40 case 'google-map': {
41 return $this->map_element( $this_data, $attributes );
42 }
43 case 'svg':
44 case 'svg-icon':
45 {
46 return $this->svg_and_icon_element( $this_data, $attributes, $options );
47 }
48 case 'textarea': {
49 return '<textarea ' . $attributes . '></textarea>';
50 }
51 case 'select': {
52 return $this->select_element( $this_data, $attributes, $options );
53 }
54 case 'section': {
55 return $this->section_element( $this_data, $attributes, $options );
56 }
57 case 'video': {
58 return $this->video_element( $this_data, $attributes, $options );
59 }
60 case 'radio-group': {
61 return $this->radio_group( $this_data, $attributes );
62 }
63 case 'checkbox-element': {
64 return $this->checkbox_element( $this_data, $attributes, $options );
65 }
66 case 'radio-button': {
67 return '<input type="radio" ' . $attributes . ' />';
68 }
69 case 'image': {
70 return $this->image_element( $this_data, $attributes, $options );
71 }
72 case 'link-block': {
73 return $this->link_block_element( $this_data, $attributes, $options );
74 }
75
76 case 'file-upload-inner': {
77 return $this->file_input_element( $this_data, $attributes, $options );
78 }
79
80 case 'file-upload-threshold-text': {
81 return $this->file_upload_threshold_text( $this_data, $attributes, $options );
82 }
83
84 case 'file-upload': {
85 return $this->file_upload_element( $this_data, $attributes, $options );
86 }
87 case 'slider':
88 case 'collection': {
89 $element_name = $this_data['name'];
90 $properties = $this_data['properties'];
91
92 $dynamic_content = $element_name === 'slider'
93 ? ( $properties['dynamicSliderContent'] ?? array() )
94 : ( $properties['dynamicContent'] ?? array() );
95
96 if ( ! empty( $dynamic_content['offset'] ) ) {
97 $options['offset'] = (int) $dynamic_content['offset'];
98 }
99
100 if ( $element_name === 'slider' ) {
101 $options['slider_mode'] = $properties['slider']['mode'] ?? 'manual'; // default manual
102 $options['element_name'] = $element_name;
103 $slider_mask_id = $this_data['children'][0];
104
105 if ( $slider_mask_id && isset( $this->data[ $slider_mask_id ] ) ) {
106 $slider_mask_data = $this->data[ $slider_mask_id ];
107 $options['slider_mask_children'] = $slider_mask_data['children'] ?? array();
108 }
109 }
110
111 $children = array();
112
113 if ( empty( $dynamic_content['collectionType'] ) ) {
114 $dynamic_content['collectionType'] = 'posts'; // default value
115 }
116
117 $children = $this->construct_items_collection_markup( $dynamic_content, $this_data, $options );
118
119 return $this->construct_collection_markup( $children, $this_data, $attributes, $element_name );
120 }
121 case 'loading': {
122 return $this->collection_loading_element( $this_data, $attributes, $options );
123 }
124 case 'terms': // TODO: migrate and remove
125 case 'users': // TODO: migrate and remove
126 case 'collection-wrapper': // TODO: migrate and remove
127 case 'slider_mask':
128 case 'items': {
129 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
130 $collection = isset( $options['collection'] ) ? $options['collection'] : array();
131 $itemType = isset( $options['itemType'] ) ? $options['itemType'] : 'post';
132 $collection_item_id = $this_data['children'][0];
133 $slider_mask_children = $this_data['children'];
134 $slider_mode = $options['slider_mode'] ?? 'manual';
135 $is_slider = isset( $options['element_name'] ) && $options['element_name'] === 'slider';
136
137 $children = array();
138
139 if ( ! $options ) {
140 $options = array();
141 }
142
143 if ( $is_slider && $slider_mode === 'manual' ) {
144 foreach ( $slider_mask_children as $key => $child_id ) {
145 $children[] = $this->recGenHTML( $child_id, $options );
146 }
147 } else { // for collection and slider (dynamic)
148 foreach ( $collection as $key => $collection_item ) {
149 $item_index = HelperFunctions::get_current_item_index( $key + 1, $options );
150 $options = array_merge(
151 $options,
152 array(
153 'itemType' => $itemType,
154 $itemType => $collection_item,
155 'item_index' => $item_index,
156 )
157 );
158
159 $children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $collection_item_id, $options, ( $key === 0 ) );
160 };
161 }
162
163 return $this->get_template(
164 'items',
165 array(
166 'attributes' => $attributes,
167 'children' => $children,
168 'tag' => $tag,
169 )
170 );
171 }
172
173 case 'pagination': {
174 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
175 $markup = '';
176 $show_pagination = isset( $options['pagination'] ) ? $options['pagination'] : true;
177 $pagination_type = isset( $options['pagination_type'] ) ? $options['pagination_type'] : 'numeric';
178 $offset = isset( $options['offset'] ) ? (int) $options['offset'] : 0;
179
180 if ( $show_pagination ) {
181 $collection_count = 0;
182
183 if ( isset( $options['itemType'], $options['collection_count'] ) ) {
184 $collection_count = $options['collection_count'];
185 }
186
187 $current_page = isset( $options['page_no'] ) ? $options['page_no'] : 1;
188 $items_per_page = isset( $options['items_per_page'] ) ? $options['items_per_page'] : 3;
189 $total_pages = $collection_count ? (int) ceil( ( $collection_count - $offset ) / $items_per_page ) : 0;
190 // $pagination_item_id = $this_data['children'][0];
191 $pagination_item_id = isset( $this_data['children'][0] ) ? $this_data['children'][0] : '';
192
193 $children = array();
194
195 // pagination type: numeric or infinite_scroll
196 if ( $pagination_type === 'numeric' ) {
197 $start = 1;
198 $end = $total_pages;
199
200 /**
201 * custom for large pagination start
202 */
203 // Determine the range to display
204 $range = 10;
205 $half_range = floor( $range / 2 );
206
207 // Calculate new $start and $end
208 $start = max( 1, $current_page - $half_range );
209 $end = min( $total_pages, $current_page + $half_range );
210
211 // Adjust $start and $end if at the boundaries
212 if ( $end - $start < $range - 1 ) {
213 if ( $start == 1 ) {
214 $end = min( $start + $range - 1, $total_pages );
215 } else {
216 $start = max( $end - $range + 1, 1 );
217 }
218 }
219 /**
220 * custom for large pagination end
221 */
222
223 if ( $end > 1 ) {
224 for ( $i = $start; $i <= $end; $i++ ) {
225 $options = array(
226 'page_number' => $i,
227 'current_page' => $current_page === $i,
228 );
229 $children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $pagination_item_id, $options, ( $i === $start ) );
230 }
231 }
232
233 $markup = $this->get_template(
234 'pagination',
235 array(
236 'attributes' => $attributes,
237 'children' => $children,
238 'tag' => $tag,
239 )
240 );
241 } elseif ( $pagination_type === 'infinite_scroll' ) {
242 $markup = $this->get_template(
243 'pagination',
244 array(
245 'attributes' => $attributes . ' data-total-pages="' . $total_pages . '" data-current-page="' . $current_page . '"' . ' data-pagination-type="' . $pagination_type . '"' . 'style="height:1px "',
246 'children' => $children,
247 'tag' => $tag,
248 )
249 );
250 } elseif ( $pagination_type === 'load_more' && $current_page !== $total_pages ) {
251 $children = isset( $this_data['children'] ) ? $this_data['children'] : array();
252
253 $child_markup = $this->construct_children_markup( $children, $options );
254
255 $attr = $attributes . ' data-total-pages="' . $total_pages . '" data-current-page="' . $current_page . '"' . ' data-pagination-type="' . $pagination_type . '"';
256 return "<$tag $attr>
257 $child_markup
258 </$tag>";
259 }
260 }
261
262 return $markup;
263 }
264
265 case 'pagination-item': {
266 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
267 $current_page = isset( $options['current_page'] ) ? $options['current_page'] : false;
268 $page_number = isset( $options['page_number'] ) ? $options['page_number'] : false;
269
270 $children = array();
271
272 foreach ( $this_data['children'] as $child ) {
273 $children[] = $this->recGenHTML(
274 $child,
275 array(
276 'page_number' => $page_number,
277 )
278 );
279 }
280
281 return $this->get_template(
282 'pagination-item',
283 array(
284 'attributes' => $attributes,
285 'children' => $children,
286 'current_page' => $current_page,
287 'page_number' => $page_number,
288 'tag' => $tag,
289 )
290 );
291 }
292
293 case 'pagination-number': {
294 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'span';
295 $page_number = isset( $options['page_number'] ) ? $options['page_number'] : 1;
296
297 return $this->get_template(
298 'pagination-number',
299 array(
300 'attributes' => $attributes,
301 'page_number' => $page_number,
302 'tag' => $tag,
303 )
304 );
305 }
306
307 case 'common': {
308 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
309 $type = isset( $this_data['properties']['type'] ) ? $this_data['properties']['type'] : false;
310
311 if ( $type ) {
312 $attributes .= ' data-kirki-type="' . $type . '"';
313 }
314
315 $children = isset( $this_data['children'] ) ? $this_data['children'] : array();
316
317 $child_markup = $this->construct_children_markup( $children, $options );
318
319 return "<$tag $attributes>
320 $child_markup
321 </$tag>";
322 }
323
324 case 'symbol': {
325 return $this->generate_symbol_html( $this_data, $attributes, $options );
326 }
327 case 'popup-body': {
328 return $this->popup_element( $this_data, $attributes, $options );
329 }
330
331 case 'button': {
332 return $this->button_element( $this_data, $attributes, $options );
333 }
334
335 case 'navigation': {
336 return $this->navigation_element( $this_data, $attributes, $options );
337 }
338
339 case 'navigation-item': {
340 return $this->navigation_item_element($this_data, $attributes, $options);
341 }
342
343 case 'navigation-items': {
344 return $this->navigation_items_element( $this_data, $attributes, $options );
345 }
346
347 case 'slider_nav':{
348 return $this->slider_nav_element( $this_data, $attributes, $options );
349 }
350 }
351 }
352
353 /**
354 * Generate collection loading element markup
355 *
356 * @param array $this_data single element block.
357 * @param array $attributes single element all attributes.
358 * @param array $options single element all options.
359 * @return string HTML markup.
360 */
361 private function collection_loading_element( $this_data, $attributes, $options ) {
362 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
363
364 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
365
366 return "<$tag $attributes kirki-collection=\"loading\" data-element_hide=\"true\">
367 $children_markup
368 </$tag>";
369 }
370
371 /**
372 * Generate section element markup
373 *
374 * @param array $this_data single element block.
375 * @param array $attributes single element all attributes.
376 * @param array $options single element all options.
377 * @return string HTML markup.
378 */
379 private function section_element( $this_data, $attributes, $options ) {
380 $id = isset( $this_data['id'] ) ? $this_data['id'] : '';
381 if ( $id ) {
382 $id = $this->get_unique_section_id_from_title( $id );
383 }
384
385 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'a';
386
387 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
388
389 return "<$tag $attributes id=\"$id\">
390 $children_markup
391 </$tag>";
392 }
393
394 private function navigation_element( $this_data, $attributes, $options ) {
395 $tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'a';
396
397 $hamburger = isset($this_data['properties']['navigation']['hamburger']) ? $this_data['properties']['navigation']['hamburger'] : false;
398
399 if ( ! is_array( $options ) ) {
400 $options = array();
401 }
402
403 if ( ! $options ) {
404 $options = array();
405 }
406 $options = array_merge(
407 $options,
408 array(
409 'navigation' => array(
410 'id' => $this_data['id'],
411 'hamburger' => $hamburger,
412 'showNavigationChildrenOn' => isset($this_data['properties']['navigation']['showNavigationChildrenOn']) ? $this_data['properties']['navigation']['showNavigationChildrenOn'] : 'hover',
413 ),
414 )
415 );
416
417 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
418
419 return "<$tag $attributes>
420 $children_markup
421 </$tag>";
422 }
423
424 private function navigation_item_element($this_data, $attributes, $options)
425 {
426 $tag = isset($this_data['properties'], $this_data['properties']['tag']) ? $this_data['properties']['tag'] : 'a';
427
428 $children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
429
430 $extra_attributes = '';
431
432 $show_on = 'hover';
433
434 // check showNavigationChildrenOn is hover or click or always then add kirki-navigation-item-trigger-on='hover'/'click'/'always'
435 if (isset($this_data['properties']['navigationItem']['showNavigationChildrenOn'])) {
436 $show_on = $this_data['properties']['navigationItem']['showNavigationChildrenOn'];
437 $extra_attributes .= ' kirki-navigation-item-trigger-on="' . $show_on . '"';
438 } else if (isset($options['navigation']['showNavigationChildrenOn'], $options['navigation']['hamburger']) && $options['navigation']['hamburger']) {
439 $show_on = $options['navigation']['showNavigationChildrenOn'];
440 $extra_attributes .= ' kirki-navigation-item-trigger-on="' . $show_on . '"';
441 } else {
442 $extra_attributes .= ' kirki-navigation-item-trigger-on="hover"';
443 }
444
445 if ('always' !== $show_on) {
446 $extra_attributes .= ' kirki-navigation-item-dismiss-on="' . ($this_data['properties']['navigationItem']['hideNavigationChildrenOn'] ?? 'mouseleave') . '"';
447 }
448
449 if (!$options) {
450 $options = array();
451 }
452
453 // add if kirki-navigation="nav-item" has in $this_data['properties']['attributes'] then set inside_nav_item = true
454 $options = array_merge(
455 $options,
456 array(
457 'inside_nav_item' => isset($this_data['properties']['attributes']['kirki-navigation']) && $this_data['properties']['attributes']['kirki-navigation'] === 'nav-item',
458 )
459 );
460
461 $children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
462
463 return "<$tag $attributes $extra_attributes>
464 $children_markup
465 </$tag>";
466 }
467
468 private function navigation_items_element($this_data, $attributes, $options)
469 {
470
471 $tag = isset($this_data['properties'], $this_data['properties']['tag']) ? $this_data['properties']['tag'] : 'a';
472
473 $extra_attr = isset($options['inside_navigation']) && $options['inside_navigation'] ? 'kirki-navigation-hide="true"' : '';
474
475 if (isset($options['navigation']['hamburger']) && $options['navigation']['hamburger']) {
476 $extra_attr .= ' kirki-navigation-type="close"';
477 }
478
479 if (!$options) {
480 $options = array();
481 }
482 $options = array_merge(
483 $options,
484 array(
485 'inside_navigation' => true,
486 )
487 );
488
489 $children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
490 // check it has kirki-menu-wrapper: true as attribute
491 // if (isset($this_data['properties']['attributes']['kirki-menu-wrapper']) && $this_data['properties']['attributes']['kirki-menu-wrapper'] === 'true') {
492 if (isset($options['inside_nav_item']) && $options['inside_nav_item'] === true) {
493 // Match the content inside class="..." and data-kirki="..."
494 preg_match('/class="([^"]+)"/', $attributes, $classMatch);
495 preg_match('/data-kirki="([^"]+)"/', $attributes, $dataMatch);
496
497 $class = $classMatch[1] ?? null;
498 $data_kirki = $dataMatch[1] ?? null;
499
500 return "
501 <div kirki-menu-wrapper-div='true'>
502 <$tag class='$class' data-kirki='$data_kirki'>
503 $children_markup
504 </$tag>
505 </div>
506 ";
507 } else {
508 return "<$tag $attributes $extra_attr>
509 $children_markup
510 </$tag>";
511 }
512
513 }
514
515 private function form_element( $this_data, $attributes, $options ) {
516 $properties = $this_data['properties'];
517 $post_id = HelperFunctions::get_post_id_if_possible_from_url();
518 $form_id = $this_data['id'];
519 $post_data = $form_id . '|' . $post_id;
520 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
521 $form_id_base64 = base64_encode( base64_encode( $post_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' ) {
761 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
762
763 $data_n_styles = array(
764 'blocks' => array(),
765 'styles' => array(),
766 );
767
768 DataHelper::get_data_and_styles_from_root( $this_data['id'], $data_n_styles, $this->data, $this->style_blocks );
769
770 if ( is_array( $children ) ) {
771 return $this->get_template(
772 'collection',
773 array(
774 'data' => $data_n_styles,
775 'attributes' => $attributes,
776 'children' => $children,
777 'tag' => $tag,
778 )
779 );
780 } else {
781 return '';
782 }
783 }
784
785 /**
786 * Generate custom code markup
787 *
788 * @param array $this_data single element block.
789 * @param array $attributes single element all attributes.
790 * @return string HTML markup.
791 */
792 private function custom_code( $this_data, $attributes ) {
793 $properties = $this_data['properties'];
794 if ( isset( $properties['content'] ) ) {
795 if ( isset( $properties['data-type'] ) && $properties['data-type'] === 'url' ) {
796 return '<div ' . $attributes . '>
797 <iframe
798 src="' . $properties['content'] . '"
799 title="' . $this_data['id'] . '"
800 allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
801 style="width:100%;height:100%;"
802 ></iframe>
803 </div>';
804 } else {
805 return '<div ' . $attributes . '>' . $properties['content'] . '</div>';
806 }
807 }
808 return '';
809 }
810
811 /**
812 * Generate Map element markup
813 *
814 * @param array $this_data single element block.
815 * @param array $attributes single element all attributes.
816 * @return string HTML markup.
817 */
818 private function map_element( $this_data, $attributes ) {
819 $properties = isset( $this_data['properties']['map'] ) ? $this_data['properties']['map'] : false;
820 if ( ! $properties ) {
821 return '';
822 }
823 return '<div ' . $attributes . '></div>';
824 }
825
826 /**
827 * Generate Video element markup
828 *
829 * @param array $this_data single element block.
830 * @param array $attributes single element all attributes.
831 * @return string HTML markup.
832 */
833 private function video_element( $this_data, $attributes, $options ) {
834 $properties = $this_data['properties'];
835 $name = $properties['attributes']['name'];
836 $src = $properties['attributes']['src'];
837 $scale = isset( $properties['scale'] ) ? $properties['scale'] : 'cover';
838 $aspectRatio = isset( $properties['aspectRatio'] ) ? $properties['aspectRatio'] : '16 / 9';
839 $type = $properties['attributes']['type'];
840 $controls = $properties['attributes']['controls'];
841 $play_inline = isset( $properties['attributes']['playInline'] ) ? $properties['attributes']['playInline'] : true;
842 $duration = isset( $properties['attributes']['duration'] ) ? $properties['attributes']['duration'] : 0;
843 $start_time = $properties['attributes']['startTime'];
844 $end_time = isset( $properties['attributes']['endTime'] ) ? $properties['attributes']['endTime'] : $duration;
845 $span_attr_string = $this->getAllAttributes(
846 $this_data,
847 array(
848 'class' => true,
849 'data-kirki' => true,
850 'rest' => false,
851 ),
852 );
853 $dynamic_content = isset( $properties['dynamicContent'] ) ? $properties['dynamicContent'] : false;
854
855 if ( isset( $this_data['properties']['attributes']['muted'] ) && $this_data['properties']['attributes']['muted'] === false ) {
856 unset( $this_data['properties']['attributes']['muted'] );
857 }
858
859 $video_attr_string = $this->getAllAttributes(
860 $this_data,
861 array(
862 'class' => false,
863 'data-kirki' => false,
864 'src' => false,
865 'autoPlay' => false,
866 'controls' => false,
867 'dataVideoPlayListener' => false,
868 'rest' => true,
869 ),
870 );
871
872 if ( $play_inline ) {
873 $video_attr_string .= ' playsinline';
874 }
875
876 $poster = '';
877 if ( isset( $properties['thumbnail'], $properties['thumbnail']['status'] ) && $properties['thumbnail']['status'] ) {
878 $poster = isset( $properties['thumbnail'], $properties['thumbnail']['url'] ) ? $properties['thumbnail']['url'] : null;
879 }
880
881 $video_src = '';
882 if ( $dynamic_content ) {
883 // TODO: Need to get dynamic course video or image url for tutor lms using hook.
884 if ( isset( $options['itemType'] ) ) {
885 if ( $options['itemType'] === 'post' ) {
886 if ( $options['post']->{$dynamic_content['value']} ) {
887 $video_obj = $options['post']->{$dynamic_content['value']};
888
889 if ( isset( $video_obj['url'] ) ) {
890 $video_src = $video_obj['url'];
891 }
892 } else {
893 $video_obj = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
894
895 if ( isset( $video_obj['url'] ) ) {
896 $video_src = $video_obj['url'];
897 }
898 }
899 }
900 } else {
901 $video_obj = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
902
903 if ( isset( $video_obj['url'] ) ) {
904 $video_src = $video_obj['url'];
905 }
906 }
907 }
908
909 // if no dynamic video src then check original source for fallback video url
910 if ( ! $video_src && ! $src ) {
911 return '';
912 } else {
913 $src = $video_src ? $video_src : $src;
914 }
915
916 $video_url_type = $this->video_type( $src );
917
918 if ( $video_url_type === 'youtube' ) {
919 $video_src = $this->get_youtube_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
920 } elseif ( $video_url_type === 'vimeo' ) {
921 $video_src = $this->get_vimeo_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
922 } elseif ( $video_url_type === 'tiktok' ) {
923 $video_src = $this->get_tiktok_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
924 } else {
925 $video_src = $src . '#t=' . $start_time . ',' . $duration;
926 }
927
928 $html = '<span ' . $span_attr_string . '>';
929 if ( $video_url_type === 'youtube' || $video_url_type === 'vimeo' || $video_url_type === 'tiktok' ) {
930 $html .= '<iframe height="100%" width="100%" title="' . $name . '" src="' . $video_src . '" style="aspect-ratio: ' . $aspectRatio . ';" ></iframe>';
931 } else {
932 if ( isset( $properties['attributes']['lazy'] ) && $properties['attributes']['lazy'] ) {
933 // `data-src` is used in `source` tag to lazy load the video using JS. Check JS preview script for videos.
934 $html .= '<video' . $video_attr_string . ' style="object-fit: ' . $scale . '; aspect-ratio: ' . $aspectRatio . ';" poster="' . $poster . '">
935 <source data-src="' . $video_src . '" type="' . $type . '"></source></video>';
936 } else {
937 $html .= '<video' . $video_attr_string . ' style="object-fit: ' . $scale . '; aspect-ratio: ' . $aspectRatio . ';" poster="' . $poster . '">
938 <source src="' . $video_src . '" type="' . $type . '"></source></video>';
939 }
940 }
941 $html .= '</span>';
942 return $html;
943 }
944
945 /**
946 * Generate Video element markup
947 *
948 * @param array $this_data single element block.
949 * @param array $attributes single element all attributes.
950 * @return string HTML markup.
951 */
952 private function radio_group( $this_data, $attributes ) {
953 $properties = $this_data['properties'];
954 $data = $properties['data']['child'];
955 $name = $properties['attributes']['name'];
956
957 $str = '<div ' . $attributes . '>';
958
959 foreach ( $data as $key => $child ) {
960 $attrs = "type='radio' name='{$name}' value='{$child['value']}'";
961 $attrs .= $child['checked'] ? ' checked' : '';
962
963 $str .= '<label>
964 <input ' . $attrs . '/>
965 <span>' . $child['content'] . '</span>
966 </label>';
967 }
968 $str .= '</div>';
969 return $str;
970 }
971
972 /**
973 * Generate popup-body element markup
974 *
975 * @param array $this_data single element block.
976 * @param array $attributes single element all attributes.
977 * @return string HTML markup.
978 */
979 private function popup_element( $this_data, $attributes, $options ) {
980 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
981 return '<div class="kirki-popup-body-wrapper"><div ' . $attributes . '>' . $children_markup . '</div></div>';
982 }
983
984 /**
985 * Recursively Generate menu items element markup
986 *
987 * @param array $submenus all submenus.
988 * @param int $depth menu nesting info.
989 * @return string HTML markup.
990 */
991 private function rec_gen_menu_items( $submenus, $depth ) {
992 if ( count( $submenus ) === 0 ) {
993 return '';
994 }
995 if ( $depth === 0 ) {
996 $str = '<ul class="' . 'kirki-nav-menu">';
997 } else {
998 $str = '<ul class="' . 'kirki-element-submenu">';
999 }
1000 $depth++;
1001 foreach ( $submenus as $key => $menu ) {
1002 $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>';
1003 }
1004 $str .= '</ul>';
1005 return $str;
1006 }
1007
1008 /**
1009 * This method will add css value and unit
1010 *
1011 * @param array $value css value and unit pair.
1012 * @return string 5px | auto.
1013 */
1014 private function add_unit( $value ) {
1015 if ( isset( $value['unit'] ) && $value['unit'] !== 'auto' ) {
1016 return $value['value'] . $value['unit'];
1017 }
1018 return 'auto';
1019 }
1020
1021 /**
1022 * Generate Image element markup
1023 *
1024 * @param array $this_data single element block.
1025 * @param array $attributes single element all attributes.
1026 * @param array $options single element all options.
1027 * @return string HTML markup.
1028 */
1029 private function image_element( $this_data, $attributes, $options ) {
1030 $properties = $this_data['properties'];
1031 $svg_outer_html = isset( $properties['svgOuterHtml'] ) ? $properties['svgOuterHtml'] : false;
1032 $dynamic_content = isset( $properties['dynamicContent'] ) ? $properties['dynamicContent'] : false;
1033 $dynamic_alt = isset( $properties['dynamicAlt'] ) ? $properties['dynamicAlt'] : false;
1034
1035 $user_initials = false;
1036
1037 $src = '';
1038
1039 if ( $dynamic_content ) {
1040 $image_data = array();
1041
1042 if ( $dynamic_content['type'] === 'reference' && isset( $options['post'], $options['post']->ID ) ) {
1043 $content_info = array(
1044 'collectionItem' => array(
1045 'ID' => $options['post']->ID,
1046 ),
1047 'dynamicContent' => $dynamic_content,
1048 );
1049
1050 $content = apply_filters( 'kirki_dynamic_content', false, $content_info );
1051 $image_data = $content;
1052 } elseif ( $dynamic_content['type'] === 'gallery' ) {
1053 $content_info = array(
1054 'collectionItem' => array(
1055 'id' => $options['gallery']['id'],
1056 'url' => $options['gallery']['url'],
1057
1058 ),
1059 'dynamicContent' => $dynamic_content,
1060 );
1061
1062 $content = apply_filters( 'kirki_dynamic_content', false, $content_info );
1063
1064 $image_data = $content;
1065 } elseif ( $dynamic_content['type'] === 'user' ) {
1066 $user_id = isset( $options['user'], $options['user']['ID'] ) ? $options['user']['ID'] : null;
1067 $src = HelperFunctions::get_user_dynamic_content( $dynamic_content['value'], $user_id, $dynamic_content['meta'] ?? '' );
1068 $image_data = array(
1069 'src' => $src,
1070 );
1071 } elseif ( isset( $options['itemType'] ) ) {
1072 if ( $options['itemType'] === 'post' ) {
1073 if ( isset( $options['post']->{$dynamic_content['value']} ) && $options['post']->{$dynamic_content['value']} ) {
1074 $image_data = $options['post']->{$dynamic_content['value']};
1075 } else {
1076 $image_data = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
1077 }
1078 } elseif ( $options['itemType'] === 'comment' ) {
1079 if ( isset( $options['comment']->{$dynamic_content['value']} ) && $options['comment']->{$dynamic_content['value']} ) {
1080 $image_data = $options['comment']->{$dynamic_content['value']};
1081 }
1082 } elseif ( $options['itemType'] === 'user' ) {
1083 if ( isset( $options['user'], $options['user'][ $dynamic_content['value'] ] ) ) {
1084 $image_data = array(
1085 'src' => $options['user'][ $dynamic_content['value'] ],
1086 );
1087 }
1088 }
1089 } else {
1090 $post = isset( $options['post'] ) ? $options['post'] : get_post( HelperFunctions::get_post_id_if_possible_from_url() );
1091 $image_data = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], $post, isset( $dynamic_content['meta'] ) ? $dynamic_content['meta'] : null );
1092 if ( is_string( $image_data ) ) {
1093 $image_data = array(
1094 'src' => $image_data,
1095 );
1096 }
1097 }
1098
1099 if ( isset( $image_data['src'] ) ) {
1100 $src = $image_data['src'];
1101 }
1102
1103 if ( isset( $image_data['wp_attachment_id'] ) ) {
1104 $properties['wp_attachment_id'] = $image_data['wp_attachment_id'];
1105 }
1106 }
1107
1108 if ( $dynamic_content && $src ) {
1109 // replace src and alt.
1110 $attributes = preg_replace( array( '/src="([^"]+")/i' ), array( '' ), $attributes );
1111 } else {
1112 $src = isset( $properties['attributes']['src'] ) ? $properties['attributes']['src'] : '';
1113 }
1114
1115 // set dynamic alt here
1116 if ( $dynamic_alt ) {
1117 $new_alt = Utils::getDynamicRichTextValue( $dynamic_alt, $options );
1118
1119 // Update properties array for consistency
1120 $properties['attributes']['alt'] = $new_alt;
1121
1122 // Replace alt attribute inside the HTML string
1123 $attributes = preg_replace(
1124 '/alt="[^"]*"/i',
1125 'alt="' . esc_attr( $new_alt ) . '"',
1126 $attributes
1127 );
1128 } elseif ( empty( $properties['attributes']['alt'] ) ) {
1129 // get WordPress attachment alt text if alt is empty
1130 if ( isset( $properties['wp_attachment_id'] ) && $properties['wp_attachment_id'] ) {
1131 $alt_text = get_post_meta( $properties['wp_attachment_id'], '_wp_attachment_image_alt', true );
1132 $attributes = preg_replace( '/alt="([^"]*)"/i', 'alt="' . esc_attr( $alt_text ) . '"', $attributes );
1133 }
1134 }
1135
1136 $srcset = null;
1137 if ( ! $dynamic_content && isset( $properties['wp_attachment_id'] ) && $properties['wp_attachment_id'] ) {
1138 $srcset = wp_get_attachment_image_srcset( $properties['wp_attachment_id'] );
1139 $attributes .= $srcset ? ' srcset="' . $srcset . '"' : '';
1140
1141 $sizes = '';
1142 $a_meta_data = wp_get_attachment_metadata( $properties['wp_attachment_id'] );
1143 if ( $a_meta_data && isset( $a_meta_data['width'] ) ) {
1144 $width = $a_meta_data['width'];
1145 $sizes = '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
1146 $attributes .= $sizes ? ' sizes="' . $sizes . '"' : '';
1147 }
1148 }
1149
1150 if ( ( isset( $properties['load'] ) && $properties['load'] !== 'auto' ) || ! isset( $properties['load'] ) ) {
1151 $attributes .= isset( $properties['load'] ) ? ' loading="' . $properties['load'] . '"' : ' loading="lazy"';
1152 }
1153
1154 if ( isset( $properties['width'] ) ) {
1155 $attributes .= ' width="' . $this->add_unit( $properties['width'] ) . '"';
1156
1157 }
1158 if ( isset( $properties['height'] ) ) {
1159 $attributes .= ' height="' . $this->add_unit( $properties['height'] ) . '"';
1160 }
1161
1162 if ( ! $src ) {
1163 return '';
1164 }
1165
1166 $str = '';
1167
1168 if ( $svg_outer_html ) {
1169 $str .= '<img ' . $attributes . ' src="' . $src . '"/>
1170 <span>' . $svg_outer_html . '</span>';
1171 } else {
1172 $str .= '<img ' . $attributes . ' src="' . $src . '"/>';
1173 }
1174
1175 return $str;
1176 }
1177
1178 /**
1179 * Get video type from url
1180 *
1181 * @param string $url single element block.
1182 * @return string|bool video url type.
1183 */
1184 private function video_type( $url ) {
1185 if ( strpos( $url, 'youtube' ) > 0 || strpos( $url, 'youtu.be' ) > 0 ) {
1186 return 'youtube';
1187 } elseif ( strpos( $url, 'vimeo' ) > 0 ) {
1188 return 'vimeo';
1189 } elseif ( strpos( $url, 'tiktok' ) > 0 ) {
1190 return 'tiktok';
1191 } else {
1192 return false;
1193 }
1194 }
1195
1196 /**
1197 * Get video type from url
1198 *
1199 * @param string $url single element block.
1200 * @return string youtube url type.
1201 */
1202 private function get_youtube_embed_url( $url ) {
1203 preg_match( '%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match );
1204 return isset( $match[1] ) ? 'https://www.youtube.com/embed/' . $match[1] : '#';
1205 }
1206
1207 private function get_vimeo_embed_url( $url ) {
1208 preg_match( '/vimeo\.com\/(?:.*\/)?(\d+)/', $url, $matches );
1209 return isset( $matches[1] ) ? 'https://player.vimeo.com/video/' . $matches[1] : '#';
1210 }
1211
1212 private function get_tiktok_embed_url( $url ) {
1213 preg_match( '/tiktok\.com\/(?:@[\w.-]+\/)?video\/(\d+)/', $url, $matches );
1214 return isset( $matches[1] ) ? 'https://www.tiktok.com/embed/' . $matches[1] : '#';
1215 }
1216
1217 /**
1218 * Generate symbol markup
1219 *
1220 * @param array $this_data single element block.
1221 * @param array $attributes single element all attributes.
1222 * @return string HTML markup.
1223 */
1224 private function generate_symbol_html( $this_data, $attributes, $options = array() ) {
1225 $properties = $this_data['properties'];
1226 $symbol_id = $properties['symbolId'];
1227 $symbolElementProp = isset( $properties['symbolElProps'] ) ? $properties['symbolElProps'] : false;
1228 $symbol = Symbol::get_single_symbol( $symbol_id, true, false, $symbolElementProp );
1229
1230 if ( ! $symbol ) {
1231 return '';
1232 }
1233
1234 $symbol_data = $symbol['symbolData'];
1235 if ( ! $symbol_data || ! isset( $symbol_data['data'] ) ) {
1236 return '';
1237 }
1238 $s = HelperFunctions::rec_update_data_id_then_return_new_html( $symbol_data['data'], $symbol_data['styleBlocks'], $symbol_data['root'], $options );
1239 $fonts_links = '';
1240 if ( isset( $symbol_data['customFonts'] ) ) {
1241 foreach ( $symbol_data['customFonts'] as $key => $f ) {
1242 if ( isset( $f['fontUrl'] ) ) {
1243 $fonts_links .= HelperFunctions::getFontsHTMLMarkup( $f );
1244 }
1245 }
1246 }
1247 return '<div ' . $attributes . '>' . $fonts_links . $s . '</div>';
1248 }
1249
1250 /**
1251 * Get html template.
1252 *
1253 * @param string $template template file name.
1254 * @param array $vars if extra variable needs inside template file.
1255 * @return string $message
1256 */
1257 private function get_template( $template, $vars ) {
1258 ob_start();
1259 include __DIR__ . "/templates/$template.view.php";
1260 $message = ob_get_contents();
1261 ob_end_clean();
1262 return $message;
1263 }
1264
1265 /**
1266 * Generate File upload element markup
1267 *
1268 * @param array $this_data single element block.
1269 * @param array $attributes single element all attributes.
1270 * @param array $options single element all options.
1271 * @return string HTML markup.
1272 */
1273 private function file_upload_element( $this_data, $attributes, $options ) {
1274 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1275 $data_attr = isset( $this_data['properties']['attributes'] ) ? $this_data['properties']['attributes'] : array();
1276 $options = array_merge(
1277 $options,
1278 array(
1279 'file_upload' => array(
1280 'name' => isset( $data_attr['name'] ) ? $data_attr['name'] : '',
1281 'accept' => isset( $data_attr['accept'] ) ? $data_attr['accept'] : '',
1282 'required' => isset( $data_attr['required'] ) ? $data_attr['required'] : '',
1283 'maxFileSize' => isset( $this_data['properties']['maxFileSize'] ) ? $this_data['properties']['maxFileSize'] : 2,
1284 ),
1285 )
1286 );
1287
1288 $attributes = $this->getAllAttributes(
1289 $this_data,
1290 array(
1291 'name' => false,
1292 'accept' => false,
1293 'required' => false,
1294 'rest' => true,
1295 ),
1296 );
1297
1298 $children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
1299 return "<$tag $attributes>
1300 $children_markup
1301 </$tag>";
1302 }
1303
1304 /**
1305 * Generate File input threshold text element markup
1306 *
1307 * @param array $this_data single element block.
1308 * @param array $attributes single element all attributes.
1309 * @param array $options single element all options.
1310 * @return string HTML markup.
1311 */
1312
1313 private function file_upload_threshold_text( $this_data, $attributes, $options ) {
1314 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'span';
1315 $max_file_size = isset( $options['file_upload']['maxFileSize'] ) ? $options['file_upload']['maxFileSize'] : 2;
1316
1317 return "<$tag $attributes>Max file size " . $max_file_size . "MB.</$tag>";
1318 }
1319
1320 /**
1321 * Generate File input element markup
1322 *
1323 * @param array $this_data single element block.
1324 * @param array $attributes single element all attributes.
1325 * @param array $options single element all options.
1326 * @return string HTML markup.
1327 */
1328 private function file_input_element( $this_data, $attributes, $options ) {
1329 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1330 $children = $this_data['children'] ?? array();
1331 $markup = '';
1332
1333 $name = isset( $options['file_upload']['name'] ) ? $options['file_upload']['name'] : '';
1334 $accept = isset( $options['file_upload']['accept'] ) ? $options['file_upload']['accept'] : '';
1335 $required = isset( $options['file_upload']['required'] ) ? $options['file_upload']['required'] : '';
1336 $max_file_size = isset( $options['file_upload']['maxFileSize'] ) ? $options['file_upload']['maxFileSize'] : 2;
1337
1338 foreach ( $children as $child ) {
1339 $markup .= $this->recGenHTML( $child, $options );
1340 }
1341
1342 return "<$tag $attributes>
1343 $markup
1344 <input
1345 type=\"file\"
1346 readonly
1347 style=\"display: none;\"
1348 name=\"$name\"
1349 accept=\"$accept\"
1350 required=\"$required\"
1351 kirki-max_file_size=$max_file_size
1352 />
1353 </$tag>";
1354 }
1355
1356 private function slider_nav_element( $this_data, $attributes, $options ) {
1357 $tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
1358 $collection = isset( $options['collection'] ) ? $options['collection'] : array();
1359 $itemType = isset( $options['itemType'] ) ? $options['itemType'] : 'post';
1360 $slider_nav_item_id = isset( $this_data['children'][0] ) ? $this_data['children'][0] : '';
1361 $slider_nav_children = isset( $this_data['children'] ) ? $this_data['children'] : array();
1362 $slider_mode = $options['slider_mode'] ?? 'manual';
1363 $page_no = isset( $options['page_no'] ) ? (int) $options['page_no'] : 1;
1364
1365 $children = array();
1366
1367 if ( $slider_mode === 'manual' ) {
1368 foreach ( $slider_nav_children as $key => $child_id ) {
1369 $children[] = $this->recGenHTML( $child_id, $options );
1370 }
1371 } else { // dynamic
1372 if ( empty( $collection ) || ! $slider_nav_item_id ) {
1373 return '';
1374 }
1375
1376 $items_per_page = isset( $options['items_per_page'] ) ? (int) $options['items_per_page'] : count( $collection );
1377
1378 $start = ( $page_no - 1 ) * $items_per_page;
1379 $items_to_render = array_slice( $collection, $start, $items_per_page );
1380
1381 foreach ( $items_to_render as $key => $collection_item ) {
1382 $item_index = HelperFunctions::get_current_item_index( $key + 1, $options );
1383
1384 $merged_options = array_merge(
1385 $options,
1386 array(
1387 'itemType' => $itemType,
1388 $itemType => $collection_item,
1389 'item_index' => $item_index,
1390 'nav_index' => $start + $key,
1391 'is_active' => $key === 0,
1392 )
1393 );
1394
1395 $children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $slider_nav_item_id, $merged_options, ( $key === 0 ) );
1396 }
1397 }
1398
1399 return $this->get_template(
1400 'pagination-item',
1401 array(
1402 'attributes' => $attributes,
1403 'children' => $children,
1404 'current_page' => 1,
1405 'page_number' => $page_no,
1406 'tag' => $tag,
1407 )
1408 );
1409 }
1410
1411 }