PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.11.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.11.3
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 1.7.0.9 All 211 releases
charitable / includes / admin / campaign-builder / class-charitable-campaign-builder.php

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

2,042 lines 77.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class that sets up the WordPress Campaign 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.10.5
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Campaign_Builder' ) ) :
19
20 /**
21 * Sets up the WordPress customizer.
22 *
23 * @since 1.8.0
24 */
25 class Charitable_Campaign_Builder {
26
27 /**
28 * Abort. Bail on proceeding to process the page.
29 *
30 * @since 1.8.0
31 *
32 * @var bool
33 */
34 public $abort = false;
35
36 /**
37 * The human-readable error message.
38 *
39 * @since 1.8.0
40 *
41 * @var string
42 */
43 private $abort_message;
44
45 /**
46 * One is the loneliest number that you'll ever do.
47 *
48 * @since 1.8.0
49 *
50 * @var object
51 */
52 private static $instance;
53
54 /**
55 * Current view (panel).
56 *
57 * @since 1.8.0
58 *
59 * @var string
60 */
61 public $view;
62
63 /**
64 * Current campaign ID (post ID).
65 *
66 * @since 1.8.0
67 *
68 * @var string
69 */
70 public $campaign_id;
71
72 /**
73 * Available panels.
74 *
75 * @since 1.8.0
76 *
77 * @var array
78 */
79 public $panels;
80
81 /**
82 * CSS Classes.
83 *
84 * @since 1.8.0
85 *
86 * @var array
87 */
88 public $classes;
89
90 /**
91 * Current form.
92 *
93 * @since 1.0.0
94 *
95 * @var WP_Post
96 */
97 public $campaign;
98
99 /**
100 * Form data and settings.
101 *
102 * @since 1.8.0
103 *
104 * @var array
105 */
106 public $campaign_data;
107
108 /**
109 * Current template information.
110 *
111 * @since 1.0.0
112 *
113 * @var array
114 */
115 public $template;
116
117 /**
118 * Main Instance.
119 *
120 * @since 1.8.0
121 *
122 * @return Charitable_Builder
123 */
124 public static function get_instance() {
125
126 if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Charitable_Campaign_Builder ) ) {
127
128 self::$instance = new Charitable_Campaign_Builder();
129
130 add_action( 'admin_init', array( self::$instance, 'init' ), 10 );
131 add_action( 'admin_init', array( self::$instance, 'deregister_common_wp_admin_styles' ), PHP_INT_MAX );
132
133 }
134
135 return self::$instance;
136 }
137
138 /**
139 * Create object instance.
140 *
141 * @since 1.8.0
142 */
143 private function __construct() {
144 }
145
146 /**
147 * Get campaign settings from an ID in the querystring.
148 *
149 * @since 1.8.0
150 * @version 1.8.2 add maybe_unserialize
151 *
152 * @param int|bool $campaign_id The campaign ID.
153 */
154 public function get_campaign_settings( $campaign_id = false ) {
155
156 if ( false === $campaign_id && ! empty( $_GET['campaign_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
157 $campaign_id = (int) $_GET['campaign_id']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
158 }
159
160 if ( 0 !== $campaign_id ) {
161
162 $this->campaign_data = get_post_meta( $campaign_id, 'campaign_settings_v2', true );
163
164 if ( empty( $this->campaign_data ) || false === $this->campaign_data ) {
165 $this->campaign_data = $this->get_default_settings();
166 }
167
168 if ( is_string( $this->campaign_data ) ) {
169 $this->campaign_data = maybe_unserialize( $this->campaign_data );
170 }
171
172 $this->campaign_data['id'] = $campaign_id;
173 $this->campaign_data['campaign_id'] = $campaign_id; // this should be fixed at some point.
174
175 } else {
176
177 $this->campaign_data = $this->get_default_settings();
178
179 }
180 }
181
182 /**
183 * Establish default settings for a new campaign.
184 *
185 * @since 1.8.0
186 */
187 public function get_default_settings() {
188
189 if ( ! is_array( $this->campaign_data ) ) {
190 $this->campaign_data = array();
191 }
192
193 $this->campaign_data['id'] = 0;
194 $this->campaign_data['campaign_id'] = 0;
195
196 $campaign_name = isset( $_POST['campaign_name'] ) && '' !== trim( $_POST['campaign_name'] ) ? esc_html( $_POST['campaign_name'] ) : ''; // phpcs:ignore
197
198 $this->campaign_data['tabs']['campaign']['title'] = esc_html__( 'Story.', 'charitable' );
199 $this->campaign_data['tabs']['campaign']['desc'] = esc_html__( 'Write Your Campaign\'s Story Here', 'charitable' );
200
201 $this->campaign_data['title'] = $campaign_name;
202 $this->campaign_data['desc'] = false; // 'test description';
203
204 $this->campaign_data['layout']['advanced']['tab_style'] = 'small';
205 $this->campaign_data['layout']['advanced']['tab_size'] = 'medium';
206
207 return $this->campaign_data;
208 }
209
210 /**
211 * Run things upon init.
212 *
213 * @since 1.8.0
214 */
215 public function init() {
216
217 if ( isset( $_POST['action'] ) && str_starts_with( $_POST['action'], 'charitable_' ) ) { // phpcs:ignore
218 $this->load_template_classes();
219 return;
220 }
221
222 // This isn't a charitable campaign builder page.
223 if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'charitable-campaign-builder' ) { // phpcs:ignore
224 return;
225 }
226
227 $this->view = isset( $_GET['view'] ) ? esc_attr( $_GET['view'] ) : false; // phpcs:ignore
228 $this->campaign_id = isset( $_GET['campaign_id'] ) ? intval( $_GET['campaign_id'] ) : false; // phpcs:ignore
229
230 // Lite has no Form panel content; fall back if ?view=form is requested directly.
231 if ( 'form' === $this->view ) {
232 $this->view = false;
233 }
234
235 // if no view was past, determine if the new campaign cofmr has been used (check settings) and if not redirect to template screen.
236 if ( $this->campaign_id && ! $this->view ) {
237 $campaign_data = get_post_meta( $this->campaign_id, 'campaign_settings_v2' );
238 if ( ! empty( $campaign_data ) && isset( $campaign_data['template'] ) && isset( $campaign_data['template']['id'] ) && 0 !== intval( $campaign_data['template']['id'] ) ) { // todo: better check?
239 $this->view = 'design';
240 } else {
241 $this->view = 'template';
242 }
243 } elseif ( ! $this->view ) {
244 $this->view = 'template';
245 }
246
247 // Load builder panels.
248 $this->load_panels();
249
250 // Load template related functions.
251 $this->load_template_classes();
252
253 // Load misc classes.
254 $this->load_misc();
255
256 add_action( 'admin_head', array( $this, 'admin_head' ) );
257 add_filter( 'admin_footer_text', '__return_false' );
258 add_action( 'admin_menu', array( $this, 'oz_admin_dashboard_footer_right' ) );
259 add_action( 'update_footer', '__return_false' );
260 add_action( 'admin_enqueue_scripts', array( $this, 'enqueues' ), PHP_INT_MAX );
261
262 // Disable displaying errors on this page because it breaks the CSS/Javascript.
263 if ( true === apply_filters( 'charitable_campaign_builder_diable_display_errors', true ) ) :
264 ini_set( 'display_errors', 0 ); // phpcs:ignore
265 endif;
266 }
267
268 /**
269 * Hide the WP version in the footer
270 *
271 * @return void
272 */
273 public function oz_admin_dashboard_footer_right() {
274 remove_filter( 'update_footer', 'core_update_footer' );
275 }
276
277 /**
278 * Enqueue assets for the builder.
279 *
280 * @since 1.8.0
281 */
282 public function enqueues() {
283
284 $this->get_campaign_settings();
285
286 // Remove conflicting scripts.
287 wp_deregister_script( 'serialize-object' );
288 wp_deregister_script( 'wpclef-ajax-settings' );
289
290 $min = '';
291 $style_version = charitable_get_style_version();
292 $version = charitable_is_break_cache() ? charitable()->get_version() . '.' . time() : charitable()->get_version();
293
294 /*
295 * Builder CSS.
296 */
297 $builder_styles = array(
298 'overlay',
299 'basic',
300 'preview',
301 'ui-general',
302 'fields',
303 'modals',
304 'alerts',
305 'onboarding',
306 'tour',
307 );
308
309 foreach ( $builder_styles as $style ) {
310 wp_enqueue_style(
311 $style === 'basic' ? 'campaign-builder' : 'charitable-builder-' . $style,
312 charitable()->get_path( 'directory', false ) . "assets/css/campaign-builder/builder-{$style}{$min}.css",
313 array(),
314 $style_version
315 );
316 }
317
318 /*
319 * Template CSS.
320 */
321
322 $template_id = isset( $this->campaign_data['template_id'] ) ? esc_attr( $this->campaign_data['template_id'] ) : charitable_campaign_builder_default_template();
323
324 $url_data = array(
325 'p' => isset( $this->campaign_data['layout']['advanced']['theme_color_primary'] ) ? preg_replace( '/[^A-Za-z0-9 ]/', '', $this->campaign_data['layout']['advanced']['theme_color_primary'] ) : '',
326 's' => isset( $this->campaign_data['layout']['advanced']['theme_color_secondary'] ) ? preg_replace( '/[^A-Za-z0-9 ]/', '', $this->campaign_data['layout']['advanced']['theme_color_secondary'] ) : '',
327 't' => isset( $this->campaign_data['layout']['advanced']['theme_color_tertiary'] ) ? preg_replace( '/[^A-Za-z0-9 ]/', '', $this->campaign_data['layout']['advanced']['theme_color_tertiary'] ) : '',
328 'b' => isset( $this->campaign_data['layout']['advanced']['theme_color_button'] ) ? preg_replace( '/[^A-Za-z0-9 ]/', '', $this->campaign_data['layout']['advanced']['theme_color_button'] ) : '',
329 'ver' => charitable()->get_version(),
330 );
331
332 $url_data_params = http_build_query( $url_data );
333
334 // Use REST API for admin CSS templates (added in 1.8.9.2)
335 wp_enqueue_style(
336 'charitable-builder-template-preview-theme',
337 add_query_arg( $url_data, rest_url( 'charitable/v1/campaign-css-admin/' . $template_id ) ),
338 array(),
339 $style_version
340 );
341 wp_enqueue_style(
342 'charitable-builder-template-preview-theme-colors-primary',
343 add_query_arg( $url_data, rest_url( 'charitable/v1/campaign-css-admin/' . $template_id . '-colors' ) ),
344 array(),
345 $style_version
346 );
347 wp_enqueue_style(
348 'charitable-builder-template-preview-theme-colors-secondary',
349 add_query_arg( $url_data, rest_url( 'charitable/v1/campaign-css-admin/' . $template_id . '-colors' ) ),
350 array(),
351 $style_version
352 );
353 wp_enqueue_style(
354 'charitable-builder-template-preview-theme-colors-tertiary',
355 add_query_arg( $url_data, rest_url( 'charitable/v1/campaign-css-admin/' . $template_id . '-colors' ) ),
356 array(),
357 $style_version
358 );
359 wp_enqueue_style(
360 'charitable-builder-template-preview-theme-colors-button',
361 add_query_arg( $url_data, rest_url( 'charitable/v1/campaign-css-admin/' . $template_id . '-colors' ) ),
362 array(),
363 $style_version
364 );
365
366 /*
367 * Third-party CSS.
368 */
369 wp_enqueue_style(
370 'charitable-font-awesome',
371 charitable()->get_path( 'directory', false ) . 'assets/lib/font-awesome/font-awesome.min.css',
372 null,
373 '4.7.0'
374 );
375
376 wp_enqueue_style(
377 'tooltipster',
378 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.css',
379 null,
380 '4.2.6'
381 );
382
383 wp_enqueue_style(
384 'jquery-confirm',
385 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.confirm/jquery-confirm.min.css',
386 null,
387 '3.3.4'
388 );
389
390 wp_enqueue_style(
391 'minicolors',
392 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.minicolors/jquery.minicolors.min.css',
393 null,
394 '2.2.6'
395 );
396
397 wp_enqueue_style(
398 'choices',
399 charitable()->get_path( 'directory', false ) . 'assets/css/campaign-builder/choices.css',
400 null,
401 '2.2.6'
402 );
403
404 wp_enqueue_style(
405 'quill-css',
406 charitable()->get_path( 'directory', false ) . 'assets/lib/quill/quill.snow.css',
407 null,
408 '2.2.6'
409 );
410
411 wp_enqueue_style(
412 'select2-css',
413 charitable()->get_path( 'directory', false ) . "assets/css/libraries/select2{$min}.css",
414 array(),
415 '4.0.12'
416 );
417
418 wp_enqueue_style(
419 'quill-mention-css',
420 charitable()->get_path( 'directory', false ) . 'assets/lib/quill/quill-mention/quill.mention.css',
421 null,
422 '2.2.6'
423 );
424
425 wp_enqueue_style(
426 'coloris-css',
427 charitable()->get_path( 'directory', false ) . 'assets/css/libraries/coloris.min.css',
428 null,
429 '2.2.6'
430 );
431
432 /**
433 * Enqueue jQuery UI smoothness theme for datepicker styling.
434 *
435 * Note: This file must be bundled locally for WordPress.org compliance.
436 * Download from: https://code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css
437 * Save to: assets/css/libraries/jquery-ui-smoothness.css
438 *
439 * @since 1.0.0
440 * @version 1.8.9.1
441 */
442 wp_enqueue_style(
443 'themeslug-jquery-css',
444 charitable()->get_path( 'directory', false ) . 'assets/css/libraries/jquery-ui-smoothness.css',
445 null,
446 '1.11.2'
447 );
448
449 // Remove TinyMCE editor styles from third-party themes and plugins.
450 remove_editor_styles();
451
452 do_action( 'charitable_campaign_builder_backend_styles', $min );
453
454 /*
455 * JavaScript.
456 */
457 wp_enqueue_media();
458 wp_enqueue_script( 'jquery-ui-sortable' );
459 wp_enqueue_script( 'jquery-ui-draggable' );
460 wp_enqueue_script( 'jquery-ui-datepicker' );
461 wp_enqueue_script( 'wp-util' );
462
463 wp_enqueue_script(
464 'tooltipster',
465 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.js',
466 array( 'jquery' ),
467 '4.2.6'
468 );
469
470 wp_enqueue_script(
471 'jquery-confirm',
472 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.confirm/jquery-confirm.min.js',
473 array( 'jquery' ),
474 '3.3.4'
475 );
476
477 wp_enqueue_script(
478 'charitable-hotkeys',
479 charitable()->get_path( 'directory', false ) . 'assets/js/libraries/hotkeys.min.js',
480 array( 'jquery' ),
481 '3.3.4'
482 );
483
484 wp_enqueue_script(
485 'charitable-utils',
486 charitable()->get_path( 'directory', false ) . "assets/js/campaign-builder/utils{$min}.js",
487 array( 'jquery', 'dom-purify' ),
488 charitable()->get_version()
489 );
490
491 wp_enqueue_script(
492 'choicesjs',
493 charitable()->get_path( 'directory', false ) . 'assets/js/libraries/choices.min.js',
494 array(),
495 '9.0.1'
496 );
497
498 wp_enqueue_script(
499 'charitable-builder-choicesjs',
500 charitable()->get_path( 'directory', false ) . "assets/js/campaign-builder/choicesjs{$min}.js",
501 array( 'jquery', 'choicesjs' ),
502 charitable()->get_version()
503 );
504
505 wp_enqueue_script(
506 'dom-purify',
507 charitable()->get_path( 'directory', false ) . 'assets/lib/purify.min.js',
508 array(),
509 '2.4.3'
510 );
511
512 wp_enqueue_script(
513 'minicolors',
514 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.minicolors/jquery.minicolors.min.js',
515 array( 'jquery' ),
516 '2.2.6'
517 );
518
519 wp_enqueue_script(
520 'quill',
521 charitable()->get_path( 'directory', false ) . 'assets/lib/quill/quill.js',
522 array( 'jquery' ),
523 '2.2.6'
524 );
525
526 wp_register_script(
527 'select2',
528 charitable()->get_path( 'directory', false ) . "assets/js/libraries/select2{$min}.js",
529 array( 'jquery' ),
530 '4.0.12',
531 true
532 );
533
534 wp_enqueue_script(
535 'quill-mention',
536 charitable()->get_path( 'directory', false ) . 'assets/lib/quill/quill-mention/quill.mention-min.js',
537 array( 'jquery', 'quill' ),
538 '2.2.6'
539 );
540
541 wp_enqueue_script(
542 'coloris',
543 charitable()->get_path( 'directory', false ) . 'assets/js/libraries/coloris.min.js',
544 array( 'jquery' ),
545 '1.0.0'
546 );
547
548 // if 'charitable-admin-utils' is already registered, deregister it and re-register it with this version.
549 if ( wp_script_is( 'charitable-admin-utils', 'registered' ) ) {
550 wp_deregister_script( 'charitable-admin-utils' );
551 }
552 wp_enqueue_script(
553 'charitable-admin-utils',
554 charitable()->get_path( 'directory', false ) . "assets/js/campaign-builder/admin-utils{$min}.js",
555 array( 'jquery', 'dom-purify' ),
556 charitable()->get_version()
557 );
558
559 wp_enqueue_script(
560 'charitable-builder',
561 charitable()->get_path( 'directory', false ) . "assets/js/campaign-builder/admin-builder{$min}.js",
562 array(
563 'jquery',
564 'charitable-utils',
565 'jquery-ui-sortable',
566 'jquery-ui-draggable',
567 'tooltipster',
568 'jquery-confirm',
569 'quill',
570 'select2',
571 'choicesjs',
572 'coloris',
573 'charitable-builder-choicesjs',
574 'wp-util',
575 ),
576 $version
577 );
578
579 wp_enqueue_script(
580 'charitable-campaign-preview-field-js',
581 charitable()->get_path( 'directory', false ) . "assets/js/campaign-builder/fields/base{$min}.js",
582 array(
583 'charitable-builder',
584 ),
585 charitable()->get_version()
586 );
587
588 wp_localize_script(
589 'charitable-builder',
590 'charitable_builder',
591 $this->get_localized_strings()
592 );
593
594 wp_localize_script(
595 'charitable-builder',
596 'charitable_addons',
597 $this->get_localized_addons()
598 );
599
600 wp_localize_script(
601 'charitable-builder',
602 'charitable_campaign_builder_field_conditionals',
603 $this->get_conditionals()
604 );
605
606 /* tour */
607
608 wp_enqueue_script(
609 'charitable-shepherd',
610 charitable()->get_path( 'directory', false ) . 'assets/js/libraries/shepherd.js',
611 array( 'jquery', 'charitable-float-ui-core', 'charitable-float-ui-dom' ),
612 charitable()->get_version()
613 );
614
615 wp_enqueue_script(
616 'charitable-admin-builder-tour',
617 charitable()->get_path( 'directory', false ) . 'assets/js/campaign-builder/admin-tour.js',
618 array( 'jquery', 'charitable-admin-utils', 'charitable-builder', 'charitable-shepherd', 'charitable-float-ui-core', 'charitable-float-ui-dom' ),
619 charitable()->get_version()
620 );
621
622 wp_localize_script(
623 'charitable-admin-builder-tour',
624 'charitable_admin_builder_onboarding',
625 [
626 'nonce' => wp_create_nonce( 'charitable_onboarding_ajax_nonce' ),
627 'ajaxurl' => admin_url( 'admin-ajax.php' ),
628 'option' => array(
629 'tour' => array(
630 'status' => $this->get_tour_option( 'status' ),
631 ),
632 ),
633 ]
634 );
635
636 wp_enqueue_style(
637 'charitable-shepherd',
638 charitable()->get_path( 'directory', false ) . "assets/css/libraries/shepherd{$min}.css",
639 array(),
640 $style_version
641 );
642
643 wp_enqueue_script(
644 'charitable-float-ui-core',
645 charitable()->get_path( 'directory', false ) . 'assets/js/libraries/floating-ui-core.min.js',
646 array( 'jquery' ),
647 charitable()->get_version()
648 );
649
650 wp_enqueue_script(
651 'charitable-float-ui-dom',
652 charitable()->get_path( 'directory', false ) . 'assets/js/libraries/floating-ui-dom.min.js',
653 array( 'charitable-float-ui-core' ),
654 charitable()->get_version()
655 );
656
657 /* color picker for admin settings */
658 wp_enqueue_script( 'wp-color-picker', false, false, false, true ); // todo: check if this is needed.
659 wp_enqueue_style( 'wp-color-picker' );
660
661 do_action( 'charitable_builder_backend_scripts', $min );
662 }
663
664 /**
665 * Get localized strings.
666 *
667 * @since 1.8.0
668 * @version 1.8.1.12 Added error_no_title.
669 * @version 1.8.5.2 Added currency_decimal_separator and currency_thousands_separator.
670 *
671 * @return array
672 */
673 private function get_localized_strings() {
674
675 $campaign_name = isset( $_POST['campaign_name'] ) && '' !== trim( $_POST['campaign_name'] ) ? esc_html( $_POST['campaign_name'] ) : ''; // phpcs:ignore
676
677 $upgrade_utm_medium = false; // todo: update this.
678
679 $builder_template = new Charitable_Campaign_Builder_Templates();
680
681 $currency_helper = charitable_get_currency_helper();
682
683 $strings = array(
684 'version' => '1.8.5.2',
685 'currency_symbol' => $currency_helper->get_currency_symbol(),
686 'currency_decimal_separator' => $currency_helper->get_decimal_separator(),
687 'currency_thousands_separator' => $currency_helper->get_thousands_separator(),
688 'and' => esc_html__( 'And', 'charitable' ),
689 'assets_url' => admin_url( 'admin-ajax.php' ),
690 'ajax_url' => admin_url( 'admin-ajax.php' ),
691 'bulk_add_button' => esc_html__( 'Add New Choices', 'charitable' ),
692 'bulk_add_show' => esc_html__( 'Bulk Add', 'charitable' ),
693 'are_you_sure_to_close' => esc_html__( 'Are you sure you want to leave? You have unsaved changes', 'charitable' ),
694 'bulk_add_hide' => esc_html__( 'Hide Bulk Add', 'charitable' ),
695 'bulk_add_heading' => esc_html__( 'Add Choices (one per line)', 'charitable' ),
696 'bulk_add_presets_show' => esc_html__( 'Show presets', 'charitable' ),
697 'bulk_add_presets_hide' => esc_html__( 'Hide presets', 'charitable' ),
698 'date_select_day' => 'DD',
699 'date_select_month' => 'MM',
700 'cancel' => esc_html__( 'Cancel', 'charitable' ),
701 'ok' => esc_html__( 'OK', 'charitable' ),
702 'save_refresh' => esc_html__( 'Save And Reload Campaign', 'charitable' ),
703 'close' => esc_html__( 'Close', 'charitable' ),
704 'conditionals_change' => esc_html__( 'Due to form changes, conditional logic rules will be removed or updated:', 'charitable' ),
705 'conditionals_disable' => esc_html__( 'Are you sure you want to disable conditional logic? This will remove the rules for this field or setting.', 'charitable' ),
706 'no_preview_must_save' => esc_html__( 'Please Save!', 'charitable' ),
707 'no_preview_must_save_msg' => esc_html__( 'You need to save this campaign before previewing.', 'charitable' ),
708 'field_locked' => esc_html__( 'Field Locked', 'charitable' ),
709 'field_locked_msg' => esc_html__( 'This field cannot be deleted or duplicated.', 'charitable' ),
710 'field' => esc_html__( 'Field', 'charitable' ),
711 'field_locked_no_delete_msg' => esc_html__( 'This field cannot be deleted.', 'charitable' ),
712 'field_locked_no_duplicate_msg' => esc_html__( 'This field cannot be duplicated.', 'charitable' ),
713 'fields_available' => esc_html__( 'Available Fields', 'charitable' ),
714 'fields_unavailable' => esc_html__( 'No fields available', 'charitable' ),
715 'heads_up' => esc_html__( 'Heads up!', 'charitable' ),
716 'photo_image_placeholder' => apply_filters(
717 'charitable_campaign_builder_photo_image_placeholder_url',
718 charitable()->get_path( 'directory', false ) . 'assets/images/campaign-builder/photo-default-image.png'
719 ),
720 'nonce' => wp_create_nonce( 'charitable-builder' ),
721 'admin_nonce' => wp_create_nonce( 'charitable-admin' ),
722 'no_email_fields' => esc_html__( 'No email fields', 'charitable' ),
723 'notification_delete' => esc_html__( 'Are you sure you want to delete this notification?', 'charitable' ),
724 'notification_prompt' => esc_html__( 'Enter a notification name', 'charitable' ),
725 'notification_ph' => esc_html__( 'Eg: User Confirmation', 'charitable' ),
726 'notification_error' => esc_html__( 'You must provide a notification name', 'charitable' ),
727 'notification_def_name' => esc_html__( 'Default Notification', 'charitable' ),
728 'confirmation_delete' => esc_html__( 'Are you sure you want to delete this confirmation?', 'charitable' ),
729 'confirmation_prompt' => esc_html__( 'Enter a confirmation name', 'charitable' ),
730 'confirmation_ph' => esc_html__( 'Eg: Alternative Confirmation', 'charitable' ),
731 'confirmation_error' => esc_html__( 'You must provide a confirmation name', 'charitable' ),
732 'confirmation_def_name' => esc_html__( 'Default Confirmation', 'charitable' ),
733 'save' => esc_html__( 'Save', 'charitable' ),
734 'saving' => esc_html__( 'Saving', 'charitable' ),
735 'saved' => esc_html__( 'Saved!', 'charitable' ),
736 'save_exit' => esc_html__( 'Save and Exit', 'charitable' ),
737 'save_embed' => esc_html__( 'Save and Embed', 'charitable' ),
738 'saved_state' => '',
739 'layout_selector_show' => esc_html__( 'Show Layouts', 'charitable' ),
740 'layout_selector_hide' => esc_html__( 'Hide Layouts', 'charitable' ),
741 'layout_selector_layout' => esc_html__( 'Select your layout', 'charitable' ),
742 'layout_selector_column' => esc_html__( 'Select your column', 'charitable' ),
743 'loading' => esc_html__( 'Loading', 'charitable' ),
744 'template_select' => esc_html__( 'Use Template', 'charitable' ),
745 'template_confirm' => esc_html__( 'Changing templates on an existing form will DELETE existing form fields. Are you sure you want apply the new template?', 'charitable' ),
746 'embed' => esc_html__( 'Embed', 'charitable' ),
747 'exit' => esc_html__( 'Exit', 'charitable' ),
748 'exit_url' => charitable_current_user_can( 'edit_campaigns' ) ? admin_url( 'edit.php?post_type=campaign' ) : admin_url(),
749 'exit_confirm' => esc_html__( 'Your campaign contains unsaved changes. Would you like to save your changes first?', 'charitable' ),
750 'delete_confirm' => esc_html__( 'Are you sure you want to delete this field?', 'charitable' ),
751 'delete_tab_confirm' => esc_html__( 'Are you sure you want to delete this tab?', 'charitable' ),
752 'delete_choice_confirm' => esc_html__( 'Are you sure you want to delete this choice?', 'charitable' ),
753 'duplicate_confirm' => esc_html__( 'Are you sure you want to duplicate this field?', 'charitable' ),
754 'duplicate_copy' => esc_html__( '(copy)', 'charitable' ),
755 'error_title' => esc_html__( 'Please enter a campaign name.', 'charitable' ),
756 'error_no_title' => esc_html__( 'You need a name for your campaign before you save.', 'charitable' ),
757 'error_choice' => esc_html__( 'This item must contain at least one choice.', 'charitable' ),
758 'off' => esc_html__( 'Off', 'charitable' ),
759 'on' => esc_html__( 'On', 'charitable' ),
760 'or' => esc_html__( 'or', 'charitable' ),
761 'other' => esc_html__( 'Other', 'charitable' ),
762 'operator_is' => esc_html__( 'is', 'charitable' ),
763 'operator_is_not' => esc_html__( 'is not', 'charitable' ),
764 'operator_empty' => esc_html__( 'empty', 'charitable' ),
765 'operator_not_empty' => esc_html__( 'not empty', 'charitable' ),
766 'operator_contains' => esc_html__( 'contains', 'charitable' ),
767 'operator_not_contains' => esc_html__( 'does not contain', 'charitable' ),
768 'operator_starts' => esc_html__( 'starts with', 'charitable' ),
769 'operator_ends' => esc_html__( 'ends with', 'charitable' ),
770 'operator_greater_than' => esc_html__( 'greater than', 'charitable' ),
771 'operator_less_than' => esc_html__( 'less than', 'charitable' ),
772 'previous' => esc_html__( 'Previous', 'charitable' ),
773 'error_save_form' => esc_html__( 'Something went wrong while saving the form. Please reload the page and try again.', 'charitable' ),
774 'error_contact_support' => esc_html__( 'Please contact the plugin support team if this behavior persists.', 'charitable' ),
775 'error_already_started_campaign' => esc_html__( 'Are you sure you want to reset your template? All your work will be lost.', 'charitable' ),
776 'something_went_wrong' => esc_html__( 'Something went wrong', 'charitable' ),
777 'field_cannot_be_reordered' => esc_html__( 'This field cannot be moved.', 'charitable' ),
778 'donation_form_donation_button' => esc_html__( 'You shouldn\'t have a donation form AND a donation button in the same campaign page. Remove the donation button if you wish to add a donation form.', 'charitable' ),
779 'remove_donation_button' => esc_html__( 'Remove Donation Button', 'charitable' ),
780 'donation_button_donation_form' => esc_html__( 'You shouldn\'t have a donation form AND a donation button in the same campaign page. Remove the donation form if you wish to add a donation button.', 'charitable' ),
781 'remove_donation_form' => esc_html__( 'Remove Donation Form', 'charitable' ),
782 'only_one_donation_form' => esc_html__( 'You shouldn\'t have more than one donation form on your campaign page. Move or delete the current donation form.', 'charitable' ),
783 'campaign_delete_confirm' => esc_html__( 'Are you sure you want to delete your campaign? You cannot undo this.', 'charitable' ),
784 'feedback_form_fields_required' => esc_html__( 'Some fields of this form are required. Please update the form and try submiting again. Thanks!', 'charitable' ),
785 'empty_label' => esc_html__( 'Empty Label', 'charitable' ),
786 'no_pages_found' => esc_html__( 'No results found', 'charitable' ),
787 'empty_tab' => sprintf(
788 /* translators: %s: configure tab settings link */
789 esc_html__( 'This tab is empty. Drag a block from the left into this area or%1$s%2$s%3$s', 'charitable' ),
790 '<br/><strong><a href="#" class="charitable-configure-tab-settings">',
791 esc_html__( 'configure tab settings', 'charitable' ),
792 '</a></strong>'
793 ),
794 'no_tabs' => sprintf(
795 /* translators: %s: configure tab settings link */
796 esc_html__( 'There are no tabs yet for this template. You can %1$s%2$s%3$s to add a tab.', 'charitable' ),
797 '<br/><strong><a href="#" class="charitable-configure-tab-settings">',
798 esc_html__( 'configure tab settings', 'charitable' ),
799 '</a></strong>'
800 ),
801 'new_tab' => esc_html__( 'New Tab', 'charitable' ),
802 'default_campaign_title' => esc_html__( 'My New Campaign', 'charitable' ),
803 'field_disabled_due_to_modal' => esc_html__( 'We\'re sorry, the %name% is not available because you have the display settings for donation form set to \'modal\' in Charitable general settings.', 'charitable' ),
804 'field_disabled_due_to_same_page' => esc_html__( 'We\'re sorry, the %name% is not available because you have the display settings for donation form set to \'same page\' in Charitable general settings.', 'charitable' ),
805 'settings_page_url' => admin_url( 'admin.php?page=charitable-settings' ),
806 'go_to_settings' => esc_html__( 'Go to Settings', 'charitable' ),
807 'update_campaign' => esc_html__( 'Update Campaign', 'charitable' ),
808 'create_campaign' => esc_html__( 'Create Campaign', 'charitable' ),
809 'upgrade' => array(
810 'pro' => array(
811 /* translators: %s - plan name. */
812 'title' => esc_html( sprintf( __( 'is a %1$s feature.', 'charitable' ), '%plan%' ) ),
813 /* translators: %s - addon name. */
814 'message' => '<p>' . esc_html( sprintf( __( 'We\'re sorry, the %1$s is not available on your plan. Please upgrade to the %2$s plan to unlock all these awesome features.', 'charitable' ), '%name%', '%plan%' ) ) . '</p>',
815 'doc' => sprintf(
816 '<div class="lite-promo"><span>Bonus:</span> Charitable Lite users save <strong class="percent">$300 or more</strong> off the regular price, automatically applied at checkout!</div><div class="already-purchased-div"><a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a></div>',
817 esc_url( charitable_utm_link( 'https://wpcharitable.com/lite-vs-pro/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
818 esc_html__( 'Already purchased?', 'charitable' )
819 ),
820 'type' => 'pro-upgrade',
821 // translators: %1$s - plan name, %2$s - addon name.
822 'button' => esc_html( sprintf( __( 'Upgrade to %1$s And Unlock %2$s', 'charitable' ), '%plan%', '%name%' ) ),
823 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
824 'url_template' => false,
825 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
826 ),
827 'plus' => array(
828 /* translators: %s - plan name. */
829 'title' => esc_html( sprintf( __( 'is a %1$s feature.', 'charitable' ), '%plan%' ) ),
830 /* translators: %s - addon name. */
831 'message' => '<p>' . esc_html( sprintf( __( 'We\'re sorry, the %1$s is not available on your plan. Please upgrade to the %2$s plan to unlock all these awesome features.', 'charitable' ), '%name%', '%plan%' ) ) . '</p>',
832 'doc' => sprintf(
833 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
834 esc_url( charitable_utm_link( 'https://wpcharitable.com/lite-vs-pro/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
835 esc_html__( 'Already purchased?', 'charitable' )
836 ),
837 'type' => 'pro-upgrade',
838 // translators: %1$s - plan name, %2$s - addon name.
839 'button' => esc_html( sprintf( __( 'Upgrade to %1$s And Unlock %2$s', 'charitable' ), '%plan%', '%name%' ) ),
840 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
841 'url_template' => false,
842 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
843 ),
844 'basic' => array(
845 /* translators: %s - plan name. */
846 'title' => esc_html( sprintf( __( 'is a %1$s feature.', 'charitable' ), '%plan%' ) ),
847 /* translators: %s - addon name. */
848 'message' => '<p>' . esc_html( sprintf( __( 'We\'re sorry, the %1$s is not available on your plan. Please upgrade to the %2$s plan to unlock all these awesome features.', 'charitable' ), '%name%', '%plan%' ) ) . '</p>',
849 'doc' => sprintf(
850 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
851 esc_url( charitable_utm_link( 'https://wpcharitable.com/lite-vs-pro/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
852 esc_html__( 'Already purchased?', 'charitable' )
853 ),
854 'type' => 'pro-upgrade',
855 // translators: %1$s - plan name, %2$s - addon name.
856 'button' => esc_html( sprintf( __( 'Upgrade to %1$s And Unlock %2$s', 'charitable' ), '%plan%', '%name%' ) ),
857 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
858 'url_template' => false,
859 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
860 ),
861 'pro-panel' => array(
862 'title' => esc_html__( 'is a PRO feature', 'charitable' ),
863 /* translators: %s - addon name. */
864 'message' => '<p>' . esc_html( sprintf( __( 'We\'re sorry, %s features are not available on your plan. Please upgrade to the PRO plan to unlock all these awesome features.', 'charitable' ), '%name%' ) ) . '</p>',
865 'doc' => sprintf(
866 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
867 esc_url( charitable_utm_link( 'https://wpcharitable.com/lite-vs-pro/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
868 esc_html__( 'Already purchased?', 'charitable' )
869 ),
870 'type' => 'pro-upgrade',
871 // translators: %1$s - plan name, %2$s - addon name.
872 'button' => esc_html( sprintf( __( 'Upgrade to %1$s And Unlock %2$s', 'charitable' ), '%plan%', '%name%' ) ),
873 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
874 'url_template' => false,
875 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
876 ),
877 ),
878 'install' => array(
879 'pro' => array(
880 'title' => esc_html__( 'is not installed or activated', 'charitable' ),
881 /* translators: %s - addon name. */
882 'message' => '<p>' . esc_html( sprintf( __( 'Good news! You have the %1$s plan. Please install and activate the %2$s to add this feature to your campaign page.', 'charitable' ), '%name%', '%addon%' ) ) . '</p>',
883 'doc' => sprintf(
884 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
885 esc_url( charitable_utm_link( 'https://wpcharitable.com/account/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
886 esc_html__( 'Access Your Account', 'charitable' )
887 ),
888 'type' => 'charitable-install',
889 'button' => esc_html__( 'Install and Activate', 'charitable' ),
890 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
891 'url_template' => false,
892 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
893 ),
894 'plus' => array(
895 'title' => esc_html__( 'is not installed or activated', 'charitable' ),
896 /* translators: %s - addon name. */
897 'message' => '<p>' . esc_html( sprintf( __( 'Good news! You have the %1$s plan. Please install and activate the %2$s to add this feature to your campaign page.', 'charitable' ), '%name%', '%addon%' ) ) . '</p>',
898 'doc' => sprintf(
899 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
900 esc_url( charitable_utm_link( 'https://wpcharitable.com/account/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
901 esc_html__( 'Access Your Account', 'charitable' )
902 ),
903 'type' => 'charitable-install',
904 'button' => esc_html__( 'Install and Activate', 'charitable' ),
905 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
906 'url_template' => false,
907 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
908 ),
909 'basic' => array(
910 'title' => esc_html__( 'is not installed or activated', 'charitable' ),
911 /* translators: %s - addon name. */
912 'message' => '<p>' . esc_html( sprintf( __( 'Good news! You have the %1$s plan. Please install and activate the %2$s to add this feature to your campaign page.', 'charitable' ), '%name%', '%addon%' ) ) . '</p>',
913 'doc' => sprintf(
914 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
915 esc_url( charitable_utm_link( 'https://wpcharitable.com/account/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
916 esc_html__( 'Access Your Account', 'charitable' )
917 ),
918 'type' => 'charitable-install',
919 'button' => esc_html__( 'Install and Activate', 'charitable' ),
920 'url' => charitable_admin_upgrade_link( 'Action+Link+Campaign+Builder+Modal' ),
921 'url_template' => false,
922 'modal' => charitable_get_upgrade_modal_text( 'pro' ),
923 ),
924 ),
925 'activate' => array(
926 'title' => esc_html__( 'is not activated', 'charitable' ),
927 /* translators: %s - addon name. */
928 'message' => '<p>' . esc_html( sprintf( __( 'Good news! You have the %1$s installed, you just need to activate it.', 'charitable' ), '%addon%' ) ) . '</p>',
929 'doc' => sprintf(
930 '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a>',
931 esc_url( charitable_utm_link( 'https://wpcharitable.com/account/', 'Action+Link+Campaign+Builder+Modal', 'AP - %name%' ) ),
932 esc_html__( 'Access Your Account', 'charitable' )
933 ),
934 'type' => 'charitable-activate',
935 'button' => esc_html__( 'Activate', 'charitable' ),
936 ),
937 'activated_title' => esc_html__( 'is activated', 'charitable' ),
938 'installing' => esc_html__( 'installing...', 'charitable' ),
939 'activating' => esc_html__( 'activating...', 'charitable' ),
940 'standby' => esc_html__( 'standby...', 'charitable' ),
941 'installed_activated_reboot' => esc_html__( 'Save your campaign and refresh the page to use the addon with your campaign.', 'charitable' ),
942 'installed_activated_title' => esc_html__( 'has been installed and activated', 'charitable' ),
943 'installed_activated_failed_title' => esc_html__( 'failed to install and activate', 'charitable' ),
944 'installed_activated_failed_reboot' => esc_html__( 'Something went wrong. Save your campaign and attempt to install and activate the plugin on the WordPress plugin page.', 'charitable' ),
945 'activated_reboot' => esc_html__( 'Save your campaign and refresh the page to use the addon with your campaign.', 'charitable' ),
946 'activated_failed_title' => esc_html__( 'failed to activate', 'charitable' ),
947 'activated_failed_reboot' => esc_html__( 'Something went wrong. Save your campaign and attempt to activate the plugin on the WordPress plugin page.', 'charitable' ),
948 'activated_refresh_title' => esc_html__( 'is activated', 'charitable' ),
949 'activated_refresh' => esc_html__( 'Save your campaign and refresh the page to use the addon with your campaign.', 'charitable' ),
950 'upgrade_bonus_modal' => wpautop(
951 wp_kses(
952 __( '<strong>Bonus:</strong> Charitable Lite users get <span>50% off</span> regular price, automatically applied at checkout.', 'charitable' ),
953 array(
954 'strong' => array(),
955 'span' => array(),
956 )
957 )
958 ),
959 'charitable_addons_page' => esc_url( admin_url( 'admin.php?page=charitable-addons' ) ),
960 'form_upgrade_modal' => array(
961 'title' => esc_html__( 'Unlock the Visual Form Builder', 'charitable' ),
962 'message' => '<p>' . esc_html__( "The Charitable Pro plugin's visual form builder lets you drag and drop fields, build multi-step donation flows, and customize every part of your donation form - all without writing code.", 'charitable' ) . '</p><p>' . esc_html__( 'Upgrade to any paid Charitable plan to unlock the Charitable Pro plugin and design your forms exactly the way you want.', 'charitable' ) . '</p>',
963 'button' => esc_html__( 'Get Charitable Pro', 'charitable' ),
964 'doc' => sprintf(
965 '<div class="already-purchased-div"><a href="%1$s" target="_blank" rel="noopener noreferrer" class="already-purchased">%2$s</a></div>',
966 esc_url( 'https://www.wpcharitable.com/documentation/how-to-use-donation-form-visual-builder/' ),
967 esc_html__( 'Learn More', 'charitable' )
968 ),
969 'upgrade_url' => charitable_admin_upgrade_link( 'Campaign+Builder+Form+Panel+Modal' ),
970 ),
971 'charitable_license_label' => esc_html( Charitable_Licenses_Settings::get_instance()->get_license_label_from_plan_id() ),
972 'charitable_form_name' => $campaign_name,
973 'charitable_assets_dir' => apply_filters(
974 'charitable_campaign_builder_charitable_assets_dir',
975 charitable()->get_path( 'directory', false ) . 'assets/'
976 ),
977 'charitable_rest_url' => rest_url( 'charitable/v1/' ),
978 );
979
980 if ( $this->is_tour_active() ) {
981 $strings['onboarding_tour'] = array(
982 'next' => esc_html__( 'Next', 'charitable' ),
983 'start_tour' => esc_html__( 'Start Tour', 'charitable' ),
984 'watch_video' => esc_html__( 'Watch Video', 'charitable' ),
985 'choose_a_template' => esc_html__( 'Choose a Template', 'charitable' ),
986 'lets_get_started' => esc_html__( 'Get Started', 'charitable' ),
987 'step_0_text' => '<h2>' . esc_html__( 'Welcome to the Campaign Builder!', 'charitable' ) . '</h2><p>' . esc_html__( 'This is where you build, manage, and add features to your campaigns. The following steps will walk you through essential areas.', 'charitable' ) . '</p><div id="charitable-tour-video"></div>',
988 'step_1_title' => esc_html__( 'Name Your Campaign', 'charitable' ),
989 'step_1_text' => sprintf(
990 '<p>%1$s <strong>%2$s</strong> %3$s.</p>',
991 esc_html__( 'Give your campaign a name so you can easily identify it. Once you have entered a name, click', 'charitable' ),
992 esc_html__( 'Next', 'charitable' ),
993 esc_html__( 'to continue', 'charitable' )
994 ),
995 'step_2_title' => esc_html__( 'Select A Template', 'charitable' ),
996 'step_2_text' => sprintf(
997 '<p>%1$s <strong>%2$s</strong> %3$s.</p><p class="charitable-tour-tip"><strong>%4$s</strong> %5$s <strong>%6$s</strong> %7$s.</p>',
998 esc_html__( 'Build your campaign from scratch or use one of our pre-made templates. Hover over a thumbnail and select', 'charitable' ),
999 esc_html__( 'Create Campaign', 'charitable' ),
1000 esc_html__( 'to get started', 'charitable' ),
1001 esc_html__( 'For example:', 'charitable' ),
1002 esc_html__( 'The', 'charitable' ),
1003 esc_html__( 'Animal Sanctuary', 'charitable' ),
1004 esc_html__( 'template is perfect for animal rescue organizations', 'charitable' )
1005 ),
1006 'step_3_title' => esc_html__( 'Campaign Fields', 'charitable' ),
1007 'step_3_text' => sprintf(
1008 '<p>%1$s</p>',
1009 esc_html__( 'Clicking on this tab shows you the available fields for your campaign. You can drag additional fields to add to your page.', 'charitable' )
1010 ),
1011 'step_4_title' => esc_html__( 'Recommended Fields', 'charitable' ),
1012 'step_4_text' => sprintf(
1013 '<p>%1$s <span class="charitable-tour-check"></span> %2$s.</p>',
1014 esc_html__( 'These fields are usually found on all campaign pages. A', 'charitable' ),
1015 esc_html__( 'means that the field already is on your campaign page', 'charitable' )
1016 ),
1017 'step_5_title' => esc_html__( 'Standard Fields', 'charitable' ),
1018 'step_5_text' => sprintf(
1019 '<p>%1$s</p>',
1020 esc_html__( 'These are common fields you can use when you need them.', 'charitable' )
1021 ),
1022 'step_6_title' => esc_html__( 'Pro Fields', 'charitable' ),
1023 'step_6_text' => sprintf(
1024 '<p>%1$s</p>',
1025 esc_html__( 'Fields that offer advanced features offered by addons or third-party integrations.', 'charitable' )
1026 ),
1027 'step_7_title' => esc_html__( 'Save', 'charitable' ),
1028 'step_7_text' => sprintf(
1029 '<p>%1$s</p>',
1030 esc_html__( 'Save your campaign progress at any time.', 'charitable' )
1031 ),
1032 'step_8_title' => esc_html__( 'Publish Your Campaign', 'charitable' ),
1033 'step_8_text' => sprintf(
1034 '<p>%1$s</p>',
1035 esc_html__( 'When you\'re ready, launch your campaign and start raising funds.', 'charitable' )
1036 ),
1037 'step_9_title' => esc_html__( 'Preview', 'charitable' ),
1038 'step_9_text' => sprintf(
1039 '<p>%1$s</p>',
1040 esc_html__( 'See how your campaign will look while in draft or before making updates.', 'charitable' )
1041 ),
1042 'step_10_title' => esc_html__( 'View', 'charitable' ),
1043 'step_10_text' => sprintf(
1044 '<p>%1$s</p>',
1045 esc_html__( 'You can also check out your campaign once it\'s live.', 'charitable' )
1046 ),
1047 'step_11_title' => esc_html__( 'Embed', 'charitable' ),
1048 'step_11_text' => sprintf(
1049 '<p>%1$s</p>',
1050 esc_html__( 'Add a campaign to a new or existing page with our embed wizard, or use the shortcode provided.', 'charitable' )
1051 ),
1052 'step_12_title' => esc_html__( 'Settings', 'charitable' ),
1053 'step_12_text' => sprintf(
1054 '<p>%1$s</p><p>%2$s</p>',
1055 esc_html__( 'Customize campaign details, preferences, and enable new functionality.', 'charitable' ),
1056 esc_html__( 'Start with general settings where you can add donation goals, end dates, suggested amounts, and more.', 'charitable' )
1057 ),
1058 'step_13_title' => esc_html__( 'We hope you enjoyed the tour!', 'charitable' ),
1059 'step_13_text' => sprintf(
1060 '<p>%1$s</p>',
1061 // translators: %s - getting started guide link.
1062 sprintf( __( 'Remember that you can view our <a href="%1$s" target="_blank">getting started guide</a>, read our <a href="%2$s" target="_blank">documentation</a>, or <a href="%3$s" target="_blank">reach out to us</a> for support if you have any questions.', 'charitable' ), 'https://wpcharitable.com/getting-started', 'https://wpcharitable.com/documentation', 'https://wpcharitable.com/support' )
1063 ),
1064 /* onboarding alts */
1065 'step_1_title_onboarding' => esc_html__( 'Your Campaign Name', 'charitable' ),
1066 'step_1_text_onboarding' => sprintf(
1067 '<p>%1$s</p>',
1068 esc_html__( 'This is where you can change or update your campaign name', 'charitable' )
1069 ),
1070 );
1071 }
1072
1073 $strings = apply_filters( 'charitable_builder_strings', $strings, $this->campaign );
1074
1075 // phpcs:disable WordPress.Security.NonceVerification.Recommended
1076 if ( ! empty( $_GET['campaign_id'] ) ) {
1077 $campaign_id = (int) $_GET['campaign_id'];
1078 $strings['preview_url'] = false;
1079 $strings['entries_url'] = esc_url( admin_url( 'admin.php?page=charitable-entries&view=list&campaign_id=' . $campaign_id ) );
1080 }
1081 // phpcs:enable
1082
1083 return $strings;
1084 }
1085
1086 /**
1087 * Get localized addons.
1088 *
1089 * @since 1.8.0
1090 *
1091 * @return array
1092 */
1093 private function get_localized_addons() {
1094
1095 $strings = apply_filters(
1096 'charitable_campaign_builder_localized_addon_strings',
1097 array()
1098 );
1099
1100 return $strings;
1101 }
1102
1103 /**
1104 * Get conditional rules for showing/hiding settings fields in the campaign builder.
1105 *
1106 * @since 1.8.0
1107 *
1108 * @return array
1109 */
1110 private function get_conditionals() {
1111
1112 $strings = apply_filters(
1113 'charitable_campaign_builder_localized_conditionals',
1114 array()
1115 );
1116
1117 return $strings;
1118 }
1119
1120 /**
1121 * Clear common wp-admin styles, keep only allowed.
1122 *
1123 * @since 1.8.0
1124 */
1125 public function deregister_common_wp_admin_styles() {
1126
1127 if ( ! campaign_is_campaign_builder_admin_page() ) {
1128 return;
1129 }
1130
1131 /**
1132 * Filters the allowed common wp-admin styles.
1133 *
1134 * @since 1.8.0
1135 *
1136 * @param array $allowed_styles Styles allowed in the Campaign builder.
1137 */
1138 $allowed_styles = (array) apply_filters(
1139 'charitable_admin_builder_allowed_common_wp_admin_styles',
1140 array(
1141 'wp-editor',
1142 'wp-editor-font',
1143 'editor-buttons',
1144 'dashicons',
1145 'media-views',
1146 'imgareaselect',
1147 'wp-mediaelement',
1148 'mediaelement',
1149 'buttons',
1150 'admin-bar',
1151 )
1152 );
1153
1154 wp_styles()->registered = array_intersect_key( wp_styles()->registered, array_flip( $allowed_styles ) );
1155 }
1156
1157 /**
1158 * Define TinyMCE buttons to use with our fancy editor instances.
1159 *
1160 * @since 1.8.0
1161 *
1162 * @param array $buttons List of default buttons.
1163 *
1164 * @return array
1165 */
1166 public function tinymce_buttons( $buttons ) { // phpcs:ignore
1167
1168 return array( 'colorpicker', 'lists', 'wordpress', 'wpeditimage', 'wplink' );
1169 }
1170
1171 /**
1172 * Load panels.
1173 *
1174 * @since 1.0.0
1175 * @version 1.8.10.5 Added Form panel (Lite upgrade-prompt stub).
1176 */
1177 public function load_panels() {
1178
1179 // Base class and functions.
1180 require_once charitable()->get_path( 'includes' ) . 'admin/campaign-builder/panels/class-base.php';
1181
1182 /**
1183 * Campaign Builder panels slugs array filter.
1184 *
1185 * Allows developers to disable loading of some builder panels.
1186 *
1187 * @since 1.8.0
1188 *
1189 * @param array $panels Panels slugs array.
1190 */
1191 $this->panels = apply_filters(
1192 'charitable_builder_panels_',
1193 array(
1194 'template',
1195 'design',
1196 'form',
1197 'settings',
1198 'marketing',
1199 'payment',
1200 'help',
1201 )
1202 );
1203
1204 foreach ( $this->panels as $panel ) {
1205 $panel = sanitize_file_name( $panel );
1206 $file = require_once charitable()->get_path( 'includes' ) . "admin/campaign-builder/panels/class-{$panel}.php";
1207
1208 if ( file_exists( $file ) ) {
1209 require_once $file;
1210 }
1211 }
1212 }
1213
1214
1215 /**
1216 * Load template classes.
1217 *
1218 * @since 1.8.0
1219 */
1220 public function load_template_classes() {
1221
1222 /**
1223 * Campaign builder panels slugs array filter.
1224 *
1225 * Allows developers to disable loading of some builder panels.
1226 *
1227 * @since 1.8.0
1228 *
1229 * @param array $panels Panels slugs array.
1230 */
1231 $this->classes = apply_filters(
1232 'charitable_builder_template_classes_',
1233 array(
1234 'templates',
1235 )
1236 );
1237
1238 foreach ( $this->classes as $class ) {
1239 $class = sanitize_file_name( $class );
1240 $file = require_once charitable()->get_path( 'includes' ) . "admin/campaign-builder/templates/class-{$class}.php";
1241
1242 if ( file_exists( $file ) ) {
1243 require_once $file;
1244 }
1245 }
1246 }
1247
1248 /**
1249 * Load misc classes.
1250 *
1251 * @since 1.8.0
1252 */
1253 public function load_misc() {
1254
1255 /**
1256 * Campaign builder panels slugs array filter.
1257 *
1258 * Allows developers to disable loading of some builder panels.
1259 *
1260 * @since 1.8.0
1261 *
1262 * @param array $panels Panels slugs array.
1263 */
1264 $this->classes = apply_filters(
1265 'charitable_builder_class_',
1266 array(
1267 'campaign-embed-wizard',
1268 'campaign-congrats-wizard',
1269 )
1270 );
1271
1272 foreach ( $this->classes as $class ) {
1273 $class = sanitize_file_name( $class );
1274 $file = require_once charitable()->get_path( 'includes' ) . "admin/campaign-builder/class-{$class}.php";
1275
1276 if ( file_exists( $file ) ) {
1277 require_once $file;
1278 }
1279 }
1280 }
1281
1282 /**
1283 * Load the appropriate files to build the page.
1284 *
1285 * @since 1.8.0
1286 * @version 1.8.8.6
1287 */
1288 public function output() {
1289
1290 if ( $this->abort ) {
1291 return;
1292 }
1293
1294 /**
1295 * Allow developers to disable Campaign builder output.
1296 *
1297 * @since 1.8.0
1298 *
1299 * @param bool $is_enabled Is builder output enabled? Defaults to `true`.
1300 */
1301 if ( ! (bool) apply_filters( 'charitable_builder_output', true ) ) {
1302 return;
1303 }
1304
1305 $this->get_campaign_settings();
1306
1307 if ( ! $this->campaign_data && intval( $_GET['campaign_id'] ) > 0 ) { // phpcs:ignore
1308 $this->campaign_data = $this->get_campaign_settings( intval( $_GET['campaign_id'] ) ); // phpcs:ignore
1309 }
1310
1311 $builder_template = new Charitable_Campaign_Builder_Templates();
1312 $load_checklist_assets = Charitable_Checklist::get_instance()->maybe_load_checklist_assets();
1313 $is_checklist_skipped = Charitable_Checklist::get_instance()->is_checklist_skipped();
1314 $display_tour_divs = $this->display_tour_divs();
1315
1316 ( $load_checklist_assets && ! $is_checklist_skipped ) ? true : false;
1317
1318 $campaign_id = $this->campaign_data ? absint( $this->campaign_data['id'] ) : 0;
1319 $template_id = $this->campaign_data && isset( $this->campaign_data['template_id'] ) ? esc_attr( $this->campaign_data['template_id'] ) : '';
1320 $template_label = ! empty( $template_id ) ? $builder_template->get_template_data_meta_field( 'label', $template_id ) : '';
1321 $field_id = ! empty( $this->campaign_data['field_id'] ) ? intval( $this->campaign_data['field_id'] ) : 0;
1322 $post_status = $campaign_id ? get_post_status( $campaign_id ) : '';
1323 $post_status_label = ucwords( $post_status );
1324
1325 $campaign_url = ( 0 !== $campaign_id ) ? get_permalink( $campaign_id ) : '';
1326
1327 $color_base_primary = $this->campaign_data && isset( $this->campaign_data['color_base_primary'] ) ? esc_attr( $this->campaign_data['color_base_primary'] ) : '';
1328 $color_base_secondary = $this->campaign_data && isset( $this->campaign_data['color_base_secondary'] ) ? esc_attr( $this->campaign_data['color_base_secondary'] ) : '';
1329 $color_base_tertiary = $this->campaign_data && isset( $this->campaign_data['color_base_tertiary'] ) ? esc_attr( $this->campaign_data['color_base_tertiary'] ) : '';
1330 $color_base_button = $this->campaign_data && isset( $this->campaign_data['color_base_button'] ) ? esc_attr( $this->campaign_data['color_base_button'] ) : '';
1331
1332 $revision = 0; // for future use.
1333 $allowed_caps = array( 'edit_posts', 'edit_other_posts', 'edit_private_posts', 'edit_published_posts', 'edit_pages', 'edit_other_pages', 'edit_published_pages', 'edit_private_pages' );
1334 $can_embed = array_filter( $allowed_caps, 'current_user_can' );
1335 $preview_classes = array( 'charitable-btn', 'charitable-btn-toolbar', 'charitable-btn-light-grey' );
1336 $builder_classes = array( 'charitable-admin-page' );
1337
1338 // for future use.
1339 if ( ! $can_embed ) {
1340 $preview_classes[] = 'charitable-alone';
1341 }
1342
1343 $revision_id = null; // for future use.
1344
1345 /**
1346 * Allow to modify builder container classes.
1347 *
1348 * @since 1.8.0
1349 *
1350 * @param array $classes List of classes.
1351 * @param array $campaign_data Form data and settings.
1352 */
1353 $builder_classes = (array) apply_filters( 'charitable_builder_output_classes', $builder_classes, $this->campaign_data );
1354
1355 /**
1356 * Allow developers to add content before the top toolbar in the Campaign builder.
1357 *
1358 * @since 1.8.0
1359 *
1360 * @param string $content Content before toolbar. Defaults to empty string.
1361 */
1362 $before_toolbar = apply_filters( 'charitable_builder_output_before_toolbar', '' );
1363 ?>
1364
1365 <?php
1366 $builder_classes_output = charitable_sanitize_classes( $builder_classes, true );
1367 ?>
1368 <div id="charitable-builder" class="<?php echo esc_attr( $builder_classes_output ); ?>">
1369
1370 <?php
1371
1372 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1373 if ( empty( $_GET['force_desktop_view'] ) ) {
1374 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1375 echo $this->mobile_notice();
1376 }
1377 ?>
1378
1379 <div id="charitable-builder-overlay">
1380 <div class="charitable-builder-overlay-content">
1381 <i class="spinner"></i>
1382 <i class="avatar"></i>
1383 </div>
1384 </div>
1385
1386 <?php
1387
1388 // determine what value to use for "form_saved". the value should represent the last time a change was made and NOT saved, so new campaigns are blank (but not saved)
1389 // any changes would add a value to this field although it doesn't have to be exact to every click.
1390
1391 $form_saved = false;
1392
1393 ?>
1394
1395 <form
1396 name="charitable-builder" id="charitable-builder-form" method="post"
1397 data-id="<?php echo esc_attr( $campaign_id ); ?>"
1398 data-template-id="<?php echo esc_attr( $template_id ); ?>"
1399 data-template-label="<?php echo esc_html( $template_label ); ?>"
1400 data-revision="<?php echo esc_attr( $revision_id ); ?>"
1401 >
1402
1403 <input type="hidden" name="id" value="<?php echo intval( $campaign_id ); ?>" />
1404 <input type="hidden" name="template_id" value="<?php echo esc_attr( $template_id ); ?>" />
1405 <input type="hidden" name="template_label" value="<?php echo esc_html( $template_label ); ?>" />
1406 <input type="hidden" name="color_base_primary" value="<?php echo esc_html( $color_base_primary ); ?>" />
1407 <input type="hidden" name="color_base_secondary" value="<?php echo esc_html( $color_base_secondary ); ?>" />
1408 <input type="hidden" name="color_base_tertiary" value="<?php echo esc_html( $color_base_tertiary ); ?>" />
1409 <input type="hidden" name="color_base_button" value="<?php echo esc_html( $color_base_button ); ?>" />
1410 <input type="hidden" name="form_saved" id="charitable-form-saved" value="<?php echo esc_html( $form_saved ); ?>" />
1411 <input type="hidden" name="post_status" id="charitable-form-post-status" value="<?php echo esc_html( $post_status ); ?>" />
1412 <input type="hidden" name="post_status_label" id="charitable-form-post-status-label" value="<?php echo esc_html( $post_status_label ); ?>" />
1413 <input type="hidden" value="<?php echo absint( $field_id ); ?>" name="field_id" id="charitable-field-id" />
1414
1415 <?php echo $before_toolbar; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1416
1417 <!-- Toolbar -->
1418 <div class="charitable-toolbar">
1419
1420 <div class="charitable-left">
1421 <div class="mascot">
1422
1423 </div>
1424 </div>
1425
1426 <div class="charitable-center">
1427
1428 <span class="charitable-edit-campaign-title-label"><?php echo esc_html__( 'Now editing', 'charitable' ); ?></span>
1429
1430 <span class="charitable-edit-campaign-title-area">
1431 <input id="charitable_settings_title" name="title" placeholder="<?php echo esc_html__( 'Enter Your Campaign Name Here...', 'charitable' ); ?>" class="charitable-center-form-name charitable-form-name" value="<?php echo esc_html( isset( $this->campaign_data['title'] ) ? $this->campaign_data['title'] : '' ); ?>" />
1432 <!--<a href="#" class="charitable-title-edit" title="<?php echo esc_html__( 'Edit Campaign Title', 'charitable' ); ?>"><img class="charitable-edit-campaign-title-icon" width="18" height="18" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/edit.png' ); ?>" /></a>-->
1433
1434 </span>
1435
1436 </div>
1437
1438 <div class="charitable-right">
1439
1440 <button id="charitable-embed" class="charitable-btn charitable-btn-toolbar
1441 <?php
1442 if ( 'publish' !== $post_status ) {
1443 echo 'charitable-disabled'; }
1444 ?>
1445 " title="<?php echo esc_html__( 'Embed Campaign Ctrl+B', 'charitable' ); ?>">
1446 <img class="topbar_icon" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/topbar_embed.svg' ); ?>" />
1447 <span class="text"><?php echo esc_html__( 'Embed', 'charitable' ); ?></span>
1448 </button>
1449
1450 <a href="<?php echo esc_url( $campaign_url ); ?>" id="charitable-view-btn" class="charitable-btn charitable-btn-toolbar
1451 <?php
1452 if ( 'publish' !== $post_status ) {
1453 echo 'charitable-disabled'; }
1454 ?>
1455 " title="<?php esc_attr_e( 'View Live', 'charitable' ); ?>" target="_blank" rel="noopener noreferrer">
1456 <img class="topbar_icon" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/view_live.svg' ); ?>" />
1457 <span class="text"><?php echo esc_html__( 'View Live', 'charitable' ); ?></span>
1458 </a>
1459
1460 <a href="<?php echo esc_url( charitable_get_campaign_preview_url( $campaign_id, true ) ); ?>" class="charitable-btn charitable-btn-toolbar charitable-disabled" id="charitable-preview-btn" target="_blank" rel="noopener noreferrer">
1461 <img class="topbar_icon" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/topbar_visibility.svg' ); ?>" />
1462 <span class="text"><?php echo esc_html__( 'Preview', 'charitable' ); ?></span>
1463 </a>
1464
1465 <div id="charitable-status" class="charitable-status-container">
1466
1467 <?php if ( $display_tour_divs ) : ?>
1468 <div id="charitable-tour-block-4" class="charitable-tour-block"></div>
1469 <?php endif; ?>
1470
1471 <button id="charitable-status-button" class="charitable-btn charitable-btn-toolbar charitable-btn-light-grey" data-status="draft">
1472 <span class="text"><?php echo esc_html__( 'Publish', 'charitable' ); ?></span>
1473 <img class="topbar_icon" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/expand_more.svg' ); ?>" />
1474 </button>
1475 <ul id="charitable-status-dropdown" class="charitable-hidden">
1476 <li><a data-status="publish" data-status-label="Publish" class="publish" href="#"><?php echo esc_html__( 'Publish', 'charitable' ); ?></a></li>
1477 <li><a data-status="pending" data-status-label="Pending" class="pending" href="#"><?php echo esc_html__( 'Pending Review', 'charitable' ); ?></a></li>
1478 <li><a data-status="draft" data-status-label="Draft" class="draft" href="#"><?php echo esc_html__( 'Draft', 'charitable' ); ?></a></li>
1479 </ul>
1480 </div>
1481
1482
1483 <button id="charitable-save" class="charitable-btn charitable-btn-toolbar charitable-btn-green" title="Save Campaign Ctrl+S">
1484 <img class="topbar_icon" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/topbar_check.svg' ); ?>" />
1485 <i class="charitable-loading-spinner charitable-loading-white charitable-loading-inline charitable-hidden"></i><span class="text"><?php echo esc_html__( 'Save', 'charitable' ); ?></span>
1486 </button>
1487
1488 <button id="charitable-exit" title="<?php esc_attr_e( 'Exit Ctrl+Q', 'charitable' ); ?>">
1489 <img class="topbar_icon" src="<?php echo esc_url( charitable()->get_path( 'assets', false ) . 'images/icons/x.png' ); ?>" />
1490 </button>
1491
1492 </div>
1493
1494 </div>
1495
1496 <!-- Panel toggle buttons. -->
1497 <div class="charitable-panels-toggle" id="charitable-panels-toggle">
1498
1499 <?php
1500 /**
1501 * Outputs the buttons to toggle between Campaign builder panels.
1502 *
1503 * @since 1.8.0
1504 *
1505 * @param WP_Post $campaign The campaign object.
1506 * @param string $view Current view (panel) name.
1507 */
1508 do_action( 'charitable_builder_panel_buttons', $this->campaign, $this->view );
1509 ?>
1510
1511 </div>
1512 <div class="charitable-panels">
1513
1514 <?php
1515 /**
1516 * Outputs the contents of Campaign builder panels.
1517 *
1518 * @since 1.8.0
1519 *
1520 * @param WP_Post $campaign The campaign object.
1521 * @param string $view Current view (panel) name.
1522 */
1523 do_action( 'charitable_builder_panels', $this->campaign, $this->view );
1524 ?>
1525
1526 </div>
1527
1528 <!-- Models -->
1529
1530 <?php
1531
1532 $create_update_css = isset( $_GET['campaign_id'] ) && 0 !== intval( $_GET['campaign_id'] ) ? 'update-campaign' : 'create-campaign'; // phpcs:ignore
1533
1534 ?>
1535
1536 <div id="charitable-builder-modal-template-preview" class="charitable-builder-modal charitable-builder-modal-template-preview">
1537
1538 <div id="charitable-templates-preview-form" class="charitable-form charitable-templates-preview-form">
1539 <div class="charitable-templates-close-icon">×</div>
1540
1541 <h4 class="charitable-templates-preview-headline"></h4>
1542 <div class="charitable-templates-preview-description">
1543
1544 </div>
1545
1546 <div class="charitable-form-row haritable-templates-form-row charitable-feedback-form-preview-image">
1547 <img title="" src="" alt="" />
1548 </div>
1549
1550 <div class="charitable-form-row charitable-feedback-form-row charitable-feedback-form-row-button">
1551 <a class="button-link button-preview-<?php echo esc_attr( $create_update_css ); ?>" data-template-id=""><?php echo esc_html__( 'Use This Template', 'charitable' ); ?></a>
1552 </div>
1553
1554 </div>
1555
1556 </div>
1557
1558
1559 </form>
1560
1561 </div>
1562
1563 <?php
1564 }
1565
1566
1567 /**
1568 * Add Settings menu item under the Campaign menu tab.
1569 *
1570 * @since 1.8.0
1571 * @since 1.8.1.5 Update capability.
1572 *
1573 * @return void
1574 */
1575 public function add_page() {
1576
1577 add_submenu_page(
1578 'null',
1579 esc_html__( 'Campaign Builder', 'charitable' ), // Page Title.
1580 esc_html__( 'Campaign Builder', 'charitable' ), // Title that would otherwise appear in the menu.
1581 'publish_pages', // Capability level.
1582 'charitable-campaign-builder', // Still accessible via admin.php?page=menu_handle.
1583 array( $this, 'output' ) // To render the page.
1584 );
1585 }
1586
1587 /**
1588 * Admin head area inside the Campaign builder.
1589 *
1590 * @since 1.8.0
1591 */
1592 public function admin_head() {
1593
1594 // Force hide admin side menu.
1595 echo '<style>#adminmenumain { display: none !important }</style>';
1596
1597 do_action( 'charitable_builder_admin_head', $this->view );
1598 }
1599
1600
1601 /**
1602 * Entry debug metabox. Hidden by default obviously.
1603 *
1604 * @since 1.8.0
1605 *
1606 * @param object $entry Submitted entry values.
1607 * @param array $form_data Form data and settings.
1608 */
1609 public function details_debug( $entry = false, $form_data = false ) {
1610
1611 if ( ! charitable_builder_debug() ) {
1612 return;
1613 }
1614
1615 if ( false === $entry ) {
1616 return;
1617 }
1618
1619 /** This filter is documented in /includes/functions.php */
1620 $allow_display = apply_filters( 'charitable_debug_data_allow_display', true ); // phpcs:ignore charitable.PHP.ValidateHooks.InvalidHookName
1621
1622 if ( ! $allow_display ) {
1623 return;
1624 }
1625
1626 ?>
1627
1628 <!-- Entry Debug metabox -->
1629 <div id="charitable-entry-debug" class="postbox">
1630
1631 <div class="postbox-header">
1632 <h2 class="hndle">
1633 <span><?php esc_html_e( 'Debug Information', 'charitable' ); ?></span>
1634 </h2>
1635 </div>
1636
1637 <div class="inside">
1638
1639 <?php charitable_builder_debug_data( $entry ); ?>
1640 <?php charitable_builder_debug_data( $form_data ); ?>
1641
1642 </div>
1643
1644 </div>
1645 <?php
1646 }
1647
1648 /**
1649 * Campaign Builder mobile / small screen notice template.
1650 *
1651 * @since 1.8.0
1652 */
1653 public function mobile_notice() {
1654
1655 ob_start();
1656
1657 ?>
1658
1659 <div id='charitable-builder-mobile-notice' class='charitable-fullscreen-notice'>
1660
1661 <h3><?php esc_html_e( 'Our campaign builder is optimized for desktop computers.', 'charitable' ); ?></h3>
1662 <p><?php esc_html_e( 'We recommend that you edit your campaign on a bigger screen. If you\'d like to proceed, please understand that some functionality might not behave as expected.', 'charitable' ); ?></p>
1663
1664 <div class="charitable-fullscreen-notice-buttons">
1665 <button type="button" class="charitable-fullscreen-notice-button charitable-fullscreen-notice-button-primary">
1666 <?php esc_html_e( 'Back to All Campaigns', 'charitable' ); ?>
1667 </button>
1668 <button type="button" class="charitable-fullscreen-notice-button charitable-fullscreen-notice-button-secondary">
1669 <?php esc_html_e( 'Continue', 'charitable' ); ?>
1670 </button>
1671
1672 <button type="button" class="close"><span class="screen-reader-text"><?php esc_html_e( 'Close', 'charitable' ); ?></span></button>
1673 </div>
1674
1675 </div>
1676
1677 <?php
1678
1679 $html = ob_get_clean();
1680
1681 return $html;
1682 }
1683
1684 /**
1685 * Adds HTML (va templates) related to onboarding to the campaign builder page, made visible if onboarding is enabled.
1686 *
1687 * @since 1.8.1.12
1688 */
1689 public function render_onboarding_html() {
1690
1691 if ( ! is_admin() || ! isset( $_GET['page'] ) || 'charitable-campaign-builder' !== $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1692 return;
1693 }
1694
1695 include charitable()->get_path( 'includes' ) . 'admin/templates/campaign-builder-onboarding.php';
1696 }
1697
1698 /* TOUR */
1699
1700 /**
1701 * Save tour option via AJAX.
1702 *
1703 * @since 1.8.1.12
1704 *
1705 * @return array
1706 */
1707 public function save_tour_option_ajax() {
1708
1709 if ( ! is_admin() ) {
1710 return;
1711 }
1712
1713 check_ajax_referer( 'charitable_onboarding_ajax_nonce', 'nonce' );
1714
1715 if ( empty( $_POST['data'] ) || empty( $_POST['data']['optionData'] ) || empty( $_POST['data']['type'] ) ) { // phpcs:ignore
1716 wp_send_json_error();
1717 }
1718
1719 $schema = $this->get_onboarding_option_schema();
1720 $schema_tour = $schema['tour'];
1721 $query = [];
1722
1723 foreach ( $schema_tour as $key => $value ) {
1724 if ( isset( $_POST['data']['optionData'][ $key ] ) ) {
1725 $query[ $key ] = sanitize_text_field( wp_unslash( $_POST['data']['optionData'][ $key ] ) );
1726 }
1727 }
1728
1729 if ( empty( $query ) ) {
1730 wp_send_json_error();
1731 }
1732
1733 if ( ! empty( $query['status'] ) && $query['status'] === 'started' ) {
1734 $query['started_date_gmt'] = current_time( 'mysql', true );
1735 }
1736
1737 if ( ! empty( $query['status'] ) && in_array( $query['status'], [ 'completed', 'canceled', 'skipped' ], true ) ) {
1738 $query['finished_date_gmt'] = current_time( 'mysql', true );
1739 }
1740
1741 if ( ! empty( $query['status'] ) && $query['status'] === 'skipped' ) {
1742 $query['started_date_gmt'] = current_time( 'mysql', true );
1743 $query['finished_date_gmt'] = $query['started_date_gmt'];
1744 }
1745
1746 $this->set_tour_option( $query );
1747
1748 wp_send_json_success();
1749 }
1750
1751 /**
1752 * Set tour parameter(s) to tour option.
1753 *
1754 * @since 1.8.1.12
1755 *
1756 * @param array $query Query using 'charitable_builder_tour' schema keys.
1757 */
1758 public function set_tour_option( $query ) {
1759
1760 if ( empty( $query ) || ! is_array( $query ) ) {
1761 return;
1762 }
1763
1764 $schema = $this->get_onboarding_option_schema();
1765 $schema_tour = $schema['tour'];
1766 $replace = array_intersect_key( $query, $schema_tour );
1767
1768 if ( ! $replace ) {
1769 return;
1770 }
1771
1772 // Validate and sanitize the data.
1773 foreach ( $replace as $key => $value ) {
1774 if ( in_array( $key, [ 'step', 'user_id' ], true ) ) {
1775 $replace[ $key ] = absint( $value );
1776
1777 continue;
1778 }
1779 $replace[ $key ] = sanitize_text_field( $value );
1780 }
1781
1782 $option = $this->get_onboarding_options();
1783 $option_tour = empty( $option['tour'] ) || ! $option['tour'] || ! is_array( $option['tour'] ) ? $schema_tour : $option['tour'];
1784 $option_tour = array_merge( $option_tour, $replace );
1785
1786 $option['tour'] = $option_tour;
1787
1788 update_option( 'charitable_builder_onboarding', $option );
1789 }
1790
1791 /**
1792 * Get tour parameter(s).
1793 *
1794 * @since 1.8.1.12
1795 * @version 1.8.1.15 - updated global defines.
1796 *
1797 * @param string $option Option key.
1798 * @return mixed
1799 */
1800 public function get_tour_option( $option = false ) {
1801
1802 $schema = $this->get_onboarding_option_schema();
1803 $options = get_option( 'charitable_builder_onboarding', array() );
1804
1805 if ( 'status' === $option && defined( 'CHARITABLE_CAMPAIGN_BUILDER_FORCE_TOUR' ) && CHARITABLE_CAMPAIGN_BUILDER_FORCE_TOUR ) {
1806 return 'init';
1807 }
1808
1809 // Step in and override here... if 'status' is the option being requested and there is already at least one campaign created then return 'skipped'.
1810 if ( 'status' === $option && ( ! empty( $tours ) || ! isset( $options['tour']['status'] ) || 'init' === $options['tour']['status'] ) ) {
1811
1812 $count_campaigns = wp_count_posts( 'campaign' );
1813 $total_campaigns = isset( $count_campaigns->publish ) ? $count_campaigns->publish : 0;
1814
1815 if ( $total_campaigns > 0 ) {
1816 return 'skipped';
1817 }
1818
1819 if ( ( defined( 'CHARITABLE_CAMPAIGN_BUILDER_FORCE_NO_TOUR' ) && CHARITABLE_CAMPAIGN_BUILDER_FORCE_NO_TOUR ) ) { // phpcs:ignore
1820 return 'skipped';
1821 }
1822 }
1823
1824 if ( ! $options || ! is_array( $options ) || ! is_array( $options['tour'] ) ) {
1825 return $schema['tour'][ $option ] ?? '';
1826 }
1827
1828 return $options['tour'][ $option ] ?? $schema['tour'][ $option ] ?? '';
1829 }
1830
1831 /**
1832 * Check if the tour is active.
1833 *
1834 * @since 1.8.1.15
1835 *
1836 * @return bool
1837 */
1838 public function is_tour_active() {
1839
1840 $status = $this->get_tour_option( 'status' );
1841
1842 return 'init' === $status || 'started' === $status;
1843 }
1844
1845
1846 /**
1847 * Display the tour divs HTML.
1848 *
1849 * @since 1.8.1.1.16
1850 *
1851 * @return bool
1852 */
1853 public function display_tour_divs() {
1854
1855 $is_tour_active = $this->is_tour_active();
1856 $tour_status = $this->get_tour_option( 'status' );
1857 if ( $is_tour_active ) {
1858 return true;
1859 }
1860
1861 return false;
1862 }
1863
1864
1865 /**
1866 * Get option schema for all the onboarding options.
1867 *
1868 * @since 1.8.1.15
1869 *
1870 * @return array
1871 */
1872 public function get_onboarding_option_schema() {
1873
1874 return [
1875 'tour' => [
1876 'status' => 'init',
1877 'step' => 0,
1878 'user_id' => get_current_user_id(),
1879 'started_date_gmt' => '',
1880 'finished_date_gmt' => '',
1881 'window_closed' => '',
1882 ],
1883 'checklist' => [
1884 'status' => 'init',
1885 ],
1886 ];
1887 }
1888
1889 /**
1890 * Get onboarding options.
1891 *
1892 * @since 1.8.1.15
1893 *
1894 * @return array
1895 */
1896 public function get_onboarding_options() {
1897
1898 $option = get_option( 'charitable_builder_onboarding' );
1899 if ( empty( $option ) ) {
1900 $option = $this->get_onboarding_option_schema();
1901 // Update the option.
1902 update_option( 'charitable_builder_onboarding', $option );
1903 }
1904 return $option;
1905 }
1906
1907 /* ONBOARDING */
1908
1909 /**
1910 * Save onboarding option via AJAX.
1911 *
1912 * @since 1.8.1.12
1913 *
1914 * @return array
1915 */
1916 public function save_onboarding_option_ajax() {
1917
1918 if ( ! is_admin() ) {
1919 return;
1920 }
1921
1922 check_admin_referer( 'charitable_onboarding_ajax_nonce' );
1923
1924 if ( empty( $_POST['option_data'] ) ) {
1925 wp_send_json_error();
1926 }
1927
1928 $schema = $this->get_onboarding_option_schema();
1929 $query = [];
1930
1931 foreach ( $schema as $key => $value ) {
1932 if ( isset( $_POST['option_data'][ $key ] ) ) {
1933 $query[ $key ] = sanitize_text_field( wp_unslash( $_POST['option_data'][ $key ] ) );
1934 }
1935 }
1936
1937 if ( empty( $query ) ) {
1938 wp_send_json_error();
1939 }
1940
1941 if ( ! empty( $query['status'] ) && $query['status'] === 'started' ) {
1942 $query['started_date_gmt'] = current_time( 'mysql', true );
1943 }
1944
1945 if ( ! empty( $query['status'] ) && in_array( $query['status'], [ 'completed', 'canceled', 'skipped' ], true ) ) {
1946 $query['finished_date_gmt'] = current_time( 'mysql', true );
1947 }
1948
1949 if ( ! empty( $query['status'] ) && $query['status'] === 'skipped' ) {
1950 $query['started_date_gmt'] = current_time( 'mysql', true );
1951 $query['finished_date_gmt'] = $query['started_date_gmt'];
1952 }
1953
1954 $this->set_onboarding_option( $query );
1955
1956 wp_send_json_success();
1957 }
1958
1959 /**
1960 * Get Onboarding parameter(s).
1961 *
1962 * @since 1.8.1.12
1963 * @version 1.8.1.15 - updated global defines.
1964 *
1965 * @param string $option Option key.
1966 * @return mixed
1967 */
1968 public function get_onboarding_option( $option = false ) {
1969
1970 $schema = $this->get_onboarding_option_schema();
1971 $onboardings = get_option( 'charitable_builder_onboarding' );
1972
1973 if ( 'status' === $option && defined( 'CHARITABLE_CAMPAIGN_BUILDER_FORCE_ONBOARDING' ) && CHARITABLE_CAMPAIGN_BUILDER_FORCE_ONBOARDING ) {
1974 return 'init';
1975 }
1976
1977 // Step in and override here... if 'status' is the option being requested and there is already at least one campaign created then return 'skipped'.
1978 if ( 'status' === $option && ( ! empty( $onboardings ) || ! isset( $onboardings['status'] ) || 'init' === $onboardings['status'] ) ) {
1979
1980 $count_campaigns = wp_count_posts( 'campaign' );
1981 $total_campaigns = isset( $count_campaigns->publish ) ? $count_campaigns->publish : 0;
1982
1983 if ( $total_campaigns > 0 ) {
1984 return 'skipped';
1985 }
1986
1987 if ( ( defined( 'CHARITABLE_CAMPAIGN_BUILDER_NO_ONBOARDING' ) && CHARITABLE_CAMPAIGN_BUILDER_NO_ONBOARDING ) ) {
1988 return 'skipped';
1989 }
1990 }
1991
1992 if ( ! $onboardings || ! is_array( $onboardings ) ) {
1993 return $schema[ $option ] ?? '';
1994 }
1995
1996 return $onboardings[ $option ] ?? $schema[ $option ] ?? '';
1997 }
1998
1999 /**
2000 * Set Onboarding parameter(s) to Onboarding option.
2001 *
2002 * @since 1.8.1.12
2003 *
2004 * @param array $query Query using 'charitable_builder_onboarding' schema keys.
2005 */
2006 public function set_onboarding_option( $query ) {
2007
2008 if ( empty( $query ) || ! is_array( $query ) ) {
2009 return;
2010 }
2011
2012 $schema = $this->get_onboarding_option_schema();
2013 $replace = array_intersect_key( $query, $schema );
2014
2015 if ( ! $replace ) {
2016 return;
2017 }
2018
2019 // Validate and sanitize the data.
2020 foreach ( $replace as $key => $value ) {
2021 if ( in_array( $key, [ 'step', 'user_id', 'form_id', 'embed_page', 'seconds_spent', 'seconds_left' ], true ) ) {
2022 $replace[ $key ] = absint( $value );
2023
2024 continue;
2025 }
2026 if ( in_array( $key, [ 'feedback_sent', 'feedback_contact_me' ], true ) ) {
2027 $replace[ $key ] = wp_validate_boolean( $value );
2028
2029 continue;
2030 }
2031 $replace[ $key ] = sanitize_text_field( $value );
2032 }
2033
2034 $option = get_option( 'charitable_builder_onboarding' );
2035 $option = ! $option || ! is_array( $option ) ? $schema : $option;
2036
2037 update_option( 'charitable_builder_onboarding', array_merge( $option, $replace ) );
2038 }
2039 }
2040
2041 endif;
2042