Completed
Push — master ( 414a92...ad72a2 )
by Stephanie
03:03
created

FrmFieldFormHtml::add_element_id()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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