PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.9
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.9
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.9, at includes/forms/views/class-charitable-public-form-view.php

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