'POST', 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, 'args' => array( 'optin' => array( 'type' => 'boolean', 'required' => true, ), 'email' => array( 'type' => 'string' ), ), 'callback' => array( $this, 'handle' ), ) ); register_rest_route( 'aim-transparency/v1', '/directory-token', array( 'methods' => 'GET', 'permission_callback' => '__return_true', 'callback' => function () { $d = get_option( self::OPTION, array() ); $pending = ! empty( $d['token_time'] ) && ( time() - (int) $d['token_time'] ) < 15 * MINUTE_IN_SECONDS; $token = ( $pending && ! empty( $d['optin'] ) && ! empty( $d['token'] ) ) ? $d['token'] : null; return rest_ensure_response( array( 'token' => $token ) ); }, ) ); } /** * Return the current opt-in state for the dashboard. * * @since 1.0.0 * @return array Associative array with opt-in flag, contact email and site URL. */ public function state() { $d = get_option( self::OPTION, array() ); return array( 'optin' => ! empty( $d['optin'] ), 'email' => ! empty( $d['email'] ) ? $d['email'] : wp_get_current_user()->user_email, 'url' => home_url(), ); } /** * Process an opt-in or opt-out request from the dashboard. * * @since 1.0.0 * @param WP_REST_Request $request The REST request carrying the opt-in flag and contact email. * @return WP_REST_Response Response containing the success flag and the updated directory state. */ public function handle( $request ) { $optin = (bool) $request->get_param( 'optin' ); $email = sanitize_email( (string) $request->get_param( 'email' ) ); $existing = get_option( self::OPTION, array() ); if ( $optin ) { $token = wp_generate_password( 24, false ); $data = array( 'optin' => 1, 'email' => is_email( $email ) ? $email : '', 'consent_version' => self::CONSENT_VERSION, 'consent_time' => current_time( 'mysql' ), 'token' => $token, 'token_time' => time(), ); update_option( self::OPTION, $data, false ); $this->push( 'register', $data ); } else { $this->push( 'remove', array( 'token' => isset( $existing['token'] ) ? $existing['token'] : '' ) ); delete_option( self::OPTION ); } return rest_ensure_response( array( 'ok' => true, 'directory' => $this->state(), ) ); } /** * Send the registration or removal request to the directory (non-blocking, best-effort). * * @since 1.0.0 * @param string $action The directory action to perform, either 'register' or 'remove'. * @param array $consent The local consent record supplying the email, consent metadata and token. * @return void */ protected function push( $action, $consent ) { /** * Filter the AI Transparency Directory endpoint URL. * * @since 1.0.0 * @param string $endpoint The directory registration endpoint URL. */ $endpoint = apply_filters( 'aicl_directory_endpoint', self::ENDPOINT ); if ( ! $endpoint ) { return; } $payload = array( 'action' => $action, 'site_url' => home_url(), 'site_name' => get_bloginfo( 'name' ), 'plugin_version' => AICL_VERSION, 'wp_version' => get_bloginfo( 'version' ), 'flagged_count' => AICL_Plugin::flagged_count(), 'email' => isset( $consent['email'] ) ? $consent['email'] : '', 'consent_version' => isset( $consent['consent_version'] ) ? $consent['consent_version'] : '', 'consent_time' => isset( $consent['consent_time'] ) ? $consent['consent_time'] : '', 'token' => isset( $consent['token'] ) ? $consent['token'] : '', 'token_url' => add_query_arg( 'rest_route', '/aim-transparency/v1/directory-token', home_url( '/' ) ), ); wp_remote_post( $endpoint, array( 'timeout' => 5, 'blocking' => false, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( $payload ), ) ); } }