Completed
Branch FET-10580-form-html-parser (5302d2)
by
unknown
25:39 queued 14:00
created
core/libraries/form_sections/strategies/parser/VsprintfParser.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -23,49 +23,49 @@
 block discarded – undo
23 23
 class VsprintfParser extends FormHtmlParser
24 24
 {
25 25
 
26
-    /**
27
-     * @var string $format
28
-     */
29
-    protected $format = '';
30
-
31
-
32
-    /**
33
-     * @var array $args
34
-     */
35
-    protected $args = array();
36
-
37
-
38
-
39
-    /**
40
-     * SprintfFormHtmlParser constructor.
41
-     *
42
-     * @param string $format
43
-     * @param array  $args
44
-     */
45
-    public function __construct($format, array $args)
46
-    {
47
-        $this->format = $format;
48
-        $this->args = $args;
49
-    }
50
-
51
-
52
-
53
-    /**
54
-     * @param                        $html
55
-     * @param EE_Form_Section_Proper $form_section
56
-     * @return string
57
-     */
58
-    public function parseHtml($html, EE_Form_Section_Proper $form_section)
59
-    {
60
-        $this->args[] = $html;
61
-        $subsections = $form_section->subsections();
62
-        if (count($subsections) > 1) {
63
-            foreach ($subsections as $subsection) {
64
-                $this->args[] = $subsection->get_html();
65
-            }
66
-        }
67
-        return vprintf($this->format, $this->args);
68
-    }
26
+	/**
27
+	 * @var string $format
28
+	 */
29
+	protected $format = '';
30
+
31
+
32
+	/**
33
+	 * @var array $args
34
+	 */
35
+	protected $args = array();
36
+
37
+
38
+
39
+	/**
40
+	 * SprintfFormHtmlParser constructor.
41
+	 *
42
+	 * @param string $format
43
+	 * @param array  $args
44
+	 */
45
+	public function __construct($format, array $args)
46
+	{
47
+		$this->format = $format;
48
+		$this->args = $args;
49
+	}
50
+
51
+
52
+
53
+	/**
54
+	 * @param                        $html
55
+	 * @param EE_Form_Section_Proper $form_section
56
+	 * @return string
57
+	 */
58
+	public function parseHtml($html, EE_Form_Section_Proper $form_section)
59
+	{
60
+		$this->args[] = $html;
61
+		$subsections = $form_section->subsections();
62
+		if (count($subsections) > 1) {
63
+			foreach ($subsections as $subsection) {
64
+				$this->args[] = $subsection->get_html();
65
+			}
66
+		}
67
+		return vprintf($this->format, $this->args);
68
+	}
69 69
 
70 70
 
71 71
 
Please login to merge, or discard this patch.
core/libraries/form_sections/strategies/parser/FormHtmlParser.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -18,12 +18,12 @@
 block discarded – undo
18 18
 abstract class FormHtmlParser
19 19
 {
20 20
 
21
-    /**
22
-     * @param                        $html
23
-     * @param EE_Form_Section_Proper $form_section
24
-     * @return string
25
-     */
26
-    abstract public function parseHtml($html, EE_Form_Section_Proper $form_section);
21
+	/**
22
+	 * @param                        $html
23
+	 * @param EE_Form_Section_Proper $form_section
24
+	 * @return string
25
+	 */
26
+	abstract public function parseHtml($html, EE_Form_Section_Proper $form_section);
27 27
 
28 28
 }
29 29
 // End of file FormHtmlParser.php
Please login to merge, or discard this patch.
core/libraries/form_sections/base/EE_Form_Section_Proper.form.php 1 patch
Indentation   +1392 added lines, -1392 removed lines patch added patch discarded remove patch
@@ -12,1398 +12,1398 @@
 block discarded – undo
12 12
 class EE_Form_Section_Proper extends EE_Form_Section_Validatable
13 13
 {
14 14
 
15
-    const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
16
-
17
-    /**
18
-     * Subsections
19
-     *
20
-     * @var EE_Form_Section_Validatable[]
21
-     */
22
-    protected $_subsections = array();
23
-
24
-    /**
25
-     * Strategy for laying out the form
26
-     *
27
-     * @var EE_Form_Section_Layout_Base
28
-     */
29
-    protected $_layout_strategy;
30
-
31
-    /**
32
-     * Strategy for parsing the form HTML upon display
33
-     *
34
-     * @var FormHtmlParser
35
-     */
36
-    protected $_form_html_parser;
37
-
38
-    /**
39
-     * Whether or not this form has received and validated a form submission yet
40
-     *
41
-     * @var boolean
42
-     */
43
-    protected $_received_submission = false;
44
-
45
-    /**
46
-     * message displayed to users upon successful form submission
47
-     *
48
-     * @var string
49
-     */
50
-    protected $_form_submission_success_message = '';
51
-
52
-    /**
53
-     * message displayed to users upon unsuccessful form submission
54
-     *
55
-     * @var string
56
-     */
57
-    protected $_form_submission_error_message = '';
58
-
59
-    /**
60
-     * Stores all the data that will localized for form validation
61
-     *
62
-     * @var array
63
-     */
64
-    static protected $_js_localization = array();
65
-
66
-    /**
67
-     * whether or not the form's localized validation JS vars have been set
68
-     *
69
-     * @type boolean
70
-     */
71
-    static protected $_scripts_localized = false;
72
-
73
-
74
-
75
-    /**
76
-     * when constructing a proper form section, calls _construct_finalize on children
77
-     * so that they know who their parent is, and what name they've been given.
78
-     *
79
-     * @param array $options_array   {
80
-     * @type        $subsections     EE_Form_Section_Validatable[] where keys are the section's name
81
-     * @type        $include         string[] numerically-indexed where values are section names to be included,
82
-     *                               and in that order. This is handy if you want
83
-     *                               the subsections to be ordered differently than the default, and if you override
84
-     *                               which fields are shown
85
-     * @type        $exclude         string[] values are subsections to be excluded. This is handy if you want
86
-     *                               to remove certain default subsections (note: if you specify BOTH 'include' AND
87
-     *                               'exclude', the inclusions will be applied first, and the exclusions will exclude
88
-     *                               items from that list of inclusions)
89
-     * @type        $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
90
-     *                               } @see EE_Form_Section_Validatable::__construct()
91
-     * @throws \EE_Error
92
-     */
93
-    public function __construct($options_array = array())
94
-    {
95
-        $options_array = (array)apply_filters('FHEE__EE_Form_Section_Proper___construct__options_array', $options_array,
96
-            $this);
97
-        //call parent first, as it may be setting the name
98
-        parent::__construct($options_array);
99
-        //if they've included subsections in the constructor, add them now
100
-        if (isset($options_array['include'])) {
101
-            //we are going to make sure we ONLY have those subsections to include
102
-            //AND we are going to make sure they're in that specified order
103
-            $reordered_subsections = array();
104
-            foreach ($options_array['include'] as $input_name) {
105
-                if (isset($this->_subsections[$input_name])) {
106
-                    $reordered_subsections[$input_name] = $this->_subsections[$input_name];
107
-                }
108
-            }
109
-            $this->_subsections = $reordered_subsections;
110
-        }
111
-        if (isset($options_array['exclude'])) {
112
-            $exclude = $options_array['exclude'];
113
-            $this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
114
-        }
115
-        if (isset($options_array['layout_strategy'])) {
116
-            $this->_layout_strategy = $options_array['layout_strategy'];
117
-        }
118
-        if (! $this->_layout_strategy) {
119
-            $this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
120
-        }
121
-        $this->_layout_strategy->_construct_finalize($this);
122
-
123
-        // set parser which allows the form section's rendered HTML to be filtered
124
-        if (isset($options_array['form_html_parser']) && $options_array['form_html_parser'] instanceof FormHtmlParser) {
125
-            $this->_form_html_parser = $options_array['form_html_parser'];
126
-        }
127
-        //ok so we are definitely going to want the forms JS,
128
-        //so enqueue it or remember to enqueue it during wp_enqueue_scripts
129
-        if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
130
-            //ok so they've constructed this object after when they should have.
131
-            //just enqueue the generic form scripts and initialize the form immediately in the JS
132
-            \EE_Form_Section_Proper::wp_enqueue_scripts(true);
133
-        } else {
134
-            add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
135
-            add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
136
-        }
137
-        add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
138
-
139
-        /**
140
-         * Gives other plugins a chance to hook in before construct finalize is called. The form probably doesn't
141
-         * yet have a parent form section. Since 4.9.32, when this action was introduced, this is the best place to
142
-         * add a subsection onto a form, assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
143
-         * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
144
-         * @since 4.9.32
145
-         * @param EE_Form_Section_Proper $this before __construct is done, but all of its logic, except maybe calling
146
-         *                                      _construct_finalize has been done
147
-         * @param array $options_array options passed into the constructor
148
-         */
149
-        do_action('AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called', $this, $options_array);
150
-
151
-        if (isset($options_array['name'])) {
152
-            $this->_construct_finalize(null, $options_array['name']);
153
-        }
154
-    }
155
-
156
-
157
-
158
-    /**
159
-     * Finishes construction given the parent form section and this form section's name
160
-     *
161
-     * @param EE_Form_Section_Proper $parent_form_section
162
-     * @param string                 $name
163
-     * @throws \EE_Error
164
-     */
165
-    public function _construct_finalize($parent_form_section, $name)
166
-    {
167
-        parent::_construct_finalize($parent_form_section, $name);
168
-        $this->_set_default_name_if_empty();
169
-        $this->_set_default_html_id_if_empty();
170
-        foreach ($this->_subsections as $subsection_name => $subsection) {
171
-            if ($subsection instanceof EE_Form_Section_Base) {
172
-                $subsection->_construct_finalize($this, $subsection_name);
173
-            } else {
174
-                throw new EE_Error(
175
-                    sprintf(
176
-                        __('Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
177
-                            'event_espresso'),
178
-                        $subsection_name,
179
-                        get_class($this),
180
-                        $subsection ? get_class($subsection) : __('NULL', 'event_espresso')
181
-                    )
182
-                );
183
-            }
184
-        }
185
-        /**
186
-         * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
187
-         * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID (or other attributes derived
188
-         * from the name like the HTML label id, etc), this is where it should be done.
189
-         * This might only happen just before displaying the form, or just before it receives form submission data.
190
-         * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
191
-         * ensured it has a name, HTML IDs, etc
192
-         * @param EE_Form_Section_Proper $this
193
-         * @param EE_Form_Section_Proper|null $parent_form_section
194
-         * @param string $name
195
-         */
196
-        do_action('AHEE__EE_Form_Section_Proper___construct_finalize__end', $this, $parent_form_section, $name);
197
-    }
198
-
199
-
200
-
201
-    /**
202
-     * Gets the layout strategy for this form section
203
-     *
204
-     * @return EE_Form_Section_Layout_Base
205
-     */
206
-    public function get_layout_strategy()
207
-    {
208
-        return $this->_layout_strategy;
209
-    }
210
-
211
-
212
-
213
-    /**
214
-     * Gets the HTML for a single input for this form section according
215
-     * to the layout strategy
216
-     *
217
-     * @param EE_Form_Input_Base $input
218
-     * @return string
219
-     */
220
-    public function get_html_for_input($input)
221
-    {
222
-        return $this->_layout_strategy->layout_input($input);
223
-    }
224
-
225
-
226
-
227
-    /**
228
-     * was_submitted - checks if form inputs are present in request data
229
-     * Basically an alias for form_data_present_in() (which is used by both
230
-     * proper form sections and form inputs)
231
-     *
232
-     * @param null $form_data
233
-     * @return boolean
234
-     */
235
-    public function was_submitted($form_data = null)
236
-    {
237
-        return $this->form_data_present_in($form_data);
238
-    }
239
-
240
-
241
-
242
-    /**
243
-     * After the form section is initially created, call this to sanitize the data in the submission
244
-     * which relates to this form section, validate it, and set it as properties on the form.
245
-     *
246
-     * @param array|null $req_data should usually be $_POST (the default).
247
-     *                             However, you CAN supply a different array.
248
-     *                             Consider using set_defaults() instead however.
249
-     *                             (If you rendered the form in the page using echo $form_x->get_html()
250
-     *                             the inputs will have the correct name in the request data for this function
251
-     *                             to find them and populate the form with them.
252
-     *                             If you have a flat form (with only input subsections),
253
-     *                             you can supply a flat array where keys
254
-     *                             are the form input names and values are their values)
255
-     * @param boolean    $validate whether or not to perform validation on this data. Default is,
256
-     *                             of course, to validate that data, and set errors on the invalid values.
257
-     *                             But if the data has already been validated
258
-     *                             (eg you validated the data then stored it in the DB)
259
-     *                             you may want to skip this step.
260
-     */
261
-    public function receive_form_submission($req_data = null, $validate = true)
262
-    {
263
-        $req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__req_data', $req_data, $this,
264
-            $validate);
265
-        if ($req_data === null) {
266
-            $req_data = array_merge($_GET, $_POST);
267
-        }
268
-        $req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__request_data', $req_data,
269
-            $this);
270
-        $this->_normalize($req_data);
271
-        if ($validate) {
272
-            $this->_validate();
273
-            //if it's invalid, we're going to want to re-display so remember what they submitted
274
-            if (! $this->is_valid()) {
275
-                $this->store_submitted_form_data_in_session();
276
-            }
277
-        }
278
-        do_action('AHEE__EE_Form_Section_Proper__receive_form_submission__end', $req_data, $this, $validate);
279
-    }
280
-
281
-
282
-
283
-    /**
284
-     * caches the originally submitted input values in the session
285
-     * so that they can be used to repopulate the form if it failed validation
286
-     *
287
-     * @return boolean whether or not the data was successfully stored in the session
288
-     */
289
-    protected function store_submitted_form_data_in_session()
290
-    {
291
-        return EE_Registry::instance()->SSN->set_session_data(
292
-            array(
293
-                \EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
294
-            )
295
-        );
296
-    }
297
-
298
-
299
-
300
-    /**
301
-     * retrieves the originally submitted input values in the session
302
-     * so that they can be used to repopulate the form if it failed validation
303
-     *
304
-     * @return array
305
-     */
306
-    protected function get_submitted_form_data_from_session()
307
-    {
308
-        $session = EE_Registry::instance()->SSN;
309
-        if ($session instanceof EE_Session) {
310
-            return $session->get_session_data(
311
-                \EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
312
-            );
313
-        } else {
314
-            return array();
315
-        }
316
-    }
317
-
318
-
319
-
320
-    /**
321
-     * flushed the originally submitted input values from the session
322
-     *
323
-     * @return boolean whether or not the data was successfully removed from the session
324
-     */
325
-    protected function flush_submitted_form_data_from_session()
326
-    {
327
-        return EE_Registry::instance()->SSN->reset_data(
328
-            array(\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
329
-        );
330
-    }
331
-
332
-
333
-
334
-    /**
335
-     * Populates this form and its subsections with data from the session.
336
-     * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
337
-     * validation errors when displaying too)
338
-     * Returns true if the form was populated from the session, false otherwise
339
-     *
340
-     * @return boolean
341
-     */
342
-    public function populate_from_session()
343
-    {
344
-        $form_data_in_session = $this->get_submitted_form_data_from_session();
345
-        if (empty($form_data_in_session)) {
346
-            return false;
347
-        }
348
-        $this->receive_form_submission($form_data_in_session);
349
-        $this->flush_submitted_form_data_from_session();
350
-        if ($this->form_data_present_in($form_data_in_session)) {
351
-            return true;
352
-        } else {
353
-            return false;
354
-        }
355
-    }
356
-
357
-
358
-
359
-    /**
360
-     * Populates the default data for the form, given an array where keys are
361
-     * the input names, and values are their values (preferably normalized to be their
362
-     * proper PHP types, not all strings... although that should be ok too).
363
-     * Proper subsections are sub-arrays, the key being the subsection's name, and
364
-     * the value being an array formatted in teh same way
365
-     *
366
-     * @param array $default_data
367
-     */
368
-    public function populate_defaults($default_data)
369
-    {
370
-        foreach ($this->subsections(false) as $subsection_name => $subsection) {
371
-            if (isset($default_data[$subsection_name])) {
372
-                if ($subsection instanceof EE_Form_Input_Base) {
373
-                    $subsection->set_default($default_data[$subsection_name]);
374
-                } elseif ($subsection instanceof EE_Form_Section_Proper) {
375
-                    $subsection->populate_defaults($default_data[$subsection_name]);
376
-                }
377
-            }
378
-        }
379
-    }
380
-
381
-
382
-
383
-    /**
384
-     * returns true if subsection exists
385
-     *
386
-     * @param string $name
387
-     * @return boolean
388
-     */
389
-    public function subsection_exists($name)
390
-    {
391
-        return isset($this->_subsections[$name]) ? true : false;
392
-    }
393
-
394
-
395
-
396
-    /**
397
-     * Gets the subsection specified by its name
398
-     *
399
-     * @param string  $name
400
-     * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
401
-     *                                                      so that the inputs will be properly configured.
402
-     *                                                      However, some client code may be ok
403
-     *                                                      with construction finalize being called later
404
-     *                                                      (realizing that the subsections' html names
405
-     *                                                      might not be set yet, etc.)
406
-     * @return EE_Form_Section_Base
407
-     * @throws \EE_Error
408
-     */
409
-    public function get_subsection($name, $require_construction_to_be_finalized = true)
410
-    {
411
-        if ($require_construction_to_be_finalized) {
412
-            $this->ensure_construct_finalized_called();
413
-        }
414
-        return $this->subsection_exists($name) ? $this->_subsections[$name] : null;
415
-    }
416
-
417
-
418
-
419
-    /**
420
-     * Gets all the validatable subsections of this form section
421
-     *
422
-     * @return EE_Form_Section_Validatable[]
423
-     */
424
-    public function get_validatable_subsections()
425
-    {
426
-        $validatable_subsections = array();
427
-        foreach ($this->subsections() as $name => $obj) {
428
-            if ($obj instanceof EE_Form_Section_Validatable) {
429
-                $validatable_subsections[$name] = $obj;
430
-            }
431
-        }
432
-        return $validatable_subsections;
433
-    }
434
-
435
-
436
-
437
-    /**
438
-     * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
439
-     * throw an EE_Error.
440
-     *
441
-     * @param string  $name
442
-     * @param boolean $require_construction_to_be_finalized most client code should
443
-     *                                                      leave this as TRUE so that the inputs will be properly
444
-     *                                                      configured. However, some client code may be ok with
445
-     *                                                      construction finalize being called later
446
-     *                                                      (realizing that the subsections' html names might not be
447
-     *                                                      set yet, etc.)
448
-     * @return EE_Form_Input_Base
449
-     * @throws EE_Error
450
-     */
451
-    public function get_input($name, $require_construction_to_be_finalized = true)
452
-    {
453
-        $subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
454
-        if (! $subsection instanceof EE_Form_Input_Base) {
455
-            throw new EE_Error(
456
-                sprintf(
457
-                    __(
458
-                        "Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
459
-                        'event_espresso'
460
-                    ),
461
-                    $name,
462
-                    get_class($this),
463
-                    $subsection ? get_class($subsection) : __("NULL", 'event_espresso')
464
-                )
465
-            );
466
-        }
467
-        return $subsection;
468
-    }
469
-
470
-
471
-
472
-    /**
473
-     * Like get_input(), gets the proper subsection of the form given the name,
474
-     * otherwise throws an EE_Error
475
-     *
476
-     * @param string  $name
477
-     * @param boolean $require_construction_to_be_finalized most client code should
478
-     *                                                      leave this as TRUE so that the inputs will be properly
479
-     *                                                      configured. However, some client code may be ok with
480
-     *                                                      construction finalize being called later
481
-     *                                                      (realizing that the subsections' html names might not be
482
-     *                                                      set yet, etc.)
483
-     * @return EE_Form_Section_Proper
484
-     * @throws EE_Error
485
-     */
486
-    public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
487
-    {
488
-        $subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
489
-        if (! $subsection instanceof EE_Form_Section_Proper) {
490
-            throw new EE_Error(
491
-                sprintf(
492
-                    __("Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'", 'event_espresso'),
493
-                    $name,
494
-                    get_class($this)
495
-                )
496
-            );
497
-        }
498
-        return $subsection;
499
-    }
500
-
501
-
502
-
503
-    /**
504
-     * Gets the value of the specified input. Should be called after receive_form_submission()
505
-     * or populate_defaults() on the form, where the normalized value on the input is set.
506
-     *
507
-     * @param string $name
508
-     * @return mixed depending on the input's type and its normalization strategy
509
-     * @throws \EE_Error
510
-     */
511
-    public function get_input_value($name)
512
-    {
513
-        $input = $this->get_input($name);
514
-        return $input->normalized_value();
515
-    }
516
-
517
-
518
-
519
-    /**
520
-     * Checks if this form section itself is valid, and then checks its subsections
521
-     *
522
-     * @throws EE_Error
523
-     * @return boolean
524
-     */
525
-    public function is_valid()
526
-    {
527
-        if (! $this->has_received_submission()) {
528
-            throw new EE_Error(
529
-                sprintf(
530
-                    __(
531
-                        "You cannot check if a form is valid before receiving the form submission using receive_form_submission",
532
-                        "event_espresso"
533
-                    )
534
-                )
535
-            );
536
-        }
537
-        if (! parent::is_valid()) {
538
-            return false;
539
-        }
540
-        // ok so no general errors to this entire form section.
541
-        // so let's check the subsections, but only set errors if that hasn't been done yet
542
-        $set_submission_errors = $this->submission_error_message() === '' ? true : false;
543
-        foreach ($this->get_validatable_subsections() as $subsection) {
544
-            if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
545
-                if ($set_submission_errors) {
546
-                    $this->set_submission_error_message($subsection->get_validation_error_string());
547
-                }
548
-                return false;
549
-            }
550
-        }
551
-        return true;
552
-    }
553
-
554
-
555
-
556
-    /**
557
-     * gets teh default name of this form section if none is specified
558
-     *
559
-     * @return string
560
-     */
561
-    protected function _set_default_name_if_empty()
562
-    {
563
-        if (! $this->_name) {
564
-            $classname = get_class($this);
565
-            $default_name = str_replace("EE_", "", $classname);
566
-            $this->_name = $default_name;
567
-        }
568
-    }
569
-
570
-
571
-
572
-    /**
573
-     * Returns the HTML for the form, except for the form opening and closing tags
574
-     * (as the form section doesn't know where you necessarily want to send the information to),
575
-     * and except for a submit button. Enqueus JS and CSS; if called early enough we will
576
-     * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
577
-     * Not doing_it_wrong because theoretically this CAN be used properly,
578
-     * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
579
-     * any CSS.
580
-     *
581
-     * @throws \EE_Error
582
-     */
583
-    public function get_html_and_js()
584
-    {
585
-        $this->enqueue_js();
586
-        return $this->get_html();
587
-    }
588
-
589
-
590
-
591
-    /**
592
-     * returns HTML for displaying this form section. recursively calls display_section() on all subsections
593
-     *
594
-     * @param bool $display_previously_submitted_data
595
-     * @return string
596
-     */
597
-    public function get_html($display_previously_submitted_data = true)
598
-    {
599
-        $this->ensure_construct_finalized_called();
600
-        if ($display_previously_submitted_data) {
601
-            $this->populate_from_session();
602
-        }
603
-        return $this->_form_html_parser
604
-            ? $this->_form_html_parser->parseHtml($this->_layout_strategy->layout_form(), $this)
605
-            : $this->_layout_strategy->layout_form();
606
-    }
607
-
608
-
609
-
610
-    /**
611
-     * enqueues JS and CSS for the form.
612
-     * It is preferred to call this before wp_enqueue_scripts so the
613
-     * scripts and styles can be put in the header, but if called later
614
-     * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
615
-     * only be in the header; but in HTML5 its ok in the body.
616
-     * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
617
-     * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
618
-     *
619
-     * @return string
620
-     * @throws \EE_Error
621
-     */
622
-    public function enqueue_js()
623
-    {
624
-        $this->_enqueue_and_localize_form_js();
625
-        foreach ($this->subsections() as $subsection) {
626
-            $subsection->enqueue_js();
627
-        }
628
-    }
629
-
630
-
631
-
632
-    /**
633
-     * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
634
-     * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
635
-     * the wp_enqueue_scripts hook.
636
-     * However, registering the form js and localizing it can happen when we
637
-     * actually output the form (which is preferred, seeing how teh form's fields
638
-     * could change until it's actually outputted)
639
-     *
640
-     * @param boolean $init_form_validation_automatically whether or not we want the form validation
641
-     *                                                    to be triggered automatically or not
642
-     * @return void
643
-     */
644
-    public static function wp_enqueue_scripts($init_form_validation_automatically = true)
645
-    {
646
-        add_filter('FHEE_load_jquery_validate', '__return_true');
647
-        wp_register_script(
648
-            'ee_form_section_validation',
649
-            EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
650
-            array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
651
-            EVENT_ESPRESSO_VERSION,
652
-            true
653
-        );
654
-        wp_localize_script(
655
-            'ee_form_section_validation',
656
-            'ee_form_section_validation_init',
657
-            array('init' => $init_form_validation_automatically ? true : false)
658
-        );
659
-    }
660
-
661
-
662
-
663
-    /**
664
-     * gets the variables used by form_section_validation.js.
665
-     * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
666
-     * but before the wordpress hook wp_loaded
667
-     *
668
-     * @throws \EE_Error
669
-     */
670
-    public function _enqueue_and_localize_form_js()
671
-    {
672
-        $this->ensure_construct_finalized_called();
673
-        //actually, we don't want to localize just yet. There may be other forms on the page.
674
-        //so we need to add our form section data to a static variable accessible by all form sections
675
-        //and localize it just before the footer
676
-        $this->localize_validation_rules();
677
-        add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
678
-        add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
679
-    }
680
-
681
-
682
-
683
-    /**
684
-     * add our form section data to a static variable accessible by all form sections
685
-     *
686
-     * @param bool $return_for_subsection
687
-     * @return void
688
-     * @throws \EE_Error
689
-     */
690
-    public function localize_validation_rules($return_for_subsection = false)
691
-    {
692
-        // we only want to localize vars ONCE for the entire form,
693
-        // so if the form section doesn't have a parent, then it must be the top dog
694
-        if ($return_for_subsection || ! $this->parent_section()) {
695
-            EE_Form_Section_Proper::$_js_localization['form_data'][$this->html_id()] = array(
696
-                'form_section_id'  => $this->html_id(true),
697
-                'validation_rules' => $this->get_jquery_validation_rules(),
698
-                'other_data'       => $this->get_other_js_data(),
699
-                'errors'           => $this->subsection_validation_errors_by_html_name(),
700
-            );
701
-            EE_Form_Section_Proper::$_scripts_localized = true;
702
-        }
703
-    }
704
-
705
-
706
-
707
-    /**
708
-     * Gets an array of extra data that will be useful for client-side javascript.
709
-     * This is primarily data added by inputs and forms in addition to any
710
-     * scripts they might enqueue
711
-     *
712
-     * @param array $form_other_js_data
713
-     * @return array
714
-     */
715
-    public function get_other_js_data($form_other_js_data = array())
716
-    {
717
-        foreach ($this->subsections() as $subsection) {
718
-            $form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
719
-        }
720
-        return $form_other_js_data;
721
-    }
722
-
723
-
724
-
725
-    /**
726
-     * Gets a flat array of inputs for this form section and its subsections.
727
-     * Keys are their form names, and values are the inputs themselves
728
-     *
729
-     * @return EE_Form_Input_Base
730
-     */
731
-    public function inputs_in_subsections()
732
-    {
733
-        $inputs = array();
734
-        foreach ($this->subsections() as $subsection) {
735
-            if ($subsection instanceof EE_Form_Input_Base) {
736
-                $inputs[$subsection->html_name()] = $subsection;
737
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
738
-                $inputs += $subsection->inputs_in_subsections();
739
-            }
740
-        }
741
-        return $inputs;
742
-    }
743
-
744
-
745
-
746
-    /**
747
-     * Gets a flat array of all the validation errors.
748
-     * Keys are html names (because those should be unique)
749
-     * and values are a string of all their validation errors
750
-     *
751
-     * @return string[]
752
-     */
753
-    public function subsection_validation_errors_by_html_name()
754
-    {
755
-        $inputs = $this->inputs();
756
-        $errors = array();
757
-        foreach ($inputs as $form_input) {
758
-            if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
759
-                $errors[$form_input->html_name()] = $form_input->get_validation_error_string();
760
-            }
761
-        }
762
-        return $errors;
763
-    }
764
-
765
-
766
-
767
-    /**
768
-     * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
769
-     * Should be setup by each form during the _enqueues_and_localize_form_js
770
-     */
771
-    public static function localize_script_for_all_forms()
772
-    {
773
-        //allow inputs and stuff to hook in their JS and stuff here
774
-        do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
775
-        EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
776
-        $email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
777
-            ? EE_Registry::instance()->CFG->registration->email_validation_level
778
-            : 'wp_default';
779
-        EE_Form_Section_Proper::$_js_localization['email_validation_level'] = $email_validation_level;
780
-        wp_enqueue_script('ee_form_section_validation');
781
-        wp_localize_script(
782
-            'ee_form_section_validation',
783
-            'ee_form_section_vars',
784
-            EE_Form_Section_Proper::$_js_localization
785
-        );
786
-    }
787
-
788
-
789
-
790
-    /**
791
-     * ensure_scripts_localized
792
-     */
793
-    public function ensure_scripts_localized()
794
-    {
795
-        if (! EE_Form_Section_Proper::$_scripts_localized) {
796
-            $this->_enqueue_and_localize_form_js();
797
-        }
798
-    }
799
-
800
-
801
-
802
-    /**
803
-     * Gets the hard-coded validation error messages to be used in the JS. The convention
804
-     * is that the key here should be the same as the custom validation rule put in the JS file
805
-     *
806
-     * @return array keys are custom validation rules, and values are internationalized strings
807
-     */
808
-    private static function _get_localized_error_messages()
809
-    {
810
-        return array(
811
-            'validUrl' => __("This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg", "event_espresso"),
812
-            'regex'    => __('Please check your input', 'event_espresso'),
813
-        );
814
-    }
815
-
816
-
817
-
818
-    /**
819
-     * @return array
820
-     */
821
-    public static function js_localization()
822
-    {
823
-        return self::$_js_localization;
824
-    }
825
-
826
-
827
-
828
-    /**
829
-     * @return array
830
-     */
831
-    public static function reset_js_localization()
832
-    {
833
-        self::$_js_localization = array();
834
-    }
835
-
836
-
837
-
838
-    /**
839
-     * Gets the JS to put inside the jquery validation rules for subsection of this form section.
840
-     * See parent function for more...
841
-     *
842
-     * @return array
843
-     */
844
-    public function get_jquery_validation_rules()
845
-    {
846
-        $jquery_validation_rules = array();
847
-        foreach ($this->get_validatable_subsections() as $subsection) {
848
-            $jquery_validation_rules = array_merge(
849
-                $jquery_validation_rules,
850
-                $subsection->get_jquery_validation_rules()
851
-            );
852
-        }
853
-        return $jquery_validation_rules;
854
-    }
855
-
856
-
857
-
858
-    /**
859
-     * Sanitizes all the data and sets the sanitized value of each field
860
-     *
861
-     * @param array $req_data like $_POST
862
-     * @return void
863
-     */
864
-    protected function _normalize($req_data)
865
-    {
866
-        $this->_received_submission = true;
867
-        $this->_validation_errors = array();
868
-        foreach ($this->get_validatable_subsections() as $subsection) {
869
-            try {
870
-                $subsection->_normalize($req_data);
871
-            } catch (EE_Validation_Error $e) {
872
-                $subsection->add_validation_error($e);
873
-            }
874
-        }
875
-    }
876
-
877
-
878
-
879
-    /**
880
-     * Performs validation on this form section and its subsections.
881
-     * For each subsection,
882
-     * calls _validate_{subsection_name} on THIS form (if the function exists)
883
-     * and passes it the subsection, then calls _validate on that subsection.
884
-     * If you need to perform validation on the form as a whole (considering multiple)
885
-     * you would be best to override this _validate method,
886
-     * calling parent::_validate() first.
887
-     */
888
-    protected function _validate()
889
-    {
890
-        foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
891
-            if (method_exists($this, '_validate_' . $subsection_name)) {
892
-                call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
893
-            }
894
-            $subsection->_validate();
895
-        }
896
-    }
897
-
898
-
899
-
900
-    /**
901
-     * Gets all the validated inputs for the form section
902
-     *
903
-     * @return array
904
-     */
905
-    public function valid_data()
906
-    {
907
-        $inputs = array();
908
-        foreach ($this->subsections() as $subsection_name => $subsection) {
909
-            if ($subsection instanceof EE_Form_Section_Proper) {
910
-                $inputs[$subsection_name] = $subsection->valid_data();
911
-            } else if ($subsection instanceof EE_Form_Input_Base) {
912
-                $inputs[$subsection_name] = $subsection->normalized_value();
913
-            }
914
-        }
915
-        return $inputs;
916
-    }
917
-
918
-
919
-
920
-    /**
921
-     * Gets all the inputs on this form section
922
-     *
923
-     * @return EE_Form_Input_Base[]
924
-     */
925
-    public function inputs()
926
-    {
927
-        $inputs = array();
928
-        foreach ($this->subsections() as $subsection_name => $subsection) {
929
-            if ($subsection instanceof EE_Form_Input_Base) {
930
-                $inputs[$subsection_name] = $subsection;
931
-            }
932
-        }
933
-        return $inputs;
934
-    }
935
-
936
-
937
-
938
-    /**
939
-     * Gets all the subsections which are a proper form
940
-     *
941
-     * @return EE_Form_Section_Proper[]
942
-     */
943
-    public function subforms()
944
-    {
945
-        $form_sections = array();
946
-        foreach ($this->subsections() as $name => $obj) {
947
-            if ($obj instanceof EE_Form_Section_Proper) {
948
-                $form_sections[$name] = $obj;
949
-            }
950
-        }
951
-        return $form_sections;
952
-    }
953
-
954
-
955
-
956
-    /**
957
-     * Gets all the subsections (inputs, proper subsections, or html-only sections).
958
-     * Consider using inputs() or subforms()
959
-     * if you only want form inputs or proper form sections.
960
-     *
961
-     * @param boolean $require_construction_to_be_finalized most client code should
962
-     *                                                      leave this as TRUE so that the inputs will be properly
963
-     *                                                      configured. However, some client code may be ok with
964
-     *                                                      construction finalize being called later
965
-     *                                                      (realizing that the subsections' html names might not be
966
-     *                                                      set yet, etc.)
967
-     * @return EE_Form_Section_Proper[]
968
-     */
969
-    public function subsections($require_construction_to_be_finalized = true)
970
-    {
971
-        if ($require_construction_to_be_finalized) {
972
-            $this->ensure_construct_finalized_called();
973
-        }
974
-        return $this->_subsections;
975
-    }
976
-
977
-
978
-
979
-    /**
980
-     * Returns a simple array where keys are input names, and values are their normalized
981
-     * values. (Similar to calling get_input_value on inputs)
982
-     *
983
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
984
-     *                                        or just this forms' direct children inputs
985
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
986
-     *                                        or allow multidimensional array
987
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
988
-     *                                        with array keys being input names
989
-     *                                        (regardless of whether they are from a subsection or not),
990
-     *                                        and if $flatten is FALSE it can be a multidimensional array
991
-     *                                        where keys are always subsection names and values are either
992
-     *                                        the input's normalized value, or an array like the top-level array
993
-     */
994
-    public function input_values($include_subform_inputs = false, $flatten = false)
995
-    {
996
-        return $this->_input_values(false, $include_subform_inputs, $flatten);
997
-    }
998
-
999
-
1000
-
1001
-    /**
1002
-     * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
1003
-     * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
1004
-     * is not necessarily the value we want to display to users. This creates an array
1005
-     * where keys are the input names, and values are their display values
1006
-     *
1007
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1008
-     *                                        or just this forms' direct children inputs
1009
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1010
-     *                                        or allow multidimensional array
1011
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
1012
-     *                                        with array keys being input names
1013
-     *                                        (regardless of whether they are from a subsection or not),
1014
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1015
-     *                                        where keys are always subsection names and values are either
1016
-     *                                        the input's normalized value, or an array like the top-level array
1017
-     */
1018
-    public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1019
-    {
1020
-        return $this->_input_values(true, $include_subform_inputs, $flatten);
1021
-    }
1022
-
1023
-
1024
-
1025
-    /**
1026
-     * Gets the input values from the form
1027
-     *
1028
-     * @param boolean $pretty                 Whether to retrieve the pretty value,
1029
-     *                                        or just the normalized value
1030
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1031
-     *                                        or just this forms' direct children inputs
1032
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1033
-     *                                        or allow multidimensional array
1034
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1035
-     *                                        input names (regardless of whether they are from a subsection or not),
1036
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1037
-     *                                        where keys are always subsection names and values are either
1038
-     *                                        the input's normalized value, or an array like the top-level array
1039
-     */
1040
-    public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1041
-    {
1042
-        $input_values = array();
1043
-        foreach ($this->subsections() as $subsection_name => $subsection) {
1044
-            if ($subsection instanceof EE_Form_Input_Base) {
1045
-                $input_values[$subsection_name] = $pretty
1046
-                    ? $subsection->pretty_value()
1047
-                    : $subsection->normalized_value();
1048
-            } else if ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1049
-                $subform_input_values = $subsection->_input_values($pretty, $include_subform_inputs, $flatten);
1050
-                if ($flatten) {
1051
-                    $input_values = array_merge($input_values, $subform_input_values);
1052
-                } else {
1053
-                    $input_values[$subsection_name] = $subform_input_values;
1054
-                }
1055
-            }
1056
-        }
1057
-        return $input_values;
1058
-    }
1059
-
1060
-
1061
-
1062
-    /**
1063
-     * Gets the originally submitted input values from the form
1064
-     *
1065
-     * @param boolean $include_subforms  Whether to include inputs from subforms,
1066
-     *                                   or just this forms' direct children inputs
1067
-     * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1068
-     *                                   with array keys being input names
1069
-     *                                   (regardless of whether they are from a subsection or not),
1070
-     *                                   and if $flatten is FALSE it can be a multidimensional array
1071
-     *                                   where keys are always subsection names and values are either
1072
-     *                                   the input's normalized value, or an array like the top-level array
1073
-     */
1074
-    public function submitted_values($include_subforms = false)
1075
-    {
1076
-        $submitted_values = array();
1077
-        foreach ($this->subsections() as $subsection) {
1078
-            if ($subsection instanceof EE_Form_Input_Base) {
1079
-                // is this input part of an array of inputs?
1080
-                if (strpos($subsection->html_name(), '[') !== false) {
1081
-                    $full_input_name = \EEH_Array::convert_array_values_to_keys(
1082
-                        explode('[', str_replace(']', '', $subsection->html_name())),
1083
-                        $subsection->raw_value()
1084
-                    );
1085
-                    $submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1086
-                } else {
1087
-                    $submitted_values[$subsection->html_name()] = $subsection->raw_value();
1088
-                }
1089
-            } else if ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1090
-                $subform_input_values = $subsection->submitted_values($include_subforms);
1091
-                $submitted_values = array_replace_recursive($submitted_values, $subform_input_values);
1092
-            }
1093
-        }
1094
-        return $submitted_values;
1095
-    }
1096
-
1097
-
1098
-
1099
-    /**
1100
-     * Indicates whether or not this form has received a submission yet
1101
-     * (ie, had receive_form_submission called on it yet)
1102
-     *
1103
-     * @return boolean
1104
-     * @throws \EE_Error
1105
-     */
1106
-    public function has_received_submission()
1107
-    {
1108
-        $this->ensure_construct_finalized_called();
1109
-        return $this->_received_submission;
1110
-    }
1111
-
1112
-
1113
-
1114
-    /**
1115
-     * Equivalent to passing 'exclude' in the constructor's options array.
1116
-     * Removes the listed inputs from the form
1117
-     *
1118
-     * @param array $inputs_to_exclude values are the input names
1119
-     * @return void
1120
-     */
1121
-    public function exclude(array $inputs_to_exclude = array())
1122
-    {
1123
-        foreach ($inputs_to_exclude as $input_to_exclude_name) {
1124
-            unset($this->_subsections[$input_to_exclude_name]);
1125
-        }
1126
-    }
1127
-
1128
-
1129
-
1130
-    /**
1131
-     * @param array $inputs_to_hide
1132
-     * @throws \EE_Error
1133
-     */
1134
-    public function hide(array $inputs_to_hide = array())
1135
-    {
1136
-        foreach ($inputs_to_hide as $input_to_hide) {
1137
-            $input = $this->get_input($input_to_hide);
1138
-            $input->set_display_strategy(new EE_Hidden_Display_Strategy());
1139
-        }
1140
-    }
1141
-
1142
-
1143
-
1144
-    /**
1145
-     * add_subsections
1146
-     * Adds the listed subsections to the form section.
1147
-     * If $subsection_name_to_target is provided,
1148
-     * then new subsections are added before or after that subsection,
1149
-     * otherwise to the start or end of the entire subsections array.
1150
-     *
1151
-     * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1152
-     *                                                          where keys are their names
1153
-     * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1154
-     *                                                          should be added before or after
1155
-     *                                                          IF $subsection_name_to_target is null,
1156
-     *                                                          then $new_subsections will be added to
1157
-     *                                                          the beginning or end of the entire subsections array
1158
-     * @param boolean                $add_before                whether to add $new_subsections, before or after
1159
-     *                                                          $subsection_name_to_target,
1160
-     *                                                          or if $subsection_name_to_target is null,
1161
-     *                                                          before or after entire subsections array
1162
-     * @return void
1163
-     * @throws \EE_Error
1164
-     */
1165
-    public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1166
-    {
1167
-        foreach ($new_subsections as $subsection_name => $subsection) {
1168
-            if (! $subsection instanceof EE_Form_Section_Base) {
1169
-                EE_Error::add_error(
1170
-                    sprintf(
1171
-                        __(
1172
-                            "Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1173
-                            "event_espresso"
1174
-                        ),
1175
-                        get_class($subsection),
1176
-                        $subsection_name,
1177
-                        $this->name()
1178
-                    )
1179
-                );
1180
-                unset($new_subsections[$subsection_name]);
1181
-            }
1182
-        }
1183
-        $this->_subsections = EEH_Array::insert_into_array(
1184
-            $this->_subsections,
1185
-            $new_subsections,
1186
-            $subsection_name_to_target,
1187
-            $add_before
1188
-        );
1189
-        if ($this->_construction_finalized) {
1190
-            foreach ($this->_subsections as $name => $subsection) {
1191
-                $subsection->_construct_finalize($this, $name);
1192
-            }
1193
-        }
1194
-    }
1195
-
1196
-
1197
-
1198
-    /**
1199
-     * Just gets all validatable subsections to clean their sensitive data
1200
-     */
1201
-    public function clean_sensitive_data()
1202
-    {
1203
-        foreach ($this->get_validatable_subsections() as $subsection) {
1204
-            $subsection->clean_sensitive_data();
1205
-        }
1206
-    }
1207
-
1208
-
1209
-
1210
-    /**
1211
-     * @param string $form_submission_error_message
1212
-     */
1213
-    public function set_submission_error_message($form_submission_error_message = '')
1214
-    {
1215
-        $this->_form_submission_error_message .= ! empty($form_submission_error_message)
1216
-            ? $form_submission_error_message
1217
-            : __('Form submission failed due to errors', 'event_espresso');
1218
-    }
1219
-
1220
-
1221
-
1222
-    /**
1223
-     * @return string
1224
-     */
1225
-    public function submission_error_message()
1226
-    {
1227
-        return $this->_form_submission_error_message;
1228
-    }
1229
-
1230
-
1231
-
1232
-    /**
1233
-     * @param string $form_submission_success_message
1234
-     */
1235
-    public function set_submission_success_message($form_submission_success_message)
1236
-    {
1237
-        $this->_form_submission_success_message .= ! empty($form_submission_success_message)
1238
-            ? $form_submission_success_message
1239
-            : __('Form submitted successfully', 'event_espresso');
1240
-    }
1241
-
1242
-
1243
-
1244
-    /**
1245
-     * @return string
1246
-     */
1247
-    public function submission_success_message()
1248
-    {
1249
-        return $this->_form_submission_success_message;
1250
-    }
1251
-
1252
-
1253
-
1254
-    /**
1255
-     * Returns the prefix that should be used on child of this form section for
1256
-     * their html names. If this form section itself has a parent, prepends ITS
1257
-     * prefix onto this form section's prefix. Used primarily by
1258
-     * EE_Form_Input_Base::_set_default_html_name_if_empty
1259
-     *
1260
-     * @return string
1261
-     * @throws \EE_Error
1262
-     */
1263
-    public function html_name_prefix()
1264
-    {
1265
-        if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1266
-            return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1267
-        } else {
1268
-            return $this->name();
1269
-        }
1270
-    }
1271
-
1272
-
1273
-
1274
-    /**
1275
-     * Gets the name, but first checks _construct_finalize has been called. If not,
1276
-     * calls it (assumes there is no parent and that we want the name to be whatever
1277
-     * was set, which is probably nothing, or the classname)
1278
-     *
1279
-     * @return string
1280
-     * @throws \EE_Error
1281
-     */
1282
-    public function name()
1283
-    {
1284
-        $this->ensure_construct_finalized_called();
1285
-        return parent::name();
1286
-    }
1287
-
1288
-
1289
-
1290
-    /**
1291
-     * @return EE_Form_Section_Proper
1292
-     * @throws \EE_Error
1293
-     */
1294
-    public function parent_section()
1295
-    {
1296
-        $this->ensure_construct_finalized_called();
1297
-        return parent::parent_section();
1298
-    }
1299
-
1300
-
1301
-
1302
-    /**
1303
-     * make sure construction finalized was called, otherwise children might not be ready
1304
-     *
1305
-     * @return void
1306
-     * @throws \EE_Error
1307
-     */
1308
-    public function ensure_construct_finalized_called()
1309
-    {
1310
-        if (! $this->_construction_finalized) {
1311
-            $this->_construct_finalize($this->_parent_section, $this->_name);
1312
-        }
1313
-    }
1314
-
1315
-
1316
-
1317
-    /**
1318
-     * Checks if any of this form section's inputs, or any of its children's inputs,
1319
-     * are in teh form data. If any are found, returns true. Else false
1320
-     *
1321
-     * @param array $req_data
1322
-     * @return boolean
1323
-     */
1324
-    public function form_data_present_in($req_data = null)
1325
-    {
1326
-        if ($req_data === null) {
1327
-            $req_data = $_POST;
1328
-        }
1329
-        foreach ($this->subsections() as $subsection) {
1330
-            if ($subsection instanceof EE_Form_Input_Base) {
1331
-                if ($subsection->form_data_present_in($req_data)) {
1332
-                    return true;
1333
-                }
1334
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
1335
-                if ($subsection->form_data_present_in($req_data)) {
1336
-                    return true;
1337
-                }
1338
-            }
1339
-        }
1340
-        return false;
1341
-    }
1342
-
1343
-
1344
-
1345
-    /**
1346
-     * Gets validation errors for this form section and subsections
1347
-     * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1348
-     * gets the validation errors for ALL subsection
1349
-     *
1350
-     * @return EE_Validation_Error[]
1351
-     */
1352
-    public function get_validation_errors_accumulated()
1353
-    {
1354
-        $validation_errors = $this->get_validation_errors();
1355
-        foreach ($this->get_validatable_subsections() as $subsection) {
1356
-            if ($subsection instanceof EE_Form_Section_Proper) {
1357
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1358
-            } else {
1359
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors();
1360
-            }
1361
-            if ($validation_errors_on_this_subsection) {
1362
-                $validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1363
-            }
1364
-        }
1365
-        return $validation_errors;
1366
-    }
1367
-
1368
-
1369
-
1370
-    /**
1371
-     * This isn't just the name of an input, it's a path pointing to an input. The
1372
-     * path is similar to a folder path: slash (/) means to descend into a subsection,
1373
-     * dot-dot-slash (../) means to ascend into the parent section.
1374
-     * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1375
-     * which will be returned.
1376
-     * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1377
-     * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1378
-     * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1379
-     * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1380
-     * Etc
1381
-     *
1382
-     * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1383
-     * @return EE_Form_Section_Base
1384
-     */
1385
-    public function find_section_from_path($form_section_path)
1386
-    {
1387
-        //check if we can find the input from purely going straight up the tree
1388
-        $input = parent::find_section_from_path($form_section_path);
1389
-        if ($input instanceof EE_Form_Section_Base) {
1390
-            return $input;
1391
-        }
1392
-        $next_slash_pos = strpos($form_section_path, '/');
1393
-        if ($next_slash_pos !== false) {
1394
-            $child_section_name = substr($form_section_path, 0, $next_slash_pos);
1395
-            $subpath = substr($form_section_path, $next_slash_pos + 1);
1396
-        } else {
1397
-            $child_section_name = $form_section_path;
1398
-            $subpath = '';
1399
-        }
1400
-        $child_section = $this->get_subsection($child_section_name);
1401
-        if ($child_section instanceof EE_Form_Section_Base) {
1402
-            return $child_section->find_section_from_path($subpath);
1403
-        } else {
1404
-            return null;
1405
-        }
1406
-    }
15
+	const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
16
+
17
+	/**
18
+	 * Subsections
19
+	 *
20
+	 * @var EE_Form_Section_Validatable[]
21
+	 */
22
+	protected $_subsections = array();
23
+
24
+	/**
25
+	 * Strategy for laying out the form
26
+	 *
27
+	 * @var EE_Form_Section_Layout_Base
28
+	 */
29
+	protected $_layout_strategy;
30
+
31
+	/**
32
+	 * Strategy for parsing the form HTML upon display
33
+	 *
34
+	 * @var FormHtmlParser
35
+	 */
36
+	protected $_form_html_parser;
37
+
38
+	/**
39
+	 * Whether or not this form has received and validated a form submission yet
40
+	 *
41
+	 * @var boolean
42
+	 */
43
+	protected $_received_submission = false;
44
+
45
+	/**
46
+	 * message displayed to users upon successful form submission
47
+	 *
48
+	 * @var string
49
+	 */
50
+	protected $_form_submission_success_message = '';
51
+
52
+	/**
53
+	 * message displayed to users upon unsuccessful form submission
54
+	 *
55
+	 * @var string
56
+	 */
57
+	protected $_form_submission_error_message = '';
58
+
59
+	/**
60
+	 * Stores all the data that will localized for form validation
61
+	 *
62
+	 * @var array
63
+	 */
64
+	static protected $_js_localization = array();
65
+
66
+	/**
67
+	 * whether or not the form's localized validation JS vars have been set
68
+	 *
69
+	 * @type boolean
70
+	 */
71
+	static protected $_scripts_localized = false;
72
+
73
+
74
+
75
+	/**
76
+	 * when constructing a proper form section, calls _construct_finalize on children
77
+	 * so that they know who their parent is, and what name they've been given.
78
+	 *
79
+	 * @param array $options_array   {
80
+	 * @type        $subsections     EE_Form_Section_Validatable[] where keys are the section's name
81
+	 * @type        $include         string[] numerically-indexed where values are section names to be included,
82
+	 *                               and in that order. This is handy if you want
83
+	 *                               the subsections to be ordered differently than the default, and if you override
84
+	 *                               which fields are shown
85
+	 * @type        $exclude         string[] values are subsections to be excluded. This is handy if you want
86
+	 *                               to remove certain default subsections (note: if you specify BOTH 'include' AND
87
+	 *                               'exclude', the inclusions will be applied first, and the exclusions will exclude
88
+	 *                               items from that list of inclusions)
89
+	 * @type        $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
90
+	 *                               } @see EE_Form_Section_Validatable::__construct()
91
+	 * @throws \EE_Error
92
+	 */
93
+	public function __construct($options_array = array())
94
+	{
95
+		$options_array = (array)apply_filters('FHEE__EE_Form_Section_Proper___construct__options_array', $options_array,
96
+			$this);
97
+		//call parent first, as it may be setting the name
98
+		parent::__construct($options_array);
99
+		//if they've included subsections in the constructor, add them now
100
+		if (isset($options_array['include'])) {
101
+			//we are going to make sure we ONLY have those subsections to include
102
+			//AND we are going to make sure they're in that specified order
103
+			$reordered_subsections = array();
104
+			foreach ($options_array['include'] as $input_name) {
105
+				if (isset($this->_subsections[$input_name])) {
106
+					$reordered_subsections[$input_name] = $this->_subsections[$input_name];
107
+				}
108
+			}
109
+			$this->_subsections = $reordered_subsections;
110
+		}
111
+		if (isset($options_array['exclude'])) {
112
+			$exclude = $options_array['exclude'];
113
+			$this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
114
+		}
115
+		if (isset($options_array['layout_strategy'])) {
116
+			$this->_layout_strategy = $options_array['layout_strategy'];
117
+		}
118
+		if (! $this->_layout_strategy) {
119
+			$this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
120
+		}
121
+		$this->_layout_strategy->_construct_finalize($this);
122
+
123
+		// set parser which allows the form section's rendered HTML to be filtered
124
+		if (isset($options_array['form_html_parser']) && $options_array['form_html_parser'] instanceof FormHtmlParser) {
125
+			$this->_form_html_parser = $options_array['form_html_parser'];
126
+		}
127
+		//ok so we are definitely going to want the forms JS,
128
+		//so enqueue it or remember to enqueue it during wp_enqueue_scripts
129
+		if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
130
+			//ok so they've constructed this object after when they should have.
131
+			//just enqueue the generic form scripts and initialize the form immediately in the JS
132
+			\EE_Form_Section_Proper::wp_enqueue_scripts(true);
133
+		} else {
134
+			add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
135
+			add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
136
+		}
137
+		add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
138
+
139
+		/**
140
+		 * Gives other plugins a chance to hook in before construct finalize is called. The form probably doesn't
141
+		 * yet have a parent form section. Since 4.9.32, when this action was introduced, this is the best place to
142
+		 * add a subsection onto a form, assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
143
+		 * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
144
+		 * @since 4.9.32
145
+		 * @param EE_Form_Section_Proper $this before __construct is done, but all of its logic, except maybe calling
146
+		 *                                      _construct_finalize has been done
147
+		 * @param array $options_array options passed into the constructor
148
+		 */
149
+		do_action('AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called', $this, $options_array);
150
+
151
+		if (isset($options_array['name'])) {
152
+			$this->_construct_finalize(null, $options_array['name']);
153
+		}
154
+	}
155
+
156
+
157
+
158
+	/**
159
+	 * Finishes construction given the parent form section and this form section's name
160
+	 *
161
+	 * @param EE_Form_Section_Proper $parent_form_section
162
+	 * @param string                 $name
163
+	 * @throws \EE_Error
164
+	 */
165
+	public function _construct_finalize($parent_form_section, $name)
166
+	{
167
+		parent::_construct_finalize($parent_form_section, $name);
168
+		$this->_set_default_name_if_empty();
169
+		$this->_set_default_html_id_if_empty();
170
+		foreach ($this->_subsections as $subsection_name => $subsection) {
171
+			if ($subsection instanceof EE_Form_Section_Base) {
172
+				$subsection->_construct_finalize($this, $subsection_name);
173
+			} else {
174
+				throw new EE_Error(
175
+					sprintf(
176
+						__('Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
177
+							'event_espresso'),
178
+						$subsection_name,
179
+						get_class($this),
180
+						$subsection ? get_class($subsection) : __('NULL', 'event_espresso')
181
+					)
182
+				);
183
+			}
184
+		}
185
+		/**
186
+		 * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
187
+		 * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID (or other attributes derived
188
+		 * from the name like the HTML label id, etc), this is where it should be done.
189
+		 * This might only happen just before displaying the form, or just before it receives form submission data.
190
+		 * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
191
+		 * ensured it has a name, HTML IDs, etc
192
+		 * @param EE_Form_Section_Proper $this
193
+		 * @param EE_Form_Section_Proper|null $parent_form_section
194
+		 * @param string $name
195
+		 */
196
+		do_action('AHEE__EE_Form_Section_Proper___construct_finalize__end', $this, $parent_form_section, $name);
197
+	}
198
+
199
+
200
+
201
+	/**
202
+	 * Gets the layout strategy for this form section
203
+	 *
204
+	 * @return EE_Form_Section_Layout_Base
205
+	 */
206
+	public function get_layout_strategy()
207
+	{
208
+		return $this->_layout_strategy;
209
+	}
210
+
211
+
212
+
213
+	/**
214
+	 * Gets the HTML for a single input for this form section according
215
+	 * to the layout strategy
216
+	 *
217
+	 * @param EE_Form_Input_Base $input
218
+	 * @return string
219
+	 */
220
+	public function get_html_for_input($input)
221
+	{
222
+		return $this->_layout_strategy->layout_input($input);
223
+	}
224
+
225
+
226
+
227
+	/**
228
+	 * was_submitted - checks if form inputs are present in request data
229
+	 * Basically an alias for form_data_present_in() (which is used by both
230
+	 * proper form sections and form inputs)
231
+	 *
232
+	 * @param null $form_data
233
+	 * @return boolean
234
+	 */
235
+	public function was_submitted($form_data = null)
236
+	{
237
+		return $this->form_data_present_in($form_data);
238
+	}
239
+
240
+
241
+
242
+	/**
243
+	 * After the form section is initially created, call this to sanitize the data in the submission
244
+	 * which relates to this form section, validate it, and set it as properties on the form.
245
+	 *
246
+	 * @param array|null $req_data should usually be $_POST (the default).
247
+	 *                             However, you CAN supply a different array.
248
+	 *                             Consider using set_defaults() instead however.
249
+	 *                             (If you rendered the form in the page using echo $form_x->get_html()
250
+	 *                             the inputs will have the correct name in the request data for this function
251
+	 *                             to find them and populate the form with them.
252
+	 *                             If you have a flat form (with only input subsections),
253
+	 *                             you can supply a flat array where keys
254
+	 *                             are the form input names and values are their values)
255
+	 * @param boolean    $validate whether or not to perform validation on this data. Default is,
256
+	 *                             of course, to validate that data, and set errors on the invalid values.
257
+	 *                             But if the data has already been validated
258
+	 *                             (eg you validated the data then stored it in the DB)
259
+	 *                             you may want to skip this step.
260
+	 */
261
+	public function receive_form_submission($req_data = null, $validate = true)
262
+	{
263
+		$req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__req_data', $req_data, $this,
264
+			$validate);
265
+		if ($req_data === null) {
266
+			$req_data = array_merge($_GET, $_POST);
267
+		}
268
+		$req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__request_data', $req_data,
269
+			$this);
270
+		$this->_normalize($req_data);
271
+		if ($validate) {
272
+			$this->_validate();
273
+			//if it's invalid, we're going to want to re-display so remember what they submitted
274
+			if (! $this->is_valid()) {
275
+				$this->store_submitted_form_data_in_session();
276
+			}
277
+		}
278
+		do_action('AHEE__EE_Form_Section_Proper__receive_form_submission__end', $req_data, $this, $validate);
279
+	}
280
+
281
+
282
+
283
+	/**
284
+	 * caches the originally submitted input values in the session
285
+	 * so that they can be used to repopulate the form if it failed validation
286
+	 *
287
+	 * @return boolean whether or not the data was successfully stored in the session
288
+	 */
289
+	protected function store_submitted_form_data_in_session()
290
+	{
291
+		return EE_Registry::instance()->SSN->set_session_data(
292
+			array(
293
+				\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
294
+			)
295
+		);
296
+	}
297
+
298
+
299
+
300
+	/**
301
+	 * retrieves the originally submitted input values in the session
302
+	 * so that they can be used to repopulate the form if it failed validation
303
+	 *
304
+	 * @return array
305
+	 */
306
+	protected function get_submitted_form_data_from_session()
307
+	{
308
+		$session = EE_Registry::instance()->SSN;
309
+		if ($session instanceof EE_Session) {
310
+			return $session->get_session_data(
311
+				\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
312
+			);
313
+		} else {
314
+			return array();
315
+		}
316
+	}
317
+
318
+
319
+
320
+	/**
321
+	 * flushed the originally submitted input values from the session
322
+	 *
323
+	 * @return boolean whether or not the data was successfully removed from the session
324
+	 */
325
+	protected function flush_submitted_form_data_from_session()
326
+	{
327
+		return EE_Registry::instance()->SSN->reset_data(
328
+			array(\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
329
+		);
330
+	}
331
+
332
+
333
+
334
+	/**
335
+	 * Populates this form and its subsections with data from the session.
336
+	 * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
337
+	 * validation errors when displaying too)
338
+	 * Returns true if the form was populated from the session, false otherwise
339
+	 *
340
+	 * @return boolean
341
+	 */
342
+	public function populate_from_session()
343
+	{
344
+		$form_data_in_session = $this->get_submitted_form_data_from_session();
345
+		if (empty($form_data_in_session)) {
346
+			return false;
347
+		}
348
+		$this->receive_form_submission($form_data_in_session);
349
+		$this->flush_submitted_form_data_from_session();
350
+		if ($this->form_data_present_in($form_data_in_session)) {
351
+			return true;
352
+		} else {
353
+			return false;
354
+		}
355
+	}
356
+
357
+
358
+
359
+	/**
360
+	 * Populates the default data for the form, given an array where keys are
361
+	 * the input names, and values are their values (preferably normalized to be their
362
+	 * proper PHP types, not all strings... although that should be ok too).
363
+	 * Proper subsections are sub-arrays, the key being the subsection's name, and
364
+	 * the value being an array formatted in teh same way
365
+	 *
366
+	 * @param array $default_data
367
+	 */
368
+	public function populate_defaults($default_data)
369
+	{
370
+		foreach ($this->subsections(false) as $subsection_name => $subsection) {
371
+			if (isset($default_data[$subsection_name])) {
372
+				if ($subsection instanceof EE_Form_Input_Base) {
373
+					$subsection->set_default($default_data[$subsection_name]);
374
+				} elseif ($subsection instanceof EE_Form_Section_Proper) {
375
+					$subsection->populate_defaults($default_data[$subsection_name]);
376
+				}
377
+			}
378
+		}
379
+	}
380
+
381
+
382
+
383
+	/**
384
+	 * returns true if subsection exists
385
+	 *
386
+	 * @param string $name
387
+	 * @return boolean
388
+	 */
389
+	public function subsection_exists($name)
390
+	{
391
+		return isset($this->_subsections[$name]) ? true : false;
392
+	}
393
+
394
+
395
+
396
+	/**
397
+	 * Gets the subsection specified by its name
398
+	 *
399
+	 * @param string  $name
400
+	 * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
401
+	 *                                                      so that the inputs will be properly configured.
402
+	 *                                                      However, some client code may be ok
403
+	 *                                                      with construction finalize being called later
404
+	 *                                                      (realizing that the subsections' html names
405
+	 *                                                      might not be set yet, etc.)
406
+	 * @return EE_Form_Section_Base
407
+	 * @throws \EE_Error
408
+	 */
409
+	public function get_subsection($name, $require_construction_to_be_finalized = true)
410
+	{
411
+		if ($require_construction_to_be_finalized) {
412
+			$this->ensure_construct_finalized_called();
413
+		}
414
+		return $this->subsection_exists($name) ? $this->_subsections[$name] : null;
415
+	}
416
+
417
+
418
+
419
+	/**
420
+	 * Gets all the validatable subsections of this form section
421
+	 *
422
+	 * @return EE_Form_Section_Validatable[]
423
+	 */
424
+	public function get_validatable_subsections()
425
+	{
426
+		$validatable_subsections = array();
427
+		foreach ($this->subsections() as $name => $obj) {
428
+			if ($obj instanceof EE_Form_Section_Validatable) {
429
+				$validatable_subsections[$name] = $obj;
430
+			}
431
+		}
432
+		return $validatable_subsections;
433
+	}
434
+
435
+
436
+
437
+	/**
438
+	 * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
439
+	 * throw an EE_Error.
440
+	 *
441
+	 * @param string  $name
442
+	 * @param boolean $require_construction_to_be_finalized most client code should
443
+	 *                                                      leave this as TRUE so that the inputs will be properly
444
+	 *                                                      configured. However, some client code may be ok with
445
+	 *                                                      construction finalize being called later
446
+	 *                                                      (realizing that the subsections' html names might not be
447
+	 *                                                      set yet, etc.)
448
+	 * @return EE_Form_Input_Base
449
+	 * @throws EE_Error
450
+	 */
451
+	public function get_input($name, $require_construction_to_be_finalized = true)
452
+	{
453
+		$subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
454
+		if (! $subsection instanceof EE_Form_Input_Base) {
455
+			throw new EE_Error(
456
+				sprintf(
457
+					__(
458
+						"Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
459
+						'event_espresso'
460
+					),
461
+					$name,
462
+					get_class($this),
463
+					$subsection ? get_class($subsection) : __("NULL", 'event_espresso')
464
+				)
465
+			);
466
+		}
467
+		return $subsection;
468
+	}
469
+
470
+
471
+
472
+	/**
473
+	 * Like get_input(), gets the proper subsection of the form given the name,
474
+	 * otherwise throws an EE_Error
475
+	 *
476
+	 * @param string  $name
477
+	 * @param boolean $require_construction_to_be_finalized most client code should
478
+	 *                                                      leave this as TRUE so that the inputs will be properly
479
+	 *                                                      configured. However, some client code may be ok with
480
+	 *                                                      construction finalize being called later
481
+	 *                                                      (realizing that the subsections' html names might not be
482
+	 *                                                      set yet, etc.)
483
+	 * @return EE_Form_Section_Proper
484
+	 * @throws EE_Error
485
+	 */
486
+	public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
487
+	{
488
+		$subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
489
+		if (! $subsection instanceof EE_Form_Section_Proper) {
490
+			throw new EE_Error(
491
+				sprintf(
492
+					__("Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'", 'event_espresso'),
493
+					$name,
494
+					get_class($this)
495
+				)
496
+			);
497
+		}
498
+		return $subsection;
499
+	}
500
+
501
+
502
+
503
+	/**
504
+	 * Gets the value of the specified input. Should be called after receive_form_submission()
505
+	 * or populate_defaults() on the form, where the normalized value on the input is set.
506
+	 *
507
+	 * @param string $name
508
+	 * @return mixed depending on the input's type and its normalization strategy
509
+	 * @throws \EE_Error
510
+	 */
511
+	public function get_input_value($name)
512
+	{
513
+		$input = $this->get_input($name);
514
+		return $input->normalized_value();
515
+	}
516
+
517
+
518
+
519
+	/**
520
+	 * Checks if this form section itself is valid, and then checks its subsections
521
+	 *
522
+	 * @throws EE_Error
523
+	 * @return boolean
524
+	 */
525
+	public function is_valid()
526
+	{
527
+		if (! $this->has_received_submission()) {
528
+			throw new EE_Error(
529
+				sprintf(
530
+					__(
531
+						"You cannot check if a form is valid before receiving the form submission using receive_form_submission",
532
+						"event_espresso"
533
+					)
534
+				)
535
+			);
536
+		}
537
+		if (! parent::is_valid()) {
538
+			return false;
539
+		}
540
+		// ok so no general errors to this entire form section.
541
+		// so let's check the subsections, but only set errors if that hasn't been done yet
542
+		$set_submission_errors = $this->submission_error_message() === '' ? true : false;
543
+		foreach ($this->get_validatable_subsections() as $subsection) {
544
+			if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
545
+				if ($set_submission_errors) {
546
+					$this->set_submission_error_message($subsection->get_validation_error_string());
547
+				}
548
+				return false;
549
+			}
550
+		}
551
+		return true;
552
+	}
553
+
554
+
555
+
556
+	/**
557
+	 * gets teh default name of this form section if none is specified
558
+	 *
559
+	 * @return string
560
+	 */
561
+	protected function _set_default_name_if_empty()
562
+	{
563
+		if (! $this->_name) {
564
+			$classname = get_class($this);
565
+			$default_name = str_replace("EE_", "", $classname);
566
+			$this->_name = $default_name;
567
+		}
568
+	}
569
+
570
+
571
+
572
+	/**
573
+	 * Returns the HTML for the form, except for the form opening and closing tags
574
+	 * (as the form section doesn't know where you necessarily want to send the information to),
575
+	 * and except for a submit button. Enqueus JS and CSS; if called early enough we will
576
+	 * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
577
+	 * Not doing_it_wrong because theoretically this CAN be used properly,
578
+	 * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
579
+	 * any CSS.
580
+	 *
581
+	 * @throws \EE_Error
582
+	 */
583
+	public function get_html_and_js()
584
+	{
585
+		$this->enqueue_js();
586
+		return $this->get_html();
587
+	}
588
+
589
+
590
+
591
+	/**
592
+	 * returns HTML for displaying this form section. recursively calls display_section() on all subsections
593
+	 *
594
+	 * @param bool $display_previously_submitted_data
595
+	 * @return string
596
+	 */
597
+	public function get_html($display_previously_submitted_data = true)
598
+	{
599
+		$this->ensure_construct_finalized_called();
600
+		if ($display_previously_submitted_data) {
601
+			$this->populate_from_session();
602
+		}
603
+		return $this->_form_html_parser
604
+			? $this->_form_html_parser->parseHtml($this->_layout_strategy->layout_form(), $this)
605
+			: $this->_layout_strategy->layout_form();
606
+	}
607
+
608
+
609
+
610
+	/**
611
+	 * enqueues JS and CSS for the form.
612
+	 * It is preferred to call this before wp_enqueue_scripts so the
613
+	 * scripts and styles can be put in the header, but if called later
614
+	 * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
615
+	 * only be in the header; but in HTML5 its ok in the body.
616
+	 * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
617
+	 * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
618
+	 *
619
+	 * @return string
620
+	 * @throws \EE_Error
621
+	 */
622
+	public function enqueue_js()
623
+	{
624
+		$this->_enqueue_and_localize_form_js();
625
+		foreach ($this->subsections() as $subsection) {
626
+			$subsection->enqueue_js();
627
+		}
628
+	}
629
+
630
+
631
+
632
+	/**
633
+	 * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
634
+	 * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
635
+	 * the wp_enqueue_scripts hook.
636
+	 * However, registering the form js and localizing it can happen when we
637
+	 * actually output the form (which is preferred, seeing how teh form's fields
638
+	 * could change until it's actually outputted)
639
+	 *
640
+	 * @param boolean $init_form_validation_automatically whether or not we want the form validation
641
+	 *                                                    to be triggered automatically or not
642
+	 * @return void
643
+	 */
644
+	public static function wp_enqueue_scripts($init_form_validation_automatically = true)
645
+	{
646
+		add_filter('FHEE_load_jquery_validate', '__return_true');
647
+		wp_register_script(
648
+			'ee_form_section_validation',
649
+			EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
650
+			array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
651
+			EVENT_ESPRESSO_VERSION,
652
+			true
653
+		);
654
+		wp_localize_script(
655
+			'ee_form_section_validation',
656
+			'ee_form_section_validation_init',
657
+			array('init' => $init_form_validation_automatically ? true : false)
658
+		);
659
+	}
660
+
661
+
662
+
663
+	/**
664
+	 * gets the variables used by form_section_validation.js.
665
+	 * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
666
+	 * but before the wordpress hook wp_loaded
667
+	 *
668
+	 * @throws \EE_Error
669
+	 */
670
+	public function _enqueue_and_localize_form_js()
671
+	{
672
+		$this->ensure_construct_finalized_called();
673
+		//actually, we don't want to localize just yet. There may be other forms on the page.
674
+		//so we need to add our form section data to a static variable accessible by all form sections
675
+		//and localize it just before the footer
676
+		$this->localize_validation_rules();
677
+		add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
678
+		add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
679
+	}
680
+
681
+
682
+
683
+	/**
684
+	 * add our form section data to a static variable accessible by all form sections
685
+	 *
686
+	 * @param bool $return_for_subsection
687
+	 * @return void
688
+	 * @throws \EE_Error
689
+	 */
690
+	public function localize_validation_rules($return_for_subsection = false)
691
+	{
692
+		// we only want to localize vars ONCE for the entire form,
693
+		// so if the form section doesn't have a parent, then it must be the top dog
694
+		if ($return_for_subsection || ! $this->parent_section()) {
695
+			EE_Form_Section_Proper::$_js_localization['form_data'][$this->html_id()] = array(
696
+				'form_section_id'  => $this->html_id(true),
697
+				'validation_rules' => $this->get_jquery_validation_rules(),
698
+				'other_data'       => $this->get_other_js_data(),
699
+				'errors'           => $this->subsection_validation_errors_by_html_name(),
700
+			);
701
+			EE_Form_Section_Proper::$_scripts_localized = true;
702
+		}
703
+	}
704
+
705
+
706
+
707
+	/**
708
+	 * Gets an array of extra data that will be useful for client-side javascript.
709
+	 * This is primarily data added by inputs and forms in addition to any
710
+	 * scripts they might enqueue
711
+	 *
712
+	 * @param array $form_other_js_data
713
+	 * @return array
714
+	 */
715
+	public function get_other_js_data($form_other_js_data = array())
716
+	{
717
+		foreach ($this->subsections() as $subsection) {
718
+			$form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
719
+		}
720
+		return $form_other_js_data;
721
+	}
722
+
723
+
724
+
725
+	/**
726
+	 * Gets a flat array of inputs for this form section and its subsections.
727
+	 * Keys are their form names, and values are the inputs themselves
728
+	 *
729
+	 * @return EE_Form_Input_Base
730
+	 */
731
+	public function inputs_in_subsections()
732
+	{
733
+		$inputs = array();
734
+		foreach ($this->subsections() as $subsection) {
735
+			if ($subsection instanceof EE_Form_Input_Base) {
736
+				$inputs[$subsection->html_name()] = $subsection;
737
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
738
+				$inputs += $subsection->inputs_in_subsections();
739
+			}
740
+		}
741
+		return $inputs;
742
+	}
743
+
744
+
745
+
746
+	/**
747
+	 * Gets a flat array of all the validation errors.
748
+	 * Keys are html names (because those should be unique)
749
+	 * and values are a string of all their validation errors
750
+	 *
751
+	 * @return string[]
752
+	 */
753
+	public function subsection_validation_errors_by_html_name()
754
+	{
755
+		$inputs = $this->inputs();
756
+		$errors = array();
757
+		foreach ($inputs as $form_input) {
758
+			if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
759
+				$errors[$form_input->html_name()] = $form_input->get_validation_error_string();
760
+			}
761
+		}
762
+		return $errors;
763
+	}
764
+
765
+
766
+
767
+	/**
768
+	 * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
769
+	 * Should be setup by each form during the _enqueues_and_localize_form_js
770
+	 */
771
+	public static function localize_script_for_all_forms()
772
+	{
773
+		//allow inputs and stuff to hook in their JS and stuff here
774
+		do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
775
+		EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
776
+		$email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
777
+			? EE_Registry::instance()->CFG->registration->email_validation_level
778
+			: 'wp_default';
779
+		EE_Form_Section_Proper::$_js_localization['email_validation_level'] = $email_validation_level;
780
+		wp_enqueue_script('ee_form_section_validation');
781
+		wp_localize_script(
782
+			'ee_form_section_validation',
783
+			'ee_form_section_vars',
784
+			EE_Form_Section_Proper::$_js_localization
785
+		);
786
+	}
787
+
788
+
789
+
790
+	/**
791
+	 * ensure_scripts_localized
792
+	 */
793
+	public function ensure_scripts_localized()
794
+	{
795
+		if (! EE_Form_Section_Proper::$_scripts_localized) {
796
+			$this->_enqueue_and_localize_form_js();
797
+		}
798
+	}
799
+
800
+
801
+
802
+	/**
803
+	 * Gets the hard-coded validation error messages to be used in the JS. The convention
804
+	 * is that the key here should be the same as the custom validation rule put in the JS file
805
+	 *
806
+	 * @return array keys are custom validation rules, and values are internationalized strings
807
+	 */
808
+	private static function _get_localized_error_messages()
809
+	{
810
+		return array(
811
+			'validUrl' => __("This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg", "event_espresso"),
812
+			'regex'    => __('Please check your input', 'event_espresso'),
813
+		);
814
+	}
815
+
816
+
817
+
818
+	/**
819
+	 * @return array
820
+	 */
821
+	public static function js_localization()
822
+	{
823
+		return self::$_js_localization;
824
+	}
825
+
826
+
827
+
828
+	/**
829
+	 * @return array
830
+	 */
831
+	public static function reset_js_localization()
832
+	{
833
+		self::$_js_localization = array();
834
+	}
835
+
836
+
837
+
838
+	/**
839
+	 * Gets the JS to put inside the jquery validation rules for subsection of this form section.
840
+	 * See parent function for more...
841
+	 *
842
+	 * @return array
843
+	 */
844
+	public function get_jquery_validation_rules()
845
+	{
846
+		$jquery_validation_rules = array();
847
+		foreach ($this->get_validatable_subsections() as $subsection) {
848
+			$jquery_validation_rules = array_merge(
849
+				$jquery_validation_rules,
850
+				$subsection->get_jquery_validation_rules()
851
+			);
852
+		}
853
+		return $jquery_validation_rules;
854
+	}
855
+
856
+
857
+
858
+	/**
859
+	 * Sanitizes all the data and sets the sanitized value of each field
860
+	 *
861
+	 * @param array $req_data like $_POST
862
+	 * @return void
863
+	 */
864
+	protected function _normalize($req_data)
865
+	{
866
+		$this->_received_submission = true;
867
+		$this->_validation_errors = array();
868
+		foreach ($this->get_validatable_subsections() as $subsection) {
869
+			try {
870
+				$subsection->_normalize($req_data);
871
+			} catch (EE_Validation_Error $e) {
872
+				$subsection->add_validation_error($e);
873
+			}
874
+		}
875
+	}
876
+
877
+
878
+
879
+	/**
880
+	 * Performs validation on this form section and its subsections.
881
+	 * For each subsection,
882
+	 * calls _validate_{subsection_name} on THIS form (if the function exists)
883
+	 * and passes it the subsection, then calls _validate on that subsection.
884
+	 * If you need to perform validation on the form as a whole (considering multiple)
885
+	 * you would be best to override this _validate method,
886
+	 * calling parent::_validate() first.
887
+	 */
888
+	protected function _validate()
889
+	{
890
+		foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
891
+			if (method_exists($this, '_validate_' . $subsection_name)) {
892
+				call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
893
+			}
894
+			$subsection->_validate();
895
+		}
896
+	}
897
+
898
+
899
+
900
+	/**
901
+	 * Gets all the validated inputs for the form section
902
+	 *
903
+	 * @return array
904
+	 */
905
+	public function valid_data()
906
+	{
907
+		$inputs = array();
908
+		foreach ($this->subsections() as $subsection_name => $subsection) {
909
+			if ($subsection instanceof EE_Form_Section_Proper) {
910
+				$inputs[$subsection_name] = $subsection->valid_data();
911
+			} else if ($subsection instanceof EE_Form_Input_Base) {
912
+				$inputs[$subsection_name] = $subsection->normalized_value();
913
+			}
914
+		}
915
+		return $inputs;
916
+	}
917
+
918
+
919
+
920
+	/**
921
+	 * Gets all the inputs on this form section
922
+	 *
923
+	 * @return EE_Form_Input_Base[]
924
+	 */
925
+	public function inputs()
926
+	{
927
+		$inputs = array();
928
+		foreach ($this->subsections() as $subsection_name => $subsection) {
929
+			if ($subsection instanceof EE_Form_Input_Base) {
930
+				$inputs[$subsection_name] = $subsection;
931
+			}
932
+		}
933
+		return $inputs;
934
+	}
935
+
936
+
937
+
938
+	/**
939
+	 * Gets all the subsections which are a proper form
940
+	 *
941
+	 * @return EE_Form_Section_Proper[]
942
+	 */
943
+	public function subforms()
944
+	{
945
+		$form_sections = array();
946
+		foreach ($this->subsections() as $name => $obj) {
947
+			if ($obj instanceof EE_Form_Section_Proper) {
948
+				$form_sections[$name] = $obj;
949
+			}
950
+		}
951
+		return $form_sections;
952
+	}
953
+
954
+
955
+
956
+	/**
957
+	 * Gets all the subsections (inputs, proper subsections, or html-only sections).
958
+	 * Consider using inputs() or subforms()
959
+	 * if you only want form inputs or proper form sections.
960
+	 *
961
+	 * @param boolean $require_construction_to_be_finalized most client code should
962
+	 *                                                      leave this as TRUE so that the inputs will be properly
963
+	 *                                                      configured. However, some client code may be ok with
964
+	 *                                                      construction finalize being called later
965
+	 *                                                      (realizing that the subsections' html names might not be
966
+	 *                                                      set yet, etc.)
967
+	 * @return EE_Form_Section_Proper[]
968
+	 */
969
+	public function subsections($require_construction_to_be_finalized = true)
970
+	{
971
+		if ($require_construction_to_be_finalized) {
972
+			$this->ensure_construct_finalized_called();
973
+		}
974
+		return $this->_subsections;
975
+	}
976
+
977
+
978
+
979
+	/**
980
+	 * Returns a simple array where keys are input names, and values are their normalized
981
+	 * values. (Similar to calling get_input_value on inputs)
982
+	 *
983
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
984
+	 *                                        or just this forms' direct children inputs
985
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
986
+	 *                                        or allow multidimensional array
987
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
988
+	 *                                        with array keys being input names
989
+	 *                                        (regardless of whether they are from a subsection or not),
990
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
991
+	 *                                        where keys are always subsection names and values are either
992
+	 *                                        the input's normalized value, or an array like the top-level array
993
+	 */
994
+	public function input_values($include_subform_inputs = false, $flatten = false)
995
+	{
996
+		return $this->_input_values(false, $include_subform_inputs, $flatten);
997
+	}
998
+
999
+
1000
+
1001
+	/**
1002
+	 * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
1003
+	 * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
1004
+	 * is not necessarily the value we want to display to users. This creates an array
1005
+	 * where keys are the input names, and values are their display values
1006
+	 *
1007
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1008
+	 *                                        or just this forms' direct children inputs
1009
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1010
+	 *                                        or allow multidimensional array
1011
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
1012
+	 *                                        with array keys being input names
1013
+	 *                                        (regardless of whether they are from a subsection or not),
1014
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1015
+	 *                                        where keys are always subsection names and values are either
1016
+	 *                                        the input's normalized value, or an array like the top-level array
1017
+	 */
1018
+	public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1019
+	{
1020
+		return $this->_input_values(true, $include_subform_inputs, $flatten);
1021
+	}
1022
+
1023
+
1024
+
1025
+	/**
1026
+	 * Gets the input values from the form
1027
+	 *
1028
+	 * @param boolean $pretty                 Whether to retrieve the pretty value,
1029
+	 *                                        or just the normalized value
1030
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1031
+	 *                                        or just this forms' direct children inputs
1032
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1033
+	 *                                        or allow multidimensional array
1034
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1035
+	 *                                        input names (regardless of whether they are from a subsection or not),
1036
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1037
+	 *                                        where keys are always subsection names and values are either
1038
+	 *                                        the input's normalized value, or an array like the top-level array
1039
+	 */
1040
+	public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1041
+	{
1042
+		$input_values = array();
1043
+		foreach ($this->subsections() as $subsection_name => $subsection) {
1044
+			if ($subsection instanceof EE_Form_Input_Base) {
1045
+				$input_values[$subsection_name] = $pretty
1046
+					? $subsection->pretty_value()
1047
+					: $subsection->normalized_value();
1048
+			} else if ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1049
+				$subform_input_values = $subsection->_input_values($pretty, $include_subform_inputs, $flatten);
1050
+				if ($flatten) {
1051
+					$input_values = array_merge($input_values, $subform_input_values);
1052
+				} else {
1053
+					$input_values[$subsection_name] = $subform_input_values;
1054
+				}
1055
+			}
1056
+		}
1057
+		return $input_values;
1058
+	}
1059
+
1060
+
1061
+
1062
+	/**
1063
+	 * Gets the originally submitted input values from the form
1064
+	 *
1065
+	 * @param boolean $include_subforms  Whether to include inputs from subforms,
1066
+	 *                                   or just this forms' direct children inputs
1067
+	 * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1068
+	 *                                   with array keys being input names
1069
+	 *                                   (regardless of whether they are from a subsection or not),
1070
+	 *                                   and if $flatten is FALSE it can be a multidimensional array
1071
+	 *                                   where keys are always subsection names and values are either
1072
+	 *                                   the input's normalized value, or an array like the top-level array
1073
+	 */
1074
+	public function submitted_values($include_subforms = false)
1075
+	{
1076
+		$submitted_values = array();
1077
+		foreach ($this->subsections() as $subsection) {
1078
+			if ($subsection instanceof EE_Form_Input_Base) {
1079
+				// is this input part of an array of inputs?
1080
+				if (strpos($subsection->html_name(), '[') !== false) {
1081
+					$full_input_name = \EEH_Array::convert_array_values_to_keys(
1082
+						explode('[', str_replace(']', '', $subsection->html_name())),
1083
+						$subsection->raw_value()
1084
+					);
1085
+					$submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1086
+				} else {
1087
+					$submitted_values[$subsection->html_name()] = $subsection->raw_value();
1088
+				}
1089
+			} else if ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1090
+				$subform_input_values = $subsection->submitted_values($include_subforms);
1091
+				$submitted_values = array_replace_recursive($submitted_values, $subform_input_values);
1092
+			}
1093
+		}
1094
+		return $submitted_values;
1095
+	}
1096
+
1097
+
1098
+
1099
+	/**
1100
+	 * Indicates whether or not this form has received a submission yet
1101
+	 * (ie, had receive_form_submission called on it yet)
1102
+	 *
1103
+	 * @return boolean
1104
+	 * @throws \EE_Error
1105
+	 */
1106
+	public function has_received_submission()
1107
+	{
1108
+		$this->ensure_construct_finalized_called();
1109
+		return $this->_received_submission;
1110
+	}
1111
+
1112
+
1113
+
1114
+	/**
1115
+	 * Equivalent to passing 'exclude' in the constructor's options array.
1116
+	 * Removes the listed inputs from the form
1117
+	 *
1118
+	 * @param array $inputs_to_exclude values are the input names
1119
+	 * @return void
1120
+	 */
1121
+	public function exclude(array $inputs_to_exclude = array())
1122
+	{
1123
+		foreach ($inputs_to_exclude as $input_to_exclude_name) {
1124
+			unset($this->_subsections[$input_to_exclude_name]);
1125
+		}
1126
+	}
1127
+
1128
+
1129
+
1130
+	/**
1131
+	 * @param array $inputs_to_hide
1132
+	 * @throws \EE_Error
1133
+	 */
1134
+	public function hide(array $inputs_to_hide = array())
1135
+	{
1136
+		foreach ($inputs_to_hide as $input_to_hide) {
1137
+			$input = $this->get_input($input_to_hide);
1138
+			$input->set_display_strategy(new EE_Hidden_Display_Strategy());
1139
+		}
1140
+	}
1141
+
1142
+
1143
+
1144
+	/**
1145
+	 * add_subsections
1146
+	 * Adds the listed subsections to the form section.
1147
+	 * If $subsection_name_to_target is provided,
1148
+	 * then new subsections are added before or after that subsection,
1149
+	 * otherwise to the start or end of the entire subsections array.
1150
+	 *
1151
+	 * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1152
+	 *                                                          where keys are their names
1153
+	 * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1154
+	 *                                                          should be added before or after
1155
+	 *                                                          IF $subsection_name_to_target is null,
1156
+	 *                                                          then $new_subsections will be added to
1157
+	 *                                                          the beginning or end of the entire subsections array
1158
+	 * @param boolean                $add_before                whether to add $new_subsections, before or after
1159
+	 *                                                          $subsection_name_to_target,
1160
+	 *                                                          or if $subsection_name_to_target is null,
1161
+	 *                                                          before or after entire subsections array
1162
+	 * @return void
1163
+	 * @throws \EE_Error
1164
+	 */
1165
+	public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1166
+	{
1167
+		foreach ($new_subsections as $subsection_name => $subsection) {
1168
+			if (! $subsection instanceof EE_Form_Section_Base) {
1169
+				EE_Error::add_error(
1170
+					sprintf(
1171
+						__(
1172
+							"Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1173
+							"event_espresso"
1174
+						),
1175
+						get_class($subsection),
1176
+						$subsection_name,
1177
+						$this->name()
1178
+					)
1179
+				);
1180
+				unset($new_subsections[$subsection_name]);
1181
+			}
1182
+		}
1183
+		$this->_subsections = EEH_Array::insert_into_array(
1184
+			$this->_subsections,
1185
+			$new_subsections,
1186
+			$subsection_name_to_target,
1187
+			$add_before
1188
+		);
1189
+		if ($this->_construction_finalized) {
1190
+			foreach ($this->_subsections as $name => $subsection) {
1191
+				$subsection->_construct_finalize($this, $name);
1192
+			}
1193
+		}
1194
+	}
1195
+
1196
+
1197
+
1198
+	/**
1199
+	 * Just gets all validatable subsections to clean their sensitive data
1200
+	 */
1201
+	public function clean_sensitive_data()
1202
+	{
1203
+		foreach ($this->get_validatable_subsections() as $subsection) {
1204
+			$subsection->clean_sensitive_data();
1205
+		}
1206
+	}
1207
+
1208
+
1209
+
1210
+	/**
1211
+	 * @param string $form_submission_error_message
1212
+	 */
1213
+	public function set_submission_error_message($form_submission_error_message = '')
1214
+	{
1215
+		$this->_form_submission_error_message .= ! empty($form_submission_error_message)
1216
+			? $form_submission_error_message
1217
+			: __('Form submission failed due to errors', 'event_espresso');
1218
+	}
1219
+
1220
+
1221
+
1222
+	/**
1223
+	 * @return string
1224
+	 */
1225
+	public function submission_error_message()
1226
+	{
1227
+		return $this->_form_submission_error_message;
1228
+	}
1229
+
1230
+
1231
+
1232
+	/**
1233
+	 * @param string $form_submission_success_message
1234
+	 */
1235
+	public function set_submission_success_message($form_submission_success_message)
1236
+	{
1237
+		$this->_form_submission_success_message .= ! empty($form_submission_success_message)
1238
+			? $form_submission_success_message
1239
+			: __('Form submitted successfully', 'event_espresso');
1240
+	}
1241
+
1242
+
1243
+
1244
+	/**
1245
+	 * @return string
1246
+	 */
1247
+	public function submission_success_message()
1248
+	{
1249
+		return $this->_form_submission_success_message;
1250
+	}
1251
+
1252
+
1253
+
1254
+	/**
1255
+	 * Returns the prefix that should be used on child of this form section for
1256
+	 * their html names. If this form section itself has a parent, prepends ITS
1257
+	 * prefix onto this form section's prefix. Used primarily by
1258
+	 * EE_Form_Input_Base::_set_default_html_name_if_empty
1259
+	 *
1260
+	 * @return string
1261
+	 * @throws \EE_Error
1262
+	 */
1263
+	public function html_name_prefix()
1264
+	{
1265
+		if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1266
+			return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1267
+		} else {
1268
+			return $this->name();
1269
+		}
1270
+	}
1271
+
1272
+
1273
+
1274
+	/**
1275
+	 * Gets the name, but first checks _construct_finalize has been called. If not,
1276
+	 * calls it (assumes there is no parent and that we want the name to be whatever
1277
+	 * was set, which is probably nothing, or the classname)
1278
+	 *
1279
+	 * @return string
1280
+	 * @throws \EE_Error
1281
+	 */
1282
+	public function name()
1283
+	{
1284
+		$this->ensure_construct_finalized_called();
1285
+		return parent::name();
1286
+	}
1287
+
1288
+
1289
+
1290
+	/**
1291
+	 * @return EE_Form_Section_Proper
1292
+	 * @throws \EE_Error
1293
+	 */
1294
+	public function parent_section()
1295
+	{
1296
+		$this->ensure_construct_finalized_called();
1297
+		return parent::parent_section();
1298
+	}
1299
+
1300
+
1301
+
1302
+	/**
1303
+	 * make sure construction finalized was called, otherwise children might not be ready
1304
+	 *
1305
+	 * @return void
1306
+	 * @throws \EE_Error
1307
+	 */
1308
+	public function ensure_construct_finalized_called()
1309
+	{
1310
+		if (! $this->_construction_finalized) {
1311
+			$this->_construct_finalize($this->_parent_section, $this->_name);
1312
+		}
1313
+	}
1314
+
1315
+
1316
+
1317
+	/**
1318
+	 * Checks if any of this form section's inputs, or any of its children's inputs,
1319
+	 * are in teh form data. If any are found, returns true. Else false
1320
+	 *
1321
+	 * @param array $req_data
1322
+	 * @return boolean
1323
+	 */
1324
+	public function form_data_present_in($req_data = null)
1325
+	{
1326
+		if ($req_data === null) {
1327
+			$req_data = $_POST;
1328
+		}
1329
+		foreach ($this->subsections() as $subsection) {
1330
+			if ($subsection instanceof EE_Form_Input_Base) {
1331
+				if ($subsection->form_data_present_in($req_data)) {
1332
+					return true;
1333
+				}
1334
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
1335
+				if ($subsection->form_data_present_in($req_data)) {
1336
+					return true;
1337
+				}
1338
+			}
1339
+		}
1340
+		return false;
1341
+	}
1342
+
1343
+
1344
+
1345
+	/**
1346
+	 * Gets validation errors for this form section and subsections
1347
+	 * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1348
+	 * gets the validation errors for ALL subsection
1349
+	 *
1350
+	 * @return EE_Validation_Error[]
1351
+	 */
1352
+	public function get_validation_errors_accumulated()
1353
+	{
1354
+		$validation_errors = $this->get_validation_errors();
1355
+		foreach ($this->get_validatable_subsections() as $subsection) {
1356
+			if ($subsection instanceof EE_Form_Section_Proper) {
1357
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1358
+			} else {
1359
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors();
1360
+			}
1361
+			if ($validation_errors_on_this_subsection) {
1362
+				$validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1363
+			}
1364
+		}
1365
+		return $validation_errors;
1366
+	}
1367
+
1368
+
1369
+
1370
+	/**
1371
+	 * This isn't just the name of an input, it's a path pointing to an input. The
1372
+	 * path is similar to a folder path: slash (/) means to descend into a subsection,
1373
+	 * dot-dot-slash (../) means to ascend into the parent section.
1374
+	 * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1375
+	 * which will be returned.
1376
+	 * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1377
+	 * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1378
+	 * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1379
+	 * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1380
+	 * Etc
1381
+	 *
1382
+	 * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1383
+	 * @return EE_Form_Section_Base
1384
+	 */
1385
+	public function find_section_from_path($form_section_path)
1386
+	{
1387
+		//check if we can find the input from purely going straight up the tree
1388
+		$input = parent::find_section_from_path($form_section_path);
1389
+		if ($input instanceof EE_Form_Section_Base) {
1390
+			return $input;
1391
+		}
1392
+		$next_slash_pos = strpos($form_section_path, '/');
1393
+		if ($next_slash_pos !== false) {
1394
+			$child_section_name = substr($form_section_path, 0, $next_slash_pos);
1395
+			$subpath = substr($form_section_path, $next_slash_pos + 1);
1396
+		} else {
1397
+			$child_section_name = $form_section_path;
1398
+			$subpath = '';
1399
+		}
1400
+		$child_section = $this->get_subsection($child_section_name);
1401
+		if ($child_section instanceof EE_Form_Section_Base) {
1402
+			return $child_section->find_section_from_path($subpath);
1403
+		} else {
1404
+			return null;
1405
+		}
1406
+	}
1407 1407
 
1408 1408
 }
1409 1409
 
Please login to merge, or discard this patch.