PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.6.1
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.6.1
1.6.1 1.6.0 1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
← All changes | inc/admin/admin.php +155 -19 1.1.2 → 1.6.1 View file →
@@ -6,13 +6,16 @@
6 6 */
7 7
8 8 namespace SureDonation\Inc\Admin;
9 9
10 +use SureDonation\Inc\Campaigns\Campaign_Cpt;
11 +use SureDonation\Inc\API\Onboarding_API;
10 12 use SureDonation\Inc\Helper;
11 13 use SureDonation\Inc\Onboarding;
12 14 use SureDonation\Inc\Pdf\Pdf_Utils;
13 15 use SureDonation\Inc\Payments\Payment_Helper;
14 16 use SureDonation\Inc\Payments\PayPal\PayPal_Helper;
17 +use SureDonation\Inc\Payments\Stripe\Stripe_Helper;
15 18 use SureDonation\Inc\Traits\Get_Instance;
16 19
17 20 // Exit if accessed directly.
18 21 if ( ! defined( 'ABSPATH' ) ) {
@@ -37,11 +40,91 @@
37 40 add_action( 'admin_menu', [ $this, 'hide_forms_submenu' ], 999 );
38 41 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
39 42 add_action( 'admin_init', [ $this, 'redirect_cpt_listings' ] );
40 43 add_action( 'admin_init', [ $this, 'register_privacy_policy_content' ] );
44 + add_action( 'admin_init', [ $this, 'register_react_notices' ], 5 );
41 45 }
42 46
43 47 /**
48 + * Register the payment-gateway React admin notice.
49 + *
50 + * Bridges the payment/test-mode nudges into the React admin app via
51 + * Notice_Manager. Runs on admin_init (priority 5) so the notice is
52 + * registered before admin_enqueue_scripts localizes the data for React.
53 + *
54 + * Two mutually-exclusive states, mirroring the existing PHP/front-end
55 + * notice chain:
56 + * - No gateway connected -> prompt to configure a gateway.
57 + * - Connected, but site in test mode -> prompt to switch to live mode.
58 + * When a gateway is connected and the site is live, no notice shows.
59 + *
60 + * Capability-gated to manage_options; the data is only consumed on the
61 + * SureDonation admin pages, where the React app is enqueued.
62 + *
63 + * Hooked - admin_init (priority 5)
64 + *
65 + * @since 1.3.0
66 + * @return void
67 + */
68 + public function register_react_notices() {
69 + if ( ! current_user_can( 'manage_options' ) ) {
70 + return;
71 + }
72 +
73 + if ( ! Payment_Helper::is_any_gateway_connected() ) {
74 + Notice_Manager::register_notice(
75 + [
76 + 'id' => 'sd-configure-gateway',
77 + 'variant' => 'error',
78 + // translators: the <a></a> tags wrap the inline link text and must be kept intact.
79 + 'message' => __( 'Your forms cannot accept donations yet. <a>Connect Stripe or PayPal</a> and you can start accepting them today.', 'suredonation' ),
80 + 'link' => [
81 + // Deep-link to the gateway connect screen, matching the dashboard Quick Access entry.
82 + 'url' => Payment_Helper::get_settings_url( 'stripe' ),
83 + ],
84 + 'event' => Analytics::TRACKED_EVENTS['configure_gateway'],
85 + 'dismissible' => false,
86 + ]
87 + );
88 + return;
89 + }
90 +
91 + if ( Stripe_Helper::is_stripe_connected() && ! Stripe_Helper::is_webhook_configured() ) {
92 + Notice_Manager::register_notice(
93 + [
94 + 'id' => 'sd-webhook-not-configured',
95 + 'variant' => 'error',
96 + // translators: the <a></a> tags wrap the inline link text and must be kept intact.
97 + 'message' => __( 'Webhooks keep SureDonation in sync with Stripe by automatically updating donation and subscription data. Please <a>configure</a> the webhook.', 'suredonation' ),
98 + 'link' => [
99 + 'url' => Payment_Helper::get_settings_url( 'stripe' ),
100 + ],
101 + 'event' => Analytics::TRACKED_EVENTS['webhook'],
102 + 'dismissible' => false,
103 + ]
104 + );
105 + return;
106 + }
107 +
108 + if ( 'test' === Payment_Helper::get_payment_mode() ) {
109 + $settings_url = Payment_Helper::get_settings_url();
110 + Notice_Manager::register_notice(
111 + [
112 + 'id' => 'sd-test-mode-react',
113 + 'variant' => 'error',
114 + // translators: the <a></a> tags wrap the inline link text and must be kept intact.
115 + 'message' => __( 'Supporters cannot donate while your site is in test mode. Anything they try now is a test and no money reaches you. <a>Switch to live mode</a> when you are ready to accept real donations.', 'suredonation' ),
116 + 'link' => [
117 + 'url' => $settings_url,
118 + ],
119 + 'event' => Analytics::TRACKED_EVENTS['test_mode'],
120 + 'dismissible' => false,
121 + ]
122 + );
123 + }
124 + }
125 +
126 + /**
44 127 * Register suggested privacy-policy text for the plugin's data transfers.
45 128 *
46 129 * Surfaces the Phone field's automatic country detection (which sends the
47 130 * visitor's IP to ipapi.co) in the WordPress Privacy Policy Guide
@@ -69,8 +152,13 @@
69 152 * For the form listing, attempt to resolve the originating campaign
70 153 * from the referer (the "back" arrow on the form editor sends the
71 154 * user here) and redirect to that campaign's single view.
72 155 *
156 + * Campaign creation (post-new.php) is redirected too, so bookmarks and
157 + * third-party links to the raw editor land in the creation drawer rather
158 + * than producing a half-configured campaign. New forms keep using
159 + * post-new.php — the campaign screen links there with a campaign_id.
160 + *
73 161 * @return void
74 162 * @since 1.0.0
75 163 */
76 164 public function redirect_cpt_listings() {
@@ -75,9 +163,9 @@
75 163 */
76 164 public function redirect_cpt_listings() {
77 165 global $pagenow;
78 166
79 - if ( 'edit.php' !== $pagenow ) {
167 + if ( 'edit.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
80 168 return;
81 169 }
82 170
83 171 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading post_type from query, no state mutation.
@@ -82,8 +170,22 @@
82 170
83 171 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading post_type from query, no state mutation.
84 172 $post_type = isset( $_GET['post_type'] ) ? sanitize_key( wp_unslash( $_GET['post_type'] ) ) : '';
85 173
174 + if ( 'post-new.php' === $pagenow ) {
175 + /*
176 + * Only for users who can actually open the destination: the admin app
177 + * requires manage_options, while the campaign post type is creatable
178 + * by any role with edit_posts. Redirecting those roles would trade the
179 + * editor for a permission error.
180 + */
181 + if ( Campaign_Cpt::POST_TYPE === $post_type && current_user_can( 'manage_options' ) ) {
182 + wp_safe_redirect( Campaign_Cpt::get_create_url() );
183 + exit;
184 + }
185 + return;
186 + }
187 +
86 188 if ( 'suredonation_form' === $post_type ) {
87 189 $campaign_id = $this->resolve_campaign_id_from_referer();
88 190 $target = $campaign_id
89 191 ? admin_url( 'admin.php?page=suredonation#/campaigns/' . $campaign_id )
@@ -92,9 +194,9 @@
92 194 wp_safe_redirect( $target );
93 195 exit;
94 196 }
95 197
96 - if ( 'suredonation_cmpgn' === $post_type ) {
198 + if ( Campaign_Cpt::POST_TYPE === $post_type ) {
97 199 wp_safe_redirect( admin_url( 'admin.php?page=suredonation#/campaigns' ) );
98 200 exit;
99 201 }
100 202 }
@@ -200,12 +302,27 @@
200 302
201 303 // Load JS translations for the admin app.
202 304 wp_set_script_translations( 'suredonation-admin', 'suredonation' );
203 305
306 + // Campaign guided tour resume point (empty when there is none).
307 + $campaign_tour_progress = get_user_meta( get_current_user_id(), Onboarding_API::TOUR_PROGRESS_META, true );
308 + $campaign_tour_progress = is_string( $campaign_tour_progress ) ? $campaign_tour_progress : '';
309 +
310 + // Campaign whose first-run tour the onboarding wizard armed (empty = none).
311 + $campaign_tour_pending = get_user_meta( get_current_user_id(), Onboarding_API::TOUR_PENDING_META, true );
312 + $campaign_tour_pending = is_scalar( $campaign_tour_pending ) ? (string) $campaign_tour_pending : '';
313 +
204 314 // Localize script with plugin data.
205 - wp_localize_script(
206 - 'suredonation-admin',
207 - 'suredonation_admin',
315 + /**
316 + * Filters the bootstrap data localized to the SureDonation admin React app
317 + * (exposed as window.suredonation_admin). Lets features inject additional
318 + * data before it reaches React.
319 + *
320 + * @since 1.3.0
321 + * @param array<string, mixed> $localized_data The admin app bootstrap data.
322 + */
323 + $localized_data = apply_filters(
324 + 'suredonation_admin_app_data',
208 325 [
209 326 'version' => SUREDONATION_VER,
210 327 'apiUrl' => rest_url( 'suredonation/v1' ),
211 328 'nonce' => wp_create_nonce( 'wp_rest' ),
@@ -214,8 +331,11 @@
214 331 'site_url' => site_url(),
215 332 'admin_url' => admin_url(),
216 333 'is_first_campaign_created' => $this->has_campaigns(),
217 334 'is_onboarding_completed' => Onboarding::get_instance()->is_completed(),
335 + 'campaign_tour_seen' => 'yes' === get_user_meta( get_current_user_id(), Onboarding_API::TOUR_SEEN_META, true ),
336 + 'campaign_tour_progress' => $campaign_tour_progress,
337 + 'campaign_tour_pending' => $campaign_tour_pending,
218 338 'rotating_plugin_banner' => $this->get_rotating_plugin_banner(),
219 339 'smart_tags' => Helper::get_smart_tags(),
220 340 'is_pro_active' => defined( 'SUREDONATION_PRO_VER' ),
221 341 'pro_plugin_version' => defined( 'SUREDONATION_PRO_VER' ) ? SUREDONATION_PRO_VER : '',
@@ -228,17 +348,25 @@
228 348 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
229 349 'plugin_manager_nonce' => wp_create_nonce( 'suredonation_plugin_manager' ),
230 350 'has_abilities_api' => class_exists( 'WP_Ability' ),
231 351 'current_user_login' => wp_get_current_user()->user_login,
352 + 'integrations' => [
353 + 'sure_triggers' => Helper::get_ottokit_integration(),
354 + ],
232 355 // Bootstrap settings data so the General currency list and the
233 356 // PayPal connection state render synchronously (no post-mount
234 357 // fetch flicker). PayPal data is the non-sensitive subset only.
235 358 'payments' => [
236 - 'currencies' => Payment_Helper::get_currencies_list(),
237 - 'paypal' => PayPal_Helper::get_connection_state(),
359 + 'currencies' => Payment_Helper::get_currencies_list(),
360 + 'paypal' => PayPal_Helper::get_connection_state(),
361 + 'currency_sign_position' => Payment_Helper::get_currency_sign_position(),
362 + 'is_any_gateway_connected' => Payment_Helper::is_any_gateway_connected(),
363 + 'gateway_config_url' => Payment_Helper::get_settings_url( 'stripe' ),
238 364 ],
239 365 ]
240 366 );
367 +
368 + wp_localize_script( 'suredonation-admin', 'suredonation_admin', $localized_data );
241 369 }
242 370
243 371 /**
244 372 * Register admin menu.
@@ -487,28 +615,36 @@
487 615 } catch ( \Throwable $e ) {
488 616 $has_givewp_data = false;
489 617 }
490 618
619 + $has_charitable_data = false;
620 + try {
621 + $has_charitable_data = \SureDonation\Inc\Import\Charitable\Source::get_instance()->has_charitable_data();
622 + } catch ( \Throwable $e ) {
623 + $has_charitable_data = false;
624 + }
625 +
491 626 wp_localize_script(
492 627 'suredonation-onboarding',
493 628 'suredonation_onboarding',
494 629 [
495 - 'apiUrl' => rest_url( 'suredonation/v1' ),
496 - 'nonce' => wp_create_nonce( 'wp_rest' ),
497 - 'pluginUrl' => SUREDONATION_URL,
498 - 'adminUrl' => admin_url(),
499 - 'dashboardUrl' => admin_url( 'admin.php?page=suredonation' ),
500 - 'paymentsUrl' => admin_url( 'admin.php?page=suredonation#/settings?tab=payments' ),
501 - 'campaignsUrl' => admin_url( 'admin.php?page=suredonation#/campaigns' ),
502 - 'docsUrl' => 'https://suredonation.com/docs/',
503 - 'isProActive' => $is_pro,
504 - 'hasGiveWPData' => $has_givewp_data,
505 - 'currentUser' => [
630 + 'apiUrl' => rest_url( 'suredonation/v1' ),
631 + 'nonce' => wp_create_nonce( 'wp_rest' ),
632 + 'pluginUrl' => SUREDONATION_URL,
633 + 'adminUrl' => admin_url(),
634 + 'dashboardUrl' => admin_url( 'admin.php?page=suredonation' ),
635 + 'paymentsUrl' => Payment_Helper::get_settings_url( 'stripe' ),
636 + 'campaignsUrl' => admin_url( 'admin.php?page=suredonation#/campaigns' ),
637 + 'docsUrl' => 'https://suredonation.com/docs/',
638 + 'isProActive' => $is_pro,
639 + 'hasGiveWPData' => $has_givewp_data,
640 + 'hasCharitableData' => $has_charitable_data,
641 + 'currentUser' => [
506 642 'firstName' => $current_user ? $current_user->first_name : '',
507 643 'lastName' => $current_user ? $current_user->last_name : '',
508 644 'email' => $current_user ? $current_user->user_email : '',
509 645 ],
510 - 'privacyUrl' => 'https://suredonation.com/privacy-policy/',
646 + 'privacyUrl' => 'https://suredonation.com/privacy-policy/',
511 647 ]
512 648 );
513 649
514 650 // Shim suredonation_admin on the onboarding page too — shared API