PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / trunk
Kubio AI Page Builder vtrunk
2.8.2 2.8.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 2.0.0 2.1.1 2.1.2 2.1.3 2.2.0 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.5 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 2.6.5 2.6.6 2.6.7 2.7.0 2.7.1 2.7.2 2.7.3 2.8.0
kubio / lib / src / Core / CustomizerImporter.php
kubio / lib / src / Core Last commit date
Background 1 year ago Blocks 1 year ago GlobalElements 1 year ago Layout 1 year ago Separators 11 months ago StyleManager 1 month ago Styles 1 year ago Activation.php 1 year ago Backup.php 1 year ago CustomizerImporter.php 11 months ago Deactivation.php 1 year ago EditInKubioCustomizerPanel.php 1 year ago Element.php 1 year ago ElementBase.php 4 years ago Importer.php 1 month ago InnerBlocks.php 1 year ago KubioFrontPageRevertNotice.php 9 months ago LodashBasic.php 1 year ago Registry.php 1 year ago ThirdPartyPluginAssetLoaderInEditor.php 3 months ago Utils.php 13 hours ago
CustomizerImporter.php
1207 lines
1 <?php
2
3 namespace Kubio\Core;
4
5 use ColibriWP\Theme\Defaults;
6 use IlluminateAgnostic\Arr\Support\Arr;
7 use Kubio\Core\StyleManager\Utils;
8 use Kubio\Flags;
9
10 class CustomizerImporter {
11
12 private static $current_data = null;
13 private $content = '';
14 private $type = '';
15 private $slug = '';
16 private $type_process_callback = array();
17
18
19 public function __construct( $content, $type, $slug ) {
20 $this->content = $content;
21 $this->type = $type;
22 $this->slug = $slug;
23
24 $this->type_process_callback = array(
25 'wp_template_part' => array(
26 'footer' => array( $this, 'processFooter' ),
27 'front-header' => array( $this, 'processHeader' ),
28 'header' => array( $this, 'processHeader' ),
29 ),
30 'wp_template' => array(
31 '*' => array( $this, 'processTemplate' ),
32 ),
33 );
34 }
35
36 public function process() {
37
38 $this->loadCurrentData();
39
40 if ( $this->canProcessCurrent() ) {
41 $this->processCurrent();
42 }
43
44 return $this->content;
45 }
46
47 private function loadCurrentData() {
48 if ( static::$current_data === null ) {
49
50 $options_data_map = array(
51 'front-header.title.localProps.content' => 'front-header.title.value',
52 'front-header.subtitle.localProps.content' => 'front-header.subtitle.value',
53 'front-header.header-menu.style.descendants.innerMenu.justifyContent' => array(
54 'option' => 'front-header.header-menu.style.descendants.main-menu-ul.justifyContent',
55 'default' => 'center',
56 ),
57 'header.header-menu.style.descendants.innerMenu.justifyContent' => array(
58 'option' => 'header.header-menu.style.descendants.main-menu-ul.justifyContent',
59 'default' => 'center',
60 ),
61 );
62
63 $data = array();
64 if ( class_exists( Defaults::class ) ) {
65 $data = Defaults::getDefaults();
66
67 // set default to lorem ipsum - inside the editor it is `Click to edit...`
68 Arr::set( $data, 'front-header.subtitle.value', $data['lorem_ipsum'] );
69
70 $options = get_theme_mods();
71
72 foreach ( $options_data_map as $option_to_map => $map ) {
73 $option_to_set = is_array( $map ) ? $map['option'] : $map;
74 $default_value = is_array( $map ) ? $map['default'] : null;
75
76 $value = Arr::get( $options, $option_to_map, $default_value );
77 Arr::forget( $options, $option_to_map );
78
79 if ( $value ) {
80 $options[ $option_to_set ] = $value;
81 }
82 }
83
84 foreach ( $options as $option => $value ) {
85
86 // remove multiple dots in path - fixes bad formatting
87 $option = preg_replace( '#\.\.+#', '.', $option );
88 Arr::set( $data, $option, $value );
89 }
90 }
91
92 // Copy layoutType for logo
93 $front_header_logo_layout_type = Arr::get( $data, 'front-header.logo.props.layoutType' );
94 $header_logo_layout_type = Arr::get( $data, 'header.logo.props.layoutType' );
95
96 if ( $front_header_logo_layout_type !== $header_logo_layout_type ) {
97 Arr::set( $data, 'header.logo.props.layoutType', $front_header_logo_layout_type );
98 }
99 //
100
101 // Copy top-bar icons from front header
102 $front_header_icon_list = Arr::get( $data, 'front-header.icon_list' );
103 $front_header_social_icons = Arr::get( $data, 'front-header.social_icons' );
104
105 Arr::forget( $data, array( 'header.icon_list', 'header.social_icons' ) );
106
107 Arr::set( $data, 'header.icon_list', $front_header_icon_list );
108 Arr::set( $data, 'header.social_icons', $front_header_social_icons );
109 //
110
111 // Set menu hover effect for front and inner header
112 $menu_effect = Arr::get( $data, 'front-header.header-menu.props.hoverEffect.group.border.transition' );
113
114 Arr::forget( $data, 'front-header.header-menu.props.hoverEffect.group' );
115 Arr::forget( $data, 'header.header-menu.props.hoverEffect.group' );
116
117 Arr::set( $data, 'front-header.header-menu.props.hoverEffect.border.effect', $menu_effect );
118 Arr::set( $data, 'header.header-menu.props.hoverEffect.border.effect', $menu_effect );
119 //
120
121 static::$current_data = $data;
122 }
123 }
124
125 private function canProcessCurrent() {
126
127 if ( $this->type === 'wp_template' ) {
128 return true;
129 }
130
131 return isset( $this->getCurrentData()[ $this->slug ] );
132 }
133
134 public function getCurrentData() {
135 return static::$current_data;
136 }
137
138 private function processCurrent() {
139 $process_fn = Arr::get( $this->type_process_callback, "{$this->type}.{$this->slug}", null );
140
141 $process_fn_for_all = Arr::get( $this->type_process_callback, "{$this->type}.*", null );
142
143 if ( $process_fn || $process_fn_for_all ) {
144 $parsed_blocks = parse_blocks( $this->content );
145
146 if ( $process_fn ) {
147 $parsed_blocks = call_user_func( $process_fn, $parsed_blocks );
148 }
149
150 if ( $process_fn_for_all ) {
151 $parsed_blocks = call_user_func( $process_fn_for_all, $parsed_blocks );
152 }
153 $this->content = kubio_serialize_blocks( $parsed_blocks );
154 }
155 }
156
157 private function processTemplate( $parsed_blocks ) {
158 if ( $this->slug === 'index' && $this->type === 'wp_template' ) { //here is the blog
159 $parsed_blocks = static::removeSidebar( $parsed_blocks );
160 }
161
162 $parsed_blocks = $this->postProcessBlocks( $parsed_blocks, $this->getCurrentData() );
163
164 return $parsed_blocks;
165 }
166
167 private function postProcessBlocks( $parsed_blocks, $current_data ) {
168 foreach ( $parsed_blocks as $index => $block ) {
169 $parsed_blocks[ $index ] = $this->postProcessBlock( $block, $current_data );
170 $inner_blocks = $this->postProcessBlocks( $block['innerBlocks'], $current_data );
171 $parsed_blocks = $this->updateBlockInnerBlocks( $parsed_blocks, $index, $inner_blocks );
172 }
173
174 return $parsed_blocks;
175 }
176
177 private function postProcessBlock( $parsed_block, $current_data ) {
178 $block_name = $parsed_block['blockName'];
179
180 if ( $block_name === 'kubio/logo' ) {
181 $data = Arr::get( $current_data, 'logo' );
182 $parsed_block = $this->normalizeLogo( $parsed_block, $data );
183 }
184
185 if ( $block_name === 'kubio/image' ) {
186 $data = Arr::get( $current_data, 'hero.image' );
187 $parsed_block = $this->normalizeImage( $parsed_block, $data );
188 }
189
190 if ( $block_name === 'kubio/query-loop' ) {
191 $items_per_row = Arr::get( $current_data, 'blog_posts_per_row', 2 );
192 $masonry = Arr::get( $current_data, 'blog_enable_masonry', true );
193
194 Arr::set( $parsed_block, 'attrs.kubio.props.layout.itemsPerRow', intval( $items_per_row ) );
195
196 Arr::set( $parsed_block, 'attrs.masonry', $masonry );
197 }
198
199 if ( $block_name === 'kubio/post-featured-image' ) {
200 Arr::set(
201 $parsed_block,
202 'attrs.kubio.style.descendants.container.background.color',
203 Arr::get( $current_data, 'blog_post_thumb_placeholder_color', 'rgba(var(--kubio-color-5-variant-2),1)' )
204 );
205
206 Arr::set(
207 $parsed_block,
208 'attrs.showPlaceholder',
209 Arr::get( $current_data, 'blog_show_post_thumb_placeholder', true )
210 );
211 }
212 if ( $block_name === 'kubio/footer' ) {
213 Arr::set(
214 $parsed_block,
215 'attrs.kubio.props.useFooterParallax',
216 Arr::get( $current_data, 'footer.footer.props.useFooterParallax' )
217 );
218 }
219
220 if ( $block_name === 'kubio/dropdown-menu' && $this->slug === 'header' ) {
221 $data = $this->getCurrentData();
222 $menu_effect = Arr::get( $data, 'front-header.header-menu.props.hoverEffect.border.effect' );
223 Arr::set( $parsed_block, 'attrs.kubio.props.hoverEffect.border.effect', $menu_effect );
224 }
225
226 return $parsed_block;
227 }
228
229 private function normalizeLogo( $parsed_block, $data ) {
230
231 $layout_type = Arr::get( $data, 'props.layoutType', null );
232 $current_data = $this->getCurrentData();
233 $menu_layout_type = Arr::get( $current_data, $this->slug . '.navigation.props.layoutType' );
234
235 if ( $layout_type ) {
236 Arr::set( $parsed_block, 'attrs.kubio.props.layoutType', $layout_type );
237
238 if ( $menu_layout_type === 'logo-above-menu' ) {
239 Arr::set( $parsed_block, 'attrs.kubio.style.descendants.container.alignItems', 'center' );
240 Arr::set( $parsed_block, 'attrs.kubio.style.descendants.container.justifyContent', 'center' );
241 }
242 }
243
244 // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
245 if ( $alternate_logo = Arr::get( $current_data, 'alternate_logo', false ) ) {
246 kubio_set_global_data( 'alternateLogo', wp_get_attachment_image_url( intval( $alternate_logo ), 'full' ) );
247 }
248
249 return $parsed_block;
250 }
251
252 private function normalizeImage( $parsed_block, $data ) {
253
254 if ( ! $data ) {
255 return $parsed_block;
256 }
257
258 $style_ref = Arr::get( $data, 'styleRef' );
259
260 if ( $style_ref === Arr::get( $parsed_block, 'attrs.kubio.styleRef' ) ) {
261 $url = Arr::get( $data, 'localProps.url', '' );
262 Arr::set(
263 $parsed_block,
264 'attrs.url',
265 $url
266 );
267 Arr::set(
268 $parsed_block,
269 'attrs.id',
270 attachment_url_to_postid( $url )
271 );
272 Arr::set(
273 $parsed_block,
274 'attrs.alt',
275 __( 'Image', 'kubio' )
276 );
277 }
278
279 $style = $data['style'];
280 $x_value = Arr::get( $style, 'descendants.frameImage.transform.translate.x_value' );
281 $width = Arr::get( $style, 'descendants.frameImage.width' );
282 $height = Arr::get( $style, 'descendants.frameImage.height' );
283 $y_value = Arr::get( $style, 'descendants.frameImage.transform.translate.y_value' );
284
285 Arr::set(
286 $style,
287 'descendants.frameImage.width',
288 array(
289 'value' => $width,
290 'unit' => '%',
291 )
292 );
293 Arr::set(
294 $style,
295 'descendants.frameImage.height',
296 array(
297 'value' => $height,
298 'unit' => '%',
299 )
300 );
301
302 Arr::set(
303 $style,
304 'descendants.frameImage.transform.translate',
305 array(
306 array(
307 'axis' => 'x',
308 'value' => array(
309 'value' => $x_value,
310 'unit' => '%',
311 ),
312 ),
313 array(
314 'axis' => 'y',
315 'value' => array(
316 'value' => $y_value,
317 'unit' => '%',
318 ),
319 ),
320 )
321 );
322
323 $color = Arr::get( $style, 'descendants.frameImage.backgroundColor' );
324 $thickness = Arr::get( $style, 'descendants.frameImage.thickness' );
325 $props = Arr::get( $data, 'props' );
326
327 Arr::forget( $style, 'descendants.frameImage.thickness' );
328
329 if ( Arr::get( $props, 'frame.type' ) === 'border' ) {
330 Arr::forget( $style, 'descendants.frameImage.backgroundColor' );
331 Arr::set(
332 $style,
333 'descendants.frameImage.border',
334 array(
335 'left' => array(
336 'style' => 'solid',
337 'color' => $color,
338 'width' => array(
339 'value' => $thickness,
340 'unit' => 'px',
341 ),
342 ),
343
344 'right' => array(
345 'style' => 'solid',
346 'color' => $color,
347 'width' => array(
348 'value' => $thickness,
349 'unit' => 'px',
350 ),
351 ),
352
353 'top' => array(
354 'style' => 'solid',
355 'color' => $color,
356 'width' => array(
357 'value' => $thickness,
358 'unit' => 'px',
359 ),
360 ),
361
362 'bottom' => array(
363 'style' => 'solid',
364 'color' => $color,
365 'width' => array(
366 'value' => $thickness,
367 'unit' => 'px',
368 ),
369 ),
370 )
371 );
372 }
373
374 if ( Arr::get( $props, 'showFrameOverImage' ) ) {
375 Arr::set( $style, 'descendants.frameImage.zIndex', 1 );
376 Arr::set( $style, 'descendants.frameImage.boxShadow.enabled', Arr::get( $props, 'showFrameShadow' ) );
377 } else {
378 Arr::forget( $style, 'descendants.frameImage.zIndex' );
379 }
380
381 // Check - image has border style from design (https://mantis.iconvert.pro/view.php?id=55688)
382 $image_border_style = Arr::get( $parsed_block, 'attrs.kubio.style.descendants.image.border' );
383 if ( $image_border_style ) {
384 Arr::set( $style, 'descendants.image.border', $image_border_style );
385 }
386
387 Arr::set( $parsed_block, 'attrs.kubio.style', $style );
388 Arr::set(
389 $parsed_block,
390 'attrs.kubio.props.frame',
391 array(
392 'type' => Arr::get( $props, 'frame.type' ),
393 'enabled' => Arr::get( $props, 'enabledFrameOption' ),
394 'showFrameOverImage' => Arr::get( $props, 'showFrameOverImage' ),
395 )
396 );
397
398 return $parsed_block;
399 }
400
401 /**
402 * @param array $parsed_blocks
403 * @param $block_index
404 * @param $next_inner_blocks
405 *
406 * @return array
407 */
408 private function updateBlockInnerBlocks( array $parsed_blocks, $block_index, $next_inner_blocks ) {
409 $parsed_blocks[ $block_index ]['innerContent'] = array_fill( 0, count( $next_inner_blocks ), null );
410
411 if ( count( $parsed_blocks[ $block_index ]['innerContent'] ) === 0 ) {
412 $parsed_blocks[ $block_index ]['innerContent'] = array( $parsed_blocks[ $block_index ]['innerHTML'] );
413 }
414
415 $parsed_blocks[ $block_index ]['innerBlocks'] = $next_inner_blocks;
416
417 return $parsed_blocks;
418 }
419
420 private function processFooter( $parsed_blocks ) {
421
422 $current_part_data = $this->getCurrentPartData();
423
424 foreach ( $current_part_data as $item_data ) {
425 $parsed_blocks = $this->updateBlocks( $parsed_blocks, $item_data );
426 }
427
428 return $parsed_blocks;
429 }
430
431 private function getCurrentPartData() {
432 return $this->getCurrentData()[ $this->slug ];
433 }
434
435 private function updateBlocks( $parsed_blocks, $item_data ) {
436
437 foreach ( $parsed_blocks as $index => &$block ) {
438
439 if ( ! isset( $item_data['styleRef'] ) ) {
440 continue;
441 }
442
443 $style_ref = Arr::get( $block, 'attrs.kubio.styleRef', null );
444
445 if ( $style_ref === $item_data['styleRef'] ) {
446 $kubio_attr = Arr::get( $block, 'attrs.kubio' );
447 $style = Arr::get( $item_data, 'style', array() );
448 $props = Arr::get( $item_data, 'props', array() );
449 $local_props = Arr::get( $item_data, 'localProps', array() );
450
451 list( $block, $kubio_attr_replacement ) = $this->normalizeBlockData(
452 $block,
453 array(
454 'style' => $style,
455 'props' => $props,
456 ),
457 $item_data
458 );
459
460 // if some prop in normalization nullified the block
461 if ( $block === null ) {
462 array_splice( $parsed_blocks, $index, 1 );
463 continue;
464 }
465
466 foreach ( $local_props as $attr => $value ) {
467 Arr::set( $block, "attrs.{$attr}", $value );
468 }
469
470 $kubio_attr = array_replace_recursive( $kubio_attr, $kubio_attr_replacement );
471
472 Arr::set( $block, 'attrs.kubio', $kubio_attr );
473 } else {
474 $next_inner_blocks = $this->updateBlocks( $block['innerBlocks'], $item_data );
475
476 // let the innerContent placeholders - null means inner block
477 $block['innerContent'] = array_fill( 0, count( $next_inner_blocks ), null );
478
479 if ( count( $block['innerContent'] ) === 0 ) {
480 $block['innerContent'] = array( $block['innerHTML'] );
481 }
482
483 $block['innerBlocks'] = $next_inner_blocks;
484 }
485
486 if ( $block ) {
487 $parsed_blocks[ $index ] = $block;
488 }
489 }
490
491 return $parsed_blocks;
492 }
493
494 private function normalizeBlockData( $parsed_block, $data, $item_data ) {
495 $block_name = $parsed_block['blockName'];
496
497 if ( $block_name === 'kubio/buttongroup' ) {
498 list( $parsed_block, $data ) = $this->normalizeButtonGroup( $parsed_block, $data, $item_data );
499 }
500
501 if ( in_array( $block_name, array( 'kubio/text', 'kubio/heading' ), true ) ) {
502 list( $parsed_block, $data ) = $this->normalizeTexts( $parsed_block, $data, $item_data );
503 }
504
505 if ( $block_name === 'kubio/navigation' ) {
506 list( $parsed_block, $data ) = $this->normalizeNavigation( $parsed_block, $data, $item_data );
507 }
508 if ( $block_name === 'kubio/iconlist' ) {
509 list( $parsed_block, $data ) = $this->normalizeIconsLists( $parsed_block, $data, $item_data );
510 }
511 if ( $block_name === 'kubio/social-icons' ) {
512 list( $parsed_block, $data ) = $this->normalizeIconsLists( $parsed_block, $data, $item_data );
513 }
514
515 if ( $block_name === 'kubio/hero' ) {
516 list( $parsed_block, $data ) = $this->normalizeHero( $parsed_block, $data, $item_data );
517 }
518
519 return array( $parsed_block, $data );
520 }
521
522 private function normalizeButtonGroup( $parsed_block, $data, $item_data ) {
523 $text_align = Arr::get( $data, 'style.textAlign', 'center' );
524 Arr::set( $data, 'style.descendants.spacing.textAlign', $text_align );
525 Arr::forget( $data, 'style.textAlign' );
526
527 $buttons = Arr::get( $item_data, 'value', array() );
528 $buttons = $this->maybeDecodeArray( $buttons );
529
530 if ( is_array( $buttons ) ) {
531 $buttons_order = array();
532 $next_inner_blocks = array();
533 foreach ( $buttons as $button ) {
534 $buttons_order[] = intval( $button['button_type'] );
535 }
536
537 foreach ( $buttons_order as $index => $button_index ) {
538 $next_inner_blocks[ $index ] = $parsed_block['innerBlocks'] [ $button_index ];
539 }
540
541 foreach ( $next_inner_blocks as $index => $inner_block ) {
542 $button = $buttons[ $index ];
543
544 $inner_block['innerHTML'] = $button['label'];
545 Arr::set( $inner_block, 'attrs.link.value', $button['url'] );
546
547 $next_inner_blocks[ $index ] = $inner_block;
548 }
549
550 $parsed_block['innerContent'] = array_fill( 0, count( $next_inner_blocks ), null );
551 $parsed_block['innerBlocks'] = $next_inner_blocks;
552 }
553
554 return array( $parsed_block, $data );
555 }
556
557 private function maybeDecodeArray( $data ) {
558 if ( is_array( $data ) ) {
559 return $data;
560 }
561
562 $decoded = json_decode( $data, true );
563
564 if ( json_last_error() === JSON_ERROR_NONE ) {
565 return $decoded;
566 }
567
568 $decoded = json_decode( urldecode( $data ), true );
569
570 if ( json_last_error() === JSON_ERROR_NONE ) {
571 return $decoded;
572 }
573
574 return array();
575 }
576
577 private function normalizeTexts( $parsed_block, $data, $item_data ) {
578 if ( Arr::get( $item_data, 'show' ) === false ) {
579 return array( null, $data );
580 }
581
582 $block_name = $parsed_block['blockName'];
583 if ( $block_name === 'kubio/heading' ) {
584 $value = Arr::get( $item_data, 'value', '' );
585 $parsed_block['innerHTML'] = $value;
586 }
587
588 // modify block innerContent to the new value
589 if ( $block_name === 'kubio/text' ) {
590 $value = Arr::get( $item_data, 'value', '' );
591 $parsed_block['innerHTML'] = $value;
592 }
593
594 return array( $parsed_block, $data );
595 }
596
597 private function normalizeNavigation( $parsed_block, $data, $item_data ) {
598 if( Arr::get( $data, 'props.useWhiteText', false ) ) {
599 $this->makeTextWhiteForInnerBlocks($parsed_block, ['kubio/logo', 'kubio/dropdown-menu']);
600 }
601
602 $show_top_bar = Arr::get( $item_data, 'props.showTopBar', false );
603 if ( ! $show_top_bar ) {
604 foreach ( $parsed_block['innerBlocks'] as $index => $inner_block ) {
605 if ( $inner_block['blockName'] === 'kubio/navigation-top-bar' ) {
606 array_splice( $parsed_block['innerBlocks'], $index, 1 );
607 }
608 }
609 $parsed_block['innerContent'] = array_fill( 0, count( $parsed_block['innerBlocks'] ), null );
610 } else {
611 foreach ( $parsed_block['innerBlocks'] as $index => $inner_block ) {
612 if ( $inner_block['blockName'] === 'kubio/navigation-top-bar' ) {
613 $nav_width = Arr::get( $data, 'props.width' );
614 Arr::set( $parsed_block, "innerBlocks.{$index}.attrs.kubio.props.width", $nav_width );
615 break;
616 }
617 }
618 }
619
620 $layout_type = Arr::get( $data, 'props.layoutType' );
621 Arr::forget( $data, 'props.layoutType' );
622
623 if ( $layout_type === 'logo-above-menu' ) {
624 $navigation_section_index = count( $parsed_block['innerBlocks'] ) - 1;
625 $navigation_row_path = "innerBlocks.{$navigation_section_index}.innerBlocks.0.innerBlocks.0";
626 $row = Arr::get( $parsed_block, $navigation_row_path );
627
628 $next_columns = array();
629
630 foreach ( $row['innerBlocks'] as $index => $column ) {
631 $column_type = Arr::get( $column, 'attrs.kubio.props.internal.navContent.type' );
632
633 if ( in_array( $column_type, array( 'logo', 'menu' ), true ) ) {
634 Arr::set(
635 $column,
636 'attrs.kubio._style.descendants.container.columnWidth',
637 array(
638 'type' => 'custom',
639 'custom' => array(
640 'value' => 100,
641 'unit' => '%',
642 ),
643 )
644 );
645
646 $next_columns[] = $column;
647 }
648 }
649
650 $row['innerBlocks'] = $next_columns;
651 $row['innerContent'] = array_fill( 0, count( $next_columns ), null );
652
653 Arr::set( $parsed_block, $navigation_row_path, $row );
654 }
655
656 $padding = Arr::get( $data, 'style.padding.top' );
657 Arr::forget( $data, 'style.padding' );
658 Arr::forget( $data, 'style.nav' );
659
660 Arr::set( $data, 'style.descendants.section.padding.top', $padding );
661 Arr::set( $data, 'style.descendants.section.padding.bottom', $padding );
662
663 return array( $parsed_block, $data );
664 }
665
666 private function normalizeIconsLists( $parsed_block, $data, $item_data ) {
667 $show = Arr::get( $item_data, 'show', false );
668 $block_name = $parsed_block['blockName'];
669
670 if ( ! $show ) {
671 return null;
672 }
673
674 if ( $block_name === 'kubio/social-icons' ) {
675 //Set default spacing for social icons
676 Arr::set(
677 $data,
678 'style.descendants.icon.margin.right',
679 array(
680 'value' => 10,
681 'unit' => 'px',
682 )
683 );
684 }
685
686 $first_icon = Arr::get( $parsed_block, 'innerBlocks.0', null );
687
688 if ( ! $first_icon ) {
689 return $parsed_block;
690 }
691
692 $icons_data = $this->maybeDecodeArray( Arr::get( $item_data, 'localProps.iconList', array() ) );
693 $next_inner_blocks = array();
694
695 foreach ( $icons_data as $icon ) {
696 $next_inner = $first_icon;
697
698 if ( $block_name === 'kubio/iconlist' ) {
699 Arr::set( $next_inner, 'attrs.text', Arr::get( $icon, 'text', '' ) );
700 Arr::set( $next_inner, 'innerHTML', Arr::get( $icon, 'text', '' ) );
701 Arr::set( $next_inner, 'innerContent.0', Arr::get( $icon, 'text', '' ) );
702 Arr::set( $next_inner, 'attrs.icon', Arr::get( $icon, 'icon.name' ) );
703 } else {
704 Arr::set(
705 $next_inner,
706 'attrs.icon',
707 array(
708 'name' => Arr::get( $icon, 'icon.name' ),
709 )
710 );
711 }
712
713 Arr::set(
714 $next_inner,
715 'attrs.link',
716 array(
717 'typeOpenLink' => 'sameWindow',
718 'value' => Arr::get( $icon, 'link_value', '' ),
719 'noFollow' => false,
720 'lightboxMedia' => '',
721 )
722 );
723
724 $next_inner_blocks[] = $next_inner;
725
726 }
727
728 if ( ! count( $next_inner_blocks ) ) {
729 return null;
730 }
731
732 $parsed_block['innerBlocks'] = $next_inner_blocks;
733 $parsed_block['innerContent'] = array_fill( 0, count( $next_inner_blocks ), null );
734
735 return array( $parsed_block, $data );
736 }
737
738 private function normalizeHero( $parsed_block, $data, $item_data ) {
739
740 $bottom_separator = Arr::get( $data, 'style.descendants.outer.separators.separatorBottom' );
741 $bg_type = Arr::get( $data, 'style.descendants.outer.background.type' );
742 $bg_slides = Arr::get( $data, 'style.descendants.outer.background.slideshow.slides' );
743 $gradient_bg = Arr::get( $data, 'style.descendants.outer.background.image.0.source.gradient' );
744 $overlay_gradient = Arr::get( $data, 'style.descendants.outer.background.overlay.gradient' );
745 $overlay_color = Arr::get( $data, 'style.descendants.outer.background.overlay.color' );
746 $overlay_gradient_opacity = Arr::get( $data, 'style.descendants.outer.background.overlay.gradient_opacity', 50 );
747 $internal_video = Arr::get( $data, 'style.descendants.outer.background.video.internalUrl', '' );
748 $external_video = Arr::get( $data, 'style.descendants.outer.background.video.externalUrl', '' );
749 $video_type = Arr::get( $data, 'style.descendants.outer.background.video.videoType', 'external' );
750
751 Arr::forget( $data, 'style.descendants.outer.background.slideshow.slides' );
752 Arr::forget( $data, 'style.descendants.outer.background.overlay.gradient_opacity' );
753 Arr::forget( $data, 'style.descendants.outer.separators.separatorBottom' );
754 Arr::forget( $data, 'style.descendants.outer.background.video.internalUrl' );
755 Arr::forget( $data, 'style.descendants.outer.background.video.externalUrl' );
756 Arr::forget( $data, 'style.descendants.outer.background.video.videoType' );
757
758 $bg_slides = static::prepareBackgroundSlides( $bg_slides );
759
760 list($r, $g, $b, $a) = sscanf( $overlay_color['value'], 'rgba(%d,%d,%d,%f)' );
761 list($r, $g, $b, $a) = sscanf( $overlay_color['value'], 'rgba(%d,%d,%d,%f)' );
762 if ( is_numeric( $r ) && is_numeric( $g ) && is_numeric( $b ) && is_numeric( $a ) ) {
763 $overlay_color = array(
764 'opacity' => $a,
765 'value' => "rgb($r,$g,$b)",
766 );
767 }
768
769 if ( is_numeric( $internal_video ) ) {
770 $internal_video = wp_get_attachment_url( (int) $internal_video );
771 }
772
773 Arr::set( $data, 'style.descendants.outer.background.slideshow.slides', $bg_slides );
774 Arr::set( $data, 'style.descendants.outer.background.overlay.color', $overlay_color );
775 Arr::set( $data, 'style.descendants.outer.separators.bottom', $bottom_separator );
776 Arr::set( $data, 'style.descendants.outer.background.video.internal.url', $internal_video );
777 Arr::set( $data, 'style.descendants.outer.background.video.external.url', $external_video );
778 Arr::set( $data, 'style.descendants.outer.background.video.type', $video_type );
779 Arr::set( $data, 'style.descendants.outer.separators.bottom', $bottom_separator );
780 Arr::set( $data, 'style.descendants.outer.textAlign', 'center' );
781
782 if( Arr::get( $data, 'props.useWhiteText', false ) ) {
783 $this->makeTextWhiteForInnerBlocks($parsed_block);
784 }
785
786 if ( $gradient_bg ) {
787 Arr::set( $data, 'style.descendants.outer.background.image.0.source.gradient', $this->composeGradient( $gradient_bg ) );
788 }
789
790 if ( $bg_type === 'color' ) {
791 Arr::set(
792 $data,
793 'style.descendants.outer.background.type',
794 'none'
795 );
796 } elseif ( $bg_type === 'image' || $bg_type === 'gradient' ) {
797 Arr::set( $data, 'style.descendants.outer.background.image.0.source.type', $bg_type );
798 }
799
800 if ( $overlay_gradient ) {
801 Arr::set( $data, 'style.descendants.outer.background.overlay.gradient', $this->composeGradient( $overlay_gradient, $overlay_gradient_opacity ) );
802 }
803
804 $shape_light = Arr::get( $data, 'style.descendants.outer.background.overlay.light' );
805 if ( ! $shape_light ) {
806 $shape_light = 0;
807 }
808 Arr::forget( $data, 'style.descendants.outer.background.overlay.light' );
809 Arr::set( $data, 'style.descendants.outer.background.overlay.shape.light', $shape_light );
810
811 $overlay_shape = Arr::get( $data, 'style.descendants.outer.background.overlay.shape.value' );
812
813 $titled_shapes = array( 'dots', 'left-tilted-lines', 'right-tilted-lines' );
814 Arr::set( $data, 'style.descendants.outer.background.overlay.shape.isTile', in_array( $overlay_shape, $titled_shapes, true ) );
815
816 $padding_style_path = 'style.descendants.outer.padding';
817 $hero_padding_top = Arr::get( $item_data, 'style.descendants.outer.padding.top.value' );
818 $hero_padding_bottom = Arr::get( $item_data, 'style.descendants.outer.padding.bottom.value' );
819 $hero_padding_left = Arr::get( $item_data, 'style.descendants.outer.padding.left', array( 'value' => 0, 'unit' => 'px' ) );
820 $hero_padding_right = Arr::get( $item_data, 'style.descendants.outer.padding.right', array( 'value' => 0, 'unit' => 'px' ) );
821 $full_height = Arr::get( $item_data, 'full_height' );
822
823 if (
824 ( Flags::get( 'import_design', false ) === true && Flags::get( 'start_source' ) !== 'customizer-sidebar' ) ||
825 ! $hero_padding_top || ! $hero_padding_bottom
826 ) {
827 if ( ! $hero_padding_top ) {
828 $hero_padding_top = Arr::get( $item_data, 'style.descendants.outer.padding.top.value' );
829 }
830 if ( ! $hero_padding_bottom ) {
831 $hero_padding_bottom = Arr::get( $item_data, 'style.descendants.outer.padding.bottom.value' );
832 }
833 }
834
835 if ( $full_height ) {
836 Arr::set( $data, 'style.descendants.outer.customHeight.type', 'full-screen' );
837 } else {
838 Arr::set( $data, 'style.descendants.outer.customHeight.type', 'fit-to-content' );
839 }
840
841 if ( $this->slug === 'header' ) {
842 $show_title = Arr::get( static::$current_data, 'header.title.show' );
843
844 if ( ! $show_title ) { // Title hidden
845 $parsed_block['innerBlocks'] = $this->removePageTitleBlocks( $parsed_block['innerBlocks'] );
846 } else {
847 //Align inner title
848 if ( class_exists( Defaults::class ) ) {
849 $default_inner_title_text_align = Defaults::get( 'header.title.style.descendants.text.textAlign', 'center' );
850 } else {
851 $default_inner_title_text_align = 'center';
852 }
853 $parsed_block = static::alignInnerTitle( $parsed_block, $default_inner_title_text_align );
854 }
855
856 $customizer_hero_padding = array(
857 'top' => array(
858 'value' => $hero_padding_top,
859 'unit' => 'px',
860 ),
861 'bottom' => array(
862 'value' => $hero_padding_bottom,
863 'unit' => 'px',
864 ),
865 'left' => array(
866 'value' => 20,
867 'unit' => 'px',
868 ),
869 'right' => array(
870 'value' => 20,
871 'unit' => 'px',
872 ),
873 );
874 }
875
876 if ( $this->slug === 'front-header' ) {
877 $show_buttons = $this->getHeroShowButtons();
878
879 if ( ! $show_buttons && isset( $parsed_block['innerBlocks'] ) ) {
880 $parsed_block['innerBlocks'] = $this->removeHeroButtons( $parsed_block['innerBlocks'] );
881 }
882
883 $customizer_hero_padding = array(
884 'top' => array(
885 'value' => $hero_padding_top,
886 'unit' => 'px',
887 ),
888 'bottom' => array(
889 'value' => $hero_padding_bottom,
890 'unit' => 'px',
891 ),
892 'left' => $hero_padding_left,
893 'right' => $hero_padding_right,
894 );
895
896 //Update hero text column width
897 $customizer_hero_column_width = get_theme_mod( 'front-header.hero.hero_column_width', Defaults::get( 'front-header.hero.hero_column_width', 66 ) );
898 $hero_custom_width = Arr::get( $parsed_block, 'innerBlocks.0.innerBlocks.0.attrs.kubio._style.descendants.container.columnWidth.custom.value' );
899 if ( $hero_custom_width && ( $hero_custom_width !== $customizer_hero_column_width ) ) {
900 Arr::set( $parsed_block, 'innerBlocks.0.innerBlocks.0.attrs.kubio._style.descendants.container.columnWidth.custom.value', $customizer_hero_column_width );
901 }
902 }
903
904 Arr::forget( $data, $padding_style_path );
905 Arr::set( $data, $padding_style_path, $customizer_hero_padding );
906
907 return array( $parsed_block, $data );
908 }
909
910 public function getHeroShowButtons() {
911 $show_buttons = Arr::get( static::$current_data, 'front-header.buttons.show' );
912
913 return $show_buttons;
914 }
915
916 /**
917 * Recursively removes kubio/buttongroup blocks from $blocks. Returns what remains after remove.
918 * @param $blocks
919 * @return array
920 */
921 public function removeHeroButtons( $blocks ) {
922 $blocks = array_filter(
923 $blocks,
924 function ( $block ) {
925 if ( $this->blockIsTypeOf( $block, 'kubio/buttongroup' ) ) {
926 return false;
927 }
928 return true;
929 }
930 );
931
932 foreach ( $blocks as &$block ) {
933 if ( isset( $block['innerBlocks'] ) && count( $block['innerBlocks'] ) ) {
934 $block['innerBlocks'] = $this->removeHeroButtons( $block['innerBlocks'] );
935 }
936 }
937
938 return $blocks;
939 }
940
941 /**
942 * Recursively removes kubio/page-title blocks from $blocks. Returns what remains after remove.
943 * @param $blocks
944 * @return array
945 */
946 public function removePageTitleBlocks( $blocks ) {
947 $blocks = array_filter(
948 $blocks,
949 function ( $block ) {
950 if ( $this->blockIsTypeOf( $block, 'kubio/page-title' ) ) {
951 return false;
952 }
953 return true;
954 }
955 );
956
957 foreach ( $blocks as &$block ) {
958 if ( isset( $block['innerBlocks'] ) && count( $block['innerBlocks'] ) ) {
959 $block['innerBlocks'] = $this->removePageTitleBlocks( $block['innerBlocks'] );
960 }
961 }
962
963 return $blocks;
964 }
965
966 /**
967 * Checks if block is of a specific type
968 * @param $block
969 * @param $type
970 * @return bool
971 */
972 public function blockIsTypeOf( $block, $type ) {
973 if ( isset( $block['blockName'] ) ) {
974 if ( $block['blockName'] === $type ) {
975 return true;
976 }
977 }
978 return false;
979 }
980
981 private function composeGradient( $value, $opacity = 100 ) {
982 $steps = $value['steps'];
983 $stepts_strings = array();
984
985 foreach ( $steps as $step ) {
986 $stepts_strings[] = $this->gradientStepToString( $step, $opacity );
987 }
988
989 $steps = implode( ', ', $stepts_strings );
990
991 return "linear-gradient({$value['angle']}deg, {$steps} )";
992 }
993
994 private function gradientStepToString( $step, $opacity = 100 ) {
995 if ( strpos( $step['color'], 'rgba' ) !== false || strpos( $step['color'], 'RGBA' ) !== false ) {
996 $color = $step['color'];
997 } else {
998 $color = Utils::hex2rgba( $step['color'], intval( $opacity ) / 100 );
999 }
1000
1001 return "{$color} {$step['position']}%";
1002 }
1003
1004
1005 private function processHeader( $parsed_blocks ) {
1006 $current_part_data = $this->getCurrentPartData();
1007
1008 foreach ( $current_part_data as $item_data ) {
1009 $parsed_blocks = $this->updateBlocks( $parsed_blocks, $item_data );
1010 }
1011
1012 $current_hero_layout = Arr::get( $current_part_data, 'hero.props.heroSection.layout' );
1013
1014 $hero_column_width = Arr::get( $current_part_data, 'hero.hero_column_width' );
1015
1016 if ( $current_hero_layout ) {
1017 switch ( $current_hero_layout ) {
1018 case 'textOnly':
1019 $parsed_blocks = $this->removeHeroMediaColumn( $parsed_blocks );
1020 break;
1021 case 'textWithMediaOnLeft':
1022 $parsed_blocks = $this->swapHeroColumns( $parsed_blocks );
1023 break;
1024 }
1025 }
1026
1027 $parsed_blocks = $this->setColumnsWidth( $parsed_blocks, $hero_column_width );
1028 $parsed_blocks = $this->postProcessBlocks( $parsed_blocks, $current_part_data );
1029
1030 return $parsed_blocks;
1031 }
1032
1033 private function removeHeroMediaColumn( $parsed_blocks ) {
1034
1035 foreach ( $parsed_blocks as $index => $block ) {
1036 if ( Arr::get( $block, 'attrs.kubio.props.internal.heroSection.type' ) === 'media' ) {
1037 array_splice( $parsed_blocks, $index, 1 );
1038 break;
1039 } else {
1040 $next_inner_blocks = $this->removeHeroMediaColumn( $block['innerBlocks'] );
1041
1042 // let the innerContent placeholders - null means inner block
1043 $parsed_blocks = $this->updateBlockInnerBlocks( $parsed_blocks, $index, $next_inner_blocks );
1044 }
1045 }
1046
1047 return $parsed_blocks;
1048 }
1049
1050 private function swapHeroColumns( $parsed_blocks ) {
1051
1052 foreach ( $parsed_blocks as $index => $block ) {
1053 $inner_blocks = $block['innerBlocks'];
1054
1055 $inner_blocks_are_hero_columns = false;
1056
1057 // check if inner blocks are hero columns, otherwise check each child children's
1058 foreach ( $inner_blocks as $inner_block ) {
1059 if ( Arr::get( $inner_block, 'attrs.kubio.props.internal.heroSection.type' ) === 'media' ) {
1060 $inner_blocks_are_hero_columns = true;
1061 break;
1062 }
1063 }
1064
1065 if ( $inner_blocks_are_hero_columns ) {
1066 $parsed_blocks[ $index ]['innerBlocks'] = array_reverse( $inner_blocks );
1067 break;
1068 } else {
1069 $parsed_blocks[ $index ]['innerBlocks'] = $this->swapHeroColumns( $inner_blocks );
1070 }
1071 }
1072
1073 return $parsed_blocks;
1074 }
1075
1076 private function setColumnsWidth( $parsed_blocks, $text_column_width ) {
1077 foreach ( $parsed_blocks as $index => $block ) {
1078 $column_type = Arr::get( $block, 'attrs.kubio.props.internal.heroSection.type' );
1079 if ( $column_type ) {
1080 $value = $column_type === 'text' ? intval( $text_column_width ) : 100 - $text_column_width;
1081 Arr::set(
1082 $block,
1083 'attrs.kubio._style.descendants.container.columnWidth',
1084 array(
1085 'type' => 'custom',
1086 'custom' => array(
1087 'value' => $value,
1088 'unit' => '%',
1089 ),
1090 )
1091 );
1092
1093 $parsed_blocks[ $index ] = $block;
1094 } else {
1095 $parsed_blocks[ $index ]['innerBlocks'] = $this->setColumnsWidth( $block['innerBlocks'], $text_column_width );
1096 }
1097 }
1098
1099 return $parsed_blocks;
1100 }
1101
1102 public static function prepareBackgroundSlides( $slides ) {
1103 foreach ( $slides as $index => &$slide ) {
1104 $slide['id'] = $index + 1;
1105 $slide['icon'] = false;
1106 }
1107
1108 return $slides;
1109 }
1110
1111 public static function alignInnerTitle( $parsed_block, $text_align ) {
1112 if ( isset( $parsed_block['blockName'] ) && $parsed_block['blockName'] === 'kubio/page-title' ) {
1113 Arr::set( $parsed_block, 'attrs.kubio.style.descendants.container.textAlign', $text_align );
1114 } else {
1115 if ( isset( $parsed_block['innerBlocks'] ) && count( $parsed_block['innerBlocks'] ) ) {
1116 foreach ( $parsed_block['innerBlocks'] as &$block ) {
1117 $block = static::alignInnerTitle( $block, $text_align );
1118 }
1119 }
1120 }
1121
1122 return $parsed_block;
1123 }
1124
1125 public static function themeHasModifiedOptions() {
1126 $keys = array_keys( get_theme_mods() );
1127
1128 foreach ( $keys as $key ) {
1129 if ( strpos( $key, 'header.' ) === 0 ||
1130 strpos( $key, 'front-header.' ) === 0 ||
1131 strpos( $key, 'blog_' ) === 0
1132 ) {
1133 return true;
1134 }
1135 }
1136 return false;
1137 }
1138
1139 static function removeSidebar( $parsed_blocks ) {
1140 $query_layout = null;
1141 $layout_index = null;
1142 $replaced = false;
1143
1144 foreach ( $parsed_blocks as $index => $block ) {
1145 if ( Arr::get( $block, 'blockName' ) === 'kubio/query-layout' ) {
1146 $query_layout = $block;
1147 $layout_index = $index;
1148 break;
1149 }
1150 }
1151
1152 if ( $query_layout ) {
1153 $row_inner_blocks = Arr::get( $query_layout, 'innerBlocks.0.innerBlocks' );
1154
1155 if ( count( $row_inner_blocks ) > 1 ) {
1156 foreach ( $row_inner_blocks as $index => $block ) {
1157 if ( Arr::get( $block, 'innerBlocks.0.blockName' ) === 'kubio/sidebar' ) {
1158 array_splice( $row_inner_blocks, $index, 1 );
1159 $replaced = true;
1160 break;
1161 }
1162 }
1163
1164 if ( $replaced ) {
1165 Arr::set( $parsed_blocks, "{$layout_index}.innerBlocks.0.innerBlocks", static::swapColumns( $row_inner_blocks ) );
1166 }
1167 }
1168 }
1169
1170 return $parsed_blocks;
1171 }
1172
1173 static function swapColumns( $row ) {
1174 if ( ! is_array( $row ) || count( $row ) < 2 ) {
1175 return $row;
1176 }
1177
1178 $temp = $row[0];
1179 $row[0] = $row[1];
1180 $row[1] = $temp;
1181
1182 return $row;
1183 }
1184
1185 private function makeTextWhiteForInnerBlocks(
1186 array &$parsed_blocks, $blockNames = [
1187 'kubio/text',
1188 'kubio/heading'
1189 ]
1190 ) {
1191 $white_color = 'rgba(255,255,255,1)';
1192
1193 foreach ( $parsed_blocks['innerBlocks'] as &$block ) {
1194 if ( isset( $block['blockName'] ) && in_array( $block['blockName'], $blockNames ) ) {
1195 if ( $block['blockName'] === 'kubio/dropdown-menu' ) {
1196 Arr::set( $block, 'attrs.kubio.style.descendants.main-menu-a.typography.color', $white_color );
1197 } else {
1198 Arr::set( $block, 'attrs.kubio.style.descendants.text.typography.color', $white_color );
1199 }
1200 }
1201 if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
1202 $this->makeTextWhiteForInnerBlocks( $block, $blockNames );
1203 }
1204 }
1205 }
1206 }
1207