PluginProbe
The Innovative Form Builder – IvyForms / 1.4
The Innovative Form Builder – IvyForms v1.4
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / backend / src / Services / Shortcode / Helpers / ShortcodeHelper.php

ShortcodeHelper.php in The Innovative Form Builder – IvyForms 1.4, at backend/src/Services/Shortcode/Helpers/ShortcodeHelper.php

361 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace IvyForms\Services\Shortcode\Helpers;
4
5 use IvyForms\Factory\Field\FieldFactory;
6 use IvyForms\Factory\Security\SecurityServiceFactory;
7 use IvyForms\Services\Settings\SettingsService;
8 use IvyForms\Services\Security\SecurityService;
9 use IvyForms\Services\Translations\FrontendStrings;
10 use IvyForms\Routes\Routes;
11 use IvyForms\Services\Shortcode\InlineStyleHelper;
12
13 // phpcs:disable PSR1.Files.SideEffects
14 if (!defined('ABSPATH')) {
15 exit; // Exit if accessed directly
16 }
17
18 /**
19 * Helper utilities used by shortcode-related services.
20 * Consolidates asset registration and small helpers so that ShortcodeService
21 * can stay focused on rendering and orchestration.
22 */
23 class ShortcodeHelper
24 {
25 /**
26 * Register frontend style handles early so external integrations can safely depend on them.
27 *
28 * @return void
29 */
30 public static function registerFrontendStyleHandles(): void
31 {
32 [, , $styleSrc, $stylePublicSrc, $scriptVersion] = self::resolveAssetPaths();
33
34 if (!wp_style_is('ivyforms_style_index', 'registered')) {
35 wp_register_style('ivyforms_style_index', $styleSrc ?: false, [], $scriptVersion);
36 }
37
38 if (!wp_style_is('ivyforms_style_public', 'registered')) {
39 wp_register_style('ivyforms_style_public', $stylePublicSrc ?: false, [], $scriptVersion);
40 }
41 }
42
43 /**
44 * Build SecurityService instance
45 *
46 * @return SecurityService
47 */
48 public static function getSecurityService(): SecurityService
49 {
50 $settingsService = new SettingsService();
51 $securityFactory = new SecurityServiceFactory($settingsService);
52 return new SecurityService($securityFactory);
53 }
54
55 /**
56 * Convert form list to runtime Field objects expected by the security service
57 *
58 * @param array<string, array<string, mixed>> $formList
59 * @return array<object>
60 */
61 public static function getAllFormFields(array $formList): array
62 {
63 $allFields = [];
64
65 foreach ($formList as $formData) {
66 foreach ($formData['fields'] as $fieldData) {
67 $field = FieldFactory::create($fieldData);
68 $allFields[] = $field;
69 }
70 }
71
72 return $allFields;
73 }
74
75 /**
76 * Enqueue provider script if configured
77 *
78 * @param string $handle
79 * @param array<string, mixed> $providerConfig
80 * @return void
81 */
82 public static function enqueueProviderScript(string $handle, array $providerConfig): void
83 {
84 $scriptUrl = $providerConfig['scriptUrl'] ?? '';
85 if (empty($scriptUrl)) {
86 return;
87 }
88
89 wp_enqueue_script(
90 $handle,
91 $scriptUrl,
92 [],
93 null,
94 true
95 );
96 }
97
98 /**
99 * Enqueue Google reCAPTCHA script if present in captcha configuration
100 *
101 * @param array<string, mixed> $captchaConfig Top-level captcha configuration array (may contain 'recaptcha')
102 * @return void
103 */
104 public static function enqueueGoogleRecaptchaScript(array $captchaConfig): void
105 {
106 if (!isset($captchaConfig['recaptcha'])) {
107 return;
108 }
109
110 self::enqueueProviderScript('google-recaptcha', $captchaConfig['recaptcha']);
111 }
112
113 /**
114 * Enqueue Cloudflare Turnstile script if present in captcha configuration
115 *
116 * @param array<string, mixed> $captchaConfig Top-level captcha configuration array (may contain 'turnstile')
117 * @return void
118 */
119 public static function enqueueTurnstileScript(array $captchaConfig): void
120 {
121 if (!isset($captchaConfig['turnstile'])) {
122 return;
123 }
124
125 self::enqueueProviderScript('cloudflare-turnstile', $captchaConfig['turnstile']);
126 }
127
128 /**
129 * Enqueue hCaptcha script if present in captcha configuration
130 *
131 * @param array<string, mixed> $captchaConfig Top-level captcha configuration array (may contain 'hcaptcha')
132 * @return void
133 */
134 public static function enqueueHCaptchaScript(array $captchaConfig): void
135 {
136 if (!isset($captchaConfig['hcaptcha'])) {
137 return;
138 }
139
140 self::enqueueProviderScript('hcaptcha', $captchaConfig['hcaptcha']);
141 }
142
143 /**
144 * Register frontend assets (script, styles) and localize data for IvyForms shortcode.
145 * Intended to be called from ShortcodeService::enqueueScripts()
146 *
147 * @param array<string, array<string, mixed>> $formList
148 * @return void
149 */
150 public static function registerFrontendAssets(array $formList): void
151 {
152 // Resolve paths and handles
153 [$scriptId, $scriptSrc, $styleSrc, $stylePublicSrc, $scriptVersion] = self::resolveAssetPaths();
154
155 // Ensure style handles are available for dependencies before enqueuing.
156 self::registerFrontendStyleHandles();
157
158 // Enqueue main script and styles
159 self::enqueueMainScript($scriptId, $scriptSrc, $scriptVersion);
160
161 if ($styleSrc) { // @phpstan-ignore-line
162 self::enqueueStyles($styleSrc, $stylePublicSrc, $scriptVersion);
163 }
164
165 // Enqueue captcha scripts and localize captcha config
166 self::enqueueCaptchaAndLocalize($scriptId, $formList);
167
168 // Localize common frontend data (forms, labels, urls, api settings, date formats)
169 self::localizeFormListAndLabels($scriptId, $formList);
170
171 do_action('ivyforms/shortcode/enqueue_scripts', $scriptId);
172 }
173
174 /**
175 * Resolve script/style handles and URLs
176 *
177 * @return array{0:string,1:string,2:string,3:string,4:mixed}
178 */
179 private static function resolveAssetPaths(): array
180 {
181 $scriptId = IVYFORMS_DEV ? 'ivyforms_scripts_dev_vite' : 'ivyforms_script_index'; // @phpstan-ignore-line
182 $scriptSrc = IVYFORMS_DEV ? // @phpstan-ignore-line
183 'http://localhost:5173/src/assets/js/public/public.ts' :
184 IVYFORMS_URL . 'frontend/dist/public.js';
185
186 $styleSrc = IVYFORMS_DEV ? '' : IVYFORMS_URL . 'frontend/dist/index.css'; // @phpstan-ignore-line
187 $stylePublicSrc = IVYFORMS_DEV ? '' : IVYFORMS_URL . 'frontend/dist/public.css'; // @phpstan-ignore-line
188 $scriptVersion = IVYFORMS_DEV ? null : IVYFORMS_VERSION;// @phpstan-ignore-line
189
190 return [$scriptId, $scriptSrc, $styleSrc, $stylePublicSrc, $scriptVersion];
191 }
192
193 /**
194 * Enqueue the main frontend script
195 *
196 * @param string $scriptId
197 * @param string $scriptSrc
198 * @param mixed $scriptVersion
199 * @return void
200 */
201 private static function enqueueMainScript(string $scriptId, string $scriptSrc, $scriptVersion): void
202 {
203 wp_enqueue_script(
204 $scriptId,
205 $scriptSrc,
206 [],
207 $scriptVersion,
208 true
209 );
210 }
211
212 /**
213 * Enqueue styles and inline css
214 *
215 * @param string $styleSrc
216 * @param string $stylePublicSrc
217 * @param mixed $scriptVersion
218 * @return void
219 */
220 private static function enqueueStyles(string $styleSrc, string $stylePublicSrc, $scriptVersion): void
221 {
222 wp_enqueue_style('ivyforms_style_index', $styleSrc, [], $scriptVersion);
223 wp_enqueue_style('ivyforms_style_public', $stylePublicSrc, [], $scriptVersion);
224
225 // Use helper for inline styles
226 wp_add_inline_style(
227 'ivyforms_style_index',
228 InlineStyleHelper::getFrontendInlineCss()
229 );
230 }
231
232 /**
233 * Enqueue captcha scripts and localize captcha configs for consumers
234 *
235 * @param string $scriptId
236 * @param array<string, array<string, mixed>> $formList
237 * @return void
238 */
239 private static function enqueueCaptchaAndLocalize(string $scriptId, array $formList): void
240 {
241 $securityService = self::getSecurityService();
242 $formFields = self::getAllFormFields($formList);
243
244 $securityConfig = $securityService->getFrontendSecurityConfig($formFields);
245
246 if ($securityConfig['captcha']['enabled'] ?? false) {
247 if (isset($securityConfig['captcha']['recaptcha'])) {
248 self::enqueueGoogleRecaptchaScript($securityConfig['captcha']);
249 }
250 if (isset($securityConfig['captcha']['turnstile'])) {
251 self::enqueueTurnstileScript($securityConfig['captcha']);
252 }
253 if (isset($securityConfig['captcha']['hcaptcha'])) {
254 self::enqueueHCaptchaScript($securityConfig['captcha']);
255 }
256 }
257
258 wp_localize_script(
259 $scriptId,
260 'wpIvyRecaptchaConfig',
261 $securityConfig['captcha'] ?? []
262 );
263
264 wp_localize_script(
265 $scriptId,
266 'wpIvyTurnstileConfig',
267 $securityConfig['captcha'] ?? []
268 );
269
270 wp_localize_script(
271 $scriptId,
272 'wpIvyHCaptchaConfig',
273 $securityConfig['captcha'] ?? []
274 );
275 }
276
277 /**
278 * Localize form list, labels, urls, api settings and date format
279 *
280 * @param string $scriptId
281 * @param array<string, array<string, mixed>> $formList
282 * @return void
283 */
284 private static function localizeFormListAndLabels(string $scriptId, array $formList): void
285 {
286 wp_localize_script(
287 $scriptId,
288 'wpIvyFormDataList',
289 $formList
290 );
291
292 $frontendLabels = array_merge(
293 FrontendStrings::getFormRenderStrings()
294 );
295
296 /**
297 * Filter frontend labels before localizing
298 * Allows Pro version to merge additional strings
299 *
300 * @since 0.1.0
301 * @param array $frontendLabels Array of frontend label strings
302 */
303 $frontendLabels = apply_filters('ivyforms/shortcode/frontend_labels', $frontendLabels);
304
305 wp_localize_script($scriptId, 'wpIvyLabels', $frontendLabels);
306
307 wp_localize_script(
308 $scriptId,
309 'wpIvyUrls',
310 [
311 'pluginURL' => IVYFORMS_URL,
312 'siteURL' => esc_url_raw(site_url()),
313 ]
314 );
315
316 wp_localize_script(
317 $scriptId,
318 'wpIvyApiSettings',
319 [
320 'root' => esc_url_raw(rest_url()),
321 'nonce' => wp_create_nonce('wp_rest'),
322 'namespace' => Routes::$routeNamespace,
323 ]
324 );
325
326 wp_localize_script(
327 $scriptId,
328 'wpIvyDateFormat',
329 [
330 'dateFormat' => get_option('date_format'),
331 'timeFormat' => get_option('time_format'),
332 'dateTimeFormat' => get_option('date_format') . ' ' . get_option('time_format'),
333 'locale' => get_locale(),
334 ]
335 );
336 }
337
338 /**
339 * Add script attribute for module type
340 *
341 * @param array<string, mixed> $attributes
342 *
343 * @return array<string, mixed>
344 */
345 public static function addScriptAttribute(array $attributes): array
346 {
347 $scriptArray = [
348 'ivyforms_scripts_dev_main-js',
349 'ivyforms_scripts_dev_vite-js',
350 'ivyforms_script_index-js',
351 'ivyforms_scripts_public-js',
352 ];
353
354 if (isset($attributes['id']) && in_array($attributes['id'], $scriptArray, true)) {
355 $attributes['type'] = 'module';
356 }
357
358 return $attributes;
359 }
360 }
361