// ─── WildApricot OAuth + Bookmarks ─────────────────────────────────────────── define( 'IASC_WA_CLIENT_ID', '5a73rqxes9' ); define( 'IASC_WA_CLIENT_SECRET', 'vrml2nsyeoy4rmnkyylt25a9j0bvcl' ); define( 'IASC_WA_ACCOUNT_URL', 'https://iasc-commons.wildapricot.org' ); define( 'IASC_COOKIE_NAME', 'iasc_wa_contact' ); define( 'IASC_COOKIE_DAYS', 30 ); add_action( 'rest_api_init', function() { // OAuth callback — WildApricot redirects here after login register_rest_route( 'iasc/v1', '/wa-callback', [ 'methods' => 'GET', 'callback' => 'iasc_wa_callback', 'permission_callback' => '__return_true', ] ); // Get bookmarks for current user register_rest_route( 'iasc/v1', '/bookmarks', [ 'methods' => 'GET', 'callback' => 'iasc_get_bookmarks', 'permission_callback' => '__return_true', ] ); // Save bookmarks for current user register_rest_route( 'iasc/v1', '/bookmarks', [ 'methods' => 'POST', 'callback' => 'iasc_save_bookmarks', 'permission_callback' => '__return_true', ] ); } ); // Exchange OAuth code for token, get contactId, set cookie, close popup function iasc_wa_callback( WP_REST_Request $request ) { $code = sanitize_text_field( $request->get_param( 'code' ) ); $error = $request->get_param( 'error' ); if ( $error || ! $code ) { iasc_wa_close_popup( false, 'Login cancelled or failed.' ); return; } // Exchange code for access token $redirect_uri = rest_url( 'iasc/v1/wa-callback' ); $token_response = wp_remote_post( 'https://oauth.wildapricot.org/auth/token', [ 'body' => [ 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $redirect_uri, 'client_id' => IASC_WA_CLIENT_ID, 'client_secret'=> IASC_WA_CLIENT_SECRET, ], 'timeout' => 15, ] ); if ( is_wp_error( $token_response ) ) { iasc_wa_close_popup( false, 'Token exchange failed.' ); return; } $token_data = json_decode( wp_remote_retrieve_body( $token_response ), true ); if ( empty( $token_data['access_token'] ) ) { iasc_wa_close_popup( false, 'No access token received.' ); return; } $access_token = $token_data['access_token']; // Get contact info from WildApricot API $account_response = wp_remote_get( IASC_WA_ACCOUNT_URL . '/api/v2.2/accounts', [ 'headers' => [ 'Authorization' => 'Bearer ' . $access_token ], 'timeout' => 15, ] ); $accounts = json_decode( wp_remote_retrieve_body( $account_response ), true ); $account_id = ! empty( $accounts[0]['Id'] ) ? $accounts[0]['Id'] : null; if ( ! $account_id ) { iasc_wa_close_popup( false, 'Could not retrieve account info.' ); return; } // Get contact details $contact_response = wp_remote_get( IASC_WA_ACCOUNT_URL . '/api/v2.2/accounts/' . $account_id . '/contacts/me', [ 'headers' => [ 'Authorization' => 'Bearer ' . $access_token ], 'timeout' => 15, ] ); $contact = json_decode( wp_remote_retrieve_body( $contact_response ), true ); $contact_id = ! empty( $contact['Id'] ) ? intval( $contact['Id'] ) : null; $contact_name = ! empty( $contact['DisplayName'] ) ? sanitize_text_field( $contact['DisplayName'] ) : ''; $contact_email= ! empty( $contact['Email'] ) ? sanitize_email( $contact['Email'] ) : ''; if ( ! $contact_id ) { iasc_wa_close_popup( false, 'Could not retrieve contact ID.' ); return; } // Set secure cookie with contactId + name $cookie_value = base64_encode( json_encode( [ 'id' => $contact_id, 'name' => $contact_name, 'email' => $contact_email, ] ) ); $expires = time() + ( IASC_COOKIE_DAYS * DAY_IN_SECONDS ); setcookie( IASC_COOKIE_NAME, $cookie_value, [ 'expires' => $expires, 'path' => '/', 'secure' => true, 'httponly' => false, 'samesite' => 'Lax', ] ); iasc_wa_close_popup( true, $contact_name ); } // Close the OAuth popup and notify the parent window function iasc_wa_close_popup( $success, $data ) { $payload = json_encode( [ 'success' => $success, 'data' => $data ] ); echo ""; exit; } // Get current user's bookmarks from WP options function iasc_get_bookmarks() { $contact = iasc_get_current_contact(); if ( ! $contact ) { return new WP_REST_Response( [ 'logged_in' => false, 'bookmarks' => [] ], 200 ); } $key = 'iasc_bookmarks_' . $contact['id']; $bookmarks = get_option( $key, [] ); return new WP_REST_Response( [ 'logged_in' => true, 'contact' => $contact, 'bookmarks' => $bookmarks, ], 200 ); } // Save bookmarks to WP options function iasc_save_bookmarks( WP_REST_Request $request ) { $contact = iasc_get_current_contact(); if ( ! $contact ) { return new WP_REST_Response( [ 'error' => 'Not authenticated' ], 401 ); } $bookmarks = $request->get_json_params(); $bookmarks = is_array( $bookmarks ) ? array_map( 'intval', $bookmarks ) : []; $key = 'iasc_bookmarks_' . $contact['id']; update_option( $key, $bookmarks, false ); return new WP_REST_Response( [ 'saved' => true, 'count' => count( $bookmarks ) ], 200 ); } // Read contact info from cookie function iasc_get_current_contact() { if ( empty( $_COOKIE[ IASC_COOKIE_NAME ] ) ) return null; $decoded = json_decode( base64_decode( $_COOKIE[ IASC_COOKIE_NAME ] ), true ); if ( empty( $decoded['id'] ) ) return null; return $decoded; } ?> Hulst, Natasha - IASC 2025 - XX Biennial Conference