PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.6
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.6
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
charitable / includes / forms / views / class-charitable-public-form-view.php

class-charitable-public-form-view.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.7.0.6, at includes/forms/views/class-charitable-public-form-view.php

676 lines 17.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Public form view.
4 *
5 * This is responsible for rendering the output of forms.
6 *
7 * @package Charitable/Forms/Charitable_Public_Form_View
8 * @author David Bisset
9 * @copyright Copyright (c) 2022, WP Charitable LLC
10 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
11 * @since 1.5.0
12 * @version 1.6.44
13 */
14
15 // Exit if accessed directly.
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 if ( ! class_exists( 'Charitable_Public_Form_View' ) ) :
21
22 /**
23 * Charitable_Public_Form_View.
24 *
25 * @since 1.5.0
26 */
27 class Charitable_Public_Form_View implements Charitable_Form_View_Interface {
28
29 /**
30 * The Form we are responsible for rendering.
31 *
32 * @since 1.5.0
33 *
34 * @var Charitable_Form
35 */
36 protected $form;
37
38 /**
39 * Whether the notices have been rendered.
40 *
41 * @since 1.5.2
42 *
43 * @var boolean
44 */
45 protected $rendered_notices;
46
47 /**
48 * Whether the hidden fields have been rendered.
49 *
50 * @since 1.5.2
51 *
52 * @var boolean
53 */
54 protected $rendered_hidden_fields;
55
56 /**
57 * Whether the honeypot has been rendered.
58 *
59 * @since 1.5.2
60 *
61 * @var boolean
62 */
63 protected $rendered_honeypot;
64
65 /**
66 * List of custom field templates.
67 *
68 * @since 1.5.0
69 *
70 * @var array
71 */
72 protected $custom_field_templates;
73
74 /**
75 * Set up view instance.
76 *
77 * @since 1.5.0
78 *
79 * @param Charitable_Form $form Form object.
80 */
81 public function __construct( Charitable_Form $form ) {
82 $this->form = $form;
83 $this->rendered_honeypot = false;
84 $this->rendered_notices = false;
85 $this->rendered_hidden_fields = false;
86 $this->custom_field_templates = $this->init_custom_field_templates();
87 }
88
89 /**
90 * Return value of a protected class property.
91 *
92 * @since 1.5.2
93 *
94 * @param string $prop The class property.
95 * @return mixed
96 */
97 public function __get( $prop ) {
98 if ( ! property_exists( $this, $prop ) ) {
99 return null;
100 }
101
102 return $this->$prop;
103 }
104
105 /**
106 * Register a custom field template.
107 *
108 * @since 1.5.0
109 *
110 * @param string $field_type The type of field we are registering this template for.
111 * @param string $class The template class name.
112 * @param string $path The path to the template.
113 * @return void
114 */
115 public function register_custom_field_template( $field_type, $class, $path ) {
116 $this->custom_field_templates[ $field_type ] = array(
117 'class' => $class,
118 'path' => $path,
119 );
120 }
121
122 /**
123 * Render a form.
124 *
125 * @since 1.5.0
126 *
127 * @return void
128 */
129 public function render() {
130
131 $form_fields = $this->form->get_fields();
132
133 $this->enqueue_script();
134 if ( ( isset( $form_fields['donation_fields'] ) && 'bottom' !== charitable_get_option( 'donation_form_notices_display', 'top' ) ) || ! isset( $form_fields['donation_fields'] ) ) {
135 $this->render_notices();
136 }
137 $this->render_honeypot();
138 $this->render_hidden_fields();
139 $this->render_fields();
140 if ( isset( $form_fields['donation_fields'] ) && 'bottom' === charitable_get_option( 'donation_form_notices_display', 'top' ) ) {
141 $this->render_notices();
142 }
143 }
144
145 /**
146 * Enqueue the forms script.
147 *
148 * @since 1.6.44
149 *
150 * @return void
151 */
152 public function enqueue_script() {
153 if ( ! wp_script_is( 'charitable-forms', 'enqueued' ) ) {
154 wp_enqueue_script( 'charitable-forms' );
155 }
156 }
157
158 /**
159 * Render notices before the form.
160 *
161 * @since 1.5.0
162 *
163 * @return void
164 */
165 public function render_notices() {
166 charitable_template_from_session(
167 'form-fields/notices.php',
168 array(
169 'notices' => charitable_get_notices()->get_notices(),
170 ),
171 'notices'
172 );
173
174 $this->rendered_notices = true;
175
176 /* Clear all notices. */
177 charitable_get_notices()->clear();
178 }
179
180 /**
181 * Render the honeypot fields.
182 *
183 * @since 1.5.0
184 *
185 * @return void
186 */
187 public function render_honeypot() {
188 printf( '<input type="hidden" name="charitable_form_id" value="%1$s" autocomplete="off" /><input type="text" name="%1$s" class="charitable-hidden" value="" autocomplete="off" />', esc_attr( $this->form->get_form_identifier() ) );
189
190 $this->rendered_honeypot = true;
191 }
192
193 /**
194 * Render a form's hidden fields.
195 *
196 * @since 1.5.0
197 *
198 * @return boolean True if any fields were rendered. False otherwise.
199 */
200 public function render_hidden_fields() {
201 $fields = $this->form->get_hidden_fields();
202
203 if ( ! is_array( $fields ) || empty( $fields ) ) {
204 return false;
205 }
206
207 array_walk( $fields, array( $this, 'render_hidden_field' ) );
208
209 $this->rendered_hidden_fields = true;
210 }
211
212 /**
213 * Render all of a form's fields.
214 *
215 * @since 1.5.0
216 *
217 * @param array $fields Optional. A set of fields to display. If not set,
218 * we will look for fields in the form's `get_fields()`
219 * method (if it has one).
220 * @return boolean True if any fields were rendered. False otherwsie.
221 */
222 public function render_fields( $fields = array() ) {
223 if ( empty( $fields ) ) {
224 $fields = $this->form->get_fields();
225
226 /* If still missing fields, return false and throw an error. */
227 if ( empty( $fields ) ) {
228 charitable_get_deprecated()->doing_it_wrong(
229 __METHOD__,
230 __( 'There are no fields to render.', 'charitable' ),
231 '1.5.0'
232 );
233 return false;
234 }
235 }
236
237 $i = 1;
238
239 foreach ( $fields as $key => $field ) {
240 $this->render_field(
241 $field,
242 $key,
243 array(
244 'index' => $i,
245 )
246 );
247
248 $i += $this->increment_index( $field, $key, $i );
249 }
250 }
251
252 /**
253 * Render a hidden field.
254 *
255 * @since 1.5.0
256 *
257 * @param string|array $value Field value.
258 * @param string $key Field key.
259 * @return void
260 */
261 public function render_hidden_field( $value, $key ) {
262 $attrs = '';
263
264 if ( is_array( $value ) ) {
265 if ( ! array_key_exists( 'value', $value ) ) {
266 return;
267 }
268
269 $args = $value;
270 $value = $args['value'];
271
272 unset( $args['value'] );
273
274 $attrs = charitable_get_arbitrary_attributes( array( 'attrs' => $args ) );
275 }
276
277 printf( '<input type="hidden" name="%s" value="%s" %s />', esc_attr( $key ), esc_attr( $value ), $attrs );
278 }
279
280 /**
281 * Render a specific form field.
282 *
283 * @since 1.5.0
284 *
285 * @param array $field Field definition.
286 * @param string $key Field key.
287 * @param array $args Mixed array of arguments.
288 * @return boolean False if the field was not rendered. True otherwise.
289 */
290 public function render_field( $field, $key, $args = array() ) {
291 if ( ! array_key_exists( 'type', $field ) ) {
292 return false;
293 }
294
295 /* Get our index and namespace, with defaults if they're not provided. */
296 $namespace = array_key_exists( 'namespace', $args ) ? $args['namespace'] : null;
297 $index = array_key_exists( 'index', $args ) ? $args['index'] : 0;
298
299 /* Set up some form attributes. */
300 $field['key'] = $this->get_field_name( $key, $namespace, $index );
301 $field['attrs'] = array_key_exists( 'attrs', $field ) ? $field['attrs'] : array();
302
303 /**
304 * Do something before the field is rendered.
305 *
306 * @since 1.0.0
307 * @since 1.5.4 Added $from_template parameter to avoid backwards compatibility issues.
308 *
309 * @param array $field Field definition.
310 * @param string $key The field's key.
311 * @param Charitable_Form $form The Charitable_Form object.
312 * @param int $index The current index.
313 * @param null $namespace Unused. Namespace for the form field's name attribute.
314 * @param false $from_template Whether the method was called from a template file.
315 */
316 do_action( 'charitable_form_field', $field, $key, $this->form, $index, null, false );
317
318 /* Get the template and make sure it's valid. */
319 $template = $this->get_field_template( $field, $index );
320
321 if ( ! $template ) {
322 return false;
323 }
324
325 $template->set_view_args( array(
326 'form' => $this->form,
327 'field' => $field,
328 'classes' => $this->get_field_classes( $field, $index ),
329 ) );
330
331 $template->render();
332
333 return true;
334 }
335
336 /**
337 * Return the key for a particular field.
338 *
339 * @since 1.5.0
340 *
341 * @param string $key Field key.
342 * @param string|null $namespace Namespace for the form field's name attribute.
343 * @param int $index The current index.
344 * @return string
345 */
346 protected function get_field_name( $key, $namespace = null, $index = 0 ) {
347 $name = $key;
348
349 if ( ! is_null( $namespace ) ) {
350 $name = $namespace . '[' . $name . ']';
351 }
352
353 /**
354 * Filter the name attribute to be used for the field.
355 *
356 * @since 1.0.0
357 *
358 * @param string $name The name attribute.
359 * @param string $key The field's key.
360 * @param string|null $namespace Namespace for the field's attribute.
361 * @param Charitable_Form $form The Charitable_Form object.
362 * @param int $index The current index.
363 */
364 return apply_filters( 'charitable_form_field_key', $name, $key, $namespace, $this->form, $index );
365 }
366
367 /**
368 * Return a field template.
369 *
370 * @since 1.5.0
371 *
372 * @param array $field Field definition.
373 * @param int $index The current index.
374 * @return Charitable_Template|false Returns a template if the template file exists. If it doesn't returns false.
375 */
376 public function get_field_template( $field, $index ) {
377 $template = $this->get_custom_template( $field['type'] );
378
379 /**
380 * Filter the template to be used for the form.
381 *
382 * Any callback hooking into this filter should return a `Charitable_Template`
383 * instance. Anything else will be ignored.
384 *
385 * @since 1.0.0
386 *
387 * @param false|Charitable_Template $template False by default.
388 * @param array $field Field definition.
389 * @param Charitable_Form $form The Charitable_Form object.
390 * @param int $index The current index.
391 */
392 $template = apply_filters( 'charitable_form_field_template', $template, $field, $this->form, $index );
393
394 /* Fall back to default Charitable_Template if no template returned or if template was not object of 'Charitable_Template' class. */
395 if ( ! $this->is_valid_template( $template ) ) {
396 $template = new Charitable_Template( $this->get_template_name( $field ), false );
397 }
398
399 if ( ! $template->template_file_exists() ) {
400 return false;
401 }
402
403 return $template;
404 }
405
406 /**
407 * Return a custom template for a particular field.
408 *
409 * @since 1.5.0
410 *
411 * @param string $field_type The type of field.
412 * @return false|Charitable_Template False if there is no matching custom template.
413 */
414 public function get_custom_template( $field_type ) {
415 if ( ! array_key_exists( $field_type, $this->custom_field_templates ) ) {
416 return false;
417 }
418
419 $class = $this->custom_field_templates[ $field_type ]['class'];
420 $path = $this->custom_field_templates[ $field_type ]['path'];
421
422 /* Final sanity check to make sure the template class exists. */
423 if ( ! class_exists( $class ) ) {
424 return false;
425 }
426
427 return new $class( $path, false );
428 }
429
430 /**
431 * Return the template name used for this field.
432 *
433 * @since 1.5.0
434 *
435 * @param array $field Field definition.
436 * @return string
437 */
438 public function get_template_name( $field ) {
439 if ( $this->use_default_field_template( $field['type'] ) ) {
440 $template_name = 'form-fields/default.php';
441 } else {
442 $template_name = 'form-fields/' . $field['type'] . '.php';
443 }
444
445 /**
446 * Filter the template name.
447 *
448 * @since 1.0.0
449 *
450 * @param string $template_name Default template name.
451 */
452 return apply_filters( 'charitable_form_field_template_name', $template_name );
453 }
454
455 /**
456 * Checks whether a template is valid.
457 *
458 * @since 1.5.0
459 *
460 * @param mixed $template Template we're checking.
461 * @return boolean
462 */
463 public function is_valid_template( $template ) {
464 return is_object( $template ) && is_a( $template, 'Charitable_Template' );
465 }
466
467 /**
468 * Whether the given field type can use the default field template.
469 *
470 * @since 1.5.0
471 *
472 * @param string $field_type Type of field.
473 * @return boolean
474 */
475 protected function use_default_field_template( $field_type ) {
476 /**
477 * Filter the list of field types that use the default template.
478 *
479 * @since 1.0.0
480 *
481 * @param string[] $types Field types.
482 */
483 $default_field_types = apply_filters( 'charitable_default_template_field_types', array(
484 'text',
485 'email',
486 'password',
487 'date',
488 ) );
489
490 return in_array( $field_type, $default_field_types );
491 }
492
493 /**
494 * Return classes that will be applied to the field.
495 *
496 * @since 1.5.0
497 *
498 * @param array $field Field definition.
499 * @param int $index Field index.
500 * @return string
501 */
502 public function get_field_classes( $field, $index = 0 ) {
503 if ( 'hidden' == $field['type'] ) {
504 return;
505 }
506
507 $classes = $this->get_field_type_classes( $field['type'] );
508
509 if ( array_key_exists( 'class', $field ) ) {
510 $classes[] = $field['class'];
511 }
512
513 if ( array_key_exists( 'required', $field ) && $field['required'] ) {
514 $classes[] = 'required-field';
515 }
516
517 if ( array_key_exists( 'fullwidth', $field ) && $field['fullwidth'] ) {
518 $classes[] = 'fullwidth';
519 } elseif ( $index > 0 ) {
520 $classes[] = $index % 2 ? 'odd' : 'even';
521 }
522
523 /**
524 * Filter the array of classes before it is returned as a string.
525 *
526 * @since 1.0.0
527 *
528 * @param array $classes List of classes.
529 * @param array $field Field definition.
530 * @param int $index The field index.
531 */
532 $classes = apply_filters( 'charitable_form_field_classes', $classes, $field, $index );
533
534 return implode( ' ', $classes );
535 }
536
537 /**
538 * Return array of classes based on the field type.
539 *
540 * @since 1.5.0
541 *
542 * @param string $type Type of field.
543 * @return string[]
544 */
545 public function get_field_type_classes( $type ) {
546 $classes = array();
547
548 switch ( $type ) {
549 case 'paragraph':
550 $classes[] = 'charitable-form-content';
551 break;
552
553 case 'fieldset':
554 case 'donation-amount-wrapper':
555 $classes[] = 'charitable-fieldset';
556 break;
557
558 default:
559 $classes[] = 'charitable-form-field';
560 $classes[] = 'charitable-form-field-' . $type;
561 }
562
563 return $classes;
564 }
565
566 /**
567 * Set how much the index should be incremented by.
568 *
569 * @since 1.5.0
570 *
571 * @param array $field The field definition.
572 * @param string $key The key of the current field. May be empty.
573 * @param int|null $index The current index. May be null.
574 * @return int
575 */
576 public function increment_index( $field, $key = '', $index = null) {
577 if ( ! $this->should_increment( $field ) ) {
578 return 0;
579 }
580
581 /**
582 * Set the default increment.
583 *
584 * @since 1.0.0
585 *
586 * @param int $increment The default increment amount. Defaults to 1.
587 * @param array $field The field definition.
588 * @param string $key The key of the current field.
589 * @param Charitable_Form $form The form we are displaying.
590 * @param int $index The current index.
591 */
592 return apply_filters( 'charitable_form_field_increment', 1, $field, $key, $this->form, $index );
593 }
594
595 /**
596 * Whether the index should be incremented.
597 *
598 * @since 1.5.0
599 *
600 * @param array $field Field definition.
601 * @return boolean
602 */
603 protected function should_increment( $field ) {
604 if ( in_array( $field['type'], array( 'hidden', 'paragraph', 'fieldset' ) ) ) {
605 return false;
606 }
607
608 if ( array_key_exists( 'fullwidth', $field ) && $field['fullwidth'] ) {
609 return false;
610 }
611
612 return true;
613 }
614
615 /**
616 * Set up custom field templates.
617 *
618 * @since 1.5.0
619 *
620 * @return array
621 */
622 protected function init_custom_field_templates() {
623 /**
624 * Filter the custom field templates.
625 *
626 * @since 1.5.0
627 */
628 $templates = apply_filters( 'charitable_public_form_view_custom_field_templates', array(
629 'donation-amount-wrapper' => array(
630 'class' => 'Charitable_Template',
631 'path' => 'donation-form/donation-amount-wrapper.php',
632 ),
633 'donation-amount' => array(
634 'class' => 'Charitable_Template',
635 'path' => 'donation-form/donation-amount.php',
636 ),
637 'donor-fields' => array(
638 'class' => 'Charitable_Template',
639 'path' => 'donation-form/donor-fields.php',
640 ),
641 'details-fields' => array(
642 'class' => 'Charitable_Template',
643 'path' => 'donation-form/details-fields.php',
644 ),
645 'meta-fields' => array(
646 'class' => 'Charitable_Template',
647 'path' => 'donation-form/meta-fields.php',
648 ),
649 'gateway-fields' => array(
650 'class' => 'Charitable_Template',
651 'path' => 'donation-form/gateway-fields.php',
652 ),
653 'cc-expiration' => array(
654 'class' => 'Charitable_Template',
655 'path' => 'donation-form/cc-expiration.php',
656 ),
657 ) );
658
659 return array_filter( $templates, array( $this, 'sanitize_custom_field_template' ) );
660 }
661
662 /**
663 * Filter custom field templates to make sure they all have a class and path.
664 *
665 * @since 1.5.0
666 *
667 * @param array $template The registered template.
668 * @return boolean
669 */
670 protected function sanitize_custom_field_template( $template ) {
671 return is_array( $template ) && array_key_exists( 'path', $template ) && array_key_exists( 'class', $template );
672 }
673 }
674
675 endif;
676