* @param $api_key String The API Key. * @return boolean Did we have access ? */ public function verify_key( string $api_key ) { try { $api_key_exists_response = wp_remote_get( AFFILIZZ_USER_API_BASE_URL . 'users/me', array( 'headers' => array( 'ApiKey' => $api_key, ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); return ! is_wp_error( $api_key_exists_response ); } catch ( Exception $e ) { return false; } } /** * Returns the list of available country codes for the API. * @author Affilizz * @return Array A list of available country codes. */ public static function get_api_country_codes() { return (array) apply_filters( 'affilizz_api_country_codes', array( 'FR' => __( 'France', 'affilizz' ), 'UK' => __( 'United Kingdom', 'affilizz' ), ) ); } /** * Gets all the organizations to which the user has been granted access. * The available accesses are retrieved from the user/me endpoint, then loop through consecutive calls to the expand endpoint. * @author Affilizz * @param $api_key String The API Key. * @return Array A list of available organizations. */ public function get_entities( string $api_key ) { $organizations = array(); try { // Get the accessible organizations $entities_query_response = wp_remote_get( AFFILIZZ_USER_API_BASE_URL . 'users/me', array( 'headers' => array( 'ApiKey' => $api_key, ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we get an error, bail if ( is_wp_error( $entities_query_response ) ) { do_action( 'affilizz_api_debug_log', '[affilizz] /users/me WP_Error: ' . $entities_query_response->get_error_message() ); return false; } else { do_action( 'affilizz_api_debug_log', sprintf( '[affilizz] /users/me url=%s status=%d body=%s', AFFILIZZ_USER_API_BASE_URL . 'users/me', wp_remote_retrieve_response_code( $entities_query_response ), wp_remote_retrieve_body( $entities_query_response ) ) ); } // Get the entities $contents = wp_remote_retrieve_body( $entities_query_response ); $data = json_decode( $contents ); if ( $data && $data->authorizations ) { foreach ( $data->authorizations as $access ) { $organizations[ $access->organizationId ] = ''; } } } catch ( Exception $e ) { return false; } // Expand the organizations, one by one if ( ! empty( $organizations ) ) { foreach ( $organizations as $id => &$name ) { try { $organizations_query_url = add_query_arg( array( 'organizationId' => $id, ), AFFILIZZ_USER_API_BASE_URL . 'expands' ); $organizations_query_response = wp_remote_get( $organizations_query_url, array( 'headers' => array( 'ApiKey' => $api_key, ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $organizations_query_response ) ) { return; } // Get the entities $contents = wp_remote_retrieve_body( $organizations_query_response ); $data = json_decode( $contents ); $name = $data->name; } catch ( Exception $e ) { } } } return $organizations; } /** * Gets all the medias for the selected organization. * @author Affilizz * @param $api_key String The API Key. * @param $organization The organization from which to get the medias from. * @return Array A list of available medias for the organization. */ public function get_media( $api_key, string $organization ) { $media = array(); try { $organizations_query_url = add_query_arg( array( 'organizationId' => $organization, ), AFFILIZZ_USER_API_BASE_URL . 'expands' ); $organizations_query_response = wp_remote_get( $organizations_query_url, array( 'headers' => array( 'ApiKey' => $api_key, ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $organizations_query_response ) ) { return; } // Get the entities $contents = wp_remote_retrieve_body( $organizations_query_response ); $data = json_decode( $contents ); if ( $data && $data->media ) { foreach ( $data->media as $item ) { $media[ $item->id ] = $item->name; } } } catch ( \Exception $e ) { return false; } return $media; } /** * Gets all the channels for the selected organization and media. * @author Affilizz * @param $organization The organization from which to get the medias from. * @param $media The media from which to get the channels from. * @return Array A list of available channels for the media and the organization. */ public function get_channels( string $organization, string $media = '' ) { $channels = array(); try { $filter = $media ? array( 'mediaId' => $media ) : array( 'organizationId' => $organization ); $media_query_url = add_query_arg( $filter, AFFILIZZ_USER_API_BASE_URL . 'expands' ); $media_query_response = wp_remote_get( $media_query_url, array( 'headers' => array( 'ApiKey' => get_option( 'affilizz_api_key' ), ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $media_query_response ) ) { return; } // Get the entities $contents = wp_remote_retrieve_body( $media_query_response ); $data = json_decode( $contents ); if ( $data && $data->media ) { foreach ( $data->media as $m ) { foreach ( $m->channels as $channel ) { $channels[ $channel->id ] = $channel->name; } } } } catch ( Exception $e ) { return false; } return $channels; } /** * Gets a list of the available publications for the current configuration. * @author Affilizz * @param $force_refresh Boolean Should we force a refresh of the publications ? * @return Array A list of available publications. */ public function get_publications( $force_refresh = false, $search = '' ) { $publications = array(); try { if ( ! $force_refresh && $search == '' ) { $publications = get_transient( \Affilizz\Core::get_publications_transient_key() ); if ( ! empty( $publications ) ) { return $publications; } } $publications_query_url = add_query_arg( array( 'organizationId' => get_option( 'affilizz_organization' ), 'mediaId' => get_option( 'affilizz_media' ), 'sort' => 'UpdatedAt,desc', 'time' => time(), ), AFFILIZZ_CMS_API_BASE_URL . 'publications' ); // Allow search if we have a search term if ( ! empty( $search ) ) { $publications_query_url = add_query_arg( array( 'query' => $search, ), $publications_query_url ); } $publications_query_response = wp_remote_get( $publications_query_url, array( 'headers' => array( 'ApiKey' => get_option( 'affilizz_api_key' ), ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $publications_query_response ) ) { return; } // Get the entities $contents = wp_remote_retrieve_body( $publications_query_response ); $api_publications = json_decode( $contents ); $recent_publications = \Affilizz\Util\Publications::recent(); if ( $api_publications ) { foreach ( $api_publications as $publication ) { if ( isset( $publication->name ) ) { $publications[ $publication->id ] = array( 'id' => $publication->id, 'name' => esc_attr( $publication->name ), 'recent' => in_array( $publication->id, $recent_publications ), 'created' => strtotime( $publication->createdAt ), ); } } } $composite_array = array(); // Sort by creation date (created) uasort( $publications, function ( $a, $b ) { return ( $a['created'] == $b['created'] ) ? 0 : ( ( $a['created'] > $b['created'] ) ? -1 : 1 ); } ); $latest_publications = array_slice( $publications, 0, \Affilizz\Core::get_suggested_latest_publications_count(), true ); foreach ( $latest_publications as $publication_id => $publication ) { /* translators: %s: human-readable time difference. */ $publication['tag'] = sprintf( __( 'Created %s ago', 'affilizz' ), human_time_diff( time(), $publication['created'] ) ); $publication['tag-class'] = 'affilizz-tag affilizz-tag--latest'; $composite_array[ $publication_id ] = $publication; } // Remove the latest publications from the main array if ( ! empty( $composite_array ) ) { $publications = array_slice( $publications, count( $latest_publications ), null, true ); } // Sort the rest of the publications by recent or not uasort( $publications, function ( $a, $b ) { return ( $a['recent'] == $b['recent'] ) ? 0 : ( $a['recent'] ? -1 : 1 ); } ); foreach ( $publications as $publication_id => $publication ) { $publication['tag'] = ''; $publication['tag-class'] = ''; $composite_array[ $publication_id ] = $publication; } $publications = $composite_array; } catch ( Exception $e ) { return false; } if ( ! $force_refresh && $search == '' ) { set_transient( \Affilizz\Core::get_publications_transient_key(), $publications, 15 * MINUTE_IN_SECONDS ); } return $publications; } /** * Retrieves an affiliate content based on its publication_id and its channel_id. * @author Affilizz * @param $publication_id The publication ID for this publication. * @param $channel_id The channel ID for this publication. * @return Object A qualified publication. */ public function get_publication( string $publication_id, string $channel_id ) { try { // If stored locally return it if ( ! empty( self::$retrieved_publications[ $publication_id ] ) ) { return self::$retrieved_publications[ $publication_id ]; } // If stored in a transient, use it except if we are in admin and want to update it if ( ! is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) { $transient_publication = get_transient( 'affilizz_publication_' . $publication_id ); if ( ! empty( $transient_publication ) ) { return $transient_publication; } } $publication_query_url = add_query_arg( array( 'channelId' => $channel_id, ), AFFILIZZ_CMS_API_BASE_URL . 'publications/' . $publication_id ); $publication_query_response = wp_remote_get( $publication_query_url, array( 'headers' => array( 'ApiKey' => get_option( 'affilizz_api_key' ), 'WPPluginVersion' => AFFILIZZ_VERSION, ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $publication_query_response ) ) { return; } // Bail if we do not have the channel anymore if ( ! empty( $publication_query_response['status'] ) && $publication_query_response['status'] == 'NOT_FOUND' ) { /* translators: %s: API error message. */ throw new \Affilizz\Exception\Missing\Channel( sprintf( __( 'Error : %s', 'affilizz' ), $publication_query_response['message'] ) ); } $contents = wp_remote_retrieve_body( $publication_query_response ); $publication_metadata = json_decode( $contents ); // Store locally self::$retrieved_publications[ $publication_id ] = $publication_metadata; // Store in a transient set_transient( 'affilizz_publication_' . $publication_id, $publication_metadata, \Affilizz\Core::get_api_check_cycle_duration() ); return $publication_metadata; } catch ( \Affilizz\Exception\Missing\Channel $e ) { return array( 'error' => true, 'message' => $e->getMessage(), ); } catch ( Exception $e ) { return false; } } /** * Retrieves a list of offers on the remote public API by passing keyword. * @param $url The URL to find offers for. * @author Affilizz */ public function find_offers_by_keyword( string $keyword, int $min_price = 0, int $max_price = 0 ) { try { $offers_search = AFFILIZZ_CMS_API_BASE_URL . 'search'; $request_body = array( 'mediaId' => get_option( 'affilizz_media' ), 'countryCode' => get_option( 'get_api_country_codes', \Affilizz\Core::get_api_country_code() ), 'keyword' => $keyword, ); if ( ! empty( $min_price ) ) { $request_body['minPrice'] = $min_price; } if ( ! empty( $min_price ) ) { $request_body['maxPrice'] = $max_price; } $request_headers = array( 'apikey' => get_option( 'affilizz_api_key' ), 'Content-Type' => 'application/json', ); $offers_response = wp_remote_post( $offers_search, array( 'body' => json_encode( $request_body ), 'headers' => $request_headers, 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $offers_response ) ) { return; } // Bail if we do not have the channel anymore if ( ! empty( $offers_response['status'] ) && $offers_response['status'] == 'NOT_FOUND' ) { /* translators: %s: API error message. */ throw new \Affilizz\Exception\Missing\Channel( sprintf( __( 'Error : %s', 'affilizz' ), $offers_response['message'] ) ); } $contents = wp_remote_retrieve_body( $offers_response ); $publication_metadata = json_decode( $contents ); return $publication_metadata; } catch ( \Affilizz\Exception\Missing\Channel $e ) { return array( 'error' => true, 'message' => $e->getMessage(), ); } catch ( Exception $e ) { return false; } } /** * Retrieves a list of offers on the remote public API by passing keyword. * @param $product_id The product ID to find offers for. * @author Affilizz */ public function find_offers_by_product( string $product_id ) { try { $offers_search_url = add_query_arg( array( 'mediaId' => get_option( 'affilizz_media' ), 'deleted' => 'false', 'productLocalizedIds' => $product_id, ), AFFILIZZ_CMS_API_BASE_URL . 'offers' ); $offers_response = wp_remote_get( $offers_search_url, array( 'headers' => array( 'apikey' => get_option( 'affilizz_api_key' ) ), 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $offers_response ) ) { return; } // Bail if we do not have the channel anymore if ( ! empty( $offers_response['status'] ) && $offers_response['status'] == 'NOT_FOUND' ) { /* translators: %s: API error message. */ throw new \Affilizz\Exception\Missing\Channel( sprintf( __( 'Error : %s', 'affilizz' ), $offers_response['message'] ) ); } $contents = wp_remote_retrieve_body( $offers_response ); $data = json_decode( $contents ); return $data; } catch ( \Affilizz\Exception\Missing\Channel $e ) { return array( 'error' => true, 'message' => $e->getMessage(), ); } catch ( Exception $e ) { return false; } } /** * Retrieve metadata on the remote public API by passing an URL. * @param $url The URL to find offers for. * @author Affilizz */ public function detect( $url ) { try { $detect_url = AFFILIZZ_CMS_API_BASE_URL . 'offers/_detect'; $request_body = array( 'mediaId' => get_option( 'affilizz_media' ), 'countryCode' => get_option( 'get_api_country_codes', \Affilizz\Core::get_api_country_code() ), 'url' => $url, ); $request_headers = array( 'apikey' => get_option( 'affilizz_api_key' ), 'Content-Type' => 'application/json', ); $detect_response = wp_remote_post( $detect_url, array( 'body' => json_encode( $request_body ), 'headers' => $request_headers, 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $detect_response ) ) { return; } // Bail if we do not have the channel anymore if ( ! empty( $detect_response['status'] ) && $detect_response['status'] == 'NOT_FOUND' ) { /* translators: %s: API error message. */ throw new \Affilizz\Exception\Missing\Channel( sprintf( __( 'Error : %s', 'affilizz' ), $detect_response['message'] ) ); } $contents = wp_remote_retrieve_body( $detect_response ); $publication_metadata = json_decode( $contents ) ?? array(); return $publication_metadata; } catch ( \Affilizz\Exception\Missing\Channel $e ) { return array( 'error' => true, 'message' => $e->getMessage(), ); } catch ( Exception $e ) { return false; } } /** * Create an offer * @author Affilizz * @param string $type link|button|table|card|custom * @param array $request Form data * @return string Offer ID */ public function create_offer( string $type, array $request ) { try { if ( ! in_array( $type, $this->get_allowed_types() ) ) { throw new Exception( sprintf( 'Type "%s" is invalid for creating an offer.', $type ) ); } $offer_id = $request['offer-id'] ?? null; $product_id = $request['product-id'] ?? null; $product_localized_id = $request['product-localized-id'] ?? null; $subtype = $request['subtype'] ?? 'single'; $price = $request['price'] ?? ''; $url = AFFILIZZ_CMS_API_BASE_URL . 'publications'; $request_headers = array( 'apikey' => get_option( 'affilizz_api_key' ), 'Content-Type' => 'application/json', ); // Items data $items_data = ( 'single' == $subtype ) ? array( 'urlSource' => $request['merchant-url'], 'userMetadata' => array( 'manualPrice' => array( 'price' => $price, 'shopId' => $request['merchant-id'], 'lock' => 'OFFER_PRICE_CHANGE', ), ), ) : array(); if ( $offer_id && 'single' === $subtype ) { $items_data['offerId'] = $offer_id; } if ( $product_id ) { $items_data['productId'] = $product_id; } if ( $product_localized_id ) { $items_data['productLocalizedIds'] = array( $product_localized_id ); } // Global request data $request_body = array( 'name' => $request['title'] ?? wp_trim_words( $request['product'], 10, '…' ), 'mediaId' => get_option( 'affilizz_media' ), 'organizationId' => get_option( 'affilizz_organization' ), 'contents' => array( array( 'display' => array( 'type' => $this->convert_types( $type ), 'config' => array( 'title' => '', ), ), 'items' => array( $items_data ), ), ), ); // Specific cases if ( in_array( $type, array( 'link', 'button', 'custom' ), true ) ) { $request_body['contents'][0]['display']['config']['title'] = ''; } elseif ( 'table' === $type ) { $request_body['contents'][0]['display']['config'] = array( 'tabs' => array( array( 'name' => $request['label'] ) ), ); } elseif ( 'card' === $type ) { $request_body['contents'][0]['display']['config'] = array( 'description' => $request['card-description'] ?? '', 'tag' => $request['card-tag'] ?? '', 'offerButtonContent' => $request['card-label'] ?? '', 'positivePoints' => $request['card-positive-arguments'] ?? array(), 'negativePoints' => $request['card-negative-arguments'] ?? array(), ); } else { wp_send_json_error( array( /* translators: %s: publication type. */ 'message' => sprintf( __( 'The "%s" publication type is not implemented yet.', 'affilizz' ), $type ), ) ); } $request_body = map_deep( $request_body, 'sanitize_text_field' ); // Send request $response = wp_remote_post( $url, array( 'body' => wp_json_encode( $request_body ), 'headers' => $request_headers, 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $response ) ) { return; } $contents = wp_remote_retrieve_body( $response ); $created_offer = json_decode( $contents ) ?? array(); return $created_offer; } catch ( \Affilizz\Exception\Missing\Channel $e ) { return array( 'error' => true, 'message' => $e->getMessage(), ); } catch ( Exception $e ) { do_action( 'affilizz_api_debug_log', $e->getMessage() ); return false; } } /** * Add contents to an existing offer * * @author Affilizz * * @param string $publication_id Publication ID * @param string $type link|button|table|card|custom * @param array $request Form data * * @return string Offer ID */ public function add_offer_contents( string $publication_id, string $type, array $request ) { try { if ( ! in_array( $type, $this->get_allowed_types() ) ) { throw new Exception( sprintf( 'Type "%s" is invalid for creating an offer.', $type ) ); } $offer_id = $request['offer-id'] ?? null; $product_id = $request['product-id'] ?? null; $product_localized_id = $request['product-localized-id'] ?? null; $subtype = $request['subtype'] ?? 'single'; $price = $request['price'] ?? ''; $url = AFFILIZZ_CMS_API_BASE_URL . 'publications/' . $publication_id . '/publicationContents/_bulk'; $request_headers = array( 'apikey' => get_option( 'affilizz_api_key' ), 'Content-Type' => 'application/json', ); // Items data $items_data = ( 'single' == $subtype ) ? array( 'urlSource' => $request['merchant-url'], 'userMetadata' => array( 'manualPrice' => array( 'price' => $price, 'shopId' => $request['merchant-id'], 'lock' => 'OFFER_PRICE_CHANGE', ), ), ) : array(); if ( $offer_id && 'single' === $subtype ) { $items_data['offerId'] = $offer_id; } if ( $product_id ) { $items_data['productId'] = $product_id; } if ( $product_localized_id ) { $items_data['productLocalizedIds'] = array( $product_localized_id ); } // Global request data $request_body = array( array( 'display' => array( 'type' => $this->convert_types( $type ), 'config' => array( 'title' => '', ), ), 'items' => array( $items_data ), ), ); // Specific cases if ( in_array( $type, array( 'link', 'button', 'custom' ), true ) ) { $request_body[0]['display']['config']['title'] = ''; } elseif ( 'table' === $type ) { $request_body[0]['display']['config'] = array( 'tabs' => array( array( 'name' => $request['label'] ) ), ); } elseif ( 'card' === $type ) { $request_body[0]['display']['config'] = array( 'description' => $request['card-description'] ?? '', 'tag' => $request['card-tag'] ?? '', 'offerButtonContent' => $request['card-label'] ?? '', 'positivePoints' => $request['card-positive-arguments'] ?? array(), 'negativePoints' => $request['card-negative-arguments'] ?? array(), ); } $request_body = map_deep( $request_body, 'sanitize_text_field' ); // Send request $response = wp_remote_post( $url, array( 'body' => wp_json_encode( $request_body ), 'headers' => $request_headers, 'timeout' => \Affilizz\Core::get_api_http_timeout(), ) ); // If we have an error, bail if ( is_wp_error( $response ) ) { return; } $contents = wp_remote_retrieve_body( $response ); $created_offer = json_decode( $contents ) ?? array(); return $created_offer; } catch ( \Affilizz\Exception\Missing\Channel $e ) { return array( 'error' => true, 'message' => $e->getMessage(), ); } catch ( Exception $e ) { do_action( 'affilizz_api_debug_log', $e->getMessage() ); return false; } } /** * Types used in React application are slightly different than * ones used with the API. */ public function convert_types( string $type ): string { $type_matching_table = array( 'button' => 'CTA', 'table' => 'BOX', ); return in_array( $type, array_keys( $type_matching_table ) ) ? $type_matching_table[ $type ] : strtoupper( $type ); } /** * Get allowed types for publication creation or content updating * * @return array allowed types */ private function get_allowed_types(): array { return array( 'link', 'button', 'table', 'card', 'custom' ); } }