PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.4
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.4
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 6.4, at classes/models/FrmFieldFormHtml.php

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