PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.12.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.12.3
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 / settings / class-charitable-tools-settings.php

class-charitable-tools-settings.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.12.3, at includes/admin/settings/class-charitable-tools-settings.php

552 lines 19.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Charitable Tools Settings UI.
4 *
5 * @package Charitable/Classes/Charitable_Tools_Settings
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.7.0.7
10 * @version 1.8.1.6
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Tools_Settings' ) ) :
19
20 /**
21 * Charitable_Tools_Settings
22 *
23 * @since 1.8.1.6
24 */
25 final class Charitable_Tools_Settings {
26
27 /**
28 * The single instance of this class.
29 *
30 * @since 1.8.1.6
31 *
32 * @var Charitable_Tools_Settings|null
33 */
34 private static $instance = null;
35
36 /**
37 * Create object instance.
38 *
39 * @since 1.8.1.6
40 */
41 private function __construct() {
42 }
43
44 /**
45 * Returns and/or create the single instance of this class.
46 *
47 * @since 1.8.1.6
48 *
49 * @return Charitable_Tools_Settings
50 */
51 public static function get_instance() {
52 if ( is_null( self::$instance ) ) {
53 self::$instance = new self();
54 }
55
56 return self::$instance;
57 }
58
59 /**
60 * Add the tools tab settings fields.
61 *
62 * @since 1.8.1.6
63 * @deprecated 1.8.10 Use add_tools_import_charitable_fields() instead.
64 *
65 * @return array<string,array>
66 */
67 public function add_tools_import_fields() {
68 return $this->add_tools_import_charitable_fields();
69 }
70
71 /**
72 * Add the Charitable sub-tab import fields (Campaign Import + Campaign Donations).
73 *
74 * @since 1.8.10
75 *
76 * @return array<string,array>
77 */
78 public function add_tools_import_charitable_fields() {
79
80 if ( ! charitable_is_tools_view( 'import' ) || ! charitable_is_tools_view( 'import__charitable' ) ) {
81 return array();
82 }
83
84 return array(
85 'section' => array(
86 'title' => '',
87 'type' => 'hidden',
88 'priority' => 1000,
89 'value' => 'import',
90 ),
91 'charitable_heading' => array(
92 'title' => __( 'Charitable', 'charitable' ),
93 'type' => 'heading',
94 'class' => 'charitable-tools-heading-pro',
95 'help' => __( 'Import campaigns and donations from Charitable JSON export files.', 'charitable' ),
96 'priority' => 15,
97 ),
98 'import_campaign' => array(
99 'label_for' => __( 'Campaign Import', 'charitable' ),
100 'type' => 'file',
101 'wrapper_class' => 'test',
102 'nonce_action_name' => 'import_campaign',
103 'nonce_field_name' => 'charitable_nonce',
104 'name' => 'campaign',
105 'action' => 'tools-campaign',
106 'button_label' => esc_html__( 'Import Campaign', 'charitable' ),
107 'help' => sprintf(
108 /* translators: %1$s: HTML strong tag. %2$s: HTML closing strong tag. %3$s: HTML break tag. */
109 esc_html__( 'Imports a campaign JSON file into this website. It will not overwrite any previous campaigns, and it will set to "inactive" with a new campaign ID.%3$s %1$sCampaign tools do not include donations or campaign creators%2$s.', 'charitable' ),
110 '<strong>',
111 '</strong>',
112 '<br />'
113 ),
114 'priority' => 25,
115 'default' => 2,
116 ),
117 'import_donations' => array(
118 'label_for' => __( 'Campaign Donations', 'charitable' ),
119 'type' => 'file',
120 'wrapper_class' => 'test',
121 'nonce_action_name' => 'import_donations',
122 'nonce_field_name' => 'charitable_nonce',
123 'name' => 'donations',
124 'action' => 'tools-donation',
125 'button_label' => esc_html__( 'Import Donations', 'charitable' ),
126 'help' => sprintf(
127 /* translators: %1$s: HTML strong tag. %2$s: HTML closing strong tag. %3$s: HTML break tag. */
128 esc_html__( 'Imports a donation JSON file into the selected campaign. It will not overwrite any previous donations or prevent duplicates.%3$s %1$sDonation tools do not include users - if a donor\'s email address is not found, the donation will not be assigned to a user%2$s.', 'charitable' ),
129 '<strong>',
130 '</strong>',
131 '<br />'
132 ),
133 'priority' => 25,
134 'default' => 2,
135 'options' => $this->get_campaign_list( true ),
136 'select_name' => 'tools_campaign',
137 ),
138 );
139 }
140
141 /**
142 * Add the GiveWP sub-tab import fields (CSV Donations Import + Migration Tool).
143 *
144 * @since 1.8.10
145 *
146 * @return array<string,array>
147 */
148 public function add_tools_import_givewp_fields() {
149
150 if ( ! charitable_is_tools_view( 'import' ) || ! charitable_is_tools_view( 'import__givewp' ) ) {
151 return array();
152 }
153
154 return array(
155 'section' => array(
156 'title' => '',
157 'type' => 'hidden',
158 'priority' => 1000,
159 'value' => 'import',
160 ),
161 'givewp_heading' => array(
162 'title' => __( 'GiveWP', 'charitable' ),
163 'type' => 'heading',
164 'class' => 'charitable-tools-heading-pro',
165 'help' => __( 'Manually import donations from GiveWP.', 'charitable' ),
166 'priority' => 15,
167 ),
168 'import_donations_givewp_csv' => array(
169 'label_for' => __( 'GiveWP CSV Donations Import', 'charitable' ),
170 'type' => 'file',
171 'wrapper_class' => 'test',
172 'nonce_action_name' => 'import_donations_givewp',
173 'nonce_field_name' => 'charitable_nonce',
174 'name' => 'donations_givewp',
175 'action' => 'tools-givewp-donations',
176 'button_label' => esc_html__( 'Import GiveWP Donations', 'charitable' ),
177 'help' => esc_html__( 'Import donations from a GiveWP CSV export file. Donors will be created or matched by email address during the import process.', 'charitable' ),
178 'accept' => '.csv',
179 'priority' => 25,
180 'default' => 2,
181 ),
182 'givewp_migration_heading' => array(
183 'title' => __( 'GiveWP Migration Tool', 'charitable' ),
184 'type' => 'heading',
185 'class' => 'charitable-tools-heading-pro',
186 'help' => __( 'Import data directly from the GiveWP database.', 'charitable' ),
187 'priority' => 45,
188 ),
189 'givewp_migration_tool' => array(
190 'title' => __( 'GiveWP Migration', 'charitable' ) . ' <span class="badge beta">' . __( 'BETA', 'charitable' ) . '</span>',
191 'label_for' => 'charitable-givewp-migrate-start',
192 'type' => 'content',
193 'render' => true,
194 'callback' => array( $this, 'render_givewp_migration_tool' ),
195 'priority' => 50,
196 'class' => 'charitable-givewp-migration-row',
197 ),
198 );
199 }
200
201 /**
202 * Render the GiveWP Pro upsell notice.
203 *
204 * @since 1.8.10
205 *
206 * @return void
207 */
208 public function render_givewp_pro_notice() {
209 echo '<div class="charitable-import-pro-notice">';
210 echo '<p>';
211 printf(
212 /* translators: %1$s: opening anchor tag. %2$s: closing anchor tag. */
213 esc_html__( '%1$sUpgrade to Charitable Pro%2$s for full GiveWP migration capabilities including recurring donations, standalone donor imports, rollback support, and import history.', 'charitable' ),
214 '<a href="' . esc_url( 'https://wpcharitable.com/lite-upgrade/' ) . '" target="_blank"><strong>',
215 '</strong></a>'
216 );
217 echo '</p>';
218 echo '</div>';
219 }
220
221 /**
222 * Render the GiveWP Migration Tool UI.
223 *
224 * @since 1.8.10
225 *
226 * @return void
227 */
228 public function render_givewp_migration_tool() {
229 $importer = Charitable_GiveWP_Importer::get_instance();
230 $is_active = $importer->is_givewp_active();
231
232 echo '<div class="charitable-givewp-migration-wrap">';
233
234 if ( ! $is_active ) {
235 echo '<div class="migration-info-box">';
236 echo '<p>' . esc_html__( 'GiveWP is not active on this site. Please install and activate GiveWP to use the migration tool.', 'charitable' ) . '</p>';
237 echo '</div>';
238 echo '</div>';
239 return;
240 }
241
242 $counts = $importer->get_counts();
243
244 // Pro upsell notice.
245 $this->render_givewp_pro_notice();
246
247 // Before You Begin box.
248 echo '<div class="migration-info-box charitable-before-import">';
249 echo '<p class="info-box-heading"><strong>' . esc_html__( 'Before You Begin:', 'charitable' ) . '</strong></p>';
250 echo '<ul>';
251 echo '<li>' . esc_html__( 'Back up your database before importing.', 'charitable' ) . '</li>';
252 echo '<li>' . esc_html__( 'Imported campaigns will be set to draft status for your review.', 'charitable' ) . '</li>';
253 echo '<li>' . esc_html__( 'Duplicate items (previously imported) will be automatically skipped.', 'charitable' ) . '</li>';
254 echo '<li>' . esc_html__( 'Keep GiveWP activated until you verify the import completed correctly.', 'charitable' ) . '</li>';
255 echo '</ul>';
256 echo '</div>';
257
258 // GiveWP Data Found box.
259 echo '<div class="migration-info-box">';
260 echo '<p class="info-box-heading"><strong>' . esc_html__( 'GiveWP Data Found:', 'charitable' ) . '</strong></p>';
261 echo '<table class="migration-data-found">';
262 echo '<tr><td class="data-count">' . intval( $counts['campaigns'] ) . '</td><td>' . esc_html__( 'Campaigns (Forms)', 'charitable' ) . '</td></tr>';
263 echo '<tr><td class="data-count">' . intval( $counts['donations'] ) . '</td><td>' . esc_html__( 'Donations', 'charitable' ) . '</td></tr>';
264 echo '</table>';
265 echo '</div>';
266
267 // Select What to Import.
268 echo '<div class="migration-select-section">';
269 echo '<p class="select-heading"><strong>' . esc_html__( 'Select What to Import:', 'charitable' ) . '</strong></p>';
270 echo '<div class="migration-options">';
271 echo '<label><input type="checkbox" name="givewp_import_campaigns" value="1" checked="checked" /> ';
272 /* translators: %d: number of GiveWP forms found. */
273 echo sprintf( esc_html__( 'Campaigns (%d GiveWP forms)', 'charitable' ), intval( $counts['campaigns'] ) );
274 echo '</label>';
275 echo '<label><input type="checkbox" name="givewp_import_donations" value="1" checked="checked" /> ';
276 /* translators: %d: number of GiveWP donations found. */
277 echo sprintf( esc_html__( 'Donations (%d)', 'charitable' ), intval( $counts['donations'] ) );
278 echo '</label>';
279 echo '</div>';
280
281 echo '<div class="migration-extra-options">';
282 echo '<label><input type="checkbox" name="givewp_dry_run" value="1" /> ';
283 echo esc_html__( 'Dry Run (Preview Only)', 'charitable' );
284 echo '<span class="option-description"> ' . esc_html__( 'Preview what will be imported without making changes', 'charitable' ) . '</span>';
285 echo '</label>';
286 echo '</div>';
287 echo '</div>';
288
289 // Start button.
290 echo '<p class="migration-button-wrap">';
291 echo '<button type="button" id="charitable-givewp-migrate-start" class="charitable-migration-btn">';
292 echo '<span class="dashicons dashicons-migrate"></span> ';
293 echo esc_html__( 'Start GiveWP Import', 'charitable' );
294 echo '</button>';
295 echo '</p>';
296
297 // Progress.
298 echo '<div class="migration-progress">';
299 echo '<div class="progress-bar-outer"><div class="progress-bar-inner"></div></div>';
300 echo '<div class="progress-status"></div>';
301 echo '</div>';
302
303 // Results.
304 echo '<div class="migration-results">';
305 echo '<h4>' . esc_html__( 'Migration Results', 'charitable' ) . '</h4>';
306 echo '<table>';
307 echo '<thead><tr><th>' . esc_html__( 'Type', 'charitable' ) . '</th><th>' . esc_html__( 'Imported', 'charitable' ) . '</th><th>' . esc_html__( 'Skipped', 'charitable' ) . '</th><th>' . esc_html__( 'Errors', 'charitable' ) . '</th></tr></thead>';
308 echo '<tbody></tbody>';
309 echo '</table>';
310 echo '</div>';
311
312 // Dry-run results.
313 echo '<div class="migration-dry-run-results" style="display:none;">';
314 echo '<h4>' . esc_html__( 'Dry Run Results', 'charitable' ) . '</h4>';
315 echo '<table>';
316 echo '<thead><tr><th>' . esc_html__( 'Type', 'charitable' ) . '</th><th>' . esc_html__( 'Would Import', 'charitable' ) . '</th><th>' . esc_html__( 'Would Skip', 'charitable' ) . '</th><th>' . esc_html__( 'Potential Issues', 'charitable' ) . '</th></tr></thead>';
317 echo '<tbody></tbody>';
318 echo '</table>';
319 echo '</div>';
320
321 // Error.
322 echo '<div class="migration-error"></div>';
323
324 echo '</div>';
325
326 wp_nonce_field( 'charitable_givewp_migration', 'charitable_givewp_migration_nonce' );
327 }
328
329 /**
330 * Add the GiveButter sub-tab import fields (CSV Donations Import only).
331 *
332 * @since 1.8.10
333 *
334 * @return array<string,array>
335 */
336 public function add_tools_import_givebutter_fields() {
337
338 if ( ! charitable_is_tools_view( 'import' ) || ! charitable_is_tools_view( 'import__givebutter' ) ) {
339 return array();
340 }
341
342 return array(
343 'section' => array(
344 'title' => '',
345 'type' => 'hidden',
346 'priority' => 1000,
347 'value' => 'import',
348 ),
349 'givebutter_heading' => array(
350 'title' => __( 'GiveButter', 'charitable' ),
351 'type' => 'heading',
352 'class' => 'charitable-tools-heading-pro',
353 'help' => __( 'Manually import donations from GiveButter.', 'charitable' ),
354 'priority' => 15,
355 ),
356 'import_donations_givebutter_csv' => array(
357 'label_for' => __( 'GiveButter CSV Donations Import', 'charitable' ),
358 'type' => 'file',
359 'wrapper_class' => 'test',
360 'nonce_action_name' => 'import_donations_givebutter',
361 'nonce_field_name' => 'charitable_nonce',
362 'name' => 'donations_givebutter',
363 'action' => 'tools-givebutter-donations',
364 'button_label' => esc_html__( 'Import GiveButter Donations', 'charitable' ),
365 'help' => esc_html__( 'Import donations from a GiveButter CSV export file. Donors will be created or matched by email address during the import process.', 'charitable' ),
366 'accept' => '.csv',
367 'priority' => 25,
368 'default' => 2,
369 ),
370 );
371 }
372
373 /**
374 * Add the tools tab settings fields.
375 *
376 * @since 1.8.1.6
377 *
378 * @return array<string,array>
379 */
380 public function add_tools_export_fields() {
381
382 if ( ! charitable_is_tools_view( 'export' ) ) {
383 return array();
384 }
385
386 return array(
387 'section' => array(
388 'title' => '',
389 'type' => 'hidden',
390 'priority' => 2000,
391 'value' => 'export',
392 ),
393 'export_campaign' => array(
394 'label_for' => __( 'Campaign Export', 'charitable' ),
395 'type' => 'select-form',
396 'wrapper_class' => 'test',
397 'nonce_action_name' => 'export_campaign',
398 'nonce_field_name' => 'charitable_nonce',
399 'name' => 'campaign',
400 'action' => 'export-campaign',
401 'button_label' => __( 'Export Campaign', 'charitable' ),
402 'help' => sprintf(
403 /* translators: %1$s: HTML strong tag. %2$s: HTML closing strong tag. %1$s: HTML break tag. */
404 __( 'Campaign exports files can be used to create a backup of your campaigns or to import campaigns into another site with Charitable installed.%3$s %1$sCampaign exports do not include donations or campaign creators%2$s.', 'charitable' ),
405 '<strong>',
406 '</strong>',
407 '<br />'
408 ),
409 'priority' => 225,
410 'default' => 2,
411 'options' => $this->get_campaigns_to_export(),
412 ),
413 'export_donations' => array(
414 'label_for' => __( 'Donations Export', 'charitable' ),
415 'type' => 'select-form',
416 'wrapper_class' => 'test',
417 'nonce_action_name' => 'export_donations_from_campaign',
418 'nonce_field_name' => 'charitable_nonce',
419 'name' => 'donations',
420 'action' => 'export-donations-from-campaign',
421 'button_label' => __( 'Export Donations', 'charitable' ),
422 'help' => sprintf(
423 /* translators: %1$s: HTML strong tag. %2$s: HTML closing strong tag. %1$s: HTML break tag. */
424 __( 'Donation exports files can be used to create a backup of your donations or to import donations if you are migrating campaigns to another site with Charitable installed. %3$s All donation types (paid, refunded, pending) will be exported. %1$sRecurring donations are not included%2$s.', 'charitable' ),
425 '<strong>',
426 '</strong>',
427 '<br />'
428 ),
429 'priority' => 227,
430 'default' => 2,
431 'options' => $this->get_campaigns_to_export( true ),
432 ),
433 );
434 }
435
436 /**
437 * Placeholder function.
438 *
439 * @since 1.8.1.6
440 */
441 public function add_tools_snippets_fields() {
442
443 return array();
444 }
445
446 /**
447 * Placeholder function.
448 *
449 * @since 1.8.2
450 */
451 public function add_tools_customize_fields() {
452
453 return array();
454 }
455
456 /**
457 * Return the list of user donation field options.
458 *
459 * @since 1.8.1.6
460 *
461 * @return string[]
462 */
463 protected function get_user_donation_field_options() {
464 $fields = charitable()->donation_fields()->get_data_type_fields( 'user' );
465
466 return array_combine(
467 array_keys( $fields ),
468 wp_list_pluck( $fields, 'label' )
469 );
470 }
471
472 /**
473 * Return the list of user donation field options.
474 *
475 * @since 1.7.0.7
476 *
477 * @param boolean $include_donations Whether to include the number of donations in the campaign name.
478 *
479 * @return string[]
480 */
481 protected function get_campaign_list( $include_donations = false ) {
482
483 $campaigns = array();
484
485 $args = array(
486 'posts_per_page' => -1,
487 'orderby' => 'post_title',
488 'order' => 'ASC',
489 'fields' => array( 'post_title', 'ID' ),
490 );
491
492 $results = Charitable_Campaigns::query( $args );
493
494 if ( empty( $results->posts ) ) {
495 return array();
496 }
497
498 foreach ( $results->posts as $index => $post ) :
499 $campaigns[ $post->ID ] = $post->post_title;
500 if ( $include_donations ) {
501 $donations = charitable_get_table( 'campaign_donations' )->get_donations_on_campaign( $post->ID );
502 $donation_count = count( $donations );
503 $plural = ( ( $donation_count > 1 ) || 0 === $donation_count ) ? 's' : '';
504 $campaigns[ $post->ID ] = $post->post_title . ' (' . count( $donations ) . ' donation' . $plural . ') ';
505 }
506 endforeach;
507
508 return( $campaigns );
509 }
510
511 /**
512 * Return the list of user donation field options.
513 *
514 * @since 1.7.0.7
515 *
516 * @param boolean $include_donations Whether to include the number of donations in the campaign name.
517 *
518 * @return string[]
519 */
520 protected function get_campaigns_to_export( $include_donations = false ) {
521
522 $campaigns = array();
523
524 $args = array(
525 'posts_per_page' => -1,
526 'orderby' => 'post_title',
527 'order' => 'ASC',
528 'fields' => array( 'post_title', 'ID' ),
529 );
530
531 $results = Charitable_Campaigns::query( $args );
532
533 if ( empty( $results->posts ) ) {
534 return array();
535 }
536
537 foreach ( $results->posts as $index => $post ) :
538 $campaigns[ $post->ID ] = $post->post_title;
539 if ( $include_donations ) {
540 $donations = charitable_get_table( 'campaign_donations' )->get_donations_on_campaign( $post->ID );
541 $donation_count = count( $donations );
542 $plural = ( ( $donation_count > 1 ) || 0 === $donation_count ) ? 's' : '';
543 $campaigns[ $post->ID ] = $post->post_title . ' (' . count( $donations ) . ' donation' . $plural . ') ';
544 }
545 endforeach;
546
547 return( $campaigns );
548 }
549 }
550
551 endif;
552