PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13.1
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13.1
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 / admin / campaign-builder / fields / class-donate-amount.php

class-donate-amount.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13.1, at includes/admin/campaign-builder/fields/class-donate-amount.php

550 lines 20.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class to add donation amount (oringially from the widget) to a campaign form in the builder.
4 *
5 * @package Charitable
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.8.0
10 * @version 1.8.0
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Field_Donate_Amount' ) ) :
18
19 /**
20 * Class to add campaign field donate amount field to a campaign form in the builder.
21 */
22 class Charitable_Field_Donate_Amount extends Charitable_Builder_Field {
23
24 /**
25 * Primary class constructor.
26 *
27 * @since 1.8.0
28 */
29 public function init() {
30
31 // Basic information.
32 $this->name = esc_html__( 'Donate Amount', 'charitable' );
33 $this->type = 'donate-amount';
34 $this->icon = 'fa fa-dollar';
35 $this->order = 100;
36 $this->group = 'standard';
37
38 $this->align_default = 'center';
39
40 // Edit/Duplication information.
41 $this->can_be_edited = true;
42 $this->can_be_deleted = true;
43 $this->can_be_duplicated = false;
44 $this->edit_label = esc_html__( 'Edit Donate Amount', 'charitable' );
45 $this->edit_type = 'donate-amount';
46 $this->edit_section = 'standard';
47 $this->max_allowed = 1;
48
49 // Misc.
50 $this->tooltip = '';
51
52 // Define additional field properties.
53 // add_action( 'charitable_frontend_js', [ $this, 'frontend_js' ] );
54 // add_action( 'charitable_builder_backend_scripts', [ $this, 'builder_js' ]); // admin_enqueue_scripts.
55 add_filter( 'charitable_builder_field_button_attributes', [ $this, 'make_unique_button' ], 10, 4 );
56 }
57
58 /**
59 * Field options panel inside the builder.
60 *
61 * @since 1.8.0
62 *
63 * @param array $field Field settings.
64 */
65 public function field_options( $field ) {
66 /*
67 * Basic field options.
68 */
69
70 // Options open markup.
71 }
72
73 /**
74 * Render the field.
75 *
76 * @since 1.8.0
77 *
78 * @param array $field_data Any field data.
79 * @param array $campaign_data Amount data and settings.
80 * @param integer $field_id The field ID.
81 * @param string $mode Where the field is being displayed ("preview" or "template").
82 * @param array $template_data Tempalate data.
83 */
84 public function render( $field_data = false, $campaign_data = false, $field_id = false, $mode = 'template', $template_data = false ) {
85
86 $headline = ! empty( $field_data['headline'] ) ? esc_html( $field_data['headline'] ) : false;
87 $campaign_id = isset( $campaign_data['id'] ) && 0 !== intval( $campaign_data['id'] ) ? intval( $campaign_data['id'] ) : false;
88
89 $preview_or_template_css = ( 'preview' === $mode ) ? 'preview' : 'template';
90 $input_disabled_attr = ( 'preview' === $mode ) ? 'disabled="true"' : false;
91 $donation_amount_found = false;
92
93 $currency_helper = charitable_get_currency_helper();
94
95 ob_start();
96
97 if ( 'preview' === $mode ) :
98 echo '<div class="placeholder">';
99 endif;
100
101 if ( 'preview' === $mode || ( 'template' === $mode && false !== $headline ) ) :
102 echo '<h5 class="charitable-field-' . esc_attr( $preview_or_template_css ) . '-headline">' . esc_html( $headline ) . '</h5>';
103 endif;
104
105 // if there is no campaign id, then we assume this is a new campaign and assign the default donation amounts.
106 if ( false === $campaign_id ) {
107
108 echo '
109 <div class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-options">
110 <ul class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amounts">
111 <li class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amount suggested-donation-amount">
112 <label><span class="amount">' . esc_html( $currency_helper->get_monetary_amount( '5.00' ) ) . '</span></label>
113 </li>
114 <li class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amount suggested-donation-amount">
115 <label><span class="amount">' . esc_html( $currency_helper->get_monetary_amount( '10.00' ) ) . '</span></label>
116 </li>
117 <li class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amount suggested-donation-amount selected">
118 <label><span class="amount">' . esc_html( $currency_helper->get_monetary_amount( '15.00' ) ) . '</span></label>
119 </li>
120 <li class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amount suggested-donation-amount">
121 <label><span class="amount">' . esc_html( $currency_helper->get_monetary_amount( '20.00' ) ) . '</span></label>
122 </li>
123 <li class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amount custom-donation-amount">
124 <span class="custom-donation-amount-wrapper">
125 <label>
126 <input type="radio" name="donation_amount" value="custom"><span class="description">' . esc_html__( 'Custom Amount', 'charitable' ) . '</span>
127 </label>
128 <input type="text" ' . esc_attr( $input_disabled_attr ) . ' class="custom-donation-input" name="custom_donation_amount" placeholder="' . esc_attr__( 'Custom Donation Amount', 'charitable' ) . '" aria-label="' . esc_attr__( 'Custom Donation Amount', 'charitable' ) . '" value="">
129 </span>
130 </li>
131 </ul>
132 </div>';
133
134 } else {
135
136 $campaign = charitable_get_campaign( $campaign_id );
137
138 // We want the button to contain a donation amount, but we go with what is in the SESSION first, then the DEFAULT amount.
139 $donation_amount_in_session = $campaign->get_donation_amount_in_session();
140
141 if ( ! $campaign ) :
142 echo '<p>Cannot recieve donations.</p>';
143 echo '</div> <!-- placeholder -->';
144 $html = ob_get_clean();
145 echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
146 return;
147 endif;
148
149 $suggested_donations = $campaign->get_suggested_donations();
150
151 if ( empty( $suggested_donations ) && ! $campaign->get( 'allow_custom_donations' ) ) :
152 echo '<p>No donation options available.</p>';
153 echo '</div> <!-- placeholder -->';
154 $html = ob_get_clean();
155 echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
156 return;
157 endif;
158
159 echo '
160 <div class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-options">
161 <ul class="charitable-' . esc_attr( $preview_or_template_css ) . '-donation-amounts">';
162
163 if ( ! empty( $suggested_donations ) ) :
164
165 $suggested_donations_default = ! empty( $campaign_data['settings']['donation-options']['suggested_donations_default'] ) ? intval( $campaign_data['settings']['donation-options']['suggested_donations_default'] ) : 0;
166
167 foreach ( $suggested_donations as $suggested_donation_id => $suggested_donation ) :
168
169 $selected_css = false;
170 $checked_attribute = false;
171
172 if ( ( $donation_amount_in_session && $donation_amount_in_session === $suggested_donation['amount'] )
173 || ( ! $donation_amount_in_session && $suggested_donation_id === $suggested_donations_default ) ) {
174 $selected_css = 'selected';
175 $checked_attribute = 'checked="true"';
176 $donation_amount_found = true;
177 }
178
179 ?>
180 <li class="charitable-<?php echo esc_attr( $preview_or_template_css ); ?>-donation-amount suggested-donation-amount <?php echo esc_attr( $selected_css ); ?>">
181 <label>
182 <input type="radio" name="donation_amount" value="<?php echo esc_attr( $suggested_donation['amount'] ); ?>" <?php echo esc_attr( $checked_attribute ); ?>>
183 <span class="amount"><?php echo esc_html( $currency_helper->get_monetary_amount( $suggested_donation['amount'] ) ); ?></span>
184 <?php
185 /*
186 * The builder's "Optional Description" beside each amount. Rows saved before
187 * that input existed, written by the legacy metabox, or added programmatically
188 * have no 'description' key at all, so this is guarded rather than read
189 * directly. The span is omitted entirely when the description is blank, which
190 * keeps the markup (and so the layout) identical for the campaigns that never
191 * filled it in.
192 *
193 * wp_kses_post() rather than esc_html() to match
194 * templates/donation-form/donation-amount-list.php, so the same description
195 * renders the same way in this block and on the donation form.
196 */
197 if ( ! empty( $suggested_donation['description'] ) ) :
198 ?>
199 <span class="description"><?php echo wp_kses_post( $suggested_donation['description'] ); ?></span>
200 <?php
201 endif;
202 ?>
203 </label>
204 </li>
205 <?php
206 endforeach;
207 endif;
208 ?>
209
210 <?php
211
212 $custom_donation_amount_class = ! empty( $campaign_data['settings']['donation-options']['allow_custom_donations'] ) ? false : 'charitable-hidden';
213
214 $value = false === $donation_amount_found && $donation_amount_in_session !== 0 ? $currency_helper->get_monetary_amount( $donation_amount_in_session ) : false;
215
216 ?>
217
218 <li class="charitable-<?php echo esc_attr( $preview_or_template_css ); ?>-donation-amount custom-donation-amount <?php echo $custom_donation_amount_class; ?>"> <?php // phpcs:ignore ?>
219 <span class="custom-donation-amount-wrapper">
220 <label>
221 <input type="radio" name="donation_amount" value="custom"><span class="description"><?php echo esc_html__( 'Custom amount', 'charitable' ); ?></span>
222 </label>
223 <?php
224 /*
225 * aria-label alongside the placeholder (WCAG 3.3.2 / 4.1.2) -- 1.8.13.1.
226 *
227 * The wrapping <label> above names the radio, not this text input, so with only
228 * a placeholder this control had no accessible name -- and a placeholder is not
229 * one: it disappears as soon as the donor types. In 'template' mode this input
230 * is live on the front end, so it is a donor-facing control, not just builder
231 * chrome. Same string as the placeholder so the two cannot drift.
232 */
233 ?>
234 <input type="text" <?php echo esc_attr( $input_disabled_attr ); ?> class="custom-donation-input" name="custom_donation_amount" placeholder="<?php echo esc_attr__( 'Custom Donation Amount', 'charitable' ); ?>" aria-label="<?php echo esc_attr__( 'Custom Donation Amount', 'charitable' ); ?>" value="<?php echo esc_attr( $value ); ?>">
235 </span>
236 </li>
237
238 <?php
239
240 echo '
241 </ul>
242 </div>';
243
244 }
245
246 if ( 'preview' === $mode ) :
247 echo '</div> <!-- placeholder -->';
248 endif;
249
250 $html = ob_get_clean();
251
252 return $html;
253 }
254
255 /**
256 * Donate Amount preview inside the builder.
257 *
258 * @since 1.8.0
259 *
260 * @param array $field_data Field data and settings.
261 * @param array $campaign_data Campaign data and settings.
262 * @param array $field_id Field ID.
263 * @param string $theme Template data.
264 */
265 public function field_preview( $field_data = false, $campaign_data = false, $field_id = false, $theme = '' ) {
266
267 $html = $this->field_title( $this->name );
268 $html .= $this->field_wrapper( $this->render( $field_data, $campaign_data, $field_id, 'preview' ), $field_data );
269
270 echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
271 }
272
273 /**
274 * The display on the campaign front-end.
275 *
276 * @since 1.8.0
277 *
278 * @param string $field_type The passed field type.
279 * @param array $field_data Any field data.
280 * @param array $campaign_data Amount data and settings.
281 */
282 public function field_display( $field_type = '', $field_data = false, $campaign_data = false ) {
283
284 $html = $this->field_display_wrapper( $this->render( $field_data, $campaign_data ), $field_data );
285
286 echo apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
287 }
288
289 /**
290 * Donate Amount display on the form front-end.
291 *
292 * @since 1.8.0
293 *
294 * @param integer $field_id Number ID.
295 * @param array $campaign_data Amount data and settings.
296 */
297 public function settings_display( $field_id = false, $campaign_data = false ) {
298
299 if ( ! class_exists( 'Charitable_Builder_Form_Fields' ) ) {
300 return;
301 }
302
303 $charitable_builder_form_fields = new Charitable_Builder_Form_Fields();
304
305 $settings = isset( $campaign_data['fields'][ $field_id ] ) ? $campaign_data['fields'][ $field_id ] : false;
306
307 ob_start();
308
309 ?>
310
311 <h4 class="charitable-panel-field" data-field-id="<?php echo intval( $field_id ); ?>"><?php echo esc_html( $this->name ); ?> (ID: <?php echo intval( $field_id ); ?>)</h4>
312
313 <?php
314
315 echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
316 isset( $settings['headline'] ) ? $settings['headline'] : '',
317 esc_html__( 'Headline', 'charitable' ),
318 array(
319 'id' => 'field_' . esc_attr( $this->type ) . '_headline' . '_' . intval( $field_id ), // phpcs:ignore
320 'name' => array( '_fields', intval( $field_id ), 'headline' ),
321 'field_id' => intval( $field_id ),
322 'tooltip' => esc_html__( 'Add a headline to this field.', 'charitable' ),
323 'class' => 'charitable-campaign-builder-headline',
324 )
325 );
326
327 echo $charitable_builder_form_fields->generate_divider( false, false, array( 'field_id' => $field_id ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
328
329 echo $charitable_builder_form_fields->generate_donation_amounts_mini( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
330 $campaign_data,
331 esc_html__( 'Suggested Donation Amounts', 'charitable' ),
332 array(
333 'from' => 'field',
334 'id' => 'field_' . esc_attr( $this->type ) . '_donation_amounts' . '_' . intval( $field_id ), // phpcs:ignore
335 'name' => array( '_fields', intval( $field_id ), 'donation_amounts' ),
336 'field_id' => intval( $field_id ),
337 'default' => false,
338 )
339 );
340
341 echo $charitable_builder_form_fields->generate_divider( false, false, array( 'field_id' => $field_id ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
342
343 $campaign_settings = false;
344
345 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display/routing parameter
346 if ( ! empty( $_GET['campaign_id'] ) ) {
347 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display/routing parameter
348 $campaign_id = intval( wp_unslash( $_GET['campaign_id'] ) );
349 if ( $campaign_id > 0 ) {
350 $campaign_settings = get_post_meta( $campaign_id, 'campaign_settings_v2', true );
351 }
352 }
353
354 $default_allow_custom = false !== $campaign_settings && ! isset( $campaign_settings['settings']['donation-options']['allow_custom_donations'] ) ? false : '1';
355
356 echo $charitable_builder_form_fields->generate_toggle( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
357 $default_allow_custom,
358 esc_html__( 'Allow Custom Donations', 'charitable' ),
359 array(
360 'id' => 'field_' . esc_attr( $this->type ) . '_allow_custom_donations' . '_' . intval( $field_id ), // phpcs:ignore
361 'name' => array( '_fields', intval( $field_id ), 'allow_custom_donations' ),
362 'container_class' => 'charitable-campaign-builder-allow-custom-donations',
363 'field_id' => esc_attr( $field_id ),
364 'checked_value' => '1',
365 )
366 );
367
368 echo $charitable_builder_form_fields->generate_divider( false, false, array( 'field_id' => $field_id ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
369
370 echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
371 isset( $settings['css_class'] ) ? $settings['css_class'] : false,
372 esc_html__( 'CSS Class', 'charitable' ),
373 array(
374 'id' => 'field_' . esc_attr( $this->type ) . '_css_class' . '_' . intval( $field_id ),
375 'name' => array( '_fields', intval( $field_id ), 'css_class' ),
376 'field_id' => intval( $field_id ),
377 'tooltip' => esc_html__( 'Add CSS classes (seperated by a space) for this field to customize it\'s appearance in your theme.', 'charitable' ),
378 )
379 );
380
381 ?>
382
383 <?php
384
385 $html = ob_get_clean();
386
387 return $html;
388 }
389
390 /**
391 * Display settings for AJAX requests.
392 *
393 * @since 1.8.0
394 * @version 1.8.9.1
395 *
396 * @return void
397 */
398 public function settings_display_ajax() {
399 // phpcs:disable WordPress.Security.NonceVerification.Missing
400 $field_id = isset( $_POST['field_id'] ) ? intval( wp_unslash( $_POST['field_id'] ) ) : 0;
401 $campaign_id = isset( $_POST['campaign_id'] ) ? intval( wp_unslash( $_POST['campaign_id'] ) ) : 0; // todo: should this be added? see a few lines down.
402 // phpcs:enable WordPress.Security.NonceVerification.Missing
403
404 if ( ! class_exists( 'Charitable_Builder_Form_Fields' ) ) {
405 wp_send_json_error( esc_html__( 'Something went wrong while performing this action.', 'charitable' ) );
406 }
407
408 $charitable_builder_form_fields = new Charitable_Builder_Form_Fields();
409
410 $campaign_data = get_post_meta( $campaign_id, 'campaign_settings_v2', true );
411 $settings = isset( $campaign_data['fields'][ $field_id ] ) ? $campaign_data['fields'][ $field_id ] : false;
412
413 ob_start();
414
415 ?>
416
417 <?php
418
419 echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
420 isset( $settings['headline'] ) ? $settings['headline'] : '',
421 esc_html__( 'Headline', 'charitable' ),
422 array(
423 'id' => 'field_' . esc_attr( $this->type ) . '_headline' . '_' . intval( $field_id ), // phpcs:ignore
424 'name' => array( '_fields', intval( $field_id ), 'headline' ),
425 'field_id' => intval( $field_id ),
426 'tooltip' => esc_html__( 'Add a headline to this field.', 'charitable' ),
427 'class' => 'charitable-campaign-builder-headline',
428 )
429 );
430
431 echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
432 $settings['css_class'],
433 esc_html__( 'CSS Class', 'charitable' ),
434 array(
435 'id' => 'field_' . esc_attr( $this->type ) . '_css_class',
436 'name' => array( 'fields', esc_attr( $this->type ), 'css_class' ),
437 'tooltip' => esc_html( $this->tooltip ),
438 )
439 );
440
441 ?>
442
443 <?php
444
445 $html = ob_get_clean();
446
447 wp_send_json_success( [ 'html' => $html ] );
448
449 exit;
450 }
451
452 /**
453 * Enqueue frontend js.
454 *
455 * @since 1.8.0
456 */
457 public function frontend_js() {
458 }
459
460 /**
461 * Enqueue frontend limit option js.
462 *
463 * @since 1.8.0
464 *
465 * @param array $min Min or not.
466 */
467 public function builder_js( $min ) {
468 }
469
470 /**
471 * Amountat and sanitize field.
472 *
473 * @since 1.8.0
474 *
475 * @param int $field_id Field type.
476 * @param mixed $field_submit Field value that was submitted.
477 * @param array $campaign_data Campaign data and settings.
478 */
479 public function format( $field_id, $field_submit, $campaign_data ) {
480 }
481
482 /**
483 * Validate field on form submit.
484 *
485 * @since 1.8.0
486 *
487 * @param int $field_id Field ID.
488 * @param mixed $field_submit Field value that was submitted.
489 * @param array $campaign_data Campaign data and settings.
490 */
491 public function validate( $field_id, $field_submit, $campaign_data ) {
492 }
493
494
495 /**
496 * Return attributes that disable the field button if campaign_data shows one already exists in the template.
497 *
498 * @since 1.8.0
499 *
500 * @param array $field_attr All the settings for this field button.
501 * @param array $field Field data.
502 * @param array $campaign_data Campaign data and settings.
503 * @param array $current_fields Current fields according to saved campaign data.
504 */
505 public function make_unique_button( $field_attr = false, $field = false, $campaign_data = false, $current_fields = false ) {
506
507 if ( false === $field || false === $campaign_data || false === $current_fields || ! is_array( $campaign_data ) || ! is_array( $current_fields ) || empty( $field['type'] ) ) {
508 return $field_attr;
509 }
510
511 if ( ! empty( $field['type'] ) && $field['type'] !== $this->type ) {
512 return $field_attr;
513 }
514
515 // is this already in the template?
516 if ( in_array( $this->type, $current_fields, true ) ) {
517 $field_attr['class'][] = 'charitable-disabled';
518 }
519
520 return $field_attr;
521 }
522
523 /**
524 * Possible depreciated function.
525 *
526 * @since 1.8.0
527 *
528 * @param string $field Field type.
529 * @param array $field_atts Field value that was submitted.
530 * @param array $campaign_data Campaign data and settings.
531 */
532 public function section_top( $field, $field_atts, $campaign_data ) {
533 }
534
535 /**
536 * Possible depreciated function.
537 *
538 * @since 1.8.0
539 *
540 * @param string $field Field type.
541 * @param array $field_atts Field value that was submitted.
542 * @param array $campaign_data Campaign data and settings.
543 */
544 public function section_bottom( $field, $field_atts, $campaign_data ) {
545 }
546 }
547
548 new Charitable_Field_Donate_Amount();
549
550 endif;