PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.6.0
GenerateBlocks v1.6.0
trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.3.0
generateblocks / includes / functions.php
generateblocks / includes Last commit date
blocks 3 years ago class-do-css.php 4 years ago class-dynamic-content.php 3 years ago class-enqueue-css.php 3 years ago class-legacy-attributes.php 4 years ago class-plugin-update.php 5 years ago class-query-loop.php 3 years ago class-render-blocks.php 3 years ago class-rest.php 4 years ago class-settings.php 4 years ago dashboard.php 4 years ago defaults.php 3 years ago functions.php 3 years ago general.php 4 years ago
functions.php
1139 lines
1 <?php
2 /**
3 * Functions used throughout the plugin.
4 *
5 * @package GenerateBlocks
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit; // Exit if accessed directly.
10 }
11
12 /**
13 * Retrive attributes from our blocks.
14 *
15 * @since 0.1
16 * @param array $content The content of our page.
17 * @param array $data Data used to loop through the function as needed.
18 * @param int $depth Keep track of how deep we are in nested blocks.
19 *
20 * @return array
21 */
22 function generateblocks_get_block_data( $content, $data = array(), $depth = 0 ) {
23 if ( ! is_array( $content ) || empty( $content ) ) {
24 return;
25 }
26
27 foreach ( $content as $index => $block ) {
28 if ( ! is_object( $block ) && is_array( $block ) && isset( $block['blockName'] ) ) {
29 if ( 'generateblocks/grid' === $block['blockName'] ) {
30 $data['grid'][] = $block['attrs'];
31 $depth++;
32 $data[ 'tempGridId-' . $depth ] = $block['attrs']['uniqueId'];
33 }
34
35 if ( 'generateblocks/container' === $block['blockName'] ) {
36 if ( isset( $block['attrs']['isGrid'] ) && $block['attrs']['isGrid'] && isset( $data[ 'tempGridId-' . $depth ] ) ) {
37 $block['attrs']['gridId'] = $data[ 'tempGridId-' . $depth ];
38 }
39
40 $data['container'][] = $block['attrs'];
41 }
42
43 if ( 'generateblocks/headline' === $block['blockName'] ) {
44 if ( isset( $block['innerHTML'] ) ) {
45 if ( strpos( trim( $block['innerHTML'] ), '<div class="gb-headline-wrapper' ) === 0 ) {
46 $block['attrs']['hasWrapper'] = true;
47 }
48 }
49
50 $data['headline'][] = $block['attrs'];
51 }
52
53 if ( 'generateblocks/button-container' === $block['blockName'] ) {
54 $data['button-container'][] = $block['attrs'];
55 }
56
57 if ( 'generateblocks/button' === $block['blockName'] ) {
58 if ( ! isset( $block['attrs']['hasUrl'] ) && isset( $block['innerHTML'] ) ) {
59 if ( strpos( trim( $block['innerHTML'] ), '<a' ) === 0 ) {
60 $block['attrs']['hasUrl'] = true;
61 }
62 }
63
64 $data['button'][] = $block['attrs'];
65 }
66
67 if ( 'generateblocks/image' === $block['blockName'] ) {
68 $data['image'][] = $block['attrs'];
69 }
70
71 if ( 'core/block' === $block['blockName'] ) {
72 if ( isset( $block['attrs'] ) && is_array( $block['attrs'] ) ) {
73 $atts = $block['attrs'];
74
75 if ( isset( $atts['ref'] ) && ( empty( $data['reusableBlockIds'] ) || ! in_array( $atts['ref'], (array) $data['reusableBlockIds'] ) ) ) {
76 $reusable_block = get_post( $atts['ref'] );
77
78 if ( $reusable_block && 'wp_block' === $reusable_block->post_type && 'publish' === $reusable_block->post_status ) {
79 $reuse_data_block = parse_blocks( $reusable_block->post_content );
80
81 if ( ! empty( $reuse_data_block ) ) {
82 $data['reusableBlockIds'][] = $atts['ref'];
83 $data = generateblocks_get_block_data( $reuse_data_block, $data );
84 }
85 }
86 }
87 }
88 }
89
90 if ( isset( $block['innerBlocks'] ) && ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
91 $data = generateblocks_get_block_data( $block['innerBlocks'], $data, $depth );
92 }
93 }
94 }
95
96 return $data;
97 }
98
99 /**
100 * Parse our content for blocks.
101 *
102 * @param string $content Optional content to parse.
103 * @since 1.1
104 */
105 function generateblocks_get_parsed_content( $content = '' ) {
106 if ( ! function_exists( 'has_blocks' ) ) {
107 return;
108 }
109
110 if ( ! $content && has_blocks( get_the_ID() ) ) {
111 global $post;
112
113 if ( ! is_object( $post ) ) {
114 return;
115 }
116
117 $content = $post->post_content;
118 }
119
120 $content = apply_filters( 'generateblocks_do_content', $content );
121
122 if ( ! function_exists( 'parse_blocks' ) ) {
123 return;
124 }
125
126 $content = parse_blocks( $content );
127
128 return $content;
129 }
130
131 /**
132 * Shorthand CSS values (padding, margin, border etc..).
133 *
134 * @since 0.1
135 *
136 * @param int $top The first value.
137 * @param int $right The second value.
138 * @param int $bottom The third value.
139 * @param int $left The fourth value.
140 * @param string $unit The unit we're adding.
141 *
142 * @return string The shorthand value.
143 */
144 function generateblocks_get_shorthand_css( $top, $right, $bottom, $left, $unit ) {
145 if ( '' === $top && '' === $right && '' === $bottom && '' === $left ) {
146 return;
147 }
148
149 $top = ( floatval( $top ) <> 0 ) ? floatval( $top ) . $unit . ' ' : '0 '; // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
150 $right = ( floatval( $right ) <> 0 ) ? floatval( $right ) . $unit . ' ' : '0 '; // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
151 $bottom = ( floatval( $bottom ) <> 0 ) ? floatval( $bottom ) . $unit . ' ' : '0 '; // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
152 $left = ( floatval( $left ) <> 0 ) ? floatval( $left ) . $unit . ' ' : '0 '; // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
153
154 if ( $right === $left ) {
155 $left = '';
156
157 if ( $top === $bottom ) {
158 $bottom = '';
159
160 if ( $top === $right ) {
161 $right = '';
162 }
163 }
164 }
165
166 return trim( $top . $right . $bottom . $left );
167 }
168
169 /**
170 * Get our media query.
171 *
172 * @since 0.1
173 * @param string $type The media query we're getting.
174 *
175 * @return string
176 */
177 function generateblocks_get_media_query( $type ) {
178 $queries = apply_filters(
179 'generateblocks_media_query',
180 array(
181 'desktop' => '(min-width: 1025px)',
182 'tablet' => '(max-width: 1024px)',
183 'tablet_only' => '(max-width: 1024px) and (min-width: 768px)',
184 'mobile' => '(max-width: 767px)',
185 )
186 );
187
188 return $queries[ $type ];
189 }
190
191 /**
192 * Build our list of Google fonts on this page.
193 *
194 * @since 0.1
195 * @param string $content Optional content to parse.
196 * @return array
197 */
198 function generateblocks_get_google_fonts( $content = '' ) {
199 $content = generateblocks_get_parsed_content( $content );
200
201 if ( ! $content ) {
202 return;
203 }
204
205 $data = generateblocks_get_block_data( $content );
206
207 $defaults = generateblocks_get_block_defaults();
208 $font_data = array();
209
210 if ( ! empty( $data ) ) {
211 foreach ( $data as $name => $blockData ) {
212 if ( 'button' === $name ) {
213 foreach ( $blockData as $atts ) {
214 $button_settings = wp_parse_args(
215 $atts,
216 $defaults['button']
217 );
218
219 if ( $button_settings['googleFont'] ) {
220 $id = $atts['uniqueId'];
221
222 $variants = $button_settings['googleFontVariants'];
223
224 if ( $variants ) {
225 $variants = str_replace( ' ', '', $variants );
226 $variants = explode( ',', $variants );
227 }
228
229 $font_data[ $id ] = array(
230 'name' => $button_settings['fontFamily'],
231 'variants' => $variants,
232 );
233 }
234 }
235 }
236
237 if ( 'headline' === $name ) {
238 foreach ( $blockData as $atts ) {
239 $headline_settings = wp_parse_args(
240 $atts,
241 $defaults['headline']
242 );
243
244 if ( $headline_settings['googleFont'] ) {
245 $id = $atts['uniqueId'];
246 $variants = $headline_settings['googleFontVariants'];
247
248 if ( $variants ) {
249 $variants = str_replace( ' ', '', $variants );
250 $variants = explode( ',', $variants );
251 }
252
253 $font_data[ $id ] = array(
254 'name' => $headline_settings['fontFamily'],
255 'variants' => $variants,
256 );
257 }
258 }
259 }
260
261 if ( 'container' === $name ) {
262 foreach ( $blockData as $atts ) {
263 $container_settings = wp_parse_args(
264 $atts,
265 $defaults['container']
266 );
267
268 if ( $container_settings['googleFont'] ) {
269 $id = $atts['uniqueId'];
270 $variants = $container_settings['googleFontVariants'];
271
272 if ( $variants ) {
273 $variants = str_replace( ' ', '', $variants );
274 $variants = explode( ',', $variants );
275 }
276
277 $font_data[ $id ] = array(
278 'name' => $container_settings['fontFamily'],
279 'variants' => $variants,
280 );
281 }
282 }
283 }
284 }
285 }
286
287 $fonts = array();
288
289 foreach ( (array) $font_data as $font ) {
290 $id = str_replace( ' ', '', strtolower( $font['name'] ) );
291
292 $fonts[ $id ]['name'] = $font['name'];
293
294 if ( ! empty( $font['variants'] ) ) {
295 foreach ( $font['variants'] as $variant ) {
296 if ( isset( $fonts[ $id ]['variants'] ) ) {
297 if ( in_array( $variant, (array) $fonts[ $id ]['variants'] ) ) {
298 continue;
299 }
300 }
301
302 $fonts[ $id ]['variants'][] = $variant;
303 }
304 }
305 }
306
307 return apply_filters( 'generateblocks_google_fonts', $fonts );
308 }
309
310 /**
311 * Build the Google Font request URI.
312 *
313 * @since 0.1
314 *
315 * @return string The request URI to Google Fonts.
316 */
317 function generateblocks_get_google_fonts_uri() {
318 $google_fonts = generateblocks_get_google_fonts();
319
320 if ( ! $google_fonts ) {
321 return;
322 }
323
324 $data = array();
325
326 foreach ( $google_fonts as $font ) {
327 $variants = array();
328
329 if ( ! empty( $font['variants'] ) ) {
330 foreach ( $font['variants'] as $variant ) {
331 $variants[] = $variant;
332 }
333 }
334
335 $variants = apply_filters( 'generateblocks_google_font_variants', $variants, $font['name'] );
336
337 $name = str_replace( ' ', '+', $font['name'] );
338
339 if ( $variants ) {
340 $data[] = $name . ':' . implode( ',', $variants );
341 } else {
342 $data[] = $name;
343 }
344 }
345
346 $font_args = apply_filters(
347 'generateblocks_google_font_args',
348 array(
349 'family' => implode( '|', $data ),
350 'subset' => null,
351 'display' => 'swap',
352 )
353 );
354
355 return add_query_arg( $font_args, 'https://fonts.googleapis.com/css' );
356 }
357
358 /**
359 * Convert hex to RGBA
360 *
361 * @since 0.1
362 * @param string $hex The hex value.
363 * @param int $alpha The opacity value.
364 *
365 * @return string The RGBA value.
366 */
367 function generateblocks_hex2rgba( $hex, $alpha ) {
368 if ( ! $hex ) {
369 return;
370 }
371
372 if ( 1 === $alpha || ! is_numeric( $alpha ) ) {
373 return $hex;
374 }
375
376 // Make sure we're dealing with a hex value.
377 if ( isset( $hex[0] ) && '#' !== $hex[0] ) {
378 return $hex;
379 }
380
381 $hex = str_replace( '#', '', $hex );
382
383 if ( strlen( $hex ) == 3 ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
384 $r = hexdec( substr( $hex, 0, 1 ) . substr( $hex, 0, 1 ) );
385 $g = hexdec( substr( $hex, 1, 1 ) . substr( $hex, 1, 1 ) );
386 $b = hexdec( substr( $hex, 2, 1 ) . substr( $hex, 2, 1 ) );
387 } else {
388 $r = hexdec( substr( $hex, 0, 2 ) );
389 $g = hexdec( substr( $hex, 2, 2 ) );
390 $b = hexdec( substr( $hex, 4, 2 ) );
391 }
392
393 $rgba = 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $alpha . ')';
394
395 return $rgba;
396 }
397
398 /**
399 * Return old flexblocks values for old browsers.
400 *
401 * @since 0.1
402 * @param string $value The value to convert.
403 *
404 * @return string The old browser value.
405 */
406 function generateblocks_get_vendor_prefix( $value ) {
407 if ( 'flex-start' === $value || 'left' === $value ) {
408 return 'start';
409 }
410
411 if ( 'flex-end' === $value || 'right' === $value ) {
412 return 'end';
413 }
414
415 return $value;
416 }
417
418 /**
419 * Return flexbox alignment values from left/right.
420 *
421 * @since 0.1
422 * @param string $value The value to convert.
423 *
424 * @return string The flexbox alignment value.
425 */
426 function generateblocks_get_flexbox_alignment( $value ) {
427 if ( 'left' === $value || 'top' === $value ) {
428 return 'flex-start';
429 }
430
431 if ( 'right' === $value || 'bottom' === $value ) {
432 return 'flex-end';
433 }
434
435 return $value;
436 }
437
438 /**
439 * Return float alignment values.
440 *
441 * @since 1.5.0
442 * @param string $value The value to convert.
443 *
444 * @return string The float alignment value.
445 */
446 function generateblocks_get_float_alignment( $value ) {
447 $floats = [
448 'floatLeft' => 'left',
449 'floatRight' => 'right',
450 'floatNone' => 'none',
451 ];
452
453 return isset( $floats[ $value ] )
454 ? $floats[ $value ]
455 : $value;
456 }
457
458 /**
459 * Get an option from the database.
460 *
461 * @param string $option The option to get.
462 * @since 0.1
463 */
464 function generateblocks_get_option( $option ) {
465 $defaults = generateblocks_get_option_defaults();
466
467 if ( ! isset( $defaults[ $option ] ) ) {
468 return;
469 }
470
471 $options = wp_parse_args(
472 get_option( 'generateblocks', array() ),
473 $defaults
474 );
475
476 return $options[ $option ];
477 }
478
479 /**
480 * Checks whether a value exists, even if it's a 0.
481 *
482 * @param int|string $value The value to check.
483 * @since 1.0
484 */
485 function generateblocks_has_number_value( $value ) {
486 if ( $value || 0 === $value || '0' === $value ) {
487 return true;
488 }
489
490 return false;
491 }
492
493 /**
494 * Check if we have a Container background image to display.
495 *
496 * @since 1.5.0
497 * @param array $settings The block settings.
498 */
499 function generateblocks_has_background_image( $settings ) {
500 return $settings['bgImage'] ||
501 (
502 $settings['useDynamicData'] &&
503 '' !== $settings['dynamicContentType']
504 );
505 }
506
507 /**
508 * Get our background image URL.
509 *
510 * @since 1.5.0
511 * @param array $settings Block settings.
512 */
513 function generateblocks_get_background_image_url( $settings ) {
514 $url = '';
515
516 if ( isset( $settings['bgImage']['id'] ) ) {
517 $image_src = wp_get_attachment_image_src( $settings['bgImage']['id'], $settings['bgImageSize'] );
518
519 if ( is_array( $image_src ) ) {
520 $url = $image_src[0];
521 } else {
522 $url = $settings['bgImage']['image']['url'];
523 }
524 } elseif ( isset( $settings['bgImage']['image']['url'] ) ) {
525 $url = $settings['bgImage']['image']['url'];
526 }
527
528 return apply_filters( 'generateblocks_background_image_url', $url, $settings );
529 }
530
531 /**
532 * Get the background-image value for our Container block.
533 *
534 * @param string $type Gradient or background image.
535 * @param array $settings Our background image settings.
536 */
537 function generateblocks_get_background_image_css( $type, $settings ) {
538 $gradient = '';
539
540 if ( $settings['gradient'] ) {
541 $gradientColorStopOneValue = '';
542 $gradientColorStopTwoValue = '';
543 $gradientColorOneValue = generateblocks_hex2rgba( $settings['gradientColorOne'], $settings['gradientColorOneOpacity'] );
544 $gradientColorTwoValue = generateblocks_hex2rgba( $settings['gradientColorTwo'], $settings['gradientColorTwoOpacity'] );
545
546 if ( $settings['gradientColorOne'] && '' !== $settings['gradientColorStopOne'] ) {
547 $gradientColorStopOneValue = ' ' . $settings['gradientColorStopOne'] . '%';
548 }
549
550 if ( $settings['gradientColorTwo'] && '' !== $settings['gradientColorStopTwo'] ) {
551 $gradientColorStopTwoValue = ' ' . $settings['gradientColorStopTwo'] . '%';
552 }
553
554 $gradient = 'linear-gradient(' . $settings['gradientDirection'] . 'deg, ' . $gradientColorOneValue . $gradientColorStopOneValue . ', ' . $gradientColorTwoValue . $gradientColorStopTwoValue . ')';
555 }
556
557 if ( 'gradient' === $type ) {
558 return $gradient;
559 }
560
561 $backgroundImage = '';
562
563 if ( generateblocks_has_background_image( $settings ) ) {
564 $url = generateblocks_get_background_image_url( $settings );
565
566 // Old background image overlays mixed with our gradients.
567 if (
568 'element' === $settings['bgOptions']['selector'] &&
569 ( $settings['backgroundColor'] || $settings['gradient'] ) &&
570 isset( $settings['bgOptions']['overlay'] ) &&
571 $settings['bgOptions']['overlay']
572 ) {
573 if ( $settings['gradient'] ) {
574 $backgroundImage = $gradient . ', url(' . esc_url( $url ) . ')';
575 } elseif ( $settings['backgroundColor'] ) {
576 $settings['backgroundColor'] = generateblocks_hex2rgba( $settings['backgroundColor'], $settings['backgroundColorOpacity'] );
577 $backgroundImage = 'linear-gradient(0deg, ' . $settings['backgroundColor'] . ', ' . $settings['backgroundColor'] . '), url(' . esc_url( $url ) . ')';
578 }
579 } else {
580 $backgroundImage = 'url(' . esc_url( $url ) . ')';
581
582 if ( $settings['bgImageInline'] && 'element' !== $settings['bgOptions']['selector'] ) {
583 $backgroundImage = 'var(--background-image)';
584 }
585 }
586 }
587
588 return $backgroundImage;
589 }
590
591 /**
592 * Build list of attributes into a string and apply contextual filter on string.
593 *
594 * The contextual filter is of the form `generateblocks_attr_{context}_output`.
595 *
596 * @since 1.2.0
597 *
598 * @param string $context The context, to build filter name.
599 * @param array $attributes Optional. Extra attributes to merge with defaults.
600 * @param array $settings Optional. Custom data to pass to filter.
601 * @param WP_Block $block Block instance.
602 * @return string String of HTML attributes and values.
603 */
604 function generateblocks_attr( $context, $attributes = array(), $settings = array(), $block = null ) {
605 $attributes = generateblocks_parse_attr( $context, $attributes, $settings );
606
607 $output = '';
608
609 // Cycle through attributes, build tag attribute string.
610 foreach ( $attributes as $key => $value ) {
611
612 if ( ! $value ) {
613 continue;
614 }
615
616 if ( true === $value ) {
617 $output .= esc_html( $key ) . ' ';
618 } else {
619 $output .= sprintf( '%s="%s" ', esc_html( $key ), esc_attr( $value ) );
620 }
621 }
622
623 $output = apply_filters( "generateblocks_attr_{$context}_output", $output, $attributes, $settings, $context, $block );
624
625 return trim( $output );
626 }
627
628 /**
629 * Merge array of attributes with defaults, and apply contextual filter on array.
630 *
631 * The contextual filter is of the form `generateblocks_attr_{context}`.
632 *
633 * @since 1.2.0
634 *
635 * @param string $context The context, to build filter name.
636 * @param array $attributes Optional. Extra attributes to merge with defaults.
637 * @param array $settings Optional. Custom data to pass to filter.
638 * @param WP_Block $block Block instance.
639 * @return array Merged and filtered attributes.
640 */
641 function generateblocks_parse_attr( $context, $attributes = array(), $settings = array(), $block = null ) {
642 $defaults = array(
643 'class' => sanitize_html_class( $context ),
644 );
645
646 $attributes = wp_parse_args( $attributes, $defaults );
647
648 // Contextual filter.
649 return apply_filters( "generateblocks_attr_{$context}", $attributes, $settings, $context, $block );
650 }
651
652 /**
653 * Generate our SVG shape dividers.
654 *
655 * @since 1.2.0
656 */
657 function generateblocks_get_svg_shapes() {
658 return apply_filters(
659 'generateblocks_svg_shapes',
660 array(
661 'gb-waves' => array(
662 'group' => esc_attr__( 'Waves', 'generateblocks' ),
663 'svgs' => array(
664 'gb-waves-1' => array(
665 /* translators: Shape number */
666 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '1' ),
667 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 194.3" preserveAspectRatio="none"><path d="M1200 133.3l-50 8.9c-50 8.6-150 26.9-250 31.1-100 4.2-200-4.2-300-26.7S400 89.2 300 62.2C200 35.8 100 17.5 50 8.9L0 0v194.3h1200v-61z"/></svg>',
668 ),
669 'gb-waves-2' => array(
670 /* translators: Shape number */
671 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '2' ),
672 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 137.6" preserveAspectRatio="none"><path d="M0 137.6h1200V21.9l-66.7 26.7c-66.7 26.7-200 80-333.3 66.7S533.3 21.9 400 4.2C266.7-13.9 133.3 31.1 66.7 53L0 75.3v62.3z"/></svg>',
673 ),
674 'gb-waves-3' => array(
675 /* translators: Shape number */
676 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '3' ),
677 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 96.2" preserveAspectRatio="none"><path d="M0 96.2h1200V72.9l-50-8.9c-50-8.6-150-26.9-250-22.2C800 46.2 700 72.9 600 64 500 55.4 400 10.4 300 1.8 200-7.1 100 19.5 50 32.9L0 46.2v50z"/></svg>',
678 ),
679 'gb-waves-4' => array(
680 /* translators: Shape number */
681 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '4' ),
682 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 130.3" preserveAspectRatio="none"><path d="M0 107.9l40-22.2c40-21.9 120-66.9 200-62.2 80 4.4 160 57.8 240 53.3C560 72 640 10.4 720 1.2S880 37 960 59c80 22.3 160 22.3 200 22.3h40v49H0v-22.4z"/></svg>',
683 ),
684 'gb-waves-5' => array(
685 /* translators: Shape number */
686 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '5' ),
687 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 218" preserveAspectRatio="none"><path d="M0 218h1200v-31.3l-40 4.4c-40 4.8-120 13.1-200 0-80-13.6-160-48.6-240-66.7-80-17.8-160-17.8-240-8.8-80 8.6-160 26.9-240 8.8-80-17.7-160-71.1-200-97.7L0 0v218z"/></svg>',
688 ),
689 'gb-waves-6' => array(
690 /* translators: Shape number */
691 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '6' ),
692 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 234" preserveAspectRatio="none"><path d="M0 0l40 40c40 40 120 120 200 115.6 80-4.8 160-93.1 240-111.2C560 26.7 640 80 720 88.9c80 8.6 160-26.4 240-13.3 80 13.6 160 75.2 200 106.7l40 31.1V234H0V0z"/></svg>',
693 ),
694 'gb-waves-7' => array(
695 /* translators: Shape number */
696 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '7' ),
697 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 217.3" preserveAspectRatio="none"><path d="M1200 195.6l-25-22.2c-25-21.9-75-66.9-125-75.5-50-8.9-100 17.8-150 26.7-50 8.6-100 .2-150-13.3-50-13.1-100-31.4-150-26.7-50 4.4-100 31.1-150 26.7-50-4.8-100-39.8-150-66.7C250 18.1 200-.2 150 0 100-.2 50 18.1 25 26.7L0 35.6v181.7h1200v-21.7z"/></svg>',
698 ),
699 'gb-waves-8' => array(
700 /* translators: Shape number */
701 'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '8' ),
702 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 230.8" preserveAspectRatio="none"><path d="M1200 179.5l-22.2-26.7c-22.2-26.7-66.9-80-111.1-75.6-44.4 4.8-89.2 66.4-133.3 102.2-44.4 35.8-89.2 44.2-133.3 8.9-44.4-35.6-89.2-115.6-133.3-155.6-44.4-40-89.2-40-133.3-17.8C488.9 37 444.2 82 400 81.7c-44.4.2-89.2-44.8-133.3-57.8-44.4-13.6-89.2 4.8-133.3 26.7-44.5 22.2-89.2 48.9-110.9 62.2L0 126.1v104.7H1199.7l.3-51.3z"/></svg>',
703 ),
704 ),
705 ),
706 'gb-angles' => array(
707 'group' => esc_attr__( 'Angles', 'generateblocks' ),
708 'svgs' => array(
709 'gb-angle-1' => array(
710 /* translators: Shape number */
711 'label' => sprintf( __( 'Angle %s', 'generateblocks' ), '1' ),
712 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 360" preserveAspectRatio="none"><path d="M1200 360H0V0l1200 348z"/></svg>',
713 ),
714 ),
715 ),
716 'gb-curves' => array(
717 'group' => esc_attr__( 'Curves', 'generateblocks' ),
718 'svgs' => array(
719 'gb-curve-1' => array(
720 /* translators: Shape number */
721 'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '1' ),
722 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 350" preserveAspectRatio="none"><path d="M1200 336.7V350H0V0s22.4 276.4 1200 336.7z"/></svg>',
723 ),
724 'gb-curve-2' => array(
725 /* translators: Shape number */
726 'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '2' ),
727 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 350" preserveAspectRatio="none"><path d="M1200 350V0C22.4 60.3 0 336.7 0 336.7V350h1200z"/></svg>',
728 ),
729 'gb-curve-3' => array(
730 /* translators: Shape number */
731 'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '3' ),
732 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 211.2" preserveAspectRatio="none"><path d="M600 188.4C321.1 188.4 84.3 109.5 0 0v211.2h1200V0c-84.3 109.5-321.1 188.4-600 188.4z"/></svg>',
733 ),
734 'gb-curve-4' => array(
735 /* translators: Shape number */
736 'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '4' ),
737 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 211.2" preserveAspectRatio="none"><path d="M1200 188.4v22.8H0v-22.8C84.3 78.9 321.1 0 600 0s515.7 78.9 600 188.4z"/></svg>',
738 ),
739 ),
740 ),
741 'gb-triangles' => array(
742 'group' => esc_attr__( 'Triangles', 'generateblocks' ),
743 'svgs' => array(
744 'gb-triangle-1' => array(
745 /* translators: Shape number */
746 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '1' ),
747 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 100" preserveAspectRatio="none"><path d="M1200 100H0V0l400 77.2L1200 0z"/></svg>',
748 ),
749 'gb-triangle-2' => array(
750 /* translators: Shape number */
751 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '2' ),
752 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 100" preserveAspectRatio="none"><path d="M1200 77.2L400 0 0 77.2V100h1200z"/></svg>',
753 ),
754 'gb-triangle-3' => array(
755 /* translators: Shape number */
756 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '3' ),
757 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 70" preserveAspectRatio="none"><path d="M1200 0v70H0V0h530l70 50 70-50z"/></svg>',
758 ),
759 'gb-triangle-4' => array(
760 /* translators: Shape number */
761 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '4' ),
762 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 70" preserveAspectRatio="none"><path d="M670 50L600 0l-70 50H0v20h1200V50z"/></svg>',
763 ),
764 'gb-triangle-5' => array(
765 /* translators: Shape number */
766 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '5' ),
767 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 50" preserveAspectRatio="none"><path d="M1200 0v50H0V0h560l40 30 40-30z"/></svg>',
768 ),
769 'gb-triangle-6' => array(
770 /* translators: Shape number */
771 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '6' ),
772 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 50" preserveAspectRatio="none"><path d="M640 30L600 0l-40 30H0v20h1200V30z"/></svg>',
773 ),
774 'gb-triangle-7' => array(
775 /* translators: Shape number */
776 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '7' ),
777 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 230" preserveAspectRatio="none"><path d="M1200 230H0V0l600 207.2L1200 0z"/></svg>',
778 ),
779 'gb-triangle-8' => array(
780 /* translators: Shape number */
781 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '8' ),
782 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 230" preserveAspectRatio="none"><path d="M1200 207.2L600 0 0 207.2V230h1200z"/></svg>',
783 ),
784 'gb-triangle-9' => array(
785 /* translators: Shape number */
786 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '9' ),
787 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 131" preserveAspectRatio="none"><path d="M1200 131H0V40l154.8 50L410 35l277 69L899 0l301 110z"/></svg>',
788 ),
789 'gb-triangle-10' => array(
790 /* translators: Shape number */
791 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '10' ),
792 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 131" preserveAspectRatio="none"><path d="M1200 0L899 110 687 6 410 75 154.8 20 0 70v61h1200z"/></svg>',
793 ),
794 'gb-triangle-11' => array(
795 /* translators: Shape number */
796 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '11' ),
797 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 176" preserveAspectRatio="none"><path d="M0 0l400 156 400-88 400 74v34H0z"/></svg>',
798 ),
799 'gb-triangle-12' => array(
800 /* translators: Shape number */
801 'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '12' ),
802 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 176" preserveAspectRatio="none"><path d="M0 176h1200V14L800 88 400 0 0 156z"/></svg>',
803 ),
804 ),
805 ),
806 )
807 );
808 }
809
810 /**
811 * Search an array to check if a key has a value.
812 *
813 * @since 1.5.0
814 * @param string $setting The setting to check.
815 * @param array $data The array to search.
816 */
817 function generateblocks_block_has_value( $setting, $data ) {
818 foreach ( (array) $data as $key => $val ) {
819 if ( isset( $val[ $setting ] ) && ( $val[ $setting ] || 0 === $val[ $setting ] ) ) {
820 return true;
821 }
822 }
823
824 return null;
825 }
826
827 /**
828 * Given an array it will change keys based on the map.
829 *
830 * @param array $arr The array to check.
831 * @param array $keyMap The array to map.
832 *
833 * @return array|false
834 *
835 * @since 1.5.0
836 */
837 function generateblocks_map_array_keys( $arr = array(), $keyMap = array() ) {
838 return array_combine(
839 array_map(
840 function( $key ) use ( $keyMap ) {
841 return isset( $keyMap[ $key ] ) ? $keyMap[ $key ] : $key;
842 },
843 array_keys( $arr )
844 ),
845 array_values( $arr )
846 );
847 }
848
849 /**
850 * Checks if the date is correctly formatted
851 *
852 * @param string $date The date to validate.
853 * @param string $format The allowed format.
854 *
855 * @return bool
856 */
857 function generateblocks_is_valid_date( $date, $format = 'Y-m-d\TH:i:s' ) {
858 $dateTime = DateTime::createFromFormat( $format, $date );
859
860 return ( $dateTime && $dateTime->format( $format ) === $date );
861 }
862
863 /**
864 * Modifies the markup of images in provided content.
865 *
866 * @param string $content The content to modify.
867 * @param array $attributes The block attributes.
868 *
869 * @since 1.5.0
870 */
871 function generateblocks_filter_images( $content, $attributes ) {
872 // Bail early if not using WP 5.5.
873 if ( ! function_exists( 'wp_img_tag_add_width_and_height_attr' ) ) {
874 return $content;
875 }
876
877 if ( ! empty( $attributes['mediaId'] ) ) {
878 // Add 'width' and 'height' attributes if applicable.
879 if ( false === strpos( $content, ' width=' ) && false === strpos( $content, ' height=' ) ) {
880 $content = wp_img_tag_add_width_and_height_attr( $content, '', $attributes['mediaId'] );
881 }
882
883 // Add 'srcset' and 'sizes' attributes if applicable.
884 if ( false === strpos( $content, ' srcset=' ) ) {
885 $content = wp_img_tag_add_srcset_and_sizes_attr( $content, '', $attributes['mediaId'] );
886 }
887 }
888
889 // Add 'loading' attribute if applicable.
890 if ( wp_lazy_loading_enabled( 'img', '' ) && false === strpos( $content, ' loading=' ) ) {
891 $content = wp_img_tag_add_loading_attr( $content, '' );
892 }
893
894 return $content;
895 }
896
897 /**
898 * Compile our CSS based on our CSS data.
899 *
900 * @since 1.6.0
901 * @param array $manual_data CSS data input directly to the function.
902 */
903 function generateblocks_get_compiled_css( $manual_data = [] ) {
904 $data = apply_filters( 'generateblocks_css_data', [] );
905
906 // Allows us to input manual data if necessary.
907 if ( count( (array) $manual_data ) > 0 ) {
908 $data = $manual_data;
909 }
910
911 $css = '';
912
913 if ( ! empty( $data['main'] ) ) {
914 $css .= $data['main'];
915 }
916
917 if ( ! empty( $data['desktop'] ) ) {
918 $css .= sprintf(
919 '@media %1$s {%2$s}',
920 generateblocks_get_media_query( 'desktop' ),
921 $data['desktop']
922 );
923 }
924
925 if ( ! empty( $data['tablet'] ) ) {
926 $css .= sprintf(
927 '@media %1$s {%2$s}',
928 generateblocks_get_media_query( 'tablet' ),
929 $data['tablet']
930 );
931 }
932
933 if ( ! empty( $data['tablet_only'] ) ) {
934 $css .= sprintf(
935 '@media %1$s {%2$s}',
936 generateblocks_get_media_query( 'tablet_only' ),
937 $data['tablet_only']
938 );
939 }
940
941 if ( ! empty( $data['mobile'] ) ) {
942 $css .= sprintf(
943 '@media %1$s {%2$s}',
944 generateblocks_get_media_query( 'mobile' ),
945 $data['mobile']
946 );
947 }
948
949 return $css;
950 }
951
952 /**
953 * This is a helper function that groups our static CSS into device-specific groups.
954 *
955 * @param array $existing_data An array of existing data to add to.
956 * @param array $new_data The new data we wish to group.
957 *
958 * @since 1.6.0
959 */
960 function generateblocks_group_css_data( $existing_data = [], $new_data = [] ) {
961 $existing_data = wp_parse_args(
962 $existing_data,
963 [
964 'main' => '',
965 'desktop' => '',
966 'tablet' => '',
967 'tablet_only' => '',
968 'mobile' => '',
969 ]
970 );
971
972 $existing_data['main'] .= generateblocks_get_parsed_css( $new_data['main'] );
973 $existing_data['desktop'] .= generateblocks_get_parsed_css( $new_data['desktop'] );
974 $existing_data['tablet'] .= generateblocks_get_parsed_css( $new_data['tablet'] );
975 $existing_data['tablet_only'] .= generateblocks_get_parsed_css( $new_data['tablet_only'] );
976 $existing_data['mobile'] .= generateblocks_get_parsed_css( $new_data['mobile'] );
977
978 return $existing_data;
979 }
980
981 /**
982 * Turn our CSS array into plain CSS.
983 *
984 * @since 1.0
985 * @param array $data Our CSS data.
986 */
987 function generateblocks_get_parsed_css( $data ) {
988 $output = '';
989
990 foreach ( $data as $selector => $properties ) {
991 if ( ! count( $properties ) ) {
992 continue;
993 }
994
995 $temporary_output = $selector . '{';
996 $elements_added = 0;
997
998 foreach ( $properties as $key => $value ) {
999 if ( empty( $value ) ) {
1000 continue;
1001 }
1002
1003 $elements_added++;
1004 $temporary_output .= $value;
1005 }
1006
1007 $temporary_output .= '}';
1008
1009 if ( $elements_added > 0 ) {
1010 $output .= $temporary_output;
1011 }
1012 }
1013
1014 return $output;
1015 }
1016
1017 /**
1018 * Build the CSS from our block attributes.
1019 *
1020 * @since 0.1
1021 * @param string $content The content we're looking through.
1022 * @param string $store_block_id_only Store the found block IDs instead of adding CSS.
1023 *
1024 * @return string The dynamic CSS.
1025 */
1026 function generateblocks_get_dynamic_css( $content = '', $store_block_id_only = false ) {
1027 if ( ! $content ) {
1028 $content = generateblocks_get_parsed_content();
1029 }
1030
1031 $data = generateblocks_get_block_data( $content );
1032
1033 if ( empty( $data ) ) {
1034 return;
1035 }
1036
1037 $blocks = [
1038 'grid' => 'GenerateBlocks_Block_Grid',
1039 'container' => 'GenerateBlocks_Block_Container',
1040 'button-container' => 'GenerateBlocks_Block_Button_Container',
1041 'button' => 'GenerateBlocks_Block_Button',
1042 'headline' => 'GenerateBlocks_Block_Headline',
1043 'image' => 'GenerateBlocks_Block_Image',
1044 ];
1045
1046 foreach ( $data as $name => $blockData ) {
1047 if ( isset( $blocks[ $name ] ) ) {
1048 if ( empty( $blockData ) ) {
1049 continue;
1050 }
1051
1052 foreach ( $blockData as $atts ) {
1053 if ( ! isset( $atts['uniqueId'] ) ) {
1054 continue;
1055 }
1056
1057 if ( is_callable( [ $blocks[ $name ], 'get_css_data' ] ) ) {
1058 if ( $store_block_id_only ) {
1059 $blocks[ $name ]::store_block_id( $atts['uniqueId'] );
1060 } elseif ( ! $blocks[ $name ]::block_id_exists( $atts['uniqueId'] ) ) {
1061 generateblocks_add_to_css_data(
1062 $blocks[ $name ]::get_css_data( $atts )
1063 );
1064 }
1065 }
1066 }
1067 }
1068 }
1069 }
1070
1071 /**
1072 * Print our CSS for each block.
1073 *
1074 * @since 0.1
1075 */
1076 function generateblocks_get_frontend_block_css() {
1077 return apply_filters( 'generateblocks_css_output', generateblocks_get_compiled_css() );
1078 }
1079
1080 /**
1081 * Add block CSS to our pool of generated CSS.
1082 *
1083 * @since 1.6.0
1084 * @param array $data Our CSS data.
1085 */
1086 function generateblocks_add_to_css_data( $data ) {
1087 add_filter(
1088 'generateblocks_css_data',
1089 function( $css_data ) use ( $data ) {
1090 return generateblocks_group_css_data( $css_data, $data );
1091 }
1092 );
1093 }
1094
1095 /**
1096 * Maybe add block CSS if it hasn't already been added for this block.
1097 *
1098 * @since 1.6.0
1099 * @param string $content Our block content.
1100 * @param array $data Block data.
1101 */
1102 function generateblocks_maybe_add_block_css( $content = '', $data = [] ) {
1103 if (
1104 isset( $data['attributes']['uniqueId'] ) &&
1105 ! in_array( $data['attributes']['uniqueId'], $data['block_ids'] )
1106 ) {
1107 // Don't try to print CSS for the Query Loop block.
1108 if ( isset( $data['attributes']['query'] ) ) {
1109 return $content;
1110 }
1111
1112 $css_data = is_callable( [ $data['class_name'], 'get_css_data' ] )
1113 ? $data['class_name']::get_css_data( $data['attributes'] )
1114 : false;
1115
1116 if ( ! $css_data ) {
1117 return $content;
1118 }
1119
1120 if ( did_action( 'wp_head' ) ) {
1121 // Add inline <style> elements if we don't have access to wp_head.
1122 $grouped_css = generateblocks_group_css_data( [], $css_data );
1123 $compiled_css = generateblocks_get_compiled_css( $grouped_css );
1124
1125 if ( $compiled_css ) {
1126 $content = sprintf(
1127 '<style>%s</style>',
1128 $compiled_css
1129 ) . $content;
1130 }
1131 } else {
1132 // Add our CSS to the pool of existing CSS in wp_head.
1133 generateblocks_add_to_css_data( $css_data );
1134 }
1135 }
1136
1137 return $content;
1138 }
1139