PluginProbe ʕ •ᴥ•ʔ
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / trunk
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz vtrunk
2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8 0.0.9 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.1.2 1.10.0 1.10.1 1.11.0 1.12.0 1.12.1 1.12.2 1.12.3 1.13.0 1.13.1 1.13.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.8.0 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.5.0 2.5.2 2.6.0
sureforms / modules / gutenberg / classes / class-spec-gb-helper.php
sureforms / modules / gutenberg / classes Last commit date
class-spec-block-config.php 2 years ago class-spec-block-helper.php 1 year ago class-spec-block-js.php 2 years ago class-spec-block-loader.php 2 years ago class-spec-filesystem.php 2 months ago class-spec-gb-helper.php 11 months ago class-spec-init-blocks.php 5 months ago class-spec-spectra-compatibility.php 5 months ago
class-spec-gb-helper.php
1192 lines
1 <?php
2 /**
3 * Sureforms Gb Helper.
4 *
5 * @package Sureforms
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit; // Exit if accessed directly.
10 }
11
12 if ( ! class_exists( 'Spec_Gb_Helper' ) ) {
13
14 /**
15 * Class Spec_Gb_Helper.
16 */
17 final class Spec_Gb_Helper {
18
19
20 /**
21 * Member Variable
22 *
23 * @since 0.0.1
24 * @var instance
25 */
26 private static $instance;
27
28 /**
29 * Member Variable
30 *
31 * @since 0.0.1
32 * @var instance
33 */
34 public static $block_list;
35
36 /**
37 * Current Block List
38 *
39 * @since 0.0.1
40 * @var current_block_list
41 */
42 public static $current_block_list = [];
43
44 /**
45 * Page Blocks Variable
46 *
47 * @since 0.0.1
48 * @var instance
49 */
50 public static $page_blocks;
51
52 /**
53 * Stylesheet
54 *
55 * @since 0.0.1
56 * @var stylesheet
57 */
58 public static $stylesheet;
59
60 /**
61 * Script
62 *
63 * @since 0.0.1
64 * @var script
65 */
66 public static $script;
67
68 /**
69 * Sureforms Block Flag
70 *
71 * @since 0.0.1
72 * @var srfm_flag
73 */
74 public static $srfm_flag = false;
75
76 /**
77 * Static CSS Added Array
78 *
79 * @since 0.0.1
80 * @var array
81 */
82 public $static_css_blocks = [];
83
84 /**
85 * Google fonts to enqueue
86 *
87 * @since 0.0.1
88 * @var array
89 */
90 public static $gfonts = [];
91
92 /**
93 * As our svg icon is too long array so we will divide that into number of icon chunks.
94 *
95 * @var int
96 * @since 0.0.1
97 */
98 public static $number_of_icon_chunks = 4;
99
100 /**
101 * Store Json variable
102 *
103 * @since 0.0.1
104 * @var instance
105 */
106 public static $icon_json;
107
108 /**
109 * We have icon list in chunks in this variable we will merge all insides array into one single array.
110 *
111 * @var array
112 * @since 0.0.1
113 */
114 public static $icon_array_merged = [];
115
116 /**
117 * Seen Refs Array
118 * This array will store the block IDs which have already been processed.
119 *
120 * @since 1.4.2
121 * @var array
122 */
123 private static $seen_refs = [];
124
125 /**
126 * Processed form IDs Array
127 * This array will store the SRFM form IDs which have already been processed to prevent duplicate styles.
128 *
129 * @since 1.11.0
130 * @var array
131 */
132 private static $processed_srfm_ids = [];
133
134 /**
135 * Initiator
136 *
137 * @since 0.0.1
138 */
139 public static function get_instance() {
140 if ( ! isset( self::$instance ) ) {
141 self::$instance = new self();
142 }
143 return self::$instance;
144 }
145
146 /**
147 * Constructor
148 */
149 public function __construct() {
150 require SRFM_DIR . 'modules/gutenberg/classes/class-spec-block-config.php';
151 require SRFM_DIR . 'modules/gutenberg/classes/class-spec-block-helper.php';
152 require SRFM_DIR . 'modules/gutenberg/classes/class-spec-block-js.php';
153
154 /**
155 * Introduce this action to execute Spec_Block_Config::get_block_attributes().
156 * This is necessary because translation functions are called within it.
157 * WordPress 6.7 introduced warnings when hook execution order is incorrect,
158 * which can lead to notices. This action ensures proper hook sequence.
159 */
160 add_action( 'init', [ $this, 'init_block_attributes' ] );
161
162 $theme_name = wp_get_theme()->get( 'Name' );
163
164 if ( 'Divi' === $theme_name ) {
165 add_action( 'et_after_main_content', [ $this, 'wp_actions' ], 10 );
166 } else {
167 add_action( 'wp', [ $this, 'wp_actions' ], 10 );
168 }
169
170 add_filter( 'render_block', [ $this, 'generate_render_styles' ], 10, 2 );
171 }
172
173 /**
174 * Initialize block attributes.
175 *
176 * @since 1.0.6
177 * @return void
178 */
179 public static function init_block_attributes() {
180 self::$block_list = Spec_Block_Config::get_block_attributes();
181 }
182
183 /**
184 * Get form id content.
185 *
186 * @param string $id form id.
187 * @since 0.0.1
188 * @return void
189 */
190 public function form_content_by_id( $id ) {
191 $args = [
192 'p' => $id,
193 'post_type' => 'sureforms_form',
194 ];
195 $loop = new WP_Query( $args );
196
197 if ( isset( $loop->posts[0] ) && $loop->posts[0] ) {
198
199 /**
200 * Filters the post to build stylesheet for.
201 *
202 * @param \WP_Post $this_post The global post.
203 */
204 $this_post = apply_filters( 'srfm_post_for_stylesheet', $loop->posts[0] );
205
206 $this->get_generated_stylesheet( $this_post );
207 }
208 }
209
210 /**
211 * Render function.
212 *
213 * @param string $block_content Entire Block Content.
214 * @param array $block Block Properties As An Array.
215 * @return string
216 */
217 public function generate_render_styles( $block_content, $block ) {
218
219 if ( isset( $block['blockName'] ) && ( 'srfm/form' === $block['blockName'] ) ) {
220
221 if ( isset( $block['attrs']['id'] ) && $block['attrs']['id'] ) {
222 self::form_content_by_id( $block['attrs']['id'] );
223 }
224 }
225
226 if ( isset( $block['blockName'] ) && ( 'core/shortcode' === $block['blockName'] ) ) {
227
228 if ( isset( $block['innerHTML'] ) ) {
229 $start_explode = ( explode( 'form-id="', $block['innerHTML'] ) );
230 if ( isset( $start_explode[1] ) ) {
231 $end_explode = explode( '"', $start_explode[1] );
232 if ( isset( $end_explode ) ) {
233 self::form_content_by_id( $end_explode[0] );
234 }
235 }
236 }
237 }
238
239 return $block_content;
240 }
241
242 /**
243 * WP Actions.
244 */
245 public function wp_actions() {
246 $this->generate_assets();
247 add_action( 'wp_enqueue_scripts', [ $this, 'block_assets' ], 10 );
248 add_action( 'wp_head', [ $this, 'frontend_gfonts' ], 120 );
249 add_action( 'wp_head', [ $this, 'print_stylesheet' ], 80 );
250 add_action( 'wp_footer', [ $this, 'print_script' ], 1000 );
251 }
252
253 /**
254 * Load the front end Google Fonts.
255 */
256 public function frontend_gfonts() {
257
258 if ( empty( self::$gfonts ) ) {
259 return;
260 }
261 $show_google_fonts = apply_filters( 'srfm_blocks_show_google_fonts', true );
262 if ( ! $show_google_fonts ) {
263 return;
264 }
265 $link = '';
266 $subsets = [];
267 foreach ( self::$gfonts as $key => $gfont_values ) {
268 if ( ! empty( $link ) ) {
269 $link .= '%7C'; // Append a new font to the string.
270 }
271 $link .= $gfont_values['fontfamily'];
272 if ( ! empty( $gfont_values['fontvariants'] ) ) {
273 $link .= ':';
274 $link .= implode( ',', $gfont_values['fontvariants'] );
275 }
276 if ( ! empty( $gfont_values['fontsubsets'] ) ) {
277 foreach ( $gfont_values['fontsubsets'] as $subset ) {
278 if ( ! in_array( $subset, $subsets, true ) ) {
279 array_push( $subsets, $subset );
280 }
281 }
282 }
283 }
284 if ( ! empty( $subsets ) ) {
285 $link .= '&amp;subset=' . implode( ',', $subsets );
286 }
287
288 if ( isset( $link ) && ! empty( $link ) ) {
289 wp_enqueue_style( 'srfm-google-fonts', '//fonts.googleapis.com/css?family=' . esc_attr( str_replace( '|', '%7C', $link ) ), [], SRFM_VER, 'all' );
290 }
291 }
292
293 /**
294 * Set alignment css function.
295 *
296 * @param string $align passed.
297 * @since 0.0.1
298 * @return array
299 */
300 public static function alignment_css( $align ) {
301 $align_css = [];
302 switch ( $align ) {
303 case 'left':
304 $align_css = [
305 'margin-left' => 0,
306 'margin-right' => 'auto',
307 ];
308 break;
309 case 'center':
310 $align_css = [
311 'margin-left' => 'auto',
312 'margin-right' => 'auto',
313 ];
314 break;
315 case 'right':
316 $align_css = [
317 'margin-right' => 0,
318 'margin-left' => 'auto',
319 ];
320 break;
321 }
322 return $align_css;
323 }
324
325 /**
326 * Print the Script in footer.
327 */
328 public function print_script() {
329
330 if ( is_null( self::$script ) || '' === self::$script ) {
331 return;
332 }
333
334 $js_uri = SRFM_URL . 'modules/gutenberg/assets/js/';
335
336 wp_enqueue_script( SRFM_SLUG . '-gutenberg', $js_uri . 'gutenberg.js', [], SRFM_VER, true );
337
338 $srfm_inline_js = self::$script;
339 if ( $srfm_inline_js ) {
340 wp_add_inline_script( SRFM_SLUG . '-gutenberg', $srfm_inline_js );
341 }
342
343 }
344
345 /**
346 * Print the Stylesheet in header.
347 */
348 public function print_stylesheet() {
349
350 if ( is_null( self::$stylesheet ) || '' === self::$stylesheet ) {
351 return;
352 }
353
354 $css_uri = SRFM_URL . 'modules/gutenberg/assets/css/';
355
356 wp_enqueue_style( SRFM_SLUG . '-gutenberg', $css_uri . 'gutenberg.css', [], SRFM_VER );
357
358 $srfm_inline_css = self::$stylesheet;
359 if ( $srfm_inline_css ) {
360 wp_add_inline_style( SRFM_SLUG . '-gutenberg', $srfm_inline_css );
361 }
362
363 }
364
365 /**
366 * Generates stylesheet and appends in head tag.
367 *
368 * @since 0.0.1
369 */
370 public function generate_assets() {
371
372 $this_post = [];
373
374 global $post;
375 $this_post = $post;
376
377 if ( ! is_object( $this_post ) ) {
378 return;
379 }
380
381 /**
382 * Filters the post to build stylesheet for.
383 *
384 * @param \WP_Post $this_post The global post.
385 */
386 $this_post = apply_filters( 'srfm_post_for_stylesheet', $this_post );
387
388 $this->get_generated_stylesheet( $this_post );
389
390 }
391
392 /**
393 *
394 * Recursively collects all SRFM form blocks from a given block structure.
395 *
396 * This method traverses the provided block array (including any nested inner blocks),
397 * finds `srfm/form` blocks, retrieves the corresponding post content for those forms,
398 * parses it into block data, and merges the results into the return array.
399 *
400 * @param array $blocks The current block data (including attributes and inner blocks).
401 * @param array $blocks_to_return The array of collected SRFM form blocks to return.
402 *
403 * @return array Collected SRFM form blocks.
404 * @since 1.11.0
405 */
406 public function get_srfm_form_blocks( $blocks, $blocks_to_return = [] ) {
407 // Ensure $blocks is an array and has required structure.
408 if ( ! is_array( $blocks ) || empty( $blocks ) ) {
409 return $blocks_to_return;
410 }
411
412 // Prevent duplicate processing by checking ID early.
413 if ( isset( $blocks['attrs']['id'] ) && in_array( $blocks['attrs']['id'], self::$processed_srfm_ids, true ) ) {
414 return $blocks_to_return;
415 }
416
417 // Check for SRFM form block.
418 if ( isset( $blocks['blockName'] ) && 'srfm/form' === $blocks['blockName'] ) {
419 if ( ! empty( $blocks['attrs']['id'] ) ) {
420 $form_id = $blocks['attrs']['id'];
421 self::$processed_srfm_ids[] = $form_id;
422
423 $get_block_from_the_form = get_post( $form_id );
424 if ( $get_block_from_the_form && ! empty( $get_block_from_the_form->post_content ) ) {
425 $parsed_blocks = $this->parse( $get_block_from_the_form->post_content );
426 if ( is_array( $parsed_blocks ) ) {
427 $blocks_to_return = array_merge( $blocks_to_return, $parsed_blocks );
428 }
429 }
430 }
431 }
432
433 // Process inner blocks if any.
434 if ( ! empty( $blocks['innerBlocks'] ) && is_array( $blocks['innerBlocks'] ) ) {
435 foreach ( $blocks['innerBlocks'] as $inner_block ) {
436 $blocks_to_return = $this->get_srfm_form_blocks( $inner_block, $blocks_to_return );
437 }
438 }
439
440 return $blocks_to_return;
441 }
442
443
444 /**
445 * Generates stylesheet in loop.
446 *
447 * @param object $this_post Current Post Object.
448 * @since 0.0.1
449 */
450 public function get_generated_stylesheet( $this_post ) {
451
452 if ( is_object( $this_post ) && isset( $this_post->ID ) && has_blocks( $this_post->ID ) && isset( $this_post->post_content ) ) {
453
454 $blocks = $this->parse( $this_post->post_content );
455
456 $count = count( $blocks );
457 for ( $i = 0; $i < $count; $i++ ) {
458
459 if ( isset( $blocks[ $i ]['blockName'] ) && ! empty( $blocks[ $i ]['blockName'] ) ) {
460 $get_form_blocks = $this->get_srfm_form_blocks( $blocks[ $i ] );
461 if ( ! empty( $get_form_blocks ) ) {
462 $blocks = array_merge( $blocks, $get_form_blocks );
463 }
464 }
465
466 if ( has_shortcode( $this_post->post_content, 'sureforms' ) && isset( $blocks[ $i ]['blockName'] ) && 'core/shortcode' === $blocks[ $i ]['blockName'] ) {
467 if ( isset( $blocks[ $i ]['innerHTML'] ) && $blocks[ $i ]['innerHTML'] && str_contains( $blocks[ $i ]['innerHTML'], '[sureforms' ) ) {
468 $form_id = preg_replace( '/\D+/', '', $blocks[ $i ]['innerHTML'] );
469 if ( $form_id ) {
470 $form_post = get_post( $form_id );
471 if ( $form_post ) {
472 $blocks = array_merge( $blocks, $this->parse( $form_post->post_content ) );
473 }
474 }
475 }
476 }
477 }
478
479 self::$page_blocks = $blocks;
480
481 if ( ! is_array( $blocks ) || empty( $blocks ) ) {
482 return;
483 }
484
485 $assets = $this->get_assets( $blocks );
486
487 self::$stylesheet .= $assets['css'];
488 self::$script .= $assets['js'];
489 }
490 }
491
492 /**
493 * Enqueue Gutenberg block assets for both frontend + backend.
494 *
495 * @since 0.0.1
496 */
497 public function block_assets() {
498
499 $block_list_for_assets = self::$current_block_list;
500
501 $blocks = Spec_Block_Config::get_block_attributes();
502
503 foreach ( $block_list_for_assets as $key => $curr_block_name ) {
504
505 $js_assets = ( isset( $blocks[ $curr_block_name ]['js_assets'] ) ) ? $blocks[ $curr_block_name ]['js_assets'] : [];
506
507 $css_assets = ( isset( $blocks[ $curr_block_name ]['css_assets'] ) ) ? $blocks[ $curr_block_name ]['css_assets'] : [];
508
509 foreach ( $js_assets as $asset_handle => $val ) {
510 // Scripts.
511 wp_enqueue_script( $val );
512 }
513
514 foreach ( $css_assets as $asset_handle => $val ) {
515 // Styles.
516 wp_enqueue_style( $val );
517 }
518 }
519
520 }
521
522 /**
523 * Parse Guten Block.
524 *
525 * @param string $content the content string.
526 * @since 0.0.1
527 */
528 public function parse( $content ) {
529
530 global $wp_version;
531
532 return ( version_compare( $wp_version, '5', '>=' ) ) ? parse_blocks( $content ) : gutenberg_parse_blocks( $content );
533 }
534
535 /**
536 * Generates stylesheet for reusable blocks.
537 *
538 * @param array $blocks Blocks array.
539 * @since 0.0.1
540 */
541 public function get_assets( $blocks ) {
542
543 $desktop = '';
544 $tablet = '';
545 $mobile = '';
546
547 $tab_styling_css = '';
548 $mob_styling_css = '';
549
550 $js = '';
551
552 foreach ( $blocks as $i => $block ) {
553
554 if ( is_array( $block ) ) {
555
556 if ( '' === $block['blockName'] ) {
557 continue;
558 }
559 if ( 'core/block' === $block['blockName'] ) {
560 $id = ( isset( $block['attrs']['ref'] ) ) ? $block['attrs']['ref'] : 0;
561
562 $is_block_seen = in_array( $id, self::$seen_refs, true );
563
564 if ( $id && ! $is_block_seen ) {
565 self::$seen_refs[] = $id;
566 $content = get_post_field( 'post_content', $id );
567
568 $reusable_blocks = $this->parse( $content );
569
570 $assets = $this->get_assets( $reusable_blocks );
571
572 self::$stylesheet .= $assets['css'];
573 self::$script .= $assets['js'];
574
575 }
576 } else {
577
578 $block_assets = $this->get_block_css_and_js( $block );
579
580 // Get CSS for the Block.
581 $css = $block_assets['css'];
582
583 if ( ! empty( $css['common'] ) ) {
584 $desktop .= $css['common'];
585 }
586
587 if ( isset( $css['desktop'] ) ) {
588 $desktop .= $css['desktop'];
589 $tablet .= $css['tablet'];
590 $mobile .= $css['mobile'];
591 }
592
593 $js .= $block_assets['js'];
594 }
595 }
596 }
597
598 if ( ! empty( $tablet ) ) {
599 $tab_styling_css .= '@media only screen and (max-width: ' . SRFM_TABLET_BREAKPOINT . 'px) {';
600 $tab_styling_css .= $tablet;
601 $tab_styling_css .= '}';
602 }
603
604 if ( ! empty( $mobile ) ) {
605 $mob_styling_css .= '@media only screen and (max-width: ' . SRFM_MOBILE_BREAKPOINT . 'px) {';
606 $mob_styling_css .= $mobile;
607 $mob_styling_css .= '}';
608 }
609
610 return [
611 'css' => $desktop . $tab_styling_css . $mob_styling_css,
612 'js' => $js,
613 ];
614 }
615
616 /**
617 * Get Typography Dynamic CSS.
618 *
619 * @param array $attr The Attribute array.
620 * @param string $slug The field slug.
621 * @param string $selector The selector array.
622 * @param array $combined_selectors The combined selector array.
623 * @since 0.0.1
624 * @return bool|string
625 */
626 public static function get_typography_css( $attr, $slug, $selector, $combined_selectors ) {
627
628 $typo_css_desktop = [];
629 $typo_css_tablet = [];
630 $typo_css_mobile = [];
631
632 $already_selectors_desktop = ( isset( $combined_selectors['desktop'][ $selector ] ) ) ? $combined_selectors['desktop'][ $selector ] : [];
633 $already_selectors_tablet = ( isset( $combined_selectors['tablet'][ $selector ] ) ) ? $combined_selectors['tablet'][ $selector ] : [];
634 $already_selectors_mobile = ( isset( $combined_selectors['mobile'][ $selector ] ) ) ? $combined_selectors['mobile'][ $selector ] : [];
635
636 $family_slug = ( '' === $slug ) ? 'fontFamily' : $slug . 'FontFamily';
637 $weight_slug = ( '' === $slug ) ? 'fontWeight' : $slug . 'FontWeight';
638 $transform_slug = ( '' === $slug ) ? 'fontTransform' : $slug . 'Transform';
639 $decoration_slug = ( '' === $slug ) ? 'fontDecoration' : $slug . 'Decoration';
640 $style_slug = ( '' === $slug ) ? 'fontStyle' : $slug . 'FontStyle';
641
642 $l_ht_slug = ( '' === $slug ) ? 'lineHeight' : $slug . 'LineHeight';
643 $f_sz_slug = ( '' === $slug ) ? 'fontSize' : $slug . 'FontSize';
644 $l_ht_type_slug = ( '' === $slug ) ? 'lineHeightType' : $slug . 'LineHeightType';
645 $f_sz_type_slug = ( '' === $slug ) ? 'fontSizeType' : $slug . 'FontSizeType';
646 $l_sp_slug = ( '' === $slug ) ? 'letterSpacing' : $slug . 'LetterSpacing';
647 $l_sp_type_slug = ( '' === $slug ) ? 'letterSpacingType' : $slug . 'LetterSpacingType';
648
649 $text_transform = isset( $attr[ $transform_slug ] ) ? $attr[ $transform_slug ] : 'normal';
650 $text_decoration = isset( $attr[ $decoration_slug ] ) ? $attr[ $decoration_slug ] : 'none';
651 $font_style = isset( $attr[ $style_slug ] ) ? $attr[ $style_slug ] : 'normal';
652
653 $typo_css_desktop[ $selector ] = [
654 'font-family' => $attr[ $family_slug ],
655 'text-transform' => $text_transform,
656 'text-decoration' => $text_decoration,
657 'font-style' => $font_style,
658 'font-weight' => $attr[ $weight_slug ],
659 'font-size' => ( isset( $attr[ $f_sz_slug ] ) ) ? self::get_css_value( $attr[ $f_sz_slug ], $attr[ $f_sz_type_slug ] ) : '',
660 'line-height' => ( isset( $attr[ $l_ht_slug ] ) ) ? self::get_css_value( $attr[ $l_ht_slug ], $attr[ $l_ht_type_slug ] ) : '',
661 'letter-spacing' => ( isset( $attr[ $l_sp_slug ] ) ) ? self::get_css_value( $attr[ $l_sp_slug ], $attr[ $l_sp_type_slug ] ) : '',
662 ];
663
664 $typo_css_desktop[ $selector ] = array_merge(
665 $typo_css_desktop[ $selector ],
666 $already_selectors_desktop
667 );
668
669 $typo_css_tablet[ $selector ] = [
670 'font-size' => ( isset( $attr[ $f_sz_slug . 'Tablet' ] ) ) ? self::get_css_value( $attr[ $f_sz_slug . 'Tablet' ], $attr[ $f_sz_type_slug ] ) : '',
671 'line-height' => ( isset( $attr[ $l_ht_slug . 'Tablet' ] ) ) ? self::get_css_value( $attr[ $l_ht_slug . 'Tablet' ], $attr[ $l_ht_type_slug ] ) : '',
672 'letter-spacing' => ( isset( $attr[ $l_sp_slug . 'Tablet' ] ) ) ? self::get_css_value( $attr[ $l_sp_slug . 'Tablet' ], $attr[ $l_sp_type_slug ] ) : '',
673 ];
674
675 $typo_css_tablet[ $selector ] = array_merge(
676 $typo_css_tablet[ $selector ],
677 $already_selectors_tablet
678 );
679
680 $typo_css_mobile[ $selector ] = [
681 'font-size' => ( isset( $attr[ $f_sz_slug . 'Mobile' ] ) ) ? self::get_css_value( $attr[ $f_sz_slug . 'Mobile' ], $attr[ $f_sz_type_slug ] ) : '',
682 'line-height' => ( isset( $attr[ $l_ht_slug . 'Mobile' ] ) ) ? self::get_css_value( $attr[ $l_ht_slug . 'Mobile' ], $attr[ $l_ht_type_slug ] ) : '',
683 'letter-spacing' => ( isset( $attr[ $l_sp_slug . 'Mobile' ] ) ) ? self::get_css_value( $attr[ $l_sp_slug . 'Mobile' ], $attr[ $l_sp_type_slug ] ) : '',
684 ];
685
686 $typo_css_mobile[ $selector ] = array_merge(
687 $typo_css_mobile[ $selector ],
688 $already_selectors_mobile
689 );
690
691 return [
692 'desktop' => array_merge(
693 $combined_selectors['desktop'],
694 $typo_css_desktop
695 ),
696 'tablet' => array_merge(
697 $combined_selectors['tablet'],
698 $typo_css_tablet
699 ),
700 'mobile' => array_merge(
701 $combined_selectors['mobile'],
702 $typo_css_mobile
703 ),
704 ];
705 }
706
707 /**
708 * Get CSS value
709 *
710 * Syntax:
711 *
712 * get_css_value( VALUE, UNIT );
713 *
714 * E.g.
715 *
716 * get_css_value( VALUE, 'em' );
717 *
718 * @param string $value CSS value.
719 * @param string $unit CSS unit.
720 * @since 0.0.1
721 */
722 public static function get_css_value( $value = '', $unit = '' ) {
723
724 $css_val = '';
725
726 if ( '' !== $value ) {
727 $css_val = esc_attr( $value ) . $unit;
728 }
729
730 return $css_val;
731 }
732
733 /**
734 * Parse CSS into correct CSS syntax.
735 *
736 * @param array $combined_selectors The combined selector array.
737 * @param string $id The selector ID.
738 * @since 0.0.1
739 */
740 public static function generate_all_css( $combined_selectors, $id ) {
741
742 return [
743 'desktop' => self::generate_css( $combined_selectors['desktop'], $id ),
744 'tablet' => self::generate_css( $combined_selectors['tablet'], $id ),
745 'mobile' => self::generate_css( $combined_selectors['mobile'], $id ),
746 ];
747 }
748
749 /**
750 * Generate the Box Shadow or Text Shadow CSS.
751 *
752 * For Text Shadow CSS:
753 * ( 'spread', 'position' ) should not be sent as params during the function call.
754 * ( 'spread_unit' ) will have no effect.
755 *
756 * For Box/Text Shadow Hover CSS:
757 * ( 'alt_color' ) should be set as the attribute used for ( 'color' ) in Box/Text Shadow Normal CSS.
758 *
759 * @param array $shadow_properties Array containing the necessary shadow properties.
760 * @return string The generated border CSS or an empty string on early return.
761 *
762 * @since 0.0.1
763 */
764 public static function generate_shadow_css( $shadow_properties ) {
765 // Get the Object Properties.
766 $horizontal = isset( $shadow_properties['horizontal'] ) ? $shadow_properties['horizontal'] : '';
767 $vertical = isset( $shadow_properties['vertical'] ) ? $shadow_properties['vertical'] : '';
768 $blur = isset( $shadow_properties['blur'] ) ? $shadow_properties['blur'] : '';
769 $spread = isset( $shadow_properties['spread'] ) ? $shadow_properties['spread'] : '';
770 $horizontal_unit = isset( $shadow_properties['horizontal_unit'] ) ? $shadow_properties['horizontal_unit'] : 'px';
771 $vertical_unit = isset( $shadow_properties['vertical_unit'] ) ? $shadow_properties['vertical_unit'] : 'px';
772 $blur_unit = isset( $shadow_properties['blur_unit'] ) ? $shadow_properties['blur_unit'] : 'px';
773 $spread_unit = isset( $shadow_properties['spread_unit'] ) ? $shadow_properties['spread_unit'] : 'px';
774 $color = isset( $shadow_properties['color'] ) ? $shadow_properties['color'] : '';
775 $position = isset( $shadow_properties['position'] ) ? $shadow_properties['position'] : 'outset';
776 $alt_color = isset( $shadow_properties['alt_color'] ) ? $shadow_properties['alt_color'] : '';
777
778 // Although optional, color is required for Sarafi on PC. Return early if color isn't set.
779 if ( ! $color && ! $alt_color ) {
780 return '';
781 }
782
783 // Get the CSS units for the number properties.
784
785 $horizontal = self::get_css_value( $horizontal, $horizontal_unit );
786 if ( '' === $horizontal ) {
787 $horizontal = 0;
788 }
789
790 $vertical = self::get_css_value( $vertical, $vertical_unit );
791 if ( '' === $vertical ) {
792 $vertical = 0;
793 }
794
795 $blur = self::get_css_value( $blur, $blur_unit );
796 if ( '' === $blur ) {
797 $blur = 0;
798 }
799
800 $spread = self::get_css_value( $spread, $spread_unit );
801 if ( '' === $spread ) {
802 $spread = 0;
803 }
804
805 // If all numeric unit values are exactly 0, don't render the CSS.
806 if ( ( 0 === $horizontal && 0 === $vertical ) && ( 0 === $blur && 0 === $spread ) ) {
807 return '';
808 }
809
810 // Return the CSS with horizontal, vertical, blur, and color - and conditionally render spread and position.
811 return (
812 $horizontal . ' ' . $vertical . ' ' . $blur . ( $spread ? " {$spread}" : '' ) . ' ' . ( $color ? $color : $alt_color ) . ( 'outset' === $position ? '' : " {$position}" )
813 );
814 }
815
816 /**
817 * Parse CSS into correct CSS syntax.
818 *
819 * @param array $selectors The block selectors.
820 * @param string $id The selector ID.
821 * @since 0.0.1
822 */
823 public static function generate_css( $selectors, $id ) {
824 $styling_css = '';
825
826 if ( ! empty( $selectors ) ) {
827 foreach ( $selectors as $key => $value ) {
828
829 $css = '';
830
831 foreach ( $value as $j => $val ) {
832
833 if ( 'font-family' === $j && 'Default' === $val ) {
834 continue;
835 }
836
837 if ( ! empty( $val ) && is_array( $val ) ) {
838 foreach ( $val as $key => $css_value ) {
839 $css .= $key . ': ' . $css_value . ';';
840 }
841 } elseif ( ! empty( $val ) || 0 === $val ) {
842 if ( 'font-family' === $j ) {
843 $css .= $j . ': "' . $val . '";';
844 } else {
845 $css .= $j . ': ' . $val . ';';
846 }
847 }
848 }
849
850 if ( ! empty( $css ) ) {
851 $styling_css .= $id;
852 $styling_css .= $key . '{';
853 $styling_css .= $css . '}';
854 }
855 }
856 }
857
858 return $styling_css;
859 }
860
861 /**
862 * Adds Google fonts all blocks.
863 *
864 * @param array $load_google_font the blocks attr.
865 * @param string $font_family the blocks attr.
866 * @param array $font_weight the blocks attr.
867 */
868 public static function blocks_google_font( $load_google_font, $font_family, $font_weight ) {
869
870 if ( true === $load_google_font ) {
871 if ( ! array_key_exists( $font_family, self::$gfonts ) ) {
872 $add_font = [
873 'fontfamily' => $font_family,
874 'fontvariants' => ( isset( $font_weight ) && ! empty( $font_weight ) ? [ $font_weight ] : [] ),
875 ];
876 self::$gfonts[ $font_family ] = $add_font;
877 } else {
878 if ( isset( $font_weight ) && ! empty( $font_weight ) && ! in_array( $font_weight, self::$gfonts[ $font_family ]['fontvariants'], true ) ) {
879 array_push( self::$gfonts[ $font_family ]['fontvariants'], $font_weight );
880 }
881 }
882 }
883 }
884
885 /**
886 * Generates CSS recurrsively.
887 *
888 * @param object $block The block object.
889 * @since 0.0.1
890 */
891 public function get_block_css_and_js( $block ) {
892
893 $block = (array) $block;
894
895 $name = isset( $block['blockName'] ) ? $block['blockName'] : '';
896 $css = [];
897 $js = '';
898 $block_id = '';
899
900 if ( ! empty( $name ) && isset( $block['attrs'] ) && is_array( $block['attrs'] ) ) {
901
902 $blockattr = $block['attrs'];
903 if ( isset( $blockattr['block_id'] ) ) {
904 $block_id = $blockattr['block_id'];
905 }
906
907 self::$current_block_list[] = $name;
908
909 if ( strpos( $name, 'srfm/' ) !== false ) {
910 self::$srfm_flag = true;
911 }
912
913 switch ( $name ) {
914 case 'srfm/separator':
915 $css = Spec_Block_Helper::get_separator_css( $blockattr, $block_id );
916 Spec_Block_JS::blocks_separator_gfont( $blockattr );
917 break;
918
919 case 'srfm/image':
920 $css = Spec_Block_Helper::get_image_css( $blockattr, $block_id );
921 Spec_Block_JS::blocks_image_gfont( $blockattr );
922 break;
923
924 case 'srfm/icon':
925 $css = Spec_Block_Helper::get_icon_css( $blockattr, $block_id );
926 break;
927
928 case 'srfm/advanced-heading':
929 $css = Spec_Block_Helper::get_advanced_heading_css( $blockattr, $block_id );
930 Spec_Block_JS::blocks_advanced_heading_gfont( $blockattr );
931 break;
932
933 default:
934 // Nothing to do here.
935 break;
936 }
937
938 // Add static css here.
939 $block_css_arr = Spec_Block_Config::get_block_assets_css();
940
941 if ( isset( $block_css_arr[ $name ] ) && ! in_array( $block_css_arr[ $name ]['name'], $this->static_css_blocks, true ) ) {
942
943 $common_css = [
944 'common' => $this->get_block_static_css( $block_css_arr[ $name ]['name'] ),
945 ];
946 $css += $common_css;
947 }
948
949 if ( isset( $block['innerBlocks'] ) ) {
950 foreach ( $block['innerBlocks'] as $j => $inner_block ) {
951 if ( 'core/block' === $inner_block['blockName'] ) {
952 $id = ( isset( $inner_block['attrs']['ref'] ) ) ? $inner_block['attrs']['ref'] : 0;
953
954 if ( $id ) {
955 $content = get_post_field( 'post_content', $id );
956
957 $reusable_blocks = $this->parse( $content );
958
959 $assets = $this->get_assets( $reusable_blocks );
960
961 self::$stylesheet .= $assets['css'];
962 self::$script .= $assets['js'];
963 }
964 } else {
965 // Get CSS for the Block.
966 $inner_assets = $this->get_block_css_and_js( $inner_block );
967 $inner_block_css = $inner_assets['css'];
968
969 $css_common = ( isset( $css['common'] ) ? $css['common'] : '' );
970 $css_desktop = ( isset( $css['desktop'] ) ? $css['desktop'] : '' );
971 $css_tablet = ( isset( $css['tablet'] ) ? $css['tablet'] : '' );
972 $css_mobile = ( isset( $css['mobile'] ) ? $css['mobile'] : '' );
973
974 if ( isset( $inner_block_css['common'] ) ) {
975 $css['common'] = $css_common . $inner_block_css['common'];
976 }
977
978 if ( isset( $inner_block_css['desktop'] ) ) {
979 $css['desktop'] = $css_desktop . $inner_block_css['desktop'];
980 $css['tablet'] = $css_tablet . $inner_block_css['tablet'];
981 $css['mobile'] = $css_mobile . $inner_block_css['mobile'];
982 }
983
984 $js .= $inner_assets['js'];
985 }
986 }
987 }
988
989 self::$current_block_list = array_unique( self::$current_block_list );
990 }
991
992 return [
993 'css' => $css,
994 'js' => $js,
995 ];
996
997 }
998
999 /**
1000 * Get block dynamic CSS selector with filters applied for extending it.
1001 *
1002 * @param string $block_name Block name to filter.
1003 * @param array $selectors Array of selectors to filter.
1004 * @param array $attr Attributes.
1005 * @return array Combined selectors array.
1006 * @since 0.0.1
1007 */
1008 public static function get_combined_selectors( $block_name, $selectors, $attr ) {
1009 if ( ! is_array( $selectors ) ) {
1010 return $selectors;
1011 }
1012
1013 $combined_selectors = [];
1014
1015 foreach ( $selectors as $key => $selector ) {
1016 $hook_prefix = ( 'desktop' === $key ) ? '' : '_' . $key;
1017 $combined_selectors[ $key ] = apply_filters( 'srfm_' . $block_name . $hook_prefix . '_styling', $selector, $attr );
1018 }
1019
1020 return $combined_selectors;
1021 }
1022
1023 /**
1024 * Get Static CSS of Block.
1025 *
1026 * @param string $block_name Block Name.
1027 *
1028 * @return string Static CSS.
1029 * @since 0.0.1
1030 */
1031 public function get_block_static_css( $block_name ) {
1032
1033 $css = '';
1034
1035 $block_static_css_path = SRFM_DIR . 'modules/gutenberg/assets/css/blocks/' . $block_name . '.css';
1036
1037 if ( file_exists( $block_static_css_path ) ) {
1038
1039 $file_system = spec_filesystem();
1040
1041 $css = $file_system->get_contents( $block_static_css_path );
1042 }
1043
1044 array_push( $this->static_css_blocks, $block_name );
1045
1046 return $css;
1047 }
1048
1049 /**
1050 * Border attribute generation Function.
1051 *
1052 * @since 0.0.1
1053 * @param array $prefix Attribute Prefix.
1054 * @param array $default_args default attributes args.
1055 * @return array
1056 */
1057 public function generate_php_border_attribute( $prefix, $default_args = [] ) {
1058
1059 $border_attr = [];
1060
1061 $device = [ '', 'Tablet', 'Mobile' ];
1062
1063 foreach ( $device as $slug => $data ) {
1064
1065 $border_attr[ "{$prefix}BorderTopWidth{$data}" ] = [
1066 'type' => 'number',
1067 ];
1068 $border_attr[ "{$prefix}BorderLeftWidth{$data}" ] = [
1069 'type' => 'number',
1070 ];
1071 $border_attr[ "{$prefix}BorderRightWidth{$data}" ] = [
1072 'type' => 'number',
1073 ];
1074 $border_attr[ "{$prefix}BorderBottomWidth{$data}" ] = [
1075 'type' => 'number',
1076 ];
1077 $border_attr[ "{$prefix}BorderTopLeftRadius{$data}" ] = [
1078 'type' => 'number',
1079 ];
1080 $border_attr[ "{$prefix}BorderTopRightRadius{$data}" ] = [
1081 'type' => 'number',
1082 ];
1083 $border_attr[ "{$prefix}BorderBottomLeftRadius{$data}" ] = [
1084 'type' => 'number',
1085 ];
1086 $border_attr[ "{$prefix}BorderBottomRightRadius{$data}" ] = [
1087 'type' => 'number',
1088 ];
1089 $border_attr[ "{$prefix}BorderRadiusUnit{$data}" ] = [
1090 'type' => 'number',
1091 ];
1092 }
1093
1094 $border_attr[ "{$prefix}BorderStyle" ] = [
1095 'type' => 'string',
1096 ];
1097 $border_attr[ "{$prefix}BorderColor" ] = [
1098 'type' => 'string',
1099 ];
1100 $border_attr[ "{$prefix}BorderHColor" ] = [
1101 'type' => 'string',
1102 ];
1103 $border_attr[ "{$prefix}BorderLink" ] = [
1104 'type' => 'boolean',
1105 'default' => true,
1106 ];
1107 $border_attr[ "{$prefix}BorderRadiusLink" ] = [
1108 'type' => 'boolean',
1109 'default' => true,
1110 ];
1111
1112 return $border_attr;
1113 }
1114
1115 /**
1116 * Get Json Data.
1117 *
1118 * @since 0.0.1
1119 * @return array
1120 */
1121 public static function backend_load_font_awesome_icons() {
1122
1123 if ( null !== self::$icon_json ) {
1124 return self::$icon_json;
1125 }
1126
1127 $icons_chunks = [];
1128 for ( $i = 0; $i < self::$number_of_icon_chunks; $i++ ) {
1129 $json_file = SRFM_DIR . "modules/gutenberg/icons/icons-v6-{$i}.php";
1130
1131 if ( file_exists( $json_file ) ) {
1132 $icons_chunks[] = include $json_file;
1133 }
1134 }
1135
1136 if ( empty( $icons_chunks ) ) {
1137 return [];
1138 }
1139
1140 self::$icon_json = $icons_chunks;
1141 return self::$icon_json;
1142 }
1143
1144 /**
1145 * Generate SVG.
1146 *
1147 * @since 0.0.1
1148 * @param array $icon Decoded fontawesome json file data.
1149 * @param bool $return The parameter decides whether to return or echo the svg markup.
1150 */
1151 public static function render_svg_html( $icon, $return = false ) {
1152 $icon = sanitize_text_field( esc_attr( $icon ) );
1153
1154 $json = self::backend_load_font_awesome_icons();
1155
1156 if ( ! empty( $json ) ) {
1157 if ( empty( $icon_array_merged ) ) {
1158 foreach ( $json as $value ) {
1159 self::$icon_array_merged = array_merge( self::$icon_array_merged, $value );
1160 }
1161 }
1162 $json = self::$icon_array_merged;
1163 }
1164
1165 $icon_brand_or_solid = isset( $json[ $icon ]['svg']['brands'] ) ? $json[ $icon ]['svg']['brands'] : ( isset( $json[ $icon ]['svg']['solid'] ) ? $json[ $icon ]['svg']['solid'] : [] );
1166 $path = isset( $icon_brand_or_solid['path'] ) ? $icon_brand_or_solid['path'] : '';
1167 $view = isset( $icon_brand_or_solid['width'] ) && isset( $icon_brand_or_solid['height'] ) ? '0 0 ' . $icon_brand_or_solid['width'] . ' ' . $icon_brand_or_solid['height'] : null;
1168
1169 if ( $path && $view ) {
1170 if ( $return ) {
1171 ob_start();
1172 ?>
1173 <svg xmlns="https://www.w3.org/2000/svg" viewBox= "<?php echo esc_attr( $view ); ?>"><path d="<?php echo esc_attr( $path ); ?>"></path></svg>
1174 <?php
1175 return ob_get_clean();
1176 } else {
1177 ?>
1178 <svg xmlns="https://www.w3.org/2000/svg" viewBox= "<?php echo esc_attr( $view ); ?>"><path d="<?php echo esc_attr( $path ); ?>"></path></svg>
1179 <?php
1180 }
1181 }
1182 }
1183
1184 }
1185
1186 /**
1187 * Prepare if class 'Spec_Gb_Helper' exist.
1188 * Kicking this off by calling 'get_instance()' method
1189 */
1190 Spec_Gb_Helper::get_instance();
1191 }
1192