cache = new Prodigy_Cache(); $this->api_client = new Prodigy_Api_Client(); $this->access_token = Prodigy_Cookies::get_cookie( Prodigy_User::ACCESS_COOKIE_NAME ); $this->store_key = get_option( Prodigy_Admin_Setup_Wizard::OPTION_STORE_KEY ); } /** * @param array|\WP_Error $query_response * @param string $query_url * * @return array */ private function do_process_response( $query_response, string $query_url ) { $http_code = wp_remote_retrieve_response_code( $query_response ); $body = is_wp_error( $query_response ) ? '' : wp_remote_retrieve_body( $query_response ); $response = ( $body === '' ) ? array() : json_decode( $body, true ); if ( ! is_wp_error( $query_response ) && ( ( $http_code === \WP_Http::NO_CONTENT ) || ( $http_code === \WP_Http::OK ) || ( $http_code === \WP_Http::CREATED ) ) ) { if ( json_last_error() !== JSON_ERROR_NONE ) { // An empty body skips json_decode(), so json_last_error() would be stale there. if ( '' !== $body ) { Prodigy_Prod_Logger::api_invalid_json( $query_url, (int) $http_code, json_last_error_msg() ); } if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, json_last_error_msg(), $query_url, '' ); } $response = array(); } } else { if ( is_wp_error( $query_response ) ) { $error_message = $query_response->get_error_message(); if ( ! empty( $error_message ) ) { $response['error'] = $error_message; } } elseif ( isset( $response['errors'][0]['detail'] ) ) { $response['error'] = $response['errors'][0]['detail']; } elseif ( isset( $query_response['response']['message'] ) ) { $response['error'] = $query_response['response']['message']; } else { $response['error'] = 'Unexpected response format.'; } if ( isset( $response['errors'][0]['detail'] ) && PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, $response['errors'][0]['detail'], $query_url ); } } if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'RESPONSE: ', $query_url, $body ); } $response['code'] = $http_code ?: \WP_Http::INTERNAL_SERVER_ERROR; return $response; } /** * @param int $product_id * @param int $rating * * @return array */ public function do_update_product_rating_request( int $product_id, int $rating ): array { $rating_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::SEND_RATING_URL; $url = str_replace( ':product_id', $product_id, $rating_url ); $params = array( 'rating' => $rating ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url, wp_json_encode( $params ) ); } $response = $this->api_client->put_remote_content( $url, $params ); return $this->do_process_response( $response, $url ); } /** * @param string $user_auth_hash * * @return array */ public function do_user_info_request( string $user_auth_hash ): array { if ( ! empty( $this->user_info ) ) { return $this->user_info; } $user_info = $this->cache->get_user_info( $user_auth_hash ); if ( ! $user_info || empty( $user_info['data'] ) ) { $includes = 'default-shipping-address,default-shipping-address.country,customer-extra-fields'; $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_CUSTOMER_MAIN_INFO_URL; $request_url = add_query_arg( array( 'include' => $includes ), $url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url ); } $response = $this->api_client->get_remote_content( $request_url ); $user_info = $this->do_process_response( $response, $url ); if ( ! empty( $user_info ) ) { $this->cache->set_user_info( $user_info, $user_auth_hash ); $this->user_info = $user_info; } } else { $this->user_info = $user_info; } return $this->user_info; } /** * @param string $refresh_key * * @return array */ public function do_user_logout( string $refresh_key ): array { $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_LOGOUT_URL; $headers = array( 'X-Refresh-Token' => $refresh_key ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url, wp_json_encode( $headers ) ); } $response = $this->api_client->delete_remote_content( $url, $headers ); return $this->do_process_response( $response, $url ); } /** * @param string $refresh_key * @param int $impersonation_id * * @return array */ public function do_delete_impersonation_user( string $refresh_key, int $impersonation_id ): array { $request_url = sprintf( '%s%s%s/%d', Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, Prodigy_Api_Client::HS_USER_IMPERSONATION_URL, $impersonation_id ); $headers = array( 'X-Refresh-Token' => $refresh_key ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url, wp_json_encode( $headers ) ); } $response = $this->api_client->delete_remote_content( $request_url, $headers ); return $this->do_process_response( $response, $request_url ); } /** * @param string $process_url * * @return array */ public function do_sync_process_request( string $process_url ): array { $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $process_url; $params = array( 'with_existed_entities' => true, ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url, wp_json_encode( $params ) ); } $response = $this->api_client->post_remote_content( $url, $params ); return $this->do_process_response( $response, $url ); } /** * @param array $params * * @return array */ public function do_admin_products_properties_request( array $params ): array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::PRODUCTS_PROPERTIES_ADMIN_URL; $request_url = add_query_arg( $params, $api_url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $response_attributes = $this->api_client->get_remote_content( $request_url ); return $this->do_process_response( $response_attributes, $request_url ); } /** * @param string $query * * @return array */ public function do_catalog_filters_request( string $query = '' ): array { $cache_key = md5( $query ); if ( isset( $this->catalog_filter_result[ $cache_key ] ) ) { return $this->catalog_filter_result[ $cache_key ]; } $cached_filters = $this->cache->get_catalog_filters( $query ); if ( isset( $cached_filters ) && ! empty( $cached_filters['data'] ) ) { $this->catalog_filter_result[ $cache_key ] = $cached_filters; return $this->catalog_filter_result[ $cache_key ]; } $relations_query = 'categories.children,categories.parent,tags,properties.options'; $enhanced_query = '?include=' . $relations_query . '&' . $query; $filter_result = $this->cache->get_catalog_filters( $enhanced_query ); if ( ! $filter_result ) { $catalog_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::CATALOG_URL . $enhanced_query; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $catalog_url ); } $response = $this->api_client->get_remote_content( $catalog_url ); $filter_result = $this->do_process_response( $response, $catalog_url ); if ( isset( $filter_result ) && ! empty( $filter_result['data'] ) ) { $this->cache->set_catalog_filters( $filter_result, $enhanced_query ); } } $this->catalog_filter_result[ $cache_key ] = $filter_result; return $this->catalog_filter_result[ $cache_key ]; } /** * @param string $query * * @return array */ public function do_admin_catalog_filters_request( string $query = '' ): array { $catalog_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::CATALOG_ADMIN_URL . '?' . $query; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $catalog_url ); } $response = $this->api_client->get_remote_content( $catalog_url ); return $this->do_process_response( $response, $catalog_url ); } /** * @param int|null $id_remote_product * @param array $params * @param string|null $includes * @param bool $redirect_on_not_found Redirect to the 404 page when the product is missing. * * @return array */ public function do_product_request( ?int $id_remote_product = null, array $params = array(), ?string $includes = null, bool $redirect_on_not_found = true ): array { $is_frontend = Prodigy_Page::prodigy_is_frontend(); if ( $this->product_result !== null && $this->last_product_id === $id_remote_product && $this->last_product_is_frontend === $is_frontend ) { if ( $this->last_product_not_found && $redirect_on_not_found ) { Prodigy_Url_Helper::redirect_to_404(); } return $this->product_result; } if ( $id_remote_product === null ) { return array(); } $url = $is_frontend ? Prodigy_Api_Client::PRODUCTS_URL : Prodigy_Api_Client::PRODUCTS_ADMIN_URL; $product_url = sprintf( '%s%s%s/%d', Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, $url, $id_remote_product ); $cache_key = $id_remote_product; if ( ! empty( $params ) ) { $product_url = add_query_arg( $params, $product_url ); $cache_key = $id_remote_product . '_' . md5( http_build_query( $params ) ); } $product_result = $this->cache->get_product( $cache_key ); if ( ! $product_result ) { $includes = $includes ?? $this->get_default_product_includes(); $params = array( 'include' => $includes ); if ( ! $is_frontend ) { $params['admin'] = true; } $request_url = add_query_arg( $params, $product_url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $product_obj_response = $this->api_client->get_remote_content( $request_url ); $http_code = wp_remote_retrieve_response_code( $product_obj_response ); $is_not_found = $http_code === \WP_Http::NOT_FOUND; if ( $is_not_found && $redirect_on_not_found ) { Prodigy_Url_Helper::redirect_to_404(); } $product_result = $this->do_process_response( $product_obj_response, $request_url ); // Admin-shaped responses (e.g. Elementor editor/preview requests) are missing // data the storefront needs (variant images, attribute options). Never persist // them under the shared product cache key - only frontend-shaped responses are cached. if ( $is_frontend && ! empty( $product_result ) && empty( $product_result['error'] ) ) { $this->cache->set_product( $cache_key, $product_result ); } $this->last_product_id = $id_remote_product; $this->product_result = $product_result; $this->last_product_not_found = $is_not_found; $this->last_product_is_frontend = $is_frontend; } return $product_result; } /** * @return string */ private function get_default_product_includes(): string { return implode( ',', array( 'tags', 'categories', 'tax-information', 'master-variant.dimension', 'master-variant.inventory', 'variants.dimension', 'variants.inventory', 'cross-sell-products', 'up-sell-products', 'descriptive-attributes.options.images', 'variant-attributes.options.images', 'images', 'master-variant.subscription-plan.subscription-conditions', 'variants.subscription-plan.subscription-conditions', 'quantity-price-breaks', 'logos', 'logo-locations', 'logo-options', 'personalization.personalization-fields', 'multiple-logo-charge-settings', ) ); } /** * @param string $query * @param string $includes * * @return array */ public function do_products_request( string $query, string $includes = '' ): array { $hash = md5( $query ); if ( ! isset( $this->products_result[ $hash ] ) ) { $products = $this->cache->get_products_shortcode( $query ); if ( ! empty( $products ) && ! empty( $products['data'] ) ) { $this->products_result[ $hash ] = $products; } else { $includes = $this->get_default_product_includes(); $request_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::PRODUCTS_URL . '?' . $query . '&include=' . $includes; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $product_response = $this->api_client->get_remote_content( $request_url ); if ( ! is_wp_error( $product_response ) ) { $this->products_result[ $hash ] = $this->do_process_response( $product_response, $request_url ); if ( isset( $this->products_result[ $hash ]['data'] ) && ! empty( $this->products_result[ $hash ]['data'] ) ) { $this->cache->set_products_shortcode( $this->products_result[ $hash ], $query ); } } } } return $this->products_result[ $hash ] ?? array(); } /** * @param string $query * * @return array */ public function do_admin_products_request( string $query = '' ): array { $includes = $this->get_default_product_includes(); $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::PRODUCTS_ADMIN_URL . '?' . $query . '&include=' . $includes; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url ); } $product_response = $this->api_client->get_remote_content( $api_url ); return $this->do_process_response( $product_response, $api_url ); } /** * @param string $query * @param string $key * * @return array */ public function do_related_products_request( string $query, string $key ): array { if ( isset( $this->related_products[ $key ] ) ) { return $this->related_products[ $key ]; } $is_frontend = Prodigy_Page::prodigy_is_frontend(); $related_products_result = $this->cache->get_related_product( $key ); if ( ! $related_products_result ) { $url = $is_frontend ? Prodigy_Api_Client::RELATED_PRODUCTS_URL : Prodigy_Api_Client::RELATED_PRODUCTS_ADMIN_URL; $includes = $this->get_default_product_includes(); $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $url . '?' . $query . '&include=' . $includes; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url ); } $product_obj_remote = $this->api_client->get_remote_content( $api_url ); $related_products_result = $this->do_process_response( $product_obj_remote, $api_url ); // Only cache frontend-shaped responses under the shared cache key (see do_product_request()). if ( $is_frontend && ! empty( $related_products_result ) ) { $this->cache->set_related_product( $key, $related_products_result ); } } $this->related_products[ $key ] = $related_products_result; return $this->related_products[ $key ]; } /** * @param string $order_token * * @return mixed */ public function do_order_request( string $order_token ): array { if ( empty( $order_token ) ) { return array(); } $order_url = Prodigy_Page::prodigy_is_frontend() ? Prodigy_Api_Client::ORDER_URL : Prodigy_Api_Client::ORDER_ADMIN_URL; $api_url = sprintf( '%s%s%s/%s', Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, $order_url, $order_token ); $request_url = add_query_arg( array( 'include' => 'line-items.subscription-condition,cross-sell-products,up-sell-products,cross-sell-products.logo-options.logo,cross-sell-products.logo-options.logo-location,up-sell-products.logo-options.logo,up-sell-products.logo-options.logo-location,line-items.logo-options.logo,line-items.logo-options.logo-location,line-items.personalization-fields', ), $api_url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $response = $this->api_client->get_remote_content( $request_url ); return $this->do_process_response( $response, $request_url ); } /** * @param string $order_token * * @return void */ public function invalidate_order_cache( string $order_token ): void { $this->order_result = null; $this->cache->delete_order( $order_token ); } /** * @param string $order_token * @param string $external_checkout_id * * @return array * @throws \Exception */ public function do_external_checkout_request( string $order_token, string $external_checkout_id ): ?array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::ORDER_URL . $order_token . '/external_checkouts'; $params = array( 'external_checkout_id' => $external_checkout_id, ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $params ) ); } $response = $this->api_client->post_remote_content( $api_url, $params ); if ( is_wp_error( $response ) || $response instanceof \WP_Error ) { $this->external_checkout_result = array( 'code' => \WP_Http::INTERNAL_SERVER_ERROR, 'error' => $response->get_error_message(), ); return $this->external_checkout_result; } $this->external_checkout_result = $this->do_process_response( $response, $api_url ); $http_code = wp_remote_retrieve_response_code( $response ); if ( $http_code === \WP_Http::OK ) { ( new Prodigy_User() )->logout(); } if ( empty( $this->external_checkout_result['error'] ) ) { $attributes = $this->external_checkout_result ?? array(); $external_cxml = $this->external_checkout_result['cxml'] ?? $attributes['cxml'] ?? $attributes['cXML'] ?? null; $external_url = $this->external_checkout_result['url'] ?? $attributes['url'] ?? null; if ( is_string( $external_cxml ) && $external_cxml !== '' && is_string( $external_url ) && $external_url !== '' ) { $xml_payload_result = $this->prepare_external_checkout_xml_payload( $api_url, $order_token, $external_checkout_id, $external_url, $external_cxml ); if ( ! empty( $xml_payload_result['error'] ) ) { $this->external_checkout_result['code'] = \WP_Http::INTERNAL_SERVER_ERROR; $this->external_checkout_result['error'] = $xml_payload_result['error']; return $this->external_checkout_result; } $this->external_checkout_result['checkout_url'] = $xml_payload_result['checkout_url']; } elseif ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, 'External checkout response missing cXML or BrowserFormPost URL', $api_url, wp_json_encode( array( 'external_checkout_id' => $external_checkout_id, 'order_token' => $order_token, 'attributes_keys' => is_array( $attributes ) ? array_keys( $attributes ) : array(), ) ) ); } } return $this->external_checkout_result; } /** * Prepare and store XML payload for external checkout return. * * @param string $api_url * @param string $order_token * @param string $external_checkout_id * @param string $external_url * @param string $external_cxml * * @return array */ private function prepare_external_checkout_xml_payload( string $api_url, string $order_token, string $external_checkout_id, string $external_url, string $external_cxml ): array { $return_key = md5( $order_token . '|' . $external_checkout_id . '|' . $external_url . '|' . $external_cxml ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'External checkout payload prepared', $api_url, wp_json_encode( array( 'external_checkout_id' => $external_checkout_id, 'order_token' => $order_token, 'browser_form_post' => $external_url, 'payload_type' => 'cxml-base64', 'return_key' => $return_key, ) ) ); } $cxml_encoded = base64_encode( $external_cxml ); $field_name = 'cxml-base64'; $transient_name = 'prodigy_punchout_return_' . $return_key; $ttl_seconds = 5 * 60; $stored = set_transient( $transient_name, array( 'browser_form_post_url' => $external_url, 'field_name' => $field_name, 'payload' => $cxml_encoded, ), $ttl_seconds ); if ( $stored === false ) { if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, 'External checkout transient save failed', $api_url, wp_json_encode( array( 'transient_name' => $transient_name, 'external_checkout_id' => $external_checkout_id, 'order_token' => $order_token, ) ) ); } return array( 'error' => 'Unable to prepare PunchOut return payload.' ); } $nonce = wp_create_nonce( 'prodigy-punchout-return' ); $checkout_url = home_url( '/punchout-return/?return_key=' . rawurlencode( $return_key ) . '&_wpnonce=' . rawurlencode( (string) $nonce ) ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'External checkout return URL generated', $api_url, wp_json_encode( array( 'checkout_url' => $checkout_url, 'external_checkout_id' => $external_checkout_id, 'order_token' => $order_token, ) ) ); } return array( 'checkout_url' => $checkout_url ); } /** * @param array $request * @param bool $is_retry_after_external_checkout_clear Internal: avoid infinite retry. * * @return array */ public function do_init_order_request( array $request, bool $is_retry_after_external_checkout_clear = false ): array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::CART_URL; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $request ) ); } $init_order_result = $this->api_client->patch_remote_content( $api_url, $request ); return $this->do_process_response( $init_order_result, $api_url ); } /** * @param string $content_url * @param string $query * * @return array */ public function do_get_sync_type_content_request( string $content_url, string $query = '' ): array { $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $content_url . $query; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url ); } $response = $this->api_client->get_remote_content( $url ); return $this->do_process_response( $response, $url ); } /** * @param string|null $includes * * @return array */ public function do_settings_request( ?string $includes = null, bool $force_fresh = false ): array { if ( ! $force_fresh && ! empty( $this->settings_result ) ) { return $this->settings_result; } $settings_result = $force_fresh ? null : $this->cache->get_settings(); if ( ! $settings_result || empty( $settings_result['data'] ) ) { $request_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_SETTINGS_URL; if ( $includes ) { $request_url = add_query_arg( array( 'include' => $includes ), $request_url ); } if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $response = $this->api_client->get_remote_content( $request_url ); $settings_result = $this->do_process_response( $response, $request_url ); if ( ! empty( $settings_result ) ) { // Forced requests fetch a partial include set; caching or memoising them would hide apps from later readers. if ( $force_fresh ) { return $settings_result; } $this->cache->set_settings( $settings_result ); $this->settings_result = $settings_result; if ( null === $includes ) { ( new Prodigy_Settings_Parser() )->set_platform_settings( $settings_result ); } } } else { $this->settings_result = $settings_result; } return $this->settings_result; } /** * @param array $query * * @return array */ public function do_categories_request( array $query = array() ): array { $hash = md5( wp_json_encode( $query ) ); if ( ! isset( $this->categories_result[ $hash ] ) ) { $this->categories_result[ $hash ] = $this->cache->get_categories_shortcode( $hash ); if ( ! $this->categories_result[ $hash ] ) { $is_frontend = Prodigy_Page::prodigy_is_frontend(); $api_url = $is_frontend ? Prodigy_Api_Client::CATEGORY_URL : Prodigy_Api_Client::CATEGORY_ADMIN_URL; $query_string = http_build_query( $query ); $query = urldecode( preg_replace( '/%5B(?:[0-9]|[1-9][0-9]+)%5D/', '[]', $query_string ) ); $request_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $api_url . '?' . $query . '&include=parent,children'; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $category_response = $this->api_client->get_remote_content( $request_url ); $this->categories_result[ $hash ] = $this->do_process_response( $category_response, $api_url ); // Only cache frontend-shaped responses under the shared key — an admin-context // response (Elementor editor/preview/ajax) must not poison what the storefront reads. if ( $is_frontend && ! empty( $this->categories_result[ $hash ] ) ) { $this->cache->set_categories_shortcode( $this->categories_result[ $hash ], $hash ); } } } return $this->categories_result[ $hash ]; } /** * @return array */ public function do_get_platform_info(): array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url ); } $response = $this->api_client->get_remote_content( $api_url ); return $this->do_process_response( $response, $api_url ); } /** * @param array $params * * @return array */ public function do_update_plugin_info( array $params ): array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $params ) ); } $response = $this->api_client->put_remote_content( $api_url, $params ); return $this->do_process_response( $response, $api_url ); } /** * @param array $params * * @return array */ public function do_connect_request( array $params ) { if ( $this->connection_result !== null ) { return $this->connection_result; } $connection_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $connection_url, wp_json_encode( $params ) ); } $response_connection = $this->api_client->post_remote_content( $connection_url, $params ); $this->connection_result = $this->do_process_response( $response_connection, $connection_url ); return $this->connection_result; } /** * @return array */ public function do_disconnect_store_request(): array { if ( $this->disconnection_result !== null ) { return $this->disconnection_result; } $connection_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $connection_url ); } $request_disconnection = $this->api_client->delete_remote_content( $connection_url ); $this->disconnection_result = $this->do_process_response( $request_disconnection, $connection_url ); return $this->disconnection_result; } /** * @param string $paired_token * * @return array */ public function do_user_request( $paired_token = '' ): array { $paired_token = (string) ( $paired_token ?? '' ); if ( $this->user_result !== null ) { return $this->user_result; } $includes = 'default-shipping-address,default-shipping-address.country,customer-extra-fields'; $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::USER_SESSION_TOKEN_URL . '/' . $paired_token; $request_url = add_query_arg( array( 'include' => $includes ), $url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url ); } $response = $this->api_client->get_remote_content( $request_url ); $this->user_result = $this->do_process_response( $response, $url ); return $this->user_result; } /** * * @param string $includes * * @return array */ public function do_brands_request( string $includes ): array { if ( $this->brands_result !== null ) { return $this->brands_result; } $brands_results = $this->cache->get_brands_shortcode(); if ( ! $brands_results ) { $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_BRANDS_URL; $params = array( 'include' => $includes ); $request_url = add_query_arg( $params, $url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url ); } $response = $this->api_client->get_remote_content( $request_url ); $brands_results = $this->do_process_response( $response, $request_url ); if ( ! empty( $brands_results ) ) { $this->cache->set_brands_shortcode( $brands_results ); } $this->brands_result = $brands_results; } else { $this->brands_result = $brands_results; } return $brands_results; } /** * @param string $id_remote_product * * @return array */ public function do_brands_list_request( string $id_remote_product ): array { if ( $this->brands_list_result !== null ) { return $this->brands_list_result; } $is_frontend = Prodigy_Page::prodigy_is_frontend(); $brands_results = $this->cache->get_brands_list( (int) $id_remote_product ); if ( ! $brands_results ) { $url = $is_frontend ? Prodigy_Api_Client::PRODUCTS_URL : Prodigy_Api_Client::PRODUCTS_ADMIN_URL; $product_url = sprintf( Prodigy_Api_Client::PRODUCT_BRANDS_PREFIX, Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, $url, $id_remote_product ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $product_url ); } $response = $this->api_client->get_remote_content( $product_url ); $brands_results = $this->do_process_response( $response, $product_url ); // Only cache frontend-shaped responses under the shared cache key (see do_product_request()). if ( $is_frontend && ! empty( $brands_results ) ) { $this->cache->set_brands_list( $brands_results, (int) $id_remote_product ); } $this->brands_list_result = $brands_results; } else { $this->brands_list_result = $brands_results; } return $brands_results; } /** * @param string $order_token * * @return array */ public function do_order_data_request( string $order_token ): array { if ( $this->order_data_result !== null ) { return $this->order_data_result; } $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::ORDER_URL . $order_token . '?include=line-items'; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url ); } $order_response = $this->api_client->get_remote_content( $api_url ); $this->order_data_result = $this->do_process_response( $order_response, $api_url ); return $this->order_data_result; } /** * @param int $line_item_id * @param array $line_item_request * * @return array */ public function do_update_line_items_request( int $line_item_id, array $line_item_request ): array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::LINE_ITEM_URL . $line_item_id; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $line_item_request ) ); } $line_item_response = $this->api_client->patch_remote_content( $api_url, $line_item_request ); return $this->do_process_response( $line_item_response, $api_url ); } /** * @param int $line_item_id * @param string $order_token * * @return array */ public function do_delete_line_item_request( int $line_item_id, string $order_token ): array { $base_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::LINE_ITEM_URL . $line_item_id; $api_url = add_query_arg( array( 'order_token' => $order_token ), $base_url ); if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url ); } $result = $this->api_client->delete_remote_content( $api_url ); $this->invalidate_order_cache( $order_token ); return $this->do_process_response( $result, $api_url ); } /** * @param string $order_token * * @return array */ public function do_delete_order_request( string $order_token ): array { $api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::ORDER_URL . $order_token; if ( PRODIGY_DEBUG_MODE ) { Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url ); } $response = $this->api_client->delete_remote_content( $api_url ); return $this->do_process_response( $response, $api_url ); } /** * @param int|null $order_id * * @return array */ public function do_redemption_rules_request( ?int $order_id = null ): array { if ( ! Prodigy_Cookies::has_cookie( Prodigy_User::USER_ID_COOKIE_NAME ) ) { return array(); } if ( $order_id === null ) { $user_session = Prodigy_Cookies::get_user_cart_cookie(); $order = ! empty( $user_session ) ? Prodigy_Order::get_last_guest_active_order_data( $user_session ) : null; if ( empty( $order ) && Prodigy_User::is_logged_in() ) { $user_id = Prodigy_User::get_user_session(); if ( $user_id !== null ) { $order = Prodigy_Order::get_last_user_active_order_data( $user_id ); } } if ( ! empty( $order['order_number'] ) ) { $order_id = (int) $order['order_number']; } } $cache_key = $order_id ?? 0; if ( isset( $this->redemption_rules_result[ $cache_key ] ) ) { return $this->redemption_rules_result[ $cache_key ]; } $url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_REDEMPTION_RULES_URL; $params = array( 'include' => 'redemption-code-categories.categories.ancestors' ); if ( $order_id !== null ) { $params['order_id'] = $order_id; } $url = add_query_arg( $params, $url ); $response = $this->api_client->get_remote_content( $url ); $this->redemption_rules_result[ $cache_key ] = $this->do_process_response( $response, $url ); return $this->redemption_rules_result[ $cache_key ]; } /** * Extracts and returns a list of error details from a remote response. * * @param mixed $response_remote */ public function get_list_errors( $response_remote ): array { $message_error = json_decode( wp_remote_retrieve_body( $response_remote ), false ); if ( isset( $message_error->errors ) && is_array( $message_error->errors ) ) { return array_column( $message_error->errors, 'detail' ); } return array(); } }