PluginProbe ʕ •ᴥ•ʔ
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.6
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.6
2.12.6 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 / inc / frontend-assets.php
sureforms / inc Last commit date
abilities 2 days ago admin 3 months ago ai-form-builder 1 month ago blocks 2 months ago compatibility 4 weeks ago database 2 days ago email 4 weeks ago fields 4 weeks ago global-settings 2 days ago lib 1 month ago migrator 2 months ago page-builders 4 weeks ago payments 2 days ago single-form-settings 2 months ago traits 2 months ago activator.php 1 year ago admin-ajax.php 2 days ago background-process.php 9 months ago client-logger.php 2 days ago create-new-form.php 3 months ago duplicate-form.php 2 days ago entries.php 4 weeks ago events-scheduler.php 2 years ago export.php 2 days ago field-validation.php 4 weeks ago form-restriction.php 2 months ago form-styling.php 1 month ago form-submit.php 2 days ago form-views.php 2 days ago forms-data.php 2 days ago frontend-assets.php 2 days ago generate-form-markup.php 2 days ago gutenberg-hooks.php 2 weeks ago helper.php 2 days ago learn.php 4 months ago onboarding.php 2 months ago post-types.php 2 days ago rest-api.php 2 days ago smart-tags.php 1 week ago submit-token.php 2 days ago translatable.php 1 month ago updater-callbacks.php 4 weeks ago updater.php 4 weeks ago
frontend-assets.php
563 lines
1 <?php
2 /**
3 * SureForms Public Class.
4 *
5 * Class file for public functions.
6 *
7 * @package SureForms
8 */
9
10 namespace SRFM\Inc;
11
12 use SRFM\Inc\Compatibility\Multilingual\String_Translator;
13 use SRFM\Inc\Traits\Get_Instance;
14 use SRFM\Inc\Payments\Payment_Helper;
15 use SRFM\Inc\Payments\Stripe\Stripe_Helper;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit; // Exit if accessed directly.
19 }
20
21 /**
22 * Public Class
23 *
24 * @since 0.0.1
25 */
26 class Frontend_Assets {
27 use Get_Instance;
28
29 /**
30 * JS Assets.
31 *
32 * @since 0.0.11
33 * @var array<string>
34 */
35 public static $js_assets = [
36 'form-submit' => 'formSubmit',
37 'frontend' => 'frontend',
38 ];
39
40 /**
41 * CSS Assets.
42 *
43 * @since 0.0.11
44 * @var array<string>
45 */
46 public static $css_assets = [
47 'frontend-default' => 'blocks/default/frontend',
48 'common' => 'common',
49 'form' => 'frontend/form',
50 'single' => 'single',
51 ];
52
53 /**
54 * External CSS Assets.
55 *
56 * @since 0.0.11
57 * @var array<string>
58 */
59 public static $css_external_assets = [
60 'tom-select' => 'tom-select',
61 'intl-tel-input' => 'intl/intlTelInput.min',
62 ];
63
64 /**
65 * Constructor
66 *
67 * @since 0.0.1
68 */
69 public function __construct() {
70 add_filter( 'template_include', [ $this, 'page_template' ], PHP_INT_MAX );
71 add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );
72 add_filter( 'render_block', [ $this, 'generate_render_script' ], 10, 2 );
73 }
74
75 /**
76 * Enqueue Script.
77 *
78 * @return void
79 * @since 0.0.1
80 */
81 public function register_scripts() {
82 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
83 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
84 $js_uri = SRFM_URL . 'assets/js/' . $dir_name . '/';
85 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
86 $css_vendor = SRFM_URL . 'assets/css/minified/deps/';
87 $is_rtl = is_rtl();
88 $rtl = $is_rtl ? '-rtl' : '';
89
90 $security_setting_options = get_option( 'srfm_security_settings_options' );
91 $is_set_v2_site_key = false;
92 if ( is_array( $security_setting_options ) && isset( $security_setting_options['srfm_v2_invisible_site_key'] ) && ! empty( $security_setting_options['srfm_v2_invisible_site_key'] ) ) {
93 $is_set_v2_site_key = true;
94 }
95
96 // Styles based on meta style.
97 foreach ( self::$css_assets as $handle => $path ) {
98 wp_register_style( SRFM_SLUG . '-' . $handle, $css_uri . $path . $file_prefix . $rtl . '.css', [], SRFM_VER );
99 }
100
101 // External styles.
102 foreach ( self::$css_external_assets as $handle => $path ) {
103 wp_register_style( SRFM_SLUG . '-' . $handle, $css_vendor . $path . '.css', [], SRFM_VER );
104 }
105
106 // Scripts.
107 foreach ( self::$js_assets as $handle => $name ) {
108 if ( 'form-submit' === $handle ) {
109 // No 'wp-api-fetch' dependency: the script talks to the REST API via a
110 // plain fetch() against the URLs localized below, not wp.apiFetch(),
111 // so submissions no longer depend on that second script having loaded
112 // and executed correctly. See the wp_localize_script() call below for
113 // why wp.apiFetch's middleware (root-URL resolution, nonce injection)
114 // isn't needed for either endpoint this script calls.
115 //
116 // 'wp-i18n' and 'wp-hooks' ARE required and must stay. The bundle imports
117 // __() and applyFilters(), which @wordpress/scripts externalises to the
118 // wp.i18n / window.wp.hooks globals instead of inlining — the generated
119 // assets/build/formSubmit.asset.php is the authority on this list. They
120 // used to arrive for free because 'wp-api-fetch' pulled them in through
121 // its own dependency graph; dropping that above removed them, and an
122 // undeclared wp.hooks is undefined under a JS-combining optimizer, which
123 // kills every submission with the same TypeError this change prevents.
124 wp_register_script(
125 SRFM_SLUG . '-' . $handle,
126 SRFM_URL . 'assets/build/' . $name . '.js',
127 [ 'wp-i18n', 'wp-hooks' ],
128 SRFM_VER,
129 true
130 );
131 } else {
132 wp_register_script(
133 SRFM_SLUG . '-' . $handle,
134 $js_uri . $name . $file_prefix . '.js',
135 [],
136 SRFM_VER,
137 true
138 );
139 }
140 }
141
142 $validation_messages = array_merge(
143 Translatable::get_frontend_validation_messages(),
144 [
145 'srfm_turnstile_error_message' => __( 'Turnstile sitekey verification failed. Please contact your site administrator.', 'sureforms' ),
146 'srfm_google_captcha_error_message' => __( 'Google Captcha sitekey verification failed. Please contact your site administrator.', 'sureforms' ),
147 'srfm_captcha_h_error_message' => __( 'HCaptcha sitekey verification failed. Please contact your site administrator.', 'sureforms' ),
148 ]
149 );
150
151 // Translate each validation message through the active provider so
152 // admin-supplied translations from WPML String Translation win over the
153 // .mo-file fallback. When no provider is active, this is a pass-through.
154 $validation_messages = String_Translator::get_instance()->translate_validation_messages( $validation_messages );
155
156 wp_localize_script(
157 SRFM_SLUG . '-form-submit',
158 SRFM_SLUG . '_submit',
159 [
160 'site_url' => site_url(),
161 'nonce' => wp_create_nonce( 'wp_rest' ),
162 // Fully resolved REST endpoint URL, so the frontend can call it with a
163 // plain fetch() instead of wp.apiFetch(). rest_url() already accounts
164 // for pretty vs. plain permalinks (the latter needs a `?rest_route=`
165 // query var rather than a path segment), subdirectory installs, and
166 // multisite domain mapping — the same resolution wp.apiFetch's root-URL
167 // middleware would otherwise do from a second, independently-loaded
168 // script. submit-form's auth does not depend on that script either: it
169 // is guarded by the X-WP-Submit-Token header (Submit_Token::verify()).
170 //
171 // The after-submission URL is deliberately NOT localized. It needs the
172 // submission id and a per-submission nonce, so it is built server-side
173 // and returned in the submit response instead (see Form_Submit). A base
174 // URL here invited the client to concatenate those on, which silently
175 // produced an unroutable URL wherever rest_url() returns a
176 // `?rest_route=` form.
177 'submit_form_url' => esc_url_raw( rest_url( 'sureforms/v1/submit-form' ) ),
178 'messages' => $validation_messages,
179 'is_rtl' => $is_rtl,
180 // Resolved RFC 5321 email limits so the client honors the
181 // srfm_email_field_char_limits filter instead of hardcoding 64/255.
182 'email_char_limits' => Field_Validation::get_email_char_limits(),
183 // Hint only. This value is baked into cached HTML and can be a full
184 // cache TTL out of date, so the server re-checks on every write --
185 // see Form_Submit::client_error_log_permissions_check(). Its job is
186 // to keep the browser from posting when logging is plainly off.
187 'logging_enabled' => Client_Logger::is_enabled(),
188 'log_error_url' => esc_url_raw( rest_url( 'sureforms/v1/log-client-error' ) ),
189 ]
190 );
191
192 $current_post = get_post();
193
194 // Let's conditionally load form assets if current requested page has our forms.
195 if ( $current_post instanceof \WP_Post ) {
196 // Handles condition for Instant Form, Block Embedded, and Shortcode Embedded forms.
197 $load_assets = ( SRFM_FORMS_POST_TYPE === $current_post->post_type || ( false !== strpos( $current_post->post_content, 'wp:srfm/form' ) || has_shortcode( $current_post->post_content, 'sureforms' ) ) );
198
199 if ( $load_assets ) {
200 // Load needed styles in head tag if current requested page has SureForms form.
201 // Skip the SureForms stylesheets when every form on the page has default styling disabled.
202 self::enqueue_scripts_and_styles( Form_Styling::should_skip_frontend_styles( $current_post ) );
203 }
204 }
205 }
206
207 /**
208 * Enqueue scripts and styles.
209 *
210 * @param bool $skip_form_styles When true, the SureForms stylesheets are not enqueued
211 * (default styling disabled for the form). External library
212 * styles and scripts are always loaded so advanced fields
213 * like Dropdown and Phone keep working.
214 * @return void
215 * @since 0.0.11
216 */
217 public static function enqueue_scripts_and_styles( $skip_form_styles = false ) {
218 // Load the styles.
219 if ( ! $skip_form_styles ) {
220 foreach ( self::$css_assets as $handle => $path ) {
221
222 // Skip single form styles if not on single form page.
223 if ( 'single' === $handle && ! is_singular( SRFM_FORMS_POST_TYPE ) ) {
224 continue;
225 }
226
227 wp_enqueue_style( SRFM_SLUG . '-' . $handle );
228 }
229 }
230
231 // Load the external styles. Like Phone and Tom Select.
232 foreach ( self::$css_external_assets as $handle => $path ) {
233 wp_enqueue_style( SRFM_SLUG . '-' . $handle );
234 }
235
236 // Load the scripts.
237 foreach ( self::$js_assets as $handle => $path ) {
238 wp_enqueue_script( SRFM_SLUG . '-' . $handle );
239 }
240 }
241
242 /**
243 * Enqueue block scripts
244 *
245 * @param string $block_type block name.
246 * @param array<string, mixed> $attr Array of block attributes.
247 * @since 0.0.1
248 * @return void
249 */
250 public function enqueue_srfm_script( $block_type, $attr ) {
251 $block_name = str_replace( 'srfm/', '', $block_type );
252 // associative array to keep the count of block that requires scripts to work.
253 $script_dep_blocks = [
254 'dropdown' => 0,
255 'multi-choice' => 0,
256 'number' => 0,
257 'textarea' => 0,
258 'url' => 0,
259 'phone' => 0,
260 'input' => 0,
261 ];
262
263 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
264 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
265
266 // Check if block is in the array and check if block is already enqueued.
267 if (
268 in_array( $block_name, array_keys( $script_dep_blocks ), true ) &&
269 0 === $script_dep_blocks[ $block_name ]
270 ) {
271 $script_dep_blocks[ $block_name ] += 1;
272 $js_uri = SRFM_URL . 'assets/js/' . $dir_name . '/blocks/';
273 $js_vendor_uri = SRFM_URL . 'assets/js/minified/deps/';
274 $css_vendor_uri = SRFM_URL . 'assets/css/minified/deps/';
275 if ( 'phone' === $block_name ) {
276 // Enqueue main intl-tel-input library.
277 wp_enqueue_script( SRFM_SLUG . "-{$block_name}-intl-input-deps", $js_vendor_uri . 'intl/intTelInputWithUtils.min.js', [], SRFM_VER, true );
278
279 // Enqueue i18n translations if available for current locale.
280 self::enqueue_intl_tel_input_i18n(
281 SRFM_SLUG . "-{$block_name}-intl-i18n",
282 SRFM_SLUG . "-{$block_name}-intl-input-deps"
283 );
284 }
285
286 if ( 'dropdown' === $block_name ) {
287 // if the dropdown / address-compact block is after any other block, then we need to dequeue the srfm-form-submit script and enqueue it again and load it with tom-select dependency.
288 wp_dequeue_script( SRFM_SLUG . '-form-submit' );
289 wp_enqueue_script( SRFM_SLUG . '-dropdown', $js_uri . 'dropdown' . $file_prefix . '.js', [ 'wp-a11y' ], SRFM_VER, true );
290 wp_enqueue_script( SRFM_SLUG . '-tom-select', $js_vendor_uri . 'tom-select.min.js', [], SRFM_VER, true );
291 // frontend utils using dropdown dependency.
292 wp_enqueue_script(
293 SRFM_SLUG . '-form-submit',
294 SRFM_URL . 'assets/build/formSubmit.js',
295 [
296 'srfm-tom-select',
297 'srfm-dropdown',
298 'wp-api-fetch',
299 ],
300 SRFM_VER,
301 true
302 );
303 }
304
305 $is_not_dropdown = 'dropdown' !== $block_name;
306 $is_not_textarea = 'textarea' !== $block_name;
307
308 if ( $is_not_dropdown && $is_not_textarea ) {
309 // Set dependencies for phone block to ensure intl-tel-input loads first.
310 $block_dependencies = [];
311 if ( 'phone' === $block_name ) {
312 // Phone.js depends on intl-tel-input library (and i18n if loaded).
313 $block_dependencies = [ SRFM_SLUG . "-{$block_name}-intl-input-deps" ];
314 }
315 wp_enqueue_script( SRFM_SLUG . "-{$block_name}", $js_uri . $block_name . $file_prefix . '.js', $block_dependencies, SRFM_VER, true );
316
317 if ( 'phone' === $block_name ) {
318 // Geo-country endpoint for per-visitor auto country detection.
319 // Built with rest_url() so it is correct regardless of permalink structure.
320 wp_localize_script(
321 SRFM_SLUG . "-{$block_name}",
322 'srfm_phone_data',
323 [
324 'geo_endpoint' => esc_url_raw( rest_url( 'sureforms/v1/geo-country' ) ),
325 ]
326 );
327 }
328 }
329
330 if ( 'input' === $block_name && isset( $attr['inputMask'] ) && 'none' !== $attr['inputMask'] ) {
331 // Input mask JS - only load when inputMask is configured.
332 wp_enqueue_script( SRFM_SLUG . '-inputmask', $js_vendor_uri . 'inputmask.min.js', [], SRFM_VER, true );
333 }
334
335 // Adding js for the input textarea block.
336 if ( 'textarea' === $block_name && ! empty( $attr['isRichText'] ) ) {
337 wp_enqueue_script( SRFM_SLUG . '-quill-editor', $js_vendor_uri . '/quill.min.js', [], SRFM_VER, true );
338
339 wp_enqueue_style( SRFM_SLUG . '-quill-editor', $css_vendor_uri . 'quill/quill.snow.css', [], SRFM_VER );
340
341 wp_enqueue_script( SRFM_SLUG . '-textarea', $js_uri . 'textarea' . $file_prefix . '.js', [], SRFM_VER, true );
342
343 wp_localize_script(
344 SRFM_SLUG . '-textarea',
345 'srfm_quill_i18n',
346 [
347 'normal' => _x( 'Normal', 'Quill heading picker: default paragraph style', 'sureforms' ),
348 'heading_1' => __( 'Heading 1', 'sureforms' ),
349 'heading_2' => __( 'Heading 2', 'sureforms' ),
350 'heading_3' => __( 'Heading 3', 'sureforms' ),
351 'heading_4' => __( 'Heading 4', 'sureforms' ),
352 'heading_5' => __( 'Heading 5', 'sureforms' ),
353 'heading_6' => __( 'Heading 6', 'sureforms' ),
354 'visit_url' => _x( 'Visit URL:', 'Quill link tooltip label', 'sureforms' ),
355 'enter_link' => _x( 'Enter link:', 'Quill link tooltip label', 'sureforms' ),
356 'edit' => _x( 'Edit', 'Quill link tooltip action', 'sureforms' ),
357 'save' => _x( 'Save', 'Quill link tooltip action', 'sureforms' ),
358 'remove' => _x( 'Remove', 'Quill link tooltip action', 'sureforms' ),
359 ]
360 );
361 }
362 }
363 /**
364 * Enqueueing the input mask JS for input and date-picker blocks.
365 * This is a workaround for the input mask JS to work with the date-picker block.
366 * Not adding in the above existing condition because code only runs when free block are added in the form.
367 * Aim is to reduce redundant code and library file duplication.
368 */
369 if ( 'date-picker' === $block_name ) {
370 // Input mask JS.
371 wp_enqueue_script( SRFM_SLUG . '-inputmask', SRFM_URL . 'assets/js/minified/deps/inputmask.min.js', [], SRFM_VER, true );
372 }
373
374 if ( 'payment' === $block_name ) {
375 // Register Stripe.js library from CDN.
376 // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Stripe CDN ignores version; version param is included to keep linter happy.
377 wp_enqueue_script(
378 'stripe-js',
379 'https://js.stripe.com/v3/',
380 [],
381 SRFM_VER,
382 true
383 );
384
385 wp_enqueue_script(
386 SRFM_SLUG . '-stripe-payment',
387 SRFM_URL . 'assets/js/stripe-payment.js',
388 [ 'stripe-js' ],
389 SRFM_VER,
390 true
391 );
392
393 // Enqueue Payment Manager for payment method switching.
394 wp_enqueue_script(
395 SRFM_SLUG . '-payment-manager',
396 SRFM_URL . 'assets/js/payment-manager.js',
397 [ SRFM_SLUG . '-stripe-payment' ],
398 SRFM_VER,
399 true
400 );
401
402 // Localize script for Stripe payment functionality.
403 wp_localize_script(
404 SRFM_SLUG . '-stripe-payment',
405 'srfm_ajax',
406 [
407 'ajax_url' => admin_url( 'admin-ajax.php' ),
408 ]
409 );
410
411 // Localize Stripe payment data for frontend.
412 wp_localize_script(
413 SRFM_SLUG . '-stripe-payment',
414 'srfmStripe',
415 [
416 'zeroDecimalCurrencies' => Payment_Helper::get_zero_decimal_currencies(),
417 'currenciesData' => Payment_Helper::get_all_currencies_data(),
418 'strings' => Payment_Helper::get_payment_strings(),
419 'currencySignPosition' => Payment_Helper::get_currency_sign_position(),
420 ]
421 );
422 }
423
424 // Trigger custom action hook to allow third-party plugins or add-ons
425 // to enqueue additional scripts/styles for specific blocks (e.g., payment providers).
426 do_action(
427 'srfm_enqueue_block_scripts',
428 [
429 'block_name' => $block_name,
430 'attr' => $attr,
431 ]
432 );
433 }
434
435 /**
436 * Maps WordPress locale to intl-tel-input language code.
437 *
438 * Converts WordPress locale format (e.g., fr_FR, de_DE, pt_BR)
439 * to intl-tel-input language codes (e.g., fr, de, pt).
440 * Returns null if the language is not supported by intl-tel-input.
441 *
442 * @since 2.5.0
443 * @param string|null $locale WordPress locale string. If null, uses get_locale().
444 * @return string|null Language code if supported, null if not supported or English.
445 */
446 public static function get_intl_tel_input_locale( $locale = null ) {
447 // Get WordPress locale if not provided.
448 if ( null === $locale ) {
449 $locale = get_locale();
450 }
451
452 // Extract language code from WordPress locale (e.g., fr_FR -> fr, pt_BR -> pt).
453 $lang_code = substr( $locale, 0, 2 );
454
455 // List of supported languages - available translation files in /assets/js/minified/deps/intl/i18n/.
456 // Reference: https://unpkg.com/browse/intl-tel-input@24.5.1/build/js/i18n/.
457 $supported_languages = [
458 'de', // German - Deutsch.
459 'es', // Spanish - Español.
460 'fr', // French - Français.
461 'it', // Italian - Italiano.
462 'nl', // Dutch - Nederlands.
463 'pl', // Polish - Polski.
464 'pt', // Portuguese - Português.
465 ];
466
467 // Return language code only if supported and not English (English is default).
468 if ( in_array( $lang_code, $supported_languages, true ) && 'en' !== $lang_code ) {
469 return $lang_code;
470 }
471
472 // Return null for unsupported languages or English (uses default English).
473 return null;
474 }
475
476 /**
477 * Enqueues intl-tel-input i18n script for the phone field.
478 *
479 * This method handles conditional loading of language files based on WordPress locale.
480 * Only enqueues if a supported non-English language is detected and the file exists.
481 *
482 * @since 2.5.0
483 * @param string $handle Script handle to enqueue.
484 * @param string $dependencies Optional. Script handle that this i18n depends on. Default empty.
485 * @return bool True if i18n was enqueued, false otherwise.
486 */
487 public static function enqueue_intl_tel_input_i18n( $handle, $dependencies = '' ) {
488 $intl_locale = self::get_intl_tel_input_locale();
489
490 // Return early if no locale or English.
491 if ( empty( $intl_locale ) ) {
492 return false;
493 }
494
495 $i18n_file_path = SRFM_DIR . "assets/js/minified/deps/intl/i18n/{$intl_locale}/index.min.js";
496
497 // Only enqueue if the language file exists.
498 if ( ! file_exists( $i18n_file_path ) ) {
499 return false;
500 }
501
502 $deps = ! empty( $dependencies ) ? [ $dependencies ] : [];
503
504 wp_enqueue_script(
505 $handle,
506 SRFM_URL . "assets/js/minified/deps/intl/i18n/{$intl_locale}/index.min.js",
507 $deps,
508 SRFM_VER,
509 true
510 );
511
512 return true;
513 }
514
515 /**
516 * Render function.
517 *
518 * @param string $block_content Entire Block Content.
519 * @param array<string> $block Block Properties As An Array.
520 * @return string
521 */
522 public function generate_render_script( $block_content, $block ) {
523
524 if ( isset( $block['attrs']['isEditing'] ) ) {
525 // Only load block assets on the frontend.
526 return $block_content;
527 }
528
529 if ( isset( $block['blockName'] ) ) {
530 $attr = isset( $block['attrs'] ) && is_array( $block['attrs'] ) ? $block['attrs'] : [];
531
532 self::enqueue_srfm_script( $block['blockName'], $attr );
533 }
534 return $block_content;
535 }
536
537 /**
538 * Form Template filter.
539 *
540 * @param string $template Template.
541 * @return string Template.
542 * @since 0.0.1
543 */
544 public function page_template( $template ) {
545
546 if ( ! is_singular( SRFM_FORMS_POST_TYPE ) ) {
547 // Bail if not SureForms post type.
548 return $template;
549 }
550
551 $file_name = 'single-form.php';
552 $template = locate_template( $file_name );
553
554 /**
555 * Hook: srfm_form_template filter.
556 *
557 * @since 0.0.1
558 */
559 return apply_filters( 'srfm_form_template', $template ? $template : SRFM_DIR . '/templates/' . $file_name );
560 }
561
562 }
563