PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.4.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.4.1
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 / models / FrmFieldFormHtml.php

FrmFieldFormHtml.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.4.1, at classes/models/FrmFieldFormHtml.php

490 lines 13.0 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 3.0
8 */
9
10 class FrmFieldFormHtml {
11
12 private $html;
13
14 private $html_id;
15
16 /**
17 * @var FrmFieldType
18 */
19 private $field_obj;
20
21 private $field_id;
22
23 private $form = array();
24
25 private $pass_args = array();
26
27 /**
28 * @since 3.0
29 *
30 * @param array $atts
31 */
32 public function __construct( $atts ) {
33 $this->_set( 'field_obj', $atts );
34 $this->set_field_id( $atts );
35 $this->_set( 'form', $atts );
36 $this->_set( 'html_id', $atts );
37 $this->set_html( $atts );
38 $this->set_pass_args( $atts );
39 }
40
41 /**
42 * @since 3.0
43 *
44 * @param string $param
45 * @param array $atts
46 */
47 private function _set( $param, $atts ) {
48 if ( isset( $atts[ $param ] ) ) {
49 $this->{$param} = $atts[ $param ];
50 }
51 }
52
53 /**
54 * @since 3.0
55 *
56 * @param array $atts
57 */
58 private function set_html( $atts ) {
59 $this->set_from_field(
60 $atts,
61 array(
62 'param' => 'html',
63 'default' => 'custom_html',
64 )
65 );
66 }
67
68 /**
69 * @since 3.0
70 *
71 * @param array $atts
72 */
73 private function set_field_id( $atts ) {
74 $this->set_from_field(
75 $atts,
76 array(
77 'param' => 'field_id',
78 'default' => 'id',
79 )
80 );
81 }
82
83 /**
84 * @since 3.0
85 *
86 * @param array $atts
87 */
88 private function set_pass_args( $atts ) {
89 $this->pass_args = $atts;
90
91 $exclude = array( 'field_obj', 'html' );
92 foreach ( $exclude as $ex ) {
93 if ( isset( $atts[ $ex ] ) ) {
94 unset( $this->pass_args[ $ex ] );
95 }
96 }
97 }
98
99 /**
100 * @since 3.0
101 *
102 * @param array $atts
103 * @param array $set
104 */
105 private function set_from_field( $atts, $set ) {
106 if ( isset( $atts[ $set['param'] ] ) ) {
107 $this->{$set['param']} = $atts[ $set['param'] ];
108 } else {
109 $this->{$set['param']} = $this->field_obj->get_field_column( $set['default'] );
110 }
111 }
112
113 public function get_html() {
114 $this->replace_shortcodes_before_input();
115 $this->replace_shortcodes_with_atts();
116 $this->replace_shortcodes_after_input();
117
118 return $this->html;
119 }
120
121 /**
122 * @since 3.0
123 */
124 private function replace_shortcodes_before_input() {
125 $this->html = apply_filters( 'frm_before_replace_shortcodes', $this->html, $this->field_obj->get_field(), $this->pass_args['errors'], $this->form );
126
127 $this->replace_field_values();
128
129 $this->replace_required_label_shortcode();
130 $this->replace_required_class();
131 $this->maybe_replace_description_shortcode( false );
132 $this->replace_error_shortcode();
133 $this->add_field_div_classes();
134
135 $this->replace_entry_key();
136 $this->replace_form_shortcodes();
137 $this->process_wp_shortcodes();
138 $this->maybe_replace_description_shortcode( true );
139 }
140
141 /**
142 * @since 3.0
143 */
144 private function replace_field_values() {
145 //replace [id]
146 $this->html = str_replace( '[id]', $this->field_id, $this->html );
147
148 // set the label for
149 $this->html = str_replace( 'field_[key]', $this->html_id, $this->html );
150
151 //replace [key]
152 $this->html = str_replace( '[key]', $this->field_obj->get_field_column( 'field_key' ), $this->html );
153
154 //replace [field_name]
155 $this->html = str_replace( '[field_name]', FrmAppHelper::maybe_kses( $this->field_obj->get_field_column( 'name' ) ), $this->html );
156 }
157
158 /**
159 * @since 3.0
160 */
161 private function replace_required_label_shortcode() {
162 $required = FrmField::is_required( $this->field_obj->get_field() ) ? $this->field_obj->get_field_column( 'required_indicator' ) : '';
163 FrmShortcodeHelper::remove_inline_conditions( ! empty( $required ), 'required_label', $required, $this->html );
164 }
165
166 /**
167 * If this is an HTML field, the values are included in the description.
168 * In this case, we don't want to run the wp shortcodes with the description included.
169 *
170 * @since 3.0
171 */
172 private function maybe_replace_description_shortcode( $wp_processed = false ) {
173 $is_html = 'html' === $this->field_obj->get_field_column( 'type' );
174 $should_replace = ( $is_html && $wp_processed ) || ( ! $is_html && ! $wp_processed );
175 if ( $should_replace ) {
176 $this->replace_description_shortcode();
177 }
178 }
179
180 /**
181 * @since 3.0
182 */
183 private function replace_description_shortcode() {
184 $this->maybe_add_description_id();
185 $description = FrmAppHelper::maybe_kses( $this->field_obj->get_field_column( 'description' ) );
186 FrmShortcodeHelper::remove_inline_conditions( ( $description && $description != '' ), 'description', $description, $this->html );
187 }
188
189 /**
190 * Add an ID to the description for aria-describedby.
191 * This ID was added to the HTML in v3.0.
192 *
193 * @since 3.0
194 */
195 private function maybe_add_description_id() {
196 $description = $this->field_obj->get_field_column( 'description' );
197 if ( $description != '' ) {
198 $this->add_element_id( 'description', 'desc' );
199 }
200 }
201
202 /**
203 * Insert an ID if it doesn't exist.
204 *
205 * @since 3.06.02
206 */
207 private function add_element_id( $param, $id ) {
208 preg_match_all( '/(\[if\s+' . $param . '\])(.*?)(\[\/if\s+' . $param . '\])/mis', $this->html, $inner_html );
209 if ( ! isset( $inner_html[2] ) ) {
210 return;
211 }
212
213 if ( ! is_string( $inner_html[2] ) && count( $inner_html[2] ) === 1 ) {
214 $inner_html[2] = $inner_html[2][0];
215 }
216
217 if ( is_string( $inner_html[2] ) ) {
218 $has_id = strpos( $inner_html[2], ' id=' );
219 if ( ! $has_id ) {
220 $id = 'frm_' . $id . '_' . $this->html_id;
221 $this->html = str_replace( 'class="frm_' . $param, 'id="' . esc_attr( $id ) . '" class="frm_' . esc_attr( $param ), $this->html );
222 }
223 }
224 }
225
226 /**
227 * @since 3.0
228 */
229 private function replace_error_shortcode() {
230 $this->maybe_add_error_id();
231 $error = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? $this->pass_args['errors'][ 'field' . $this->field_id ] : false;
232
233 if ( ! empty( $error ) && false === strpos( $this->html, 'role="alert"' ) && FrmAppHelper::should_include_alert_role_on_field_errors() ) {
234 $error_body = self::get_error_body( $this->html );
235 if ( is_string( $error_body ) && false === strpos( $error_body, 'role=' ) ) {
236 $new_error_body = preg_replace( '/class="frm_error/', 'role="alert" class="frm_error', $error_body, 1 );
237 $this->html = str_replace( '[if error]' . $error_body . '[/if error]', '[if error]' . $new_error_body . '[/if error]', $this->html );
238 }
239 }
240
241 FrmShortcodeHelper::remove_inline_conditions( ! empty( $error ), 'error', $error, $this->html );
242 }
243
244 /**
245 * Pull the HTML between [if error] and [/if error] shortcodes.
246 *
247 * @param string $html
248 * @return string|false
249 */
250 private static function get_error_body( $html ) {
251 $start = strpos( $html, '[if error]' );
252 if ( false === $start ) {
253 return false;
254 }
255
256 $end = strpos( $html, '[/if error]', $start );
257 if ( false === $end ) {
258 return false;
259 }
260
261 $error_body = substr( $html, $start + 10, $end - $start - 10 );
262 return $error_body;
263 }
264
265 /**
266 * Add an ID to the error message for aria-describedby.
267 * This ID was added to the HTML in v3.06.02.
268 *
269 * @since 3.06.02
270 */
271 private function maybe_add_error_id() {
272 if ( ! isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ) {
273 return;
274 }
275
276 $this->add_element_id( 'error', 'error' );
277 }
278
279 /**
280 * Replace [required_class]
281 *
282 * @since 3.0
283 */
284 private function replace_required_class() {
285 $required_class = FrmField::is_required( $this->field_obj->get_field() ) ? ' frm_required_field' : '';
286 $this->html = str_replace( '[required_class]', $required_class, $this->html );
287 }
288
289 /**
290 * @since 3.0
291 */
292 private function replace_form_shortcodes() {
293 if ( ! empty( $this->form ) ) {
294 $form = (array) $this->form;
295
296 //replace [form_key]
297 $this->html = str_replace( '[form_key]', $form['form_key'], $this->html );
298
299 //replace [form_name]
300 $this->html = str_replace( '[form_name]', $form['name'], $this->html );
301 }
302 }
303
304 /**
305 * @since 3.0
306 */
307 public function replace_shortcodes_after_input() {
308 $this->html .= "\n";
309
310 // Stop html filtering on confirmation field to prevent loop
311 if ( $this->field_obj->get_field_column( 'conf_field' ) != 'stop' ) {
312 $this->filter_for_more_shortcodes();
313 }
314 }
315
316 /**
317 * @since 3.0
318 */
319 private function filter_for_more_shortcodes() {
320 $atts = $this->pass_args;
321
322 //If field is not in repeating section
323 if ( empty( $atts['section_id'] ) ) {
324 $atts = array(
325 'errors' => $this->pass_args['errors'],
326 'form' => $this->form,
327 );
328 }
329 $this->html = apply_filters( 'frm_replace_shortcodes', $this->html, $this->field_obj->get_field(), $atts );
330 }
331
332 /**
333 * Remove [collapse_this] if it's still included after all processing
334 *
335 * @since 3.0
336 *
337 * @param string $html
338 */
339 public function remove_collapse_shortcode( &$html ) {
340 if ( strpos( $html, '[collapse_this]' ) ) {
341 $html = str_replace( '[collapse_this]', '', $html );
342 }
343 }
344
345 /**
346 * @since 3.0
347 */
348 private function replace_shortcodes_with_atts() {
349 preg_match_all( "/\[(input|deletelink)\b(.*?)(?:(\/))?\]/s", $this->html, $shortcodes, PREG_PATTERN_ORDER );
350
351 foreach ( $shortcodes[0] as $short_key => $tag ) {
352 $shortcode_atts = FrmShortcodeHelper::get_shortcode_attribute_array( $shortcodes[2][ $short_key ] );
353 $tag = FrmShortcodeHelper::get_shortcode_tag( $shortcodes, $short_key );
354
355 $replace_with = '';
356
357 if ( $tag == 'deletelink' && FrmAppHelper::pro_is_installed() ) {
358 $replace_with = FrmProEntriesController::entry_delete_link( $shortcode_atts );
359 } elseif ( $tag == 'input' ) {
360 $replace_with = $this->replace_input_shortcode( $shortcode_atts );
361 }
362
363 $this->html = str_replace( $shortcodes[0][ $short_key ], $replace_with, $this->html );
364 }
365 }
366
367 /**
368 * @param array $shortcode_atts
369 *
370 * @return string
371 */
372 private function replace_input_shortcode( $shortcode_atts ) {
373 $shortcode_atts = $this->prepare_input_shortcode_atts( $shortcode_atts );
374
375 return $this->field_obj->include_front_field_input( $this->pass_args, $shortcode_atts );
376 }
377
378 /**
379 * @param array $shortcode_atts
380 *
381 * @return array
382 */
383 private function prepare_input_shortcode_atts( $shortcode_atts ) {
384 if ( isset( $shortcode_atts['opt'] ) ) {
385 $shortcode_atts['opt'] --;
386 }
387
388 $field_class = isset( $shortcode_atts['class'] ) ? $shortcode_atts['class'] : '';
389 $this->field_obj->set_field_column( 'input_class', $field_class );
390
391 if ( isset( $shortcode_atts['class'] ) ) {
392 unset( $shortcode_atts['class'] );
393 }
394
395 $shortcode_atts['aria-invalid'] = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? 'true' : 'false';
396
397 $this->field_obj->set_field_column( 'shortcodes', $shortcode_atts );
398
399 return $shortcode_atts;
400 }
401
402 /**
403 * Add the label position class into the HTML
404 * If the label position is inside, add a class to show the label if the field has a value.
405 *
406 * @since 3.0
407 */
408 private function add_class_to_label() {
409 $label_class = $this->field_obj->get_label_class();
410 $this->html = str_replace( '[label_position]', $label_class, $this->html );
411 if ( $this->field_obj->get_field_column( 'label' ) == 'inside' && $this->field_obj->get_field_column( 'value' ) != '' ) {
412 $this->html = str_replace( 'frm_primary_label', 'frm_primary_label frm_visible', $this->html );
413 }
414 }
415
416 /**
417 * Replace [entry_key]
418 *
419 * @since 3.0
420 */
421 private function replace_entry_key() {
422 $entry_key = FrmAppHelper::simple_get( 'entry', 'sanitize_title' );
423 $this->html = str_replace( '[entry_key]', $entry_key, $this->html );
424 }
425
426 /**
427 * Add classes to a field div
428 *
429 * @since 3.0
430 */
431 private function add_field_div_classes() {
432 $classes = $this->get_field_div_classes();
433
434 if ( $this->field_obj->get_field_column( 'type' ) == 'html' && strpos( $this->html, '[error_class]' ) === false ) {
435 // there is no error_class shortcode for HTML fields
436 $this->html = str_replace( 'class="frm_form_field', 'class="frm_form_field ' . $classes, $this->html );
437 }
438 $this->html = str_replace( '[error_class]', $classes, $this->html );
439 }
440
441 /**
442 * Get the classes for a field div
443 *
444 * @since 3.0
445 *
446 * @return string $classes
447 */
448 private function get_field_div_classes() {
449 // Add error class
450 $classes = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? ' frm_blank_field' : '';
451
452 // Add label position class
453 $settings = $this->field_obj->display_field_settings();
454 if ( isset( $settings['label_position'] ) && $settings['label_position'] ) {
455 $label_position = $this->field_obj->get_field_column( 'label' );
456 $classes .= ' frm_' . $label_position . '_container';
457
458 // Add class if field has value, to be used for floating label styling.
459 if ( 'inside' === $label_position && $this->field_obj->get_field_column( 'value' ) ) {
460 $classes .= ' frm_label_float_top';
461 }
462 }
463
464 // Add CSS layout classes
465 $extra_classes = $this->field_obj->get_field_column( 'classes' );
466 if ( ! empty( $extra_classes ) ) {
467 if ( ! strpos( $this->html, 'frm_form_field ' ) ) {
468 $classes .= ' frm_form_field';
469 }
470 $classes .= ' ' . $extra_classes;
471 }
472
473 $classes .= $this->field_obj->get_container_class();
474
475 // Get additional classes
476 return apply_filters( 'frm_field_div_classes', $classes, $this->field_obj->get_field(), array( 'field_id' => $this->field_id ) );
477 }
478
479 /**
480 * This filters shortcodes in the field HTML
481 *
482 * @since 3.0
483 */
484 private function process_wp_shortcodes() {
485 if ( apply_filters( 'frm_do_html_shortcodes', true ) ) {
486 $this->html = do_shortcode( $this->html );
487 }
488 }
489 }
490