resolve_campaign_id_from_referer(); $target = $campaign_id ? admin_url( 'admin.php?page=suredonation#/campaigns/' . $campaign_id ) : admin_url( 'admin.php?page=suredonation#/campaigns' ); wp_safe_redirect( $target ); exit; } if ( 'suredonation_cmpgn' === $post_type ) { wp_safe_redirect( admin_url( 'admin.php?page=suredonation#/campaigns' ) ); exit; } } /** * Resolve the campaign ID from the referer when the form list page * is reached from the form editor's "back" button. * * @return int Campaign ID, or 0 when it cannot be determined. * @since 1.0.0 */ private function resolve_campaign_id_from_referer() { $referer = wp_get_referer(); if ( ! $referer ) { return 0; } $parts = wp_parse_url( $referer ); if ( empty( $parts['query'] ) ) { return 0; } $query = []; parse_str( $parts['query'], $query ); if ( empty( $query['post'] ) || ! is_numeric( $query['post'] ) ) { return 0; } $form_id = absint( $query['post'] ); if ( 'suredonation_form' !== get_post_type( $form_id ) ) { return 0; } $campaign_id = get_post_meta( $form_id, '_suredonation_campaign_id', true ); if ( ! is_numeric( $campaign_id ) ) { return 0; } return absint( $campaign_id ); } /** * Enqueue admin scripts and styles. * * @param string $hook Current admin page hook. * @return void * @since 0.0.1 */ public function enqueue_admin_scripts( $hook ) { // Only load on our plugin pages. if ( strpos( $hook, 'suredonation' ) === false ) { return; } // Onboarding gets its own lean bundle — bail before enqueuing the // main admin app on that page. if ( false !== strpos( $hook, Onboarding::PAGE_SLUG ) ) { $this->enqueue_onboarding_assets(); return; } $asset_file = SUREDONATION_DIR . 'assets/build/admin.asset.php'; if ( ! file_exists( $asset_file ) ) { return; } $asset = include $asset_file; // Enqueue WordPress editor for TinyMCE support. wp_enqueue_editor(); // Enqueue the media library so the campaign image picker can open it. wp_enqueue_media(); // Enqueue editor buttons style (needed for TinyMCE icons). wp_enqueue_style( 'editor-buttons' ); // Enqueue admin app script. wp_enqueue_script( 'suredonation-admin', SUREDONATION_URL . 'assets/build/admin.js', $asset['dependencies'], $asset['version'], true ); // Enqueue admin app styles. wp_enqueue_style( 'suredonation-admin', SUREDONATION_URL . 'assets/build/admin.css', [], $asset['version'] ); // The campaign drawer sits at a very high z-index. Lift the media library // above it, and keep the media modal above its OWN backdrop so the picker // is not dimmed by either overlay. wp_add_inline_style( 'suredonation-admin', '.media-modal-backdrop{z-index:2147483646 !important;}.media-modal{z-index:2147483647 !important;}' ); // Load JS translations for the admin app. wp_set_script_translations( 'suredonation-admin', 'suredonation' ); // Localize script with plugin data. wp_localize_script( 'suredonation-admin', 'suredonation_admin', [ 'version' => SUREDONATION_VER, 'apiUrl' => rest_url( 'suredonation/v1' ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'docsURL' => 'https://suredonation.com/docs/', 'plugin_url' => SUREDONATION_URL, 'site_url' => site_url(), 'admin_url' => admin_url(), 'is_first_campaign_created' => $this->has_campaigns(), 'is_onboarding_completed' => Onboarding::get_instance()->is_completed(), 'rotating_plugin_banner' => $this->get_rotating_plugin_banner(), 'smart_tags' => Helper::get_smart_tags(), 'is_pro_active' => defined( 'SUREDONATION_PRO_VER' ), 'pro_plugin_version' => defined( 'SUREDONATION_PRO_VER' ) ? SUREDONATION_PRO_VER : '', 'pro_plugin_name' => defined( 'SUREDONATION_PRO_PRODUCT' ) ? SUREDONATION_PRO_PRODUCT : 'SureDonation Pro', 'is_license_active' => defined( 'SUREDONATION_PRO_VER' ) && class_exists( 'SureDonationPro\Inc\Licensing\Licensing' ) ? \SureDonationPro\Inc\Licensing\Licensing::is_license_active() : false, 'pdf_library_exists' => Pdf_Utils::check_if_library_exists(), 'php_version_compatible' => Pdf_Utils::is_php_compatible(), 'pdf_nonce' => wp_create_nonce( 'suredonation_pdf_nonce' ), 'ajax_url' => admin_url( 'admin-ajax.php' ), 'plugin_installer_nonce' => wp_create_nonce( 'updates' ), 'plugin_manager_nonce' => wp_create_nonce( 'suredonation_plugin_manager' ), 'has_abilities_api' => class_exists( 'WP_Ability' ), 'current_user_login' => wp_get_current_user()->user_login, 'integrations' => [ 'sure_triggers' => Helper::get_ottokit_integration(), ], // Bootstrap settings data so the General currency list and the // PayPal connection state render synchronously (no post-mount // fetch flicker). PayPal data is the non-sensitive subset only. 'payments' => [ 'currencies' => Payment_Helper::get_currencies_list(), 'paypal' => PayPal_Helper::get_connection_state(), ], ] ); } /** * Register admin menu. * * @return void * @since 0.0.1 */ public function register_menu() { $menu_slug = 'suredonation'; // SureDonation mark for the admin menu — single path with evenodd // fill so the inner heart cuts a hole that reveals the sidebar // background (mirrors the pattern used by SureForms). $menu_icon_svg = ''; // Main menu page. add_menu_page( __( 'SureDonation', 'suredonation' ), __( 'SureDonation', 'suredonation' ), 'manage_options', $menu_slug, [ $this, 'render_dashboard' ], 'data:image/svg+xml;base64,' . base64_encode( $menu_icon_svg ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Building data URI for menu icon. 25 ); // Register submenus. $this->register_submenus( $menu_slug ); } /** * Render dashboard page. * * @return void * @since 0.0.1 */ public function render_dashboard() { ?>
'suredonation_cmpgn', 'posts_per_page' => 1, 'post_status' => [ 'publish', 'draft', 'private' ], 'fields' => 'ids', ] ); return ! empty( $campaigns ); } /** * Get rotating plugin banner data. * * @return array|null Plugin banner data, or null when the plugin is already active. * @since 0.0.1 */ private function get_rotating_plugin_banner() { // Match SureForms: never nudge a plugin that is already active, so the // dashboard card is hidden once SureRank is activated. $status = $this->get_plugin_status( 'surerank/surerank.php' ); if ( 'Activated' === $status ) { return null; } // Get SVG logo as base64. $logo_svg = file_get_contents( SUREDONATION_DIR . 'images/surerank.svg' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local file read. $logo_data = $logo_svg ? 'data:image/svg+xml;base64,' . base64_encode( $logo_svg ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode // SureRank plugin data. return [ 'slug' => 'surerank', 'path' => 'surerank/surerank.php', 'title' => 'SureRank', 'singleLineDescription' => __( 'SEO Made Easy for Your Website', 'suredonation' ), 'subtitle' => __( 'Beautiful pages, persuasive content, and custom code in seconds. The possibilities are endless!', 'suredonation' ), 'logo' => $logo_data, 'status' => $status, ]; } /** * Get plugin installation status. * * @param string $plugin_file Plugin file path (e.g., 'plugin-folder/plugin-file.php'). * @return string Plugin status: 'Activated', 'Installed', or 'Install'. * @since 0.0.1 */ private function get_plugin_status( $plugin_file ) { if ( ! function_exists( 'is_plugin_active' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin.php'; } if ( is_plugin_active( $plugin_file ) ) { return 'Activated'; } $all_plugins = get_plugins(); if ( isset( $all_plugins[ $plugin_file ] ) ) { return 'Installed'; } return 'Install'; } /** * Register submenus. * * @param string $menu_slug Menu slug. * @return void * @since 0.0.1 */ private function register_submenus( $menu_slug ) { $capability = 'manage_options'; $submenus = [ [ 'id' => $menu_slug, 'page_title' => __( 'Dashboard', 'suredonation' ), ], [ 'id' => 'suredonation#/campaigns', 'page_title' => __( 'Campaigns', 'suredonation' ), ], [ 'id' => 'suredonation#/donations', 'page_title' => __( 'Donations', 'suredonation' ), ], [ 'id' => 'suredonation#/donors', 'page_title' => __( 'Donors', 'suredonation' ), ], [ 'id' => 'suredonation#/reports', 'page_title' => __( 'Reports', 'suredonation' ), ], [ 'id' => 'suredonation#/settings', 'page_title' => __( 'Settings', 'suredonation' ), ], ]; // Register the submenus. foreach ( $submenus as $submenu ) { add_submenu_page( $menu_slug, $submenu['page_title'], $submenu['page_title'], $capability, $submenu['id'], [ $this, 'render_dashboard' ] ); } // Hidden onboarding page (no menu parent so it never shows in // the sidebar but is still routable via admin.php?page=...). add_submenu_page( '', __( 'SureDonation Setup', 'suredonation' ), __( 'SureDonation Setup', 'suredonation' ), $capability, Onboarding::PAGE_SLUG, [ $this, 'render_onboarding' ] ); } /** * Render onboarding root container. * * @return void * @since 1.0.0 */ public function render_onboarding() { ?>
has_givewp_data(); } catch ( \Throwable $e ) { $has_givewp_data = false; } wp_localize_script( 'suredonation-onboarding', 'suredonation_onboarding', [ 'apiUrl' => rest_url( 'suredonation/v1' ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'pluginUrl' => SUREDONATION_URL, 'adminUrl' => admin_url(), 'dashboardUrl' => admin_url( 'admin.php?page=suredonation' ), 'paymentsUrl' => admin_url( 'admin.php?page=suredonation#/settings?tab=payments' ), 'campaignsUrl' => admin_url( 'admin.php?page=suredonation#/campaigns' ), 'docsUrl' => 'https://suredonation.com/docs/', 'isProActive' => $is_pro, 'hasGiveWPData' => $has_givewp_data, 'currentUser' => [ 'firstName' => $current_user ? $current_user->first_name : '', 'lastName' => $current_user ? $current_user->last_name : '', 'email' => $current_user ? $current_user->user_email : '', ], 'privacyUrl' => 'https://suredonation.com/privacy-policy/', ] ); // Shim suredonation_admin on the onboarding page too — shared API // helpers (e.g. importApi.js) read apiUrl + nonce from that global, // so without this the migration session fails the REST cookie check. wp_localize_script( 'suredonation-onboarding', 'suredonation_admin', [ 'apiUrl' => rest_url( 'suredonation/v1' ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'is_pro_active' => $is_pro, ] ); } }