user_session = Prodigy_Parameters::get_parameter( $_GET, 'session_token' ); if ( empty( $this->user_session ) ) { $this->user_session = Prodigy_Parameters::get_parameter( $_POST, 'session_token' ); } $this->set_external_checkout_id_cookie(); $this->set_guest_user_cookie(); } /** * @return void * @throws \Exception */ private function set_external_checkout_id_cookie(): void { $external_checkout_id = Prodigy_Parameters::get_parameter( $_GET, 'external_checkout_id' ); if ( empty( $external_checkout_id ) || ! is_string( $external_checkout_id ) ) { return; } $external_checkout_id = sanitize_text_field( wp_unslash( $external_checkout_id ) ); if ( $external_checkout_id === '' ) { return; } Prodigy_Cookies::set_cookie( self::EXTERNAL_CHECKOUT_ID_COOKIE_NAME, $external_checkout_id, time() + self::GUEST_COOKIE_LIFETIME_SECONDS, '/', ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'External checkout id cookie set', 'prodigy-user', wp_json_encode( array( 'cookie_name' => self::EXTERNAL_CHECKOUT_ID_COOKIE_NAME, 'external_checkout_id' => $external_checkout_id, ) ) ); } } /** * @throws \Exception */ private function set_guest_user_cookie(): void { if ( ! Prodigy_Cookies::get_cookie( self::USER_GROUP_COOKIE_NAME ) ) { // Every guest gets the same group, so first visits (and cookieless bots) stay cacheable. Prodigy_Cookies::set_cookie( self::USER_GROUP_COOKIE_NAME, self::PRODIGY_USER_GROUP_NAME, time() + self::GUEST_COOKIE_LIFETIME_SECONDS, '/', null, false, true ); } } /** * @return array */ public static function get_user_info(): array { $user_auth_hash = Prodigy_Cookies::get_cookie( self::AUTHORIZATION_COOKIE_NAME ); return Prodigy_Request_Maker::get_instance()->do_user_info_request( $user_auth_hash ); } /** * @return string|null */ public static function get_user_session(): ?string { return self::is_logged_in() ? self::get_user_id() : Prodigy_Cookies::get_user_cart_cookie(); } /** * @return string|null */ public static function get_external_checkout_id(): ?string { $value = Prodigy_Cookies::get_cookie( self::EXTERNAL_CHECKOUT_ID_COOKIE_NAME ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'External checkout id cookie read', 'prodigy-user', wp_json_encode( array( 'cookie_name' => self::EXTERNAL_CHECKOUT_ID_COOKIE_NAME, 'present' => $value !== '', ) ) ); } return $value !== '' ? $value : null; } /** * Gift card balance of the current customer, read from their own user-info response * (cached per authorization token), never from shared storage. * * @return float|false False when the customer is not logged in or the balance is unknown. */ public static function get_customer_balance() { if ( ! self::is_logged_in() ) { return false; } $response = Prodigy_Request_Maker::get_instance()->do_user_info_request( Prodigy_Cookies::get_cookie( self::AUTHORIZATION_COOKIE_NAME ) ); $balance = $response['data']['attributes']['customer-balance-amount'] ?? null; if ( ( $response['code'] ?? null ) !== \WP_Http::OK || ! is_numeric( $balance ) ) { return false; } return (float) $balance; } /** * Access token expiry stored at login, or null when it is missing, malformed or already past. * * @return string|null */ public static function get_session_expiration(): ?string { $expiration = Prodigy_Cookies::get_cookie( self::SESSION_EXPIRES_COOKIE_NAME ); if ( $expiration === '' ) { return null; } $date_time = \DateTime::createFromFormat( 'Y-m-d\TH:i:s.uP', $expiration ); return ( $date_time !== false && $date_time->getTimestamp() > time() ) ? $expiration : null; } /** * @return int */ public static function get_user_id(): ?int { $user_hash = Prodigy_Cookies::get_cookie( self::USER_ID_COOKIE_NAME ); return self::prodigy_decrypt_user_id( $user_hash ?? 0 ); } /** * @return bool */ public function is_logout_action(): bool { $action = Prodigy_Parameters::get_parameter( $_POST, 'action' ); return $action === 'prodigy-user-logout'; } /** * @param bool $user_logged_in * @param bool $require_login * @param bool $has_session_token * * @return bool */ public function should_return_early( bool $user_logged_in, bool $require_login, bool $has_session_token ): bool { if ( ! $has_session_token && ! $user_logged_in && ! $require_login ) { return true; } if ( ! Helpers\Prodigy_Page::prodigy_is_need_user_authorise( $require_login ) ) { return true; } return false; } /** * @param bool $require_login * @param string $request_uri * * @return void * @throws \Exception */ public function handle_unauthenticated_user( bool $require_login, string $request_uri ): void { if ( $require_login && self::is_frontend_authentication_required( $request_uri ) ) { $this->set_user_require_authentication(); } else { $this->process_login_redirect(); } } /** * @param string $url * * @return bool */ public static function is_frontend_authentication_required( string $url ): bool { if ( wp_doing_ajax() ) { return false; } $result = false; $array = array( Prodigy::get_prodigy_category_slug(), Prodigy::get_prodigy_tag_slug(), Prodigy::get_prodigy_brand_slug(), Prodigy::get_prodigy_product_slug(), Prodigy_Page::PAGE_TYPE_SHOP, Prodigy_Page::PAGE_TYPE_CART, Prodigy_Page::PAGE_TYPE_THANK, ); $path = wp_parse_url( $url, PHP_URL_PATH ); if ( $path === '/' ) { $result = true; } foreach ( $array as $value ) { if ( is_string( $path ) && str_contains( $path, $value ) ) { if ( str_contains( $path, $value ) ) { $result = true; } } } $result = $result && ( ! isset( $_SERVER['HTTP_SEC_FETCH_DEST'] ) || $_SERVER['HTTP_SEC_FETCH_DEST'] !== 'iframe' ); if ( ! $result && ! is_admin() ) { return true; } return $result; } /** * @return void * @throws \Exception */ public function set_user_require_authentication(): void { if ( self::is_logged_in() ) { return; } if ( ! empty( $this->user_session ) ) { $this->process_login_redirect(); } $url = self::get_hosted_system_login_url(); Prodigy_Url_Helper::login_redirect( $url ); } /** * @return bool */ public static function is_logged_in(): bool { return isset( $_COOKIE[ self::AUTHORIZATION_COOKIE_NAME ], $_COOKIE[ self::ACCESS_COOKIE_NAME ] ); } /** * @return void * @throws \Exception */ public function process_login_redirect(): void { if ( ! $this->authorization() ) { return; } $cart = new Prodigy_Cart( Prodigy_Request_Maker::get_instance(), new Prodigy_Order(), new Cart_Error_Handler() ); $cart->move_guest_order_to_customer_order(); $request_uri = Prodigy_Url_Helper::prodigy_parse_request_uri( - 1 ); $redirect_url = $this->clear_url( $request_uri ); Prodigy_Url_Helper::login_redirect( $redirect_url ); } /** * * @return bool * @throws \Exception */ public function authorization(): bool { $user_data = Prodigy_Request_Maker::get_instance()->do_user_request( $this->user_session ?? '' ); if ( isset( $user_data['meta']['jwt'] ) ) { $is_logged_in = $this->login( $user_data['meta']['jwt'] ); if ( ! $is_logged_in ) { return false; } $this->set_user_info( $user_data['data'], $user_data['meta']['jwt']['access_expires_at'] ); Prodigy_Cookies::set_cookie( self::PRODIGY_USER_PAIRED_SESSION_COOKIE_NAME, $this->user_session, Prodigy_Cookies::calculate_expiration_time( $user_data['meta']['jwt']['access_expires_at'] ) ); return true; } return false; } /** * @param array $data * * @return bool * @throws \Exception */ public function login( array $data ): bool { if ( ! isset( $data['refresh'], $data['access'], $data['csrf'] ) ) { return false; } $is_set_refresh_cookie = Prodigy_Cookies::set_cookie( self::REFRESH_COOKIE_NAME, $data['refresh'], Prodigy_Cookies::calculate_expiration_time( $data['refresh_expires_at'] ) ); $is_set_access_cookie = Prodigy_Cookies::set_cookie( self::ACCESS_COOKIE_NAME, $data['access'], Prodigy_Cookies::calculate_expiration_time( $data['access_expires_at'] ) ); $is_set_jwt_cookie = Prodigy_Cookies::set_cookie( self::AUTHORIZATION_COOKIE_NAME, $data['csrf'], Prodigy_Cookies::calculate_expiration_time( $data['access_expires_at'] ) ); Prodigy_Cookies::set_cookie( self::SESSION_EXPIRES_COOKIE_NAME, (string) $data['access_expires_at'], Prodigy_Cookies::calculate_expiration_time( $data['access_expires_at'] ) ); return $is_set_refresh_cookie && $is_set_access_cookie && $is_set_jwt_cookie; } /** * Writes the customer's info cookies. On login ($expiration given) every cookie is (re)written * with the session's expiry. On the per-page refresh ($expiration null) a cookie is written only * when its value changed or it is missing, with the session expiry stored at login: an unchanged * page response then carries no Set-Cookie and stays cacheable per customer group, while a * changed one is marked private. Sessions started before that expiry was stored keep the old * behaviour (all cookies renewed for an hour on every page) until the customer logs in again. * * @param array $data_attributes * @param string|null $expiration * * @return bool * @throws \Exception */ public function set_user_info( array $data_attributes, ?string $expiration = null ): bool { $session_expiration = $expiration === null ? self::get_session_expiration() : null; $expiration_time = Prodigy_Cookies::calculate_expiration_time( $expiration ?? $session_expiration ); $user_attributes = $this->get_user_attributes( $data_attributes ); $is_refresh = $session_expiration !== null; if ( isset( $user_attributes['impersonated'], $user_attributes['impersonation-id'] ) && $user_attributes['impersonated'] ) { $this->set_user_info_cookie( self::IMPERSONATION_COOKIE_ID, (string) $user_attributes['impersonation-id'], $expiration_time, '/', $is_refresh ); } if ( isset( $user_attributes['customer-group-name'] ) ) { $this->set_user_info_cookie( self::USER_GROUP_COOKIE_NAME, (string) $user_attributes['customer-group-name'], $expiration_time, '/', $is_refresh ); } // The encrypted ID differs on every call (random nonce), so compare the decrypted value. if ( isset( $data_attributes['id'] ) && is_numeric( $data_attributes['id'] ) && ( ! $is_refresh || self::get_user_id() !== (int) $data_attributes['id'] ) ) { Prodigy_Cookies::set_cookie( self::USER_ID_COOKIE_NAME, self::prodigy_encrypt_user_id( (int) $data_attributes['id'] ), $expiration_time, '/', ); } $is_set_name_cookie = $this->set_user_info_cookie( self::USER_INFO_COOKIE_LAST_NAME, $this->get_user_cookie_value( $user_attributes, 'last-name', self::USER_INFO_COOKIE_LAST_NAME ), $expiration_time, null, $is_refresh ); $is_set_last_name_cookie = $this->set_user_info_cookie( self::USER_INFO_COOKIE_NAME, $this->get_user_cookie_value( $user_attributes, 'first-name', self::USER_INFO_COOKIE_NAME ), $expiration_time, null, $is_refresh ); $is_set_email_cookie = $this->set_user_info_cookie( self::USER_INFO_COOKIE_EMAIL, $this->get_user_cookie_value( $user_attributes, 'email', self::USER_INFO_COOKIE_EMAIL ), $expiration_time, '/', $is_refresh ); $is_set_phone_cookie = $this->set_user_info_cookie( self::USER_INFO_COOKIE_PHONE, $this->get_user_cookie_value( $user_attributes, 'phone', self::USER_INFO_COOKIE_PHONE ), $expiration_time, null, $is_refresh ); return $is_set_name_cookie && $is_set_last_name_cookie && $is_set_email_cookie && $is_set_phone_cookie; } /** * @param string $name * @param string $value * @param string $expiration * @param string|null $path * @param bool $skip_unchanged Leave an existing cookie with the same value untouched. * * @return bool * @throws \Exception */ private function set_user_info_cookie( string $name, string $value, string $expiration, ?string $path, bool $skip_unchanged ): bool { if ( $skip_unchanged ) { $has_cookie = Prodigy_Cookies::has_cookie( $name ); // An empty value deletes the cookie, so a missing cookie already matches it. if ( ( $has_cookie && Prodigy_Cookies::get_cookie( $name ) === sanitize_text_field( $value ) ) || ( ! $has_cookie && $value === '' ) ) { return true; } } return Prodigy_Cookies::set_cookie( $name, $value, $expiration, $path ); } /** * @param array $user_data * * @return array */ private function get_user_attributes( array $user_data ): array { if ( isset( $user_data['attributes'] ) && is_array( $user_data['attributes'] ) ) { return $user_data['attributes']; } return $user_data; } /** * @param array $user_attributes * @param string $attribute_key * @param string $cookie_name * * @return string */ private function get_user_cookie_value( array $user_attributes, string $attribute_key, string $cookie_name ): string { if ( array_key_exists( $attribute_key, $user_attributes ) ) { return (string) $user_attributes[ $attribute_key ]; } return Prodigy_Cookies::get_cookie( $cookie_name ); } /** * @param int $user_id * * @return string * @throws \Random\RandomException */ public static function prodigy_encrypt_user_id( int $user_id ): string { $key = hash( 'sha256', AUTH_SALT, true ); $nonce = random_bytes( 12 ); $plaintext = (string) $user_id; $tag = ''; $ciphertext = openssl_encrypt( $plaintext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $tag, '', 16 ); $blob = $nonce . $tag . $ciphertext; return rtrim( strtr( base64_encode( $blob ), '+/', '-_' ), '=' ); } /** * @param array $urlComponents * * @return string */ public function clear_url( array $urlComponents ): string { parse_str( $urlComponents['query'] ?? '', $queryParams ); unset( $queryParams['session_token'], $queryParams['external_checkout_id'] ); $newQueryString = http_build_query( $queryParams ); $newUrl = ( $urlComponents['host'] ?? '' ) . ( $urlComponents['path'] ?? '' ); if ( ! empty( $newQueryString ) ) { $newUrl .= '?' . $newQueryString; } return $newUrl; } /** * Generate url for Hosted System * * @return string */ public static function get_hosted_system_login_url(): string { $store_subdomain = Prodigy_Url_Helper::get_hs_store_subdomain(); return Prodigy_Api_Client::API_PROTOCOL . $store_subdomain . '.' . PRODIGY_CHECKOUT_DOMAIN . Prodigy_Api_Client::HS_CUSTOMER_LOGIN_URL; } /** * @param string $token * * @return int|null */ public static function prodigy_decrypt_user_id( string $token ): ?int { $key = hash( 'sha256', AUTH_SALT, true ); $blob = base64_decode( strtr( $token, '-_', '+/' ), true ); if ( $blob === false || strlen( $blob ) < ( 12 + 16 + 1 ) ) { return null; } $nonce = substr( $blob, 0, 12 ); $tag = substr( $blob, 12, 16 ); $ciphertext = substr( $blob, 28 ); $plaintext = openssl_decrypt( $ciphertext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $tag, '' ); if ( $plaintext === false || ! ctype_digit( $plaintext ) ) { return null; } return (int) $plaintext; } /** * Get user info from Hosted System * * @return void * @throws \Exception */ public function get_user_info_from_hosted_system(): void { $user_auth_hash = Prodigy_Cookies::get_cookie( self::AUTHORIZATION_COOKIE_NAME ); $response = Prodigy_Request_Maker::get_instance()->do_user_info_request( $user_auth_hash ); if ( ( $response['code'] ?? null ) !== \WP_Http::OK ) { // The customer's cookies could not be verified, so this page must not be shared with their group. Prodigy_Cookies::mark_response_private(); } if ( ! isset( $response['code'] ) ) { return; } if ( ( $response['code'] === \WP_Http::OK ) && isset( $response['data']['attributes']['customer-balance-amount'], $response['data']['attributes']['subscriptions-present'] ) ) { $this->set_user_info( $response['data'] ); } // Without a group of their own the customer shares the guests' cache key, so keep the page private. $group = Prodigy_Cookies::get_cookie( self::USER_GROUP_COOKIE_NAME ); if ( $group === '' || $group === self::PRODIGY_USER_GROUP_NAME ) { Prodigy_Cookies::mark_response_private(); } if ( $response['code'] === \WP_Http::UNAUTHORIZED ) { self::$session_expired = true; $refresh_key = Prodigy_Cookies::get_cookie( self::REFRESH_COOKIE_NAME ); $this->remove_impersonation_user( $refresh_key ); $this->hosted_system_logout_process( $refresh_key ); $this->logout(); $this->delete_user_cookie(); $this->clear_external_checkout_cookie(); if ( ! Prodigy_Platform_Settings::is_redemption_store_status() && ! $this->is_ajax_request() ) { $this->redirect_to_hosted_system_login(); } } } /** * Extracts normalized profile field values (name, contact info, default shipping * address, customer group, and custom fields) from the Hosted System user-info * response, for use by the My Account profile widget. * * Purely additive: reuses do_user_info_request() (already memoised per-request and * cached by Prodigy_Request_Maker, so this does not fire a second HTTP request when * called after get_user_info_from_hosted_system() in the same request) and does not * write cookies or otherwise touch the behaviour of get_user_info_from_hosted_system(). * * Note: the exact Hosted System attribute keys for the shipping-address fields * (line 1/2, state, zip, notes) are not yet confirmed against a live payload for * this endpoint, so a small set of plausible kebab-case variants is checked * defensively for each of those fields; verify against a real response and narrow * these once confirmed. * * @return array{ * name: string, * email: string, * phone: string, * notes: string, * group: string, * address: string, * city: string, * state: string, * country: string, * zip: string, * full_address: string[], * custom_fields: array * } * @throws \Exception */ public function get_profile_field_values(): array { $user_auth_hash = Prodigy_Cookies::get_cookie( self::AUTHORIZATION_COOKIE_NAME ); $response = Prodigy_Request_Maker::get_instance()->do_user_info_request( $user_auth_hash ); $attributes = $response['data']['attributes'] ?? array(); $included_by_type = Prodigy_Includes_Helper::prepare_included_by_type( $response['included'] ?? array() ); $address_resource = $this->resolve_profile_relationship( $response['data']['relationships']['default-shipping-address'] ?? array(), $included_by_type ); $address_attributes = $address_resource['attributes'] ?? array(); $country_resource = $this->resolve_profile_relationship( $address_resource['relationships']['country'] ?? array(), $included_by_type ); $country_attributes = $country_resource['attributes'] ?? array(); $first_name = (string) ( $attributes['first-name'] ?? '' ); $last_name = (string) ( $attributes['last-name'] ?? '' ); $address_line_1 = (string) ( $address_attributes['address-line-1'] ?? $address_attributes['street-address-line-1'] ?? $address_attributes['line1'] ?? '' ); $address_line_2 = (string) ( $address_attributes['address-line-2'] ?? $address_attributes['street-address-line-2'] ?? $address_attributes['line2'] ?? '' ); $city = (string) ( $address_attributes['city'] ?? '' ); $state = (string) ( $address_attributes['state'] ?? $address_attributes['region'] ?? $address_attributes['province'] ?? '' ); $zip = (string) ( $address_attributes['zip'] ?? $address_attributes['postal-code'] ?? $address_attributes['zip-code'] ?? $address_attributes['postcode'] ?? '' ); $country = (string) ( $country_attributes['name'] ?? $country_attributes['country-name'] ?? '' ); $address = trim( $address_line_1 . ( $address_line_2 !== '' ? ' ' . $address_line_2 : '' ) ); $full_address = array_values( array_filter( array( $address_line_1, $address_line_2, $city, $state, $zip, $country ), static function ( string $part ): bool { return $part !== ''; } ) ); $custom_fields = $this->get_custom_field_values( $included_by_type ); return array( 'name' => trim( $first_name . ' ' . $last_name ), 'email' => (string) ( $attributes['email'] ?? '' ), 'phone' => ( (string) ( $attributes['phone'] ?? '' ) ) ?: ( $custom_fields['phone'] ?? '' ) ?: Prodigy_Cookies::get_cookie( self::USER_INFO_COOKIE_PHONE ), 'notes' => (string) ( $attributes['notes'] ?? $attributes['customer-notes'] ?? '' ), 'group' => (string) ( $attributes['customer-group-name'] ?? '' ), 'address' => $address, 'city' => $city, 'state' => $state, 'country' => $country, 'zip' => $zip, 'full_address' => $full_address, 'custom_fields' => $custom_fields, ); } /** * Maps `customer-extra-fields` included resources to an associative array keyed * by the field's `name` attribute. * * @param array $included_by_type Map built by Prodigy_Includes_Helper::prepare_included_by_type(). * * @return array */ private function get_custom_field_values( array $included_by_type ): array { $custom_fields = array(); foreach ( $included_by_type['customer-extra-fields'] ?? array() as $custom_field ) { $field_name = $custom_field['attributes']['name'] ?? ''; if ( $field_name === '' ) { continue; } $custom_fields[ $field_name ] = (string) ( $custom_field['attributes']['value'] ?? '' ); } return $custom_fields; } /** * Resolve a JSON:API relationship node (e.g. `$response['data']['relationships']['default-shipping-address']`) * to the included resource it points to, using the type/id map built by * Prodigy_Includes_Helper::prepare_included_by_type(). * * Hand-rolled to mirror the relationship-traversal pattern used by * Prodigy_Main_Content::resolve_relationship() (see e.g. Prodigy_Product_Parser); * duplicated locally instead of reused since Prodigy_User does not extend * Prodigy_Main_Content. * * @param array $relationship Relationship node with a `data.id` / `data.type` pair. * @param array $included_by_type Map built by Prodigy_Includes_Helper::prepare_included_by_type(). * * @return array */ private function resolve_profile_relationship( array $relationship, array $included_by_type ): array { $id = $relationship['data']['id'] ?? null; $type = $relationship['data']['type'] ?? null; if ( ! $id || ! $type ) { return array(); } return $included_by_type[ $type ][ (int) $id ] ?? array(); } /** * Wrapper for wp_doing_ajax() so the AJAX guard can be overridden in unit tests. * * @return bool */ protected function is_ajax_request(): bool { return wp_doing_ajax(); } /** * Redirects the current request to the Hosted System Customer Login page. * Extracted to a protected wrapper (Prodigy_Url_Helper::login_redirect() calls * wp_redirect() + exit()) so it can be overridden in unit tests. * * @return void */ protected function redirect_to_hosted_system_login(): void { Prodigy_Url_Helper::login_redirect( self::get_hosted_system_login_url() ); } /** * * @return void * @throws \Exception */ public function delete_user_cookie(): void { if ( Prodigy_Cookies::has_cookie( self::USER_ID_COOKIE_NAME ) ) { Prodigy_Cookies::remove_cookie( self::USER_ID_COOKIE_NAME ); } } /** * @param string $refresh_key * * @return true|void */ public function remove_impersonation_user( string $refresh_key ) { $impersonation_cookie = Prodigy_Cookies::has_cookie( self::IMPERSONATION_COOKIE_ID ); if ( ! empty( $refresh_key ) ) { if ( $impersonation_cookie ) { $impersonation_id = Prodigy_Cookies::get_cookie( self::IMPERSONATION_COOKIE_ID ); if ( isset( $impersonation_id ) ) { $response = Prodigy_Request_Maker::get_instance() ->do_delete_impersonation_user( $refresh_key, $impersonation_id ); if ( $response['code'] === \WP_Http::NO_CONTENT ) { Prodigy_Cookies::remove_cookie( self::IMPERSONATION_COOKIE_ID ); Prodigy_Cookies::remove_cookie( Prodigy_Cart::CART_COOKIE_NAME ); } if ( PRODIGY_DEBUG_MODE && isset( $response['errors'][0]['details'] ) ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'Failed removing impersonation user! Impersonation id ' . $impersonation_id . ' Response code ' . $response['errors'][0]['details'] . ' Refresh key ' . $refresh_key ); } } return true; } } } /** * @param string $refresh_key * * @return bool */ public function hosted_system_logout_process( string $refresh_key ): bool { if ( ! empty( $refresh_key ) ) { $response = Prodigy_Request_Maker::get_instance()->do_user_logout( $refresh_key ); if ( $response['code'] === \WP_Http::NO_CONTENT ) { if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'store successfully logout with token ' . $refresh_key . ' Response code ' . $response['code'] ); } return true; } } if ( PRODIGY_DEBUG_MODE ) { $error_code = isset( $response ) ? $response['code'] : 'unknown'; Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, 'store unsuccessfully logout error code' . $error_code ); } return false; } /** * @return void * @throws \Exception */ public function logout(): void { Prodigy_Cookies::remove_cookie( self::AUTHORIZATION_COOKIE_NAME ); Prodigy_Cookies::remove_cookie( self::ACCESS_COOKIE_NAME ); Prodigy_Cookies::remove_cookie( self::USER_INFO_COOKIE_EMAIL ); Prodigy_Cookies::remove_cookie( self::USER_INFO_COOKIE_NAME ); Prodigy_Cookies::remove_cookie( self::USER_INFO_COOKIE_LAST_NAME ); Prodigy_Cookies::remove_cookie( self::REFRESH_COOKIE_NAME ); Prodigy_Cookies::remove_cookie( self::IMPERSONATION_COOKIE_ID ); Prodigy_Cookies::remove_cookie( self::USER_GROUP_COOKIE_NAME ); Prodigy_Cookies::remove_cookie( self::PRODIGY_USER_PAIRED_SESSION_COOKIE_NAME ); Prodigy_Cookies::remove_cookie( self::SESSION_EXPIRES_COOKIE_NAME ); $current_domain = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : wp_parse_url( home_url(), PHP_URL_HOST ); if ( ! empty( $current_domain ) ) { $cookie_domain = ltrim( strtok( $current_domain, ':' ), '.' ); Prodigy_Cookies::remove_cookie( Prodigy_Cart::CART_COOKIE_NAME, '/', $cookie_domain ); } else { Prodigy_Cookies::remove_cookie( Prodigy_Cart::CART_COOKIE_NAME, '/' ); } } /** * Clears punch-out external checkout cookie (call on explicit user logout, not when rotating session_token). * * @return void */ public function clear_external_checkout_cookie(): void { Prodigy_Cookies::remove_cookie( self::EXTERNAL_CHECKOUT_ID_COOKIE_NAME ); } }