PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.1.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.1.0
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 +255 -4 0.0.11.1.0 View file →
@@ -6,8 +6,13 @@
6 6 */
7 7
8 8 namespace SureDonation\Inc\Admin;
9 9
10 +use SureDonation\Inc\Helper;
11 +use SureDonation\Inc\Onboarding;
12 +use SureDonation\Inc\Pdf\Pdf_Utils;
13 +use SureDonation\Inc\Payments\Payment_Helper;
14 +use SureDonation\Inc\Payments\PayPal\PayPal_Helper;
10 15 use SureDonation\Inc\Traits\Get_Instance;
11 16
12 17 // Exit if accessed directly.
13 18 if ( ! defined( 'ABSPATH' ) ) {
@@ -30,11 +35,86 @@
30 35 public function __construct() {
31 36 add_action( 'admin_menu', [ $this, 'register_menu' ] );
32 37 add_action( 'admin_menu', [ $this, 'hide_forms_submenu' ], 999 );
33 38 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
39 + add_action( 'admin_init', [ $this, 'redirect_cpt_listings' ] );
34 40 }
35 41
36 42 /**
43 + * Redirect the default CPT list screens for suredonation_form and
44 + * suredonation_cmpgn to their corresponding plugin pages.
45 + *
46 + * For the form listing, attempt to resolve the originating campaign
47 + * from the referer (the "back" arrow on the form editor sends the
48 + * user here) and redirect to that campaign's single view.
49 + *
50 + * @return void
51 + * @since 1.0.0
52 + */
53 + public function redirect_cpt_listings() {
54 + global $pagenow;
55 +
56 + if ( 'edit.php' !== $pagenow ) {
57 + return;
58 + }
59 +
60 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading post_type from query, no state mutation.
61 + $post_type = isset( $_GET['post_type'] ) ? sanitize_key( wp_unslash( $_GET['post_type'] ) ) : '';
62 +
63 + if ( 'suredonation_form' === $post_type ) {
64 + $campaign_id = $this->resolve_campaign_id_from_referer();
65 + $target = $campaign_id
66 + ? admin_url( 'admin.php?page=suredonation#/campaigns/' . $campaign_id )
67 + : admin_url( 'admin.php?page=suredonation#/campaigns' );
68 +
69 + wp_safe_redirect( $target );
70 + exit;
71 + }
72 +
73 + if ( 'suredonation_cmpgn' === $post_type ) {
74 + wp_safe_redirect( admin_url( 'admin.php?page=suredonation#/campaigns' ) );
75 + exit;
76 + }
77 + }
78 +
79 + /**
80 + * Resolve the campaign ID from the referer when the form list page
81 + * is reached from the form editor's "back" button.
82 + *
83 + * @return int Campaign ID, or 0 when it cannot be determined.
84 + * @since 1.0.0
85 + */
86 + private function resolve_campaign_id_from_referer() {
87 + $referer = wp_get_referer();
88 + if ( ! $referer ) {
89 + return 0;
90 + }
91 +
92 + $parts = wp_parse_url( $referer );
93 + if ( empty( $parts['query'] ) ) {
94 + return 0;
95 + }
96 +
97 + $query = [];
98 + parse_str( $parts['query'], $query );
99 +
100 + if ( empty( $query['post'] ) || ! is_numeric( $query['post'] ) ) {
101 + return 0;
102 + }
103 +
104 + $form_id = absint( $query['post'] );
105 + if ( 'suredonation_form' !== get_post_type( $form_id ) ) {
106 + return 0;
107 + }
108 +
109 + $campaign_id = get_post_meta( $form_id, '_suredonation_campaign_id', true );
110 + if ( ! is_numeric( $campaign_id ) ) {
111 + return 0;
112 + }
113 + return absint( $campaign_id );
114 + }
115 +
116 + /**
37 117 * Enqueue admin scripts and styles.
38 118 *
39 119 * @param string $hook Current admin page hook.
40 120 * @return void
@@ -45,8 +125,15 @@
45 125 if ( strpos( $hook, 'suredonation' ) === false ) {
46 126 return;
47 127 }
48 128
129 + // Onboarding gets its own lean bundle — bail before enqueuing the
130 + // main admin app on that page.
131 + if ( false !== strpos( $hook, Onboarding::PAGE_SLUG ) ) {
132 + $this->enqueue_onboarding_assets();
133 + return;
134 + }
135 +
49 136 $asset_file = SUREDONATION_DIR . 'assets/build/admin.asset.php';
50 137
51 138 if ( ! file_exists( $asset_file ) ) {
52 139 return;
@@ -56,8 +143,11 @@
56 143
57 144 // Enqueue WordPress editor for TinyMCE support.
58 145 wp_enqueue_editor();
59 146
147 + // Enqueue the media library so the campaign image picker can open it.
148 + wp_enqueue_media();
149 +
60 150 // Enqueue editor buttons style (needed for TinyMCE icons).
61 151 wp_enqueue_style( 'editor-buttons' );
62 152
63 153 // Enqueue admin app script.
@@ -76,8 +166,19 @@
76 166 [],
77 167 $asset['version']
78 168 );
79 169
170 + // The campaign drawer sits at a very high z-index. Lift the media library
171 + // above it, and keep the media modal above its OWN backdrop so the picker
172 + // is not dimmed by either overlay.
173 + wp_add_inline_style(
174 + 'suredonation-admin',
175 + '.media-modal-backdrop{z-index:2147483646 !important;}.media-modal{z-index:2147483647 !important;}'
176 + );
177 +
178 + // Load JS translations for the admin app.
179 + wp_set_script_translations( 'suredonation-admin', 'suredonation' );
180 +
80 181 // Localize script with plugin data.
81 182 wp_localize_script(
82 183 'suredonation-admin',
83 184 'suredonation_admin',
@@ -89,9 +190,30 @@
89 190 'plugin_url' => SUREDONATION_URL,
90 191 'site_url' => site_url(),
91 192 'admin_url' => admin_url(),
92 193 'is_first_campaign_created' => $this->has_campaigns(),
194 + 'is_onboarding_completed' => Onboarding::get_instance()->is_completed(),
93 195 'rotating_plugin_banner' => $this->get_rotating_plugin_banner(),
196 + 'smart_tags' => Helper::get_smart_tags(),
197 + 'is_pro_active' => defined( 'SUREDONATION_PRO_VER' ),
198 + 'pro_plugin_version' => defined( 'SUREDONATION_PRO_VER' ) ? SUREDONATION_PRO_VER : '',
199 + 'pro_plugin_name' => defined( 'SUREDONATION_PRO_PRODUCT' ) ? SUREDONATION_PRO_PRODUCT : 'SureDonation Pro',
200 + 'is_license_active' => defined( 'SUREDONATION_PRO_VER' ) && class_exists( 'SureDonationPro\Inc\Licensing\Licensing' ) ? \SureDonationPro\Inc\Licensing\Licensing::is_license_active() : false,
201 + 'pdf_library_exists' => Pdf_Utils::check_if_library_exists(),
202 + 'php_version_compatible' => Pdf_Utils::is_php_compatible(),
203 + 'pdf_nonce' => wp_create_nonce( 'suredonation_pdf_nonce' ),
204 + 'ajax_url' => admin_url( 'admin-ajax.php' ),
205 + 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
206 + 'plugin_manager_nonce' => wp_create_nonce( 'suredonation_plugin_manager' ),
207 + 'has_abilities_api' => class_exists( 'WP_Ability' ),
208 + 'current_user_login' => wp_get_current_user()->user_login,
209 + // Bootstrap settings data so the General currency list and the
210 + // PayPal connection state render synchronously (no post-mount
211 + // fetch flicker). PayPal data is the non-sensitive subset only.
212 + 'payments' => [
213 + 'currencies' => Payment_Helper::get_currencies_list(),
214 + 'paypal' => PayPal_Helper::get_connection_state(),
215 + ],
94 216 ]
95 217 );
96 218 }
97 219
@@ -103,8 +225,13 @@
103 225 */
104 226 public function register_menu() {
105 227 $menu_slug = 'suredonation';
106 228
229 + // SureDonation mark for the admin menu — single path with evenodd
230 + // fill so the inner heart cuts a hole that reveals the sidebar
231 + // background (mirrors the pattern used by SureForms).
232 + $menu_icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 3.64405C0 1.6315 1.62712 0 3.63425 0H20.2517C22.2588 0 23.886 1.6315 23.886 3.64405V20.3063C23.886 22.3188 22.2588 23.9503 20.2517 23.9503H3.63425C1.62712 23.9503 0 22.3188 0 20.3063V3.64405ZM12.6516 5.79655C14.4525 3.99075 17.3723 3.99075 19.1734 5.79655C20.9742 7.60234 20.9742 10.5301 19.1734 12.3359L17.5686 13.9451C17.2776 14.2368 16.8057 14.2368 16.5147 13.9451C16.2237 13.6533 16.2237 13.1802 16.5147 12.8884L18.1196 11.2793C19.3385 10.0571 19.3385 8.07537 18.1196 6.85312C16.9007 5.6309 14.9243 5.63092 13.7054 6.85312L11.3607 9.20415C11.0701 9.49552 11.0701 9.96791 11.3607 10.2593C11.6513 10.5506 12.1224 10.5506 12.413 10.2593L13.4659 9.20346C13.7569 8.91169 14.2288 8.91169 14.5198 9.20346C14.8107 9.49523 14.8107 9.96828 14.5198 10.26L13.4667 11.3159C12.5942 12.1909 11.1794 12.1909 10.3069 11.3159C9.43429 10.441 9.43429 9.02249 10.3069 8.14757L10.8879 7.56486L10.1781 6.85312C8.95914 5.63089 6.98277 5.63089 5.76382 6.85312C4.54486 8.07537 4.54488 10.0571 5.76382 11.2793L12.6985 18.2326C12.9895 18.5244 12.9895 18.9974 12.6985 19.2892C12.4075 19.581 11.9358 19.581 11.6448 19.2892L4.71008 12.3359C2.90915 10.5301 2.90913 7.60233 4.71008 5.79655C6.51102 3.99075 9.43091 3.99075 11.2318 5.79655L11.9417 6.50827L12.6516 5.79655ZM11.8605 14.9781C12.1515 14.6863 12.6233 14.6863 12.9143 14.9781L14.5397 16.6079C14.8307 16.8996 14.8307 17.3727 14.5397 17.6645C14.2487 17.9562 13.7769 17.9562 13.4859 17.6645L11.8605 16.0347C11.5695 15.7429 11.5695 15.2699 11.8605 14.9781ZM13.6482 13.1856C13.9392 12.8939 14.4109 12.8939 14.7019 13.1856L16.3273 14.8154C16.6183 15.1072 16.6183 15.5802 16.3273 15.872C16.0363 16.1638 15.5645 16.1638 15.2735 15.872L13.6482 14.2422C13.3572 13.9504 13.3572 13.4774 13.6482 13.1856Z" fill="#D1D5DB"/></svg>';
233 +
107 234 // Main menu page.
108 235 add_menu_page(
109 236 __( 'SureDonation', 'suredonation' ),
110 237 __( 'SureDonation', 'suredonation' ),
@@ -110,9 +237,9 @@
110 237 __( 'SureDonation', 'suredonation' ),
111 238 'manage_options',
112 239 $menu_slug,
113 240 [ $this, 'render_dashboard' ],
114 - 'dashicons-money-alt',
241 + 'data:image/svg+xml;base64,' . base64_encode( $menu_icon_svg ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Building data URI for menu icon.
115 242 25
116 243 );
117 244
118 245 // Register submenus.
@@ -165,12 +292,19 @@
165 292
166 293 /**
167 294 * Get rotating plugin banner data.
168 295 *
169 - * @return array<string,mixed> Plugin banner data or null if not available.
296 + * @return array<string,mixed>|null Plugin banner data, or null when the plugin is already active.
170 297 * @since 0.0.1
171 298 */
172 299 private function get_rotating_plugin_banner() {
300 + // Match SureForms: never nudge a plugin that is already active, so the
301 + // dashboard card is hidden once SureRank is activated.
302 + $status = $this->get_plugin_status( 'surerank/surerank.php' );
303 + if ( 'Activated' === $status ) {
304 + return null;
305 + }
306 +
173 307 // Get SVG logo as base64.
174 308 $logo_svg = file_get_contents( SUREDONATION_DIR . 'images/surerank.svg' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local file read.
175 309 $logo_data = $logo_svg ? 'data:image/svg+xml;base64,' . base64_encode( $logo_svg ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
176 310
@@ -175,14 +309,15 @@
175 309 $logo_data = $logo_svg ? 'data:image/svg+xml;base64,' . base64_encode( $logo_svg ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
176 310
177 311 // SureRank plugin data.
178 312 return [
179 - 'slug' => 'flavor',
313 + 'slug' => 'surerank',
314 + 'path' => 'surerank/surerank.php',
180 315 'title' => 'SureRank',
181 316 'singleLineDescription' => __( 'SEO Made Easy for Your Website', 'suredonation' ),
182 317 'subtitle' => __( 'Beautiful pages, persuasive content, and custom code in seconds. The possibilities are endless!', 'suredonation' ),
183 318 'logo' => $logo_data,
184 - 'status' => $this->get_plugin_status( 'flavor/flavor.php' ),
319 + 'status' => $status,
185 320 ];
186 321 }
187 322
188 323 /**
@@ -232,8 +367,16 @@
232 367 'id' => 'suredonation#/donations',
233 368 'page_title' => __( 'Donations', 'suredonation' ),
234 369 ],
235 370 [
371 + 'id' => 'suredonation#/donors',
372 + 'page_title' => __( 'Donors', 'suredonation' ),
373 + ],
374 + [
375 + 'id' => 'suredonation#/reports',
376 + 'page_title' => __( 'Reports', 'suredonation' ),
377 + ],
378 + [
236 379 'id' => 'suredonation#/settings',
237 380 'page_title' => __( 'Settings', 'suredonation' ),
238 381 ],
239 382 ];
@@ -248,6 +391,114 @@
248 391 $submenu['id'],
249 392 [ $this, 'render_dashboard' ]
250 393 );
251 394 }
395 +
396 + // Hidden onboarding page (no menu parent so it never shows in
397 + // the sidebar but is still routable via admin.php?page=...).
398 + add_submenu_page(
399 + '',
400 + __( 'SureDonation Setup', 'suredonation' ),
401 + __( 'SureDonation Setup', 'suredonation' ),
402 + $capability,
403 + Onboarding::PAGE_SLUG,
404 + [ $this, 'render_onboarding' ]
405 + );
406 + }
407 +
408 + /**
409 + * Render onboarding root container.
410 + *
411 + * @return void
412 + * @since 1.0.0
413 + */
414 + public function render_onboarding() {
415 + ?>
416 + <div id="suredonation-onboarding-root"></div>
417 + <?php
418 + }
419 +
420 + /**
421 + * Enqueue the dedicated onboarding bundle.
422 + *
423 + * Loaded only on the onboarding admin page so the main admin app
424 + * doesn't pay the cost on activation redirects.
425 + *
426 + * @return void
427 + * @since 1.0.0
428 + */
429 + private function enqueue_onboarding_assets() {
430 + $asset_file = SUREDONATION_DIR . 'assets/build/admin/onboarding/index.asset.php';
431 +
432 + if ( ! file_exists( $asset_file ) ) {
433 + return;
434 + }
435 +
436 + $asset = include $asset_file;
437 +
438 + wp_enqueue_script(
439 + 'suredonation-onboarding',
440 + SUREDONATION_URL . 'assets/build/admin/onboarding/index.js',
441 + $asset['dependencies'],
442 + $asset['version'],
443 + true
444 + );
445 +
446 + wp_enqueue_style(
447 + 'suredonation-onboarding',
448 + SUREDONATION_URL . 'assets/build/admin/onboarding/index.css',
449 + [],
450 + $asset['version']
451 + );
452 +
453 + wp_set_script_translations( 'suredonation-onboarding', 'suredonation' );
454 +
455 + $current_user = wp_get_current_user();
456 + $is_pro = defined( 'SUREDONATION_PRO_VER' );
457 +
458 + // Detect GiveWP rows once at enqueue time so the JS doesn't have to
459 + // spin a loader (and won't ever flash an error) just to decide whether
460 + // to render the optional migration step.
461 + $has_givewp_data = false;
462 + try {
463 + $has_givewp_data = \SureDonation\Inc\Import\Givewp\Source::get_instance()->has_givewp_data();
464 + } catch ( \Throwable $e ) {
465 + $has_givewp_data = false;
466 + }
467 +
468 + wp_localize_script(
469 + 'suredonation-onboarding',
470 + 'suredonation_onboarding',
471 + [
472 + 'apiUrl' => rest_url( 'suredonation/v1' ),
473 + 'nonce' => wp_create_nonce( 'wp_rest' ),
474 + 'pluginUrl' => SUREDONATION_URL,
475 + 'adminUrl' => admin_url(),
476 + 'dashboardUrl' => admin_url( 'admin.php?page=suredonation' ),
477 + 'paymentsUrl' => admin_url( 'admin.php?page=suredonation#/settings?tab=payments' ),
478 + 'campaignsUrl' => admin_url( 'admin.php?page=suredonation#/campaigns' ),
479 + 'docsUrl' => 'https://suredonation.com/docs/',
480 + 'isProActive' => $is_pro,
481 + 'hasGiveWPData' => $has_givewp_data,
482 + 'currentUser' => [
483 + 'firstName' => $current_user ? $current_user->first_name : '',
484 + 'lastName' => $current_user ? $current_user->last_name : '',
485 + 'email' => $current_user ? $current_user->user_email : '',
486 + ],
487 + 'privacyUrl' => 'https://suredonation.com/privacy-policy/',
488 + ]
489 + );
490 +
491 + // Shim suredonation_admin on the onboarding page too — shared API
492 + // helpers (e.g. importApi.js) read apiUrl + nonce from that global,
493 + // so without this the migration session fails the REST cookie check.
494 + wp_localize_script(
495 + 'suredonation-onboarding',
496 + 'suredonation_admin',
497 + [
498 + 'apiUrl' => rest_url( 'suredonation/v1' ),
499 + 'nonce' => wp_create_nonce( 'wp_rest' ),
500 + 'is_pro_active' => $is_pro,
501 + ]
502 + );
252 503 }
253 504 }