PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.33
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.33
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / helpers / FrmStylesPreviewHelper.php

FrmStylesPreviewHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.33, at classes/helpers/FrmStylesPreviewHelper.php

442 lines 11.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /**
7 * @since 6.0
8 */
9 class FrmStylesPreviewHelper {
10
11 /**
12 * @var int
13 */
14 private $form_id;
15
16 /**
17 * This is tracked so we can show a note that the CAPTCHA was turned off.
18 *
19 * @var bool
20 */
21 private $form_includes_captcha = false;
22
23 /**
24 * Track the field ids with the default label position.
25 * A field with a default label position will have a frm-default-label-position class in the styler preview.
26 * Only fields with this class will change when you update the position setting in the styler.
27 *
28 * @since 6.0.1
29 *
30 * @var array
31 */
32 private $default_label_position_field_ids;
33
34 /**
35 * @param int|string $form_id
36 *
37 * @return void
38 */
39 public function __construct( $form_id ) {
40 $this->form_id = (int) $form_id;
41 $this->default_label_position_field_ids = array();
42 }
43
44 /**
45 * Modify form behaviours for the styler preview.
46 *
47 * @since 6.0
48 *
49 * @return void
50 */
51 public function adjust_form_for_preview() {
52 // Don't bother including the antispam token in the preview as the form isn't submitted.
53 add_filter( 'frm_run_antispam', '__return_false', 99 );
54
55 // We don't need the honeypot in the preview so leave it out.
56 add_filter( 'frm_run_honeypot', '__return_false' );
57 $this->hide_captcha_fields();
58 $this->disable_javascript_validation();
59 $this->add_a_div_class_for_default_label_positions();
60 $this->add_a_div_class_for_style_driven_alignment();
61 }
62
63 /**
64 * Add a marker class to radio and checkbox fields that use the style's option
65 * alignment setting rather than a field level override.
66 *
67 * Only fields with this class change when the radio or checkbox alignment style
68 * setting is updated in the styler preview. Fields with their own alignment
69 * override are left untouched.
70 *
71 * @since 6.32
72 *
73 * @return void
74 */
75 private function add_a_div_class_for_style_driven_alignment() {
76 add_filter(
77 'frm_field_div_classes',
78 /**
79 * @param string $classes
80 * @param array|object $field
81 *
82 * @return string
83 */
84 function ( $classes, $field ) {
85 if ( ! FrmField::is_radio( $field ) && ! FrmField::is_checkbox( $field ) ) {
86 return $classes;
87 }
88
89 // Mirror FrmFieldType::get_container_class(): an override only exists in Pro.
90 $align = FrmAppHelper::pro_is_installed() ? FrmField::get_option( $field, 'align' ) : '';
91
92 if ( ! $align ) {
93 $classes .= ' frm-default-option-align';
94 }
95
96 return $classes;
97 },
98 10,
99 2
100 );
101 }
102
103 /**
104 * Add a frm-default-label-position class to any field with a default label position.
105 * A field with a custom label position shouldn't ever change in the styler preview.
106 *
107 * @since 6.0.1
108 *
109 * @return void
110 */
111 private function add_a_div_class_for_default_label_positions() {
112 // Only fields with no label position set hit this filter, so track those for the frm_field_div_classes filter.
113 add_filter(
114 'frm_html_label_position',
115 /**
116 * @param string $position
117 * @param array|object $field
118 *
119 * @return string
120 */
121 function ( $position, $field ) {
122 if ( is_array( $field ) ) {
123 $this->default_label_position_field_ids[] = (int) $field['id'];
124 }
125 return $position;
126 },
127 10,
128 2
129 );
130
131 add_filter(
132 'frm_field_div_classes',
133 /**
134 * @param string $classes
135 * @param array|object $field
136 *
137 * @return string
138 */
139 function ( $classes, $field ) {
140 if ( is_array( $field ) && in_array( (int) $field['id'], $this->default_label_position_field_ids, true ) ) {
141 $classes .= ' frm-default-label-position';
142 }
143 return $classes;
144 },
145 10,
146 2
147 );
148 }
149
150 /**
151 * Captcha does not initialize in the preview. Hide it so we don't see the label either.
152 *
153 * @since 6.0
154 *
155 * @return void
156 */
157 private function hide_captcha_fields() {
158 add_filter(
159 'frm_show_normal_field_type',
160 /**
161 * @param bool $show
162 * @param string $field_type
163 * @param string $target_field_type
164 *
165 * @return bool
166 */
167 function ( $show, $field_type ) {
168 return 'captcha' === $field_type ? false : $show;
169 },
170 10,
171 2
172 );
173 }
174
175 /**
176 * Turn off JavaScript validation for the preview.
177 * Without this we hit a "PHP Fatal error: Uncaught Error: Maximum function nesting level of '256' reached" error.
178 * This only happened with specific Look up fields when FrmProLookupFieldsController::get_independent_lookup_field_options is called in Pro.
179 *
180 * @since 6.0
181 *
182 * @return void
183 */
184 private function disable_javascript_validation() {
185 add_filter(
186 'frm_form_object',
187 /**
188 * @param stdClass|null $form
189 * @param int $form_id
190 *
191 * @return stdClass|null
192 */
193 function ( $form ) {
194 if ( is_object( $form ) && is_array( $form->options ) ) {
195 $form->options['js_validate'] = false;
196 }
197 return $form;
198 }
199 );
200 }
201
202 /**
203 * @since 6.0
204 *
205 * @return string
206 */
207 public function get_html_for_form_preview() {
208 // Force is_admin to false so the "Entry Key" field doesn't render in the preview.
209 add_filter( 'frm_is_admin', '__return_false' );
210
211 $target_form_preview_html = FrmFormsController::show_form( $this->form_id, '', 'auto', 'auto' );
212
213 $this->form_includes_captcha = wp_script_is( 'captcha-api', 'enqueued' );
214
215 if ( $this->form_includes_captcha ) {
216 // If a form includes a CAPTCHA field, don't try to load the CAPTCHA scripts for the visual styler preview.
217 wp_dequeue_script( 'captcha-api' );
218 }
219
220 // Return the is_admin status.
221 // Otherwise success messages won't use the proper mark up and will appear without the green background and padding.
222 remove_filter( 'frm_is_admin', '__return_false' );
223
224 return $target_form_preview_html;
225 }
226
227 /**
228 * @since 6.0
229 *
230 * @return array<string>
231 */
232 public function get_notes_for_styler_preview() {
233 $notes = array();
234 $fallback_form_note = $this->get_fallback_form_note();
235
236 if ( is_string( $fallback_form_note ) ) {
237 $notes[] = $fallback_form_note;
238 }
239
240 $frm_settings = FrmAppHelper::get_settings();
241
242 if ( 'none' === $frm_settings->load_style ) {
243 $notes[] = function () {
244 printf(
245 // translators: %1$s: Anchor tag open, %2$s: Anchor tag close.
246 esc_html__( 'Formidable styles are disabled. This needs to be enabled in %1$sGlobal Settings%2$s.', 'formidable' ),
247 '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-settings' ) ) . '">',
248 '</a>'
249 );
250 };
251 }
252
253 if ( is_callable( 'FrmProStylesController::get_notes_for_styler_preview' ) ) {
254 $notes = array_merge( $notes, FrmProStylesController::get_notes_for_styler_preview() );
255 }
256
257 $disabled_features_note = $this->get_disabled_features_note();
258
259 if ( is_string( $disabled_features_note ) ) {
260 $notes[] = $disabled_features_note;
261 }
262
263 return $notes;
264 }
265
266 /**
267 * @since 6.0
268 *
269 * @return string
270 */
271 private function get_disabled_features_note() {
272 return __( 'Not all JavaScript is loaded in this preview. Some features will appear differently on the front end.', 'formidable' );
273 }
274
275 /**
276 * @since 6.0
277 *
278 * @return false|string
279 */
280 private function get_fallback_form_note() {
281 if ( ! FrmAppHelper::simple_get( 'form', 'absint' ) ) {
282 return __( 'This form is being previewed because no form was selected. Use the form dropdown to select a new preview target.', 'formidable' );
283 }
284 return false;
285 }
286
287 /**
288 * Get all warnings to display above the visual styler preview.
289 *
290 * @since 6.0
291 *
292 * @param stdClass|WP_Post $style A new style is not a WP_Post object.
293 * @param WP_Post $default_style
294 * @param string $view Either 'list' or 'edit'.
295 *
296 * @return array<string>
297 */
298 public function get_warnings_for_styler_preview( $style, $default_style, $view ) {
299 $warnings = array();
300
301 if ( 'edit' === $view && $this->should_show_multiple_forms_warning( $style->ID, $default_style->ID ) ) {
302 $warnings[] = __( 'Changes that you will make to this style will apply to every form using this style.', 'formidable' );
303 }
304
305 return $warnings;
306 }
307
308 /**
309 * @since 6.0
310 *
311 * @param int $style_id
312 * @param int $default_style_id
313 *
314 * @return bool
315 */
316 private function should_show_multiple_forms_warning( $style_id, $default_style_id ) {
317 $is_default_style = $style_id === $default_style_id;
318
319 if ( ! $is_default_style ) {
320 // Also check for the conversational default.
321 $conversational_style_id = FrmDb::get_var( 'posts', array( 'post_name' => 'lines-no-boxes' ), 'ID' );
322
323 if ( $conversational_style_id && (int) $conversational_style_id === $style_id ) {
324 $is_default_style = true;
325 }
326 }
327
328 $form_count = FrmStylesHelper::get_form_count_for_style( $style_id, $is_default_style );
329
330 if ( $form_count <= 1 ) {
331 return false;
332 }
333
334 // Only show the warning once per user per style.
335 $user_id = get_current_user_id();
336 $meta_key = 'frm_dismiss_multiple_forms_warning_' . $style_id;
337 $meta = get_user_meta( $user_id, $meta_key, true );
338
339 if ( $meta ) {
340 return false;
341 }
342
343 add_user_meta( $user_id, $meta_key, 1 );
344 return true;
345 }
346
347 /**
348 * @since 6.0
349 *
350 * @param WP_Styles $styles
351 *
352 * @return void
353 */
354 public static function disable_conflicting_wp_admin_css( $styles ) {
355 if ( ! is_callable( array( $styles, 'remove' ) ) || ! array_key_exists( 'wp-admin', $styles->registered ) ) {
356 return;
357 }
358
359 $styles->remove( 'edit' );
360
361 $wp_admin_dependencies = $styles->registered['wp-admin']->deps;
362 $edit_key = array_search( 'edit', $wp_admin_dependencies, true );
363
364 if ( false === $edit_key ) {
365 return;
366 }
367
368 // Remove the edit dependency from wp-admin so it still loads, just without edit.css.
369 self::remove_wp_admin_dependency( $styles, 'edit' );
370 }
371
372 /**
373 * Provides few fixes for style preview.
374 * Fix the "Width" from Fields Settings to get reflected on each style preview ajax update.
375 * Fix the Radio & Checkbox "Single Row" or "Multiple Row" to get reflected in style preview ajax update.
376 *
377 * @since 6.14
378 *
379 * @param array $settings The style options.
380 * @param bool $is_preview
381 *
382 * @return void
383 */
384 public static function get_additional_preview_style( $settings, $is_preview = false ) {
385 if ( ! $is_preview ) {
386 return;
387 }
388
389 $radio_display_type = 'inline' === $settings['radio_align'] ? 'inline-block' : 'block';
390 $check_display_type = 'inline' === $settings['check_align'] ? 'inline-block' : 'block';
391
392 $style = '#frm_style_preview .with_frm_style input[type=text],
393 #frm_style_preview .with_frm_style input[type=password],
394 #frm_style_preview .with_frm_style input[type=email],
395 #frm_style_preview .with_frm_style input[type=number],
396 #frm_style_preview .with_frm_style input[type=url],
397 #frm_style_preview .with_frm_style input[type=tel],
398 #frm_style_preview .with_frm_style input[type=phone],
399 #frm_style_preview .with_frm_style input[type=search],
400 #frm_style_preview .with_frm_style textarea,
401 #frm_style_preview .frm_form_fields_style,
402 #frm_style_preview .with_frm_style .frm_scroll_box .frm_opt_container,
403 #frm_style_preview .frm_form_fields_active_style,
404 #frm_style_preview .frm_form_fields_error_style,
405 #frm_style_preview .with_frm_style .frm-card-element.StripeElement,
406 #frm_style_preview .with_frm_style .frm_slimselect.ss-main {
407 width: var(--field-width);
408 }
409 #frm_style_preview .with_frm_style .frm_radio {
410 display:' . $radio_display_type . ';
411 }
412 #frm_style_preview .with_frm_style .frm_checkbox {
413 display:' . $check_display_type . ';
414 }';
415
416 echo esc_html( $style );
417 }
418
419 /**
420 * @since 6.0
421 *
422 * @param WP_Styles $styles
423 * @param string $key
424 *
425 * @return void
426 */
427 private static function remove_wp_admin_dependency( $styles, $key ) {
428 $dependencies = $styles->registered['wp-admin']->deps;
429 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
430 $index = array_search( $key, $dependencies );
431
432 if ( false === $index ) {
433 return;
434 }
435
436 unset( $dependencies[ $index ] );
437 $dependencies = array_values( $dependencies );
438
439 $styles->registered['wp-admin']->deps = $dependencies;
440 }
441 }
442