admin_url( 'admin-ajax.php' ), 'action' => self::ACTION, 'nonce' => wp_create_nonce( self::NONCE_ACTION ), ); wp_enqueue_script( self::SCRIPT_HANDLE, NOTIFYPRESS_ASSETS_URL . 'token-bridge.js', array(), (string) filemtime( NOTIFYPRESS_ASSETS_DIR . 'token-bridge.js' ), true ); wp_add_inline_script( self::SCRIPT_HANDLE, 'window.notifypressTokenBridge = ' . wp_json_encode( $config ) . ';', 'before' ); } /** * Persist the posted token for this visitor. * * @return void */ public function store_token(): void { if ( ! check_ajax_referer( self::NONCE_ACTION, 'nonce', false ) ) { wp_send_json_error( __( 'Expired request.', 'notifypress' ), 403 ); } $token = sanitize_text_field( wp_unslash( $_POST['token'] ?? '' ) ); if ( ! $this->is_valid_token( $token ) ) { wp_send_json_error( __( 'Invalid subscriber token.', 'notifypress' ), 400 ); } $user_id = get_current_user_id(); if ( $user_id ) { update_user_meta( $user_id, SubscriberToken::USER_META, $token ); } // Stored for guests, and also for logged-in customers, so a shopper // who signs in mid-checkout is covered by whichever is read first. if ( function_exists( 'WC' ) && WC()->session ) { // A guest with an empty cart has no session cookie yet. Without // one, the value set below is never saved and the token is lost. if ( ! WC()->session->has_session() ) { WC()->session->set_customer_session_cookie( true ); } WC()->session->set( SubscriberToken::SESSION, $token ); } wp_send_json_success(); } /** * Whether a posted value looks like a subscriber token. * * @param string $token The posted token. * * @return bool */ private function is_valid_token( string $token ): bool { $length = strlen( $token ); if ( $length < self::TOKEN_MIN || $length > self::TOKEN_MAX ) { return false; } return 1 === preg_match( '/^[A-Za-z0-9_:.-]+$/', $token ); } }