Marketplace: cache Discover page content in a transient (#39782)
This commit is contained in:
commit
3c92e9078c
|
@ -8,21 +8,29 @@ import { useEffect, useState } from '@wordpress/element';
|
||||||
*/
|
*/
|
||||||
import ProductList from '../product-list/product-list';
|
import ProductList from '../product-list/product-list';
|
||||||
import { fetchDiscoverPageData, ProductGroup } from '../../utils/functions';
|
import { fetchDiscoverPageData, ProductGroup } from '../../utils/functions';
|
||||||
|
import ProductLoader from '../product-loader/product-loader';
|
||||||
import './discover.scss';
|
import './discover.scss';
|
||||||
|
|
||||||
export default function Discover(): JSX.Element | null {
|
export default function Discover(): JSX.Element | null {
|
||||||
const [ productGroups, setProductGroups ] = useState<
|
const [ productGroups, setProductGroups ] = useState<
|
||||||
Array< ProductGroup >
|
Array< ProductGroup >
|
||||||
>( [] );
|
>( [] );
|
||||||
|
const [ isLoading, setIsLoading ] = useState( false );
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
fetchDiscoverPageData().then( ( products: Array< ProductGroup > ) => {
|
setIsLoading( true );
|
||||||
|
|
||||||
|
fetchDiscoverPageData()
|
||||||
|
.then( ( products: Array< ProductGroup > ) => {
|
||||||
setProductGroups( products );
|
setProductGroups( products );
|
||||||
|
} )
|
||||||
|
.finally( () => {
|
||||||
|
setIsLoading( false );
|
||||||
} );
|
} );
|
||||||
}, [] );
|
}, [] );
|
||||||
|
|
||||||
if ( ! productGroups.length ) {
|
if ( isLoading ) {
|
||||||
return null;
|
return <ProductLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupsList = productGroups.flatMap( ( group ) => group );
|
const groupsList = productGroups.flatMap( ( group ) => group );
|
||||||
|
|
|
@ -25,6 +25,8 @@ export default function NoResults(): JSX.Element {
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
if ( query.term ) {
|
if ( query.term ) {
|
||||||
setNoResultsTerm( query.term );
|
setNoResultsTerm( query.term );
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( query.category ) {
|
if ( query.category ) {
|
||||||
|
@ -42,7 +44,7 @@ export default function NoResults(): JSX.Element {
|
||||||
setisLoadingProductGroup( true );
|
setisLoadingProductGroup( true );
|
||||||
|
|
||||||
fetchDiscoverPageData()
|
fetchDiscoverPageData()
|
||||||
.then( ( products: Array< ProductGroup > ) => {
|
.then( ( products: ProductGroup[] ) => {
|
||||||
const mostPopularGroup = products.find(
|
const mostPopularGroup = products.find(
|
||||||
( group ) => group.id === 'most-popular'
|
( group ) => group.id === 'most-popular'
|
||||||
);
|
);
|
||||||
|
|
|
@ -23,15 +23,9 @@ export const ProductListContext = createContext< ProductListContextType >( {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
type ProductListContextProviderProps = {
|
export function ProductListContextProvider( props: {
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
country?: string;
|
} ): JSX.Element {
|
||||||
locale?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ProductListContextProvider(
|
|
||||||
props: ProductListContextProviderProps
|
|
||||||
): JSX.Element {
|
|
||||||
const [ isLoading, setIsLoading ] = useState( false );
|
const [ isLoading, setIsLoading ] = useState( false );
|
||||||
const [ productList, setProductList ] = useState< Product[] >( [] );
|
const [ productList, setProductList ] = useState< Product[] >( [] );
|
||||||
|
|
||||||
|
@ -47,9 +41,9 @@ export function ProductListContextProvider(
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
params.append( 'term', query.term ?? '' );
|
if ( query.term ) {
|
||||||
params.append( 'country', props.country ?? '' );
|
params.append( 'term', query.term );
|
||||||
params.append( 'locale', props.locale ?? '' );
|
}
|
||||||
|
|
||||||
if ( query.category ) {
|
if ( query.category ) {
|
||||||
params.append( 'category', query.category );
|
params.append( 'category', query.category );
|
||||||
|
@ -94,7 +88,7 @@ export function ProductListContextProvider(
|
||||||
.finally( () => {
|
.finally( () => {
|
||||||
setIsLoading( false );
|
setIsLoading( false );
|
||||||
} );
|
} );
|
||||||
}, [ query, props.country, props.locale ] );
|
}, [ query ] );
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProductListContext.Provider value={ contextValue }>
|
<ProductListContext.Provider value={ contextValue }>
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import apiFetch from '@wordpress/api-fetch';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { Product } from '../components/product-list/types';
|
import { Product } from '../components/product-list/types';
|
||||||
import { MARKETPLACE_URL } from '../components/constants';
|
import { MARKETPLACE_URL } from '../components/constants';
|
||||||
import { CategoryAPIItem } from '../components/category-selector/types';
|
import { CategoryAPIItem } from '../components/category-selector/types';
|
||||||
|
import { LOCALE } from '../../utils/admin-settings';
|
||||||
|
|
||||||
interface ProductGroup {
|
interface ProductGroup {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -13,26 +19,28 @@ interface ProductGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch data for the discover page from the WooCommerce.com API
|
// Fetch data for the discover page from the WooCommerce.com API
|
||||||
const fetchDiscoverPageData = async (): Promise< Array< ProductGroup > > => {
|
async function fetchDiscoverPageData(): Promise< ProductGroup[] > {
|
||||||
const fetchUrl = MARKETPLACE_URL + '/wp-json/wccom-extensions/2.0/featured';
|
let url = '/wc/v3/marketplace/featured';
|
||||||
|
|
||||||
return fetch( fetchUrl )
|
if ( LOCALE.userLocale ) {
|
||||||
.then( ( response ) => {
|
url = `${ url }?locale=${ LOCALE.userLocale }`;
|
||||||
if ( ! response.ok ) {
|
|
||||||
throw new Error( response.statusText );
|
|
||||||
}
|
}
|
||||||
return response.json();
|
|
||||||
} )
|
try {
|
||||||
.then( ( json ) => {
|
return await apiFetch( { path: url.toString() } );
|
||||||
return json;
|
} catch ( error ) {
|
||||||
} )
|
|
||||||
.catch( () => {
|
|
||||||
return [];
|
return [];
|
||||||
} );
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function fetchCategories(): Promise< CategoryAPIItem[] > {
|
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 ) => {
|
.then( ( response ) => {
|
||||||
if ( ! response.ok ) {
|
if ( ! response.ok ) {
|
||||||
throw new Error( response.statusText );
|
throw new Error( response.statusText );
|
||||||
|
|
|
@ -64,8 +64,24 @@ class WC_Admin_Addons {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function render_featured() {
|
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();
|
$locale = get_user_locale();
|
||||||
$featured = self::get_locale_data_from_transient( 'wc_addons_featured', $locale );
|
$featured = self::get_locale_data_from_transient( 'wc_addons_featured', $locale );
|
||||||
|
|
||||||
if ( false === $featured ) {
|
if ( false === $featured ) {
|
||||||
$headers = array();
|
$headers = array();
|
||||||
$auth = WC_Helper_Options::get( 'auth' );
|
$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' )
|
? __( 'We encountered an SSL error. Please ensure your site supports TLS version 1.2 or above.', 'woocommerce' )
|
||||||
: $raw_featured->get_error_message();
|
: $raw_featured->get_error_message();
|
||||||
|
|
||||||
self::output_empty( $message );
|
return new WP_Error( 'wc-addons-connection-error', $message );
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$response_code = (int) wp_remote_retrieve_response_code( $raw_featured );
|
$response_code = (int) wp_remote_retrieve_response_code( $raw_featured );
|
||||||
|
@ -117,18 +131,15 @@ class WC_Admin_Addons {
|
||||||
$response_code
|
$response_code
|
||||||
);
|
);
|
||||||
|
|
||||||
self::output_empty( $message );
|
return new WP_Error( 'wc-addons-connection-error', $message );
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$featured = json_decode( wp_remote_retrieve_body( $raw_featured ) );
|
$featured = json_decode( wp_remote_retrieve_body( $raw_featured ) );
|
||||||
if ( empty( $featured ) || ! is_array( $featured ) ) {
|
if ( empty( $featured ) || ! is_array( $featured ) ) {
|
||||||
do_action( 'woocommerce_page_wc-addons_connection_error', 'Empty or malformed response' );
|
do_action( 'woocommerce_page_wc-addons_connection_error', 'Empty or malformed response' );
|
||||||
$message = __( 'Our request to the featured API got a malformed response.', 'woocommerce' );
|
$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 ) {
|
if ( $featured ) {
|
||||||
|
@ -136,7 +147,7 @@ class WC_Admin_Addons {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self::output_featured( $featured );
|
return $featured;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@ class WC_Helper_Admin {
|
||||||
*/
|
*/
|
||||||
public static function load() {
|
public static function load() {
|
||||||
add_filter( 'woocommerce_admin_shared_settings', array( __CLASS__, 'add_marketplace_settings' ) );
|
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;
|
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();
|
WC_Helper_Admin::load();
|
||||||
|
|
Loading…
Reference in New Issue