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 . '&start=' . $start_time . '&end=' . $end_time; |
| 920 | } elseif ( $video_url_type === 'vimeo' ) { |
| 921 | $video_src = $this->get_vimeo_embed_url( $src ) . '?controls=' . $controls . '&start=' . $start_time . '&end=' . $end_time; |
| 922 | } elseif ( $video_url_type === 'tiktok' ) { |
| 923 | $video_src = $this->get_tiktok_embed_url( $src ) . '?controls=' . $controls . '&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 | } |