diff --git a/plugins/woocommerce-admin/client/marketplace/components/discover/discover.tsx b/plugins/woocommerce-admin/client/marketplace/components/discover/discover.tsx
index b16ecb68098..52842d3625f 100644
--- a/plugins/woocommerce-admin/client/marketplace/components/discover/discover.tsx
+++ b/plugins/woocommerce-admin/client/marketplace/components/discover/discover.tsx
@@ -8,21 +8,29 @@ import { useEffect, useState } from '@wordpress/element';
*/
import ProductList from '../product-list/product-list';
import { fetchDiscoverPageData, ProductGroup } from '../../utils/functions';
+import ProductLoader from '../product-loader/product-loader';
import './discover.scss';
export default function Discover(): JSX.Element | null {
const [ productGroups, setProductGroups ] = useState<
Array< ProductGroup >
>( [] );
+ const [ isLoading, setIsLoading ] = useState( false );
useEffect( () => {
- fetchDiscoverPageData().then( ( products: Array< ProductGroup > ) => {
- setProductGroups( products );
- } );
+ setIsLoading( true );
+
+ fetchDiscoverPageData()
+ .then( ( products: Array< ProductGroup > ) => {
+ setProductGroups( products );
+ } )
+ .finally( () => {
+ setIsLoading( false );
+ } );
}, [] );
- if ( ! productGroups.length ) {
- return null;
+ if ( isLoading ) {
+ return ;
}
const groupsList = productGroups.flatMap( ( group ) => group );
diff --git a/plugins/woocommerce-admin/client/marketplace/components/product-list-content/no-results.tsx b/plugins/woocommerce-admin/client/marketplace/components/product-list-content/no-results.tsx
index 10285383534..63a69d81407 100644
--- a/plugins/woocommerce-admin/client/marketplace/components/product-list-content/no-results.tsx
+++ b/plugins/woocommerce-admin/client/marketplace/components/product-list-content/no-results.tsx
@@ -25,6 +25,8 @@ export default function NoResults(): JSX.Element {
useEffect( () => {
if ( query.term ) {
setNoResultsTerm( query.term );
+
+ return;
}
if ( query.category ) {
@@ -42,7 +44,7 @@ export default function NoResults(): JSX.Element {
setisLoadingProductGroup( true );
fetchDiscoverPageData()
- .then( ( products: Array< ProductGroup > ) => {
+ .then( ( products: ProductGroup[] ) => {
const mostPopularGroup = products.find(
( group ) => group.id === 'most-popular'
);
diff --git a/plugins/woocommerce-admin/client/marketplace/contexts/product-list-context.tsx b/plugins/woocommerce-admin/client/marketplace/contexts/product-list-context.tsx
index bdbdb14da56..9104602391d 100644
--- a/plugins/woocommerce-admin/client/marketplace/contexts/product-list-context.tsx
+++ b/plugins/woocommerce-admin/client/marketplace/contexts/product-list-context.tsx
@@ -23,15 +23,9 @@ export const ProductListContext = createContext< ProductListContextType >( {
isLoading: false,
} );
-type ProductListContextProviderProps = {
+export function ProductListContextProvider( props: {
children: JSX.Element;
- country?: string;
- locale?: string;
-};
-
-export function ProductListContextProvider(
- props: ProductListContextProviderProps
-): JSX.Element {
+} ): JSX.Element {
const [ isLoading, setIsLoading ] = useState( false );
const [ productList, setProductList ] = useState< Product[] >( [] );
@@ -47,9 +41,9 @@ export function ProductListContextProvider(
const params = new URLSearchParams();
- params.append( 'term', query.term ?? '' );
- params.append( 'country', props.country ?? '' );
- params.append( 'locale', props.locale ?? '' );
+ if ( query.term ) {
+ params.append( 'term', query.term );
+ }
if ( query.category ) {
params.append( 'category', query.category );
@@ -94,7 +88,7 @@ export function ProductListContextProvider(
.finally( () => {
setIsLoading( false );
} );
- }, [ query, props.country, props.locale ] );
+ }, [ query ] );
return (
diff --git a/plugins/woocommerce-admin/client/marketplace/utils/functions.tsx b/plugins/woocommerce-admin/client/marketplace/utils/functions.tsx
index 8695d3e9403..39b9d39d828 100644
--- a/plugins/woocommerce-admin/client/marketplace/utils/functions.tsx
+++ b/plugins/woocommerce-admin/client/marketplace/utils/functions.tsx
@@ -1,9 +1,15 @@
+/**
+ * External dependencies
+ */
+import apiFetch from '@wordpress/api-fetch';
+
/**
* Internal dependencies
*/
import { Product } from '../components/product-list/types';
import { MARKETPLACE_URL } from '../components/constants';
import { CategoryAPIItem } from '../components/category-selector/types';
+import { LOCALE } from '../../utils/admin-settings';
interface ProductGroup {
id: string;
@@ -13,26 +19,28 @@ interface ProductGroup {
}
// Fetch data for the discover page from the WooCommerce.com API
-const fetchDiscoverPageData = async (): Promise< Array< ProductGroup > > => {
- const fetchUrl = MARKETPLACE_URL + '/wp-json/wccom-extensions/2.0/featured';
+async function fetchDiscoverPageData(): Promise< ProductGroup[] > {
+ let url = '/wc/v3/marketplace/featured';
- return fetch( fetchUrl )
- .then( ( response ) => {
- if ( ! response.ok ) {
- throw new Error( response.statusText );
- }
- return response.json();
- } )
- .then( ( json ) => {
- return json;
- } )
- .catch( () => {
- return [];
- } );
-};
+ if ( LOCALE.userLocale ) {
+ url = `${ url }?locale=${ LOCALE.userLocale }`;
+ }
+
+ try {
+ return await apiFetch( { path: url.toString() } );
+ } catch ( error ) {
+ return [];
+ }
+}
function fetchCategories(): Promise< CategoryAPIItem[] > {
- return fetch( MARKETPLACE_URL + '/wp-json/wccom-extensions/1.0/categories' )
+ let url = MARKETPLACE_URL + '/wp-json/wccom-extensions/1.0/categories';
+
+ if ( LOCALE.userLocale ) {
+ url = `${ url }?locale=${ LOCALE.userLocale }`;
+ }
+
+ return fetch( url.toString() )
.then( ( response ) => {
if ( ! response.ok ) {
throw new Error( response.statusText );
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-addons.php b/plugins/woocommerce/includes/admin/class-wc-admin-addons.php
index 41b0accf525..6f00b9dbfa0 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-addons.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-addons.php
@@ -64,8 +64,24 @@ class WC_Admin_Addons {
* @return void
*/
public static function render_featured() {
+ $featured = self::fetch_featured();
+
+ if ( is_wp_error( $featured ) ) {
+ self::output_empty( $featured->get_error_message() );
+ }
+
+ self::output_featured( $featured );
+ }
+
+ /**
+ * Fetch featured products from WCCOM's the Featured 2.0 Endpoint and cache the data for a day.
+ *
+ * @return array|WP_Error
+ */
+ public static function fetch_featured() {
$locale = get_user_locale();
$featured = self::get_locale_data_from_transient( 'wc_addons_featured', $locale );
+
if ( false === $featured ) {
$headers = array();
$auth = WC_Helper_Options::get( 'auth' );
@@ -96,9 +112,7 @@ class WC_Admin_Addons {
? __( 'We encountered an SSL error. Please ensure your site supports TLS version 1.2 or above.', 'woocommerce' )
: $raw_featured->get_error_message();
- self::output_empty( $message );
-
- return;
+ return new WP_Error( 'wc-addons-connection-error', $message );
}
$response_code = (int) wp_remote_retrieve_response_code( $raw_featured );
@@ -117,18 +131,15 @@ class WC_Admin_Addons {
$response_code
);
- self::output_empty( $message );
-
- return;
+ return new WP_Error( 'wc-addons-connection-error', $message );
}
$featured = json_decode( wp_remote_retrieve_body( $raw_featured ) );
if ( empty( $featured ) || ! is_array( $featured ) ) {
do_action( 'woocommerce_page_wc-addons_connection_error', 'Empty or malformed response' );
$message = __( 'Our request to the featured API got a malformed response.', 'woocommerce' );
- self::output_empty( $message );
- return;
+ return new WP_Error( 'wc-addons-connection-error', $message );
}
if ( $featured ) {
@@ -136,7 +147,7 @@ class WC_Admin_Addons {
}
}
- self::output_featured( $featured );
+ return $featured;
}
/**
diff --git a/plugins/woocommerce/includes/admin/helper/class-wc-helper-admin.php b/plugins/woocommerce/includes/admin/helper/class-wc-helper-admin.php
index f45fa4c370c..0d1484be925 100644
--- a/plugins/woocommerce/includes/admin/helper/class-wc-helper-admin.php
+++ b/plugins/woocommerce/includes/admin/helper/class-wc-helper-admin.php
@@ -25,6 +25,7 @@ class WC_Helper_Admin {
*/
public static function load() {
add_filter( 'woocommerce_admin_shared_settings', array( __CLASS__, 'add_marketplace_settings' ) );
+ add_filter( 'rest_api_init', array( __CLASS__, 'register_rest_routes' ) );
}
/**
@@ -82,6 +83,46 @@ class WC_Helper_Admin {
return $connect_url;
}
+
+ /**
+ * Registers the REST routes for the featured products endpoint.
+ * This endpoint is used by the WooCommerce > Extensions > Discover
+ * page.
+ */
+ public static function register_rest_routes() {
+ register_rest_route(
+ 'wc/v3',
+ '/marketplace/featured',
+ array(
+ 'methods' => 'GET',
+ 'callback' => array( __CLASS__, 'get_featured' ),
+ 'permission_callback' => array( __CLASS__, 'get_permission' ),
+ )
+ );
+ }
+
+ /**
+ * The Extensions page can only be accessed by users with the manage_woocommerce
+ * capability. So the API mimics that behavior.
+ */
+ public static function get_permission() {
+ return current_user_can( 'manage_woocommerce' );
+ }
+
+ /**
+ * Fetch featured procucts from WooCommerce.com and serve them
+ * as JSON.
+ */
+ public static function get_featured() {
+ $featured = WC_Admin_Addons::fetch_featured();
+
+ if ( is_wp_error( $featured ) ) {
+ wp_send_json_error( array( 'message' => $featured->get_error_message() ) );
+ }
+
+ wp_send_json( $featured );
+ }
+
}
WC_Helper_Admin::load();