Update payment method suggestion endpoint (https://github.com/woocommerce/woocommerce-admin/pull/7913)
* Initial refactor * Update payment recommendations to use new endpoint data * Make sure to run specs * Fix test * Delete old PaymentPlugins class * Update url to point to woocommerce.com * Remove unused displayable prop * Move option name * Fix js tests * Add changelog
This commit is contained in:
parent
f0aebb8046
commit
dc03c6fbb5
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: Dev
|
||||
|
||||
Update payment method recommendation to new woocommerce.com endpoint. #7913
|
|
@ -10,11 +10,9 @@ import { EllipsisMenu, List, Pill } from '@woocommerce/components';
|
|||
import { Text } from '@woocommerce/experimental';
|
||||
import {
|
||||
PLUGINS_STORE_NAME,
|
||||
SETTINGS_STORE_NAME,
|
||||
WCDataSelector,
|
||||
Plugin,
|
||||
WPDataSelectors,
|
||||
OPTIONS_STORE_NAME,
|
||||
PluginsStoreActions,
|
||||
} from '@woocommerce/data';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import ExternalIcon from 'gridicons/dist/external';
|
||||
|
@ -24,64 +22,23 @@ import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import './payment-recommendations.scss';
|
||||
import { getCountryCode } from '../dashboard/utils';
|
||||
import { createNoticesFromResponse } from '../lib/notices';
|
||||
import { isWCPaySupported } from '~/tasks/fills/PaymentGatewaySuggestions/components/WCPay';
|
||||
|
||||
const SEE_MORE_LINK =
|
||||
'https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations';
|
||||
const DISMISS_OPTION = 'woocommerce_setting_payments_recommendations_hidden';
|
||||
type SettingsSelector = WPDataSelectors & {
|
||||
getSettings: (
|
||||
type: string
|
||||
) => { general: { woocommerce_default_country?: string } };
|
||||
};
|
||||
|
||||
type OptionsSelector = WPDataSelectors & {
|
||||
getOption: ( option: string ) => boolean | string;
|
||||
};
|
||||
|
||||
export function getPaymentRecommendationData(
|
||||
select: WCDataSelector
|
||||
): {
|
||||
displayable: boolean;
|
||||
recommendedPlugins?: Plugin[];
|
||||
isLoading: boolean;
|
||||
} {
|
||||
const { getOption, isResolving: isResolvingOption } = select(
|
||||
OPTIONS_STORE_NAME
|
||||
) as OptionsSelector;
|
||||
const { getSettings } = select( SETTINGS_STORE_NAME ) as SettingsSelector;
|
||||
const { getRecommendedPlugins } = select( PLUGINS_STORE_NAME );
|
||||
const { general: settings } = getSettings( 'general' );
|
||||
|
||||
const hidden = getOption( DISMISS_OPTION );
|
||||
const countryCode =
|
||||
settings && settings.woocommerce_default_country
|
||||
? getCountryCode( settings.woocommerce_default_country )
|
||||
: null;
|
||||
const countrySupported = countryCode
|
||||
? isWCPaySupported( countryCode )
|
||||
: false;
|
||||
const isRequestingOptions = isResolvingOption( 'getOption', [
|
||||
DISMISS_OPTION,
|
||||
] );
|
||||
|
||||
const displayable =
|
||||
! isRequestingOptions && hidden !== 'yes' && countrySupported;
|
||||
let plugins = null;
|
||||
if ( displayable ) {
|
||||
// don't get recommended plugins until it is displayable.
|
||||
plugins = getRecommendedPlugins( 'payments' );
|
||||
}
|
||||
const isLoading =
|
||||
isRequestingOptions ||
|
||||
hidden === undefined ||
|
||||
settings === undefined ||
|
||||
plugins === undefined;
|
||||
const plugins = getRecommendedPlugins( 'payments' );
|
||||
const isLoading = plugins === undefined;
|
||||
|
||||
return {
|
||||
displayable,
|
||||
recommendedPlugins: plugins,
|
||||
isLoading,
|
||||
};
|
||||
|
@ -95,14 +52,18 @@ const PaymentRecommendations: React.FC = () => {
|
|||
const [ installingPlugin, setInstallingPlugin ] = useState< string | null >(
|
||||
null
|
||||
);
|
||||
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
|
||||
const { installAndActivatePlugins } = useDispatch( PLUGINS_STORE_NAME );
|
||||
const { displayable, recommendedPlugins, isLoading } = useSelect(
|
||||
const {
|
||||
installAndActivatePlugins,
|
||||
dismissRecommendedPlugins,
|
||||
invalidateResolution,
|
||||
}: PluginsStoreActions = useDispatch( PLUGINS_STORE_NAME );
|
||||
const { createNotice } = useDispatch( 'core/notices' );
|
||||
const { recommendedPlugins, isLoading } = useSelect(
|
||||
getPaymentRecommendationData
|
||||
);
|
||||
const triggeredPageViewRef = useRef( false );
|
||||
const shouldShowRecommendations =
|
||||
displayable && recommendedPlugins && recommendedPlugins.length > 0;
|
||||
recommendedPlugins && recommendedPlugins.length > 0;
|
||||
|
||||
useEffect( () => {
|
||||
if (
|
||||
|
@ -113,10 +74,10 @@ const PaymentRecommendations: React.FC = () => {
|
|||
triggeredPageViewRef.current = true;
|
||||
const eventProps = ( recommendedPlugins || [] ).reduce(
|
||||
( props, plugin ) => {
|
||||
if ( plugin.product ) {
|
||||
if ( plugin.plugins && plugin.plugins.length > 0 ) {
|
||||
return {
|
||||
...props,
|
||||
[ plugin.product.replace( /\-/g, '_' ) +
|
||||
[ plugin.plugins[ 0 ].replace( /\-/g, '_' ) +
|
||||
'_displayed' ]: true,
|
||||
};
|
||||
}
|
||||
|
@ -136,23 +97,31 @@ const PaymentRecommendations: React.FC = () => {
|
|||
if ( ! shouldShowRecommendations ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dismissPaymentRecommendations = () => {
|
||||
const dismissPaymentRecommendations = async () => {
|
||||
recordEvent( 'settings_payments_recommendations_dismiss', {} );
|
||||
updateOptions( {
|
||||
[ DISMISS_OPTION ]: 'yes',
|
||||
} );
|
||||
const success = await dismissRecommendedPlugins( 'payments' );
|
||||
if ( success ) {
|
||||
invalidateResolution( 'getRecommendedPlugins', [ 'payments' ] );
|
||||
} else {
|
||||
createNotice(
|
||||
'error',
|
||||
__(
|
||||
'There was a problem hiding the "Recommended ways to get paid" card.',
|
||||
'woocommerce-admin'
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const setupPlugin = ( plugin: Plugin ) => {
|
||||
if ( installingPlugin ) {
|
||||
return;
|
||||
}
|
||||
setInstallingPlugin( plugin.product );
|
||||
setInstallingPlugin( plugin.id );
|
||||
recordEvent( 'settings_payments_recommendations_setup', {
|
||||
extension_selected: plugin.product,
|
||||
extension_selected: plugin.plugins[ 0 ],
|
||||
} );
|
||||
installAndActivatePlugins( [ plugin.product ] )
|
||||
installAndActivatePlugins( [ plugin.plugins[ 0 ] ] )
|
||||
.then( () => {
|
||||
window.location.href = getAdminLink(
|
||||
plugin[ 'setup-link' ].replace( '/wp-admin/', '' )
|
||||
|
@ -167,7 +136,7 @@ const PaymentRecommendations: React.FC = () => {
|
|||
const pluginsList = ( recommendedPlugins || [] ).map(
|
||||
( plugin: Plugin ) => {
|
||||
return {
|
||||
key: plugin.slug,
|
||||
key: plugin.id,
|
||||
title: (
|
||||
<>
|
||||
{ plugin.title }
|
||||
|
@ -178,18 +147,18 @@ const PaymentRecommendations: React.FC = () => {
|
|||
) }
|
||||
</>
|
||||
),
|
||||
content: decodeEntities( plugin.copy ),
|
||||
content: decodeEntities( plugin.content ),
|
||||
after: (
|
||||
<Button
|
||||
isSecondary
|
||||
onClick={ () => setupPlugin( plugin ) }
|
||||
isBusy={ installingPlugin === plugin.product }
|
||||
isBusy={ installingPlugin === plugin.id }
|
||||
disabled={ !! installingPlugin }
|
||||
>
|
||||
{ plugin[ 'button-text' ] }
|
||||
</Button>
|
||||
),
|
||||
before: <img src={ plugin.icon } alt="" />,
|
||||
before: <img src={ plugin.image } alt="" />,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
|
@ -4,21 +4,12 @@
|
|||
import { render, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import {
|
||||
PLUGINS_STORE_NAME,
|
||||
SETTINGS_STORE_NAME,
|
||||
OPTIONS_STORE_NAME,
|
||||
WCDataStoreName,
|
||||
Plugin,
|
||||
} from '@woocommerce/data';
|
||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import PaymentRecommendations, {
|
||||
getPaymentRecommendationData,
|
||||
} from '../payment-recommendations';
|
||||
import PaymentRecommendations from '../payment-recommendations';
|
||||
import { isWCPaySupported } from '../../tasks/fills/PaymentGatewaySuggestions/components/WCPay';
|
||||
import { createNoticesFromResponse } from '~/lib/notices';
|
||||
|
||||
|
@ -74,7 +65,6 @@ jest.mock( '../../lib/notices', () => ( {
|
|||
describe( 'Payment recommendations', () => {
|
||||
it( 'should render nothing with no recommendedPlugins and country not defined', () => {
|
||||
( useSelect as jest.Mock ).mockReturnValue( {
|
||||
displayable: false,
|
||||
recommendedPlugins: undefined,
|
||||
} );
|
||||
const { container } = render( <PaymentRecommendations /> );
|
||||
|
@ -82,151 +72,12 @@ describe( 'Payment recommendations', () => {
|
|||
expect( container.firstChild ).toBe( null );
|
||||
} );
|
||||
|
||||
describe( 'getPaymentRecommendationData', () => {
|
||||
const plugin = {
|
||||
title: 'test',
|
||||
slug: 'test',
|
||||
product: 'test',
|
||||
} as Plugin;
|
||||
const baseSelectValues = {
|
||||
plugins: undefined,
|
||||
optionsResolving: false,
|
||||
country: undefined,
|
||||
optionValues: {},
|
||||
};
|
||||
const recommendedPluginsMock = jest.fn();
|
||||
const createFakeSelect = ( data: {
|
||||
optionsResolving?: boolean;
|
||||
optionValues: Record< string, boolean | string >;
|
||||
country?: string;
|
||||
plugins?: Plugin[];
|
||||
} ) => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation( ( storeName: WCDataStoreName ) => {
|
||||
switch ( storeName ) {
|
||||
case OPTIONS_STORE_NAME:
|
||||
return {
|
||||
isResolving: () => data.optionsResolving,
|
||||
getOption: ( option: string ) =>
|
||||
data.optionValues[ option ],
|
||||
};
|
||||
case SETTINGS_STORE_NAME:
|
||||
return {
|
||||
getSettings: () => ( {
|
||||
general: {
|
||||
woocommerce_default_country:
|
||||
data.country,
|
||||
},
|
||||
} ),
|
||||
};
|
||||
case PLUGINS_STORE_NAME:
|
||||
return {
|
||||
getRecommendedPlugins: recommendedPluginsMock.mockReturnValue(
|
||||
data.plugins
|
||||
),
|
||||
};
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
it( 'should render nothing if the country is not supported', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( false );
|
||||
|
||||
const selectData = getPaymentRecommendationData(
|
||||
createFakeSelect( {
|
||||
...baseSelectValues,
|
||||
country: 'FR',
|
||||
plugins: [ plugin ],
|
||||
} )
|
||||
);
|
||||
|
||||
expect( selectData.displayable ).toBe( false );
|
||||
} );
|
||||
|
||||
it( 'should not call getRecommendedPlugins when displayable is false', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( false );
|
||||
|
||||
const selectData = getPaymentRecommendationData(
|
||||
createFakeSelect( {
|
||||
...baseSelectValues,
|
||||
country: 'FR',
|
||||
plugins: [ plugin ],
|
||||
} )
|
||||
);
|
||||
|
||||
expect( selectData.displayable ).toBe( false );
|
||||
expect( recommendedPluginsMock ).not.toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'should have displayable as true if country is supported', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
const selectData = getPaymentRecommendationData(
|
||||
createFakeSelect( {
|
||||
...baseSelectValues,
|
||||
country: 'US',
|
||||
plugins: [ plugin ],
|
||||
optionValues: {},
|
||||
} )
|
||||
);
|
||||
|
||||
expect( selectData.displayable ).toBeTruthy();
|
||||
} );
|
||||
|
||||
it( 'should have displayable as false if hidden is set to true', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
const selectData = getPaymentRecommendationData(
|
||||
createFakeSelect( {
|
||||
...baseSelectValues,
|
||||
country: 'US',
|
||||
plugins: [ plugin ],
|
||||
optionValues: {
|
||||
woocommerce_setting_payments_recommendations_hidden:
|
||||
'yes',
|
||||
},
|
||||
} )
|
||||
);
|
||||
|
||||
expect( selectData.displayable ).toBeFalsy();
|
||||
} );
|
||||
|
||||
it( 'should set displayable to true if isHidden is not defined', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
const selectData = getPaymentRecommendationData(
|
||||
createFakeSelect( {
|
||||
...baseSelectValues,
|
||||
country: 'US',
|
||||
plugins: [ plugin ],
|
||||
optionValues: {
|
||||
woocommerce_setting_payments_recommendations_hidden:
|
||||
'no',
|
||||
},
|
||||
} )
|
||||
);
|
||||
|
||||
expect( selectData.displayable ).toBeTruthy();
|
||||
} );
|
||||
|
||||
it( 'have displayable as false if still requesting options', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
const selectData = getPaymentRecommendationData(
|
||||
createFakeSelect( {
|
||||
...baseSelectValues,
|
||||
country: 'US',
|
||||
plugins: [ plugin ],
|
||||
optionsResolving: true,
|
||||
} )
|
||||
);
|
||||
|
||||
expect( selectData.displayable ).toBeFalsy();
|
||||
} );
|
||||
} );
|
||||
|
||||
it( 'should render the list if displayable is true and has recommendedPlugins', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
( useSelect as jest.Mock ).mockReturnValue( {
|
||||
displayable: true,
|
||||
recommendedPlugins: [ { title: 'test', slug: 'test' } ],
|
||||
recommendedPlugins: [
|
||||
{ title: 'test', id: 'test', plugins: [ 'test' ] },
|
||||
],
|
||||
} );
|
||||
const { container, getByText } = render( <PaymentRecommendations /> );
|
||||
|
||||
|
@ -252,9 +103,8 @@ describe( 'Payment recommendations', () => {
|
|||
it( 'should trigger event payments_recommendations_pageview, when first rendered', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
( useSelect as jest.Mock ).mockReturnValue( {
|
||||
displayable: true,
|
||||
recommendedPlugins: [
|
||||
{ title: 'test', slug: 'test', product: 'test' },
|
||||
{ title: 'test', id: 'test', plugins: [ 'test' ] },
|
||||
],
|
||||
} );
|
||||
const { container } = render( <PaymentRecommendations /> );
|
||||
|
@ -272,9 +122,8 @@ describe( 'Payment recommendations', () => {
|
|||
it( 'should set woocommerce-payments-displayed prop to true if pre install wc pay promotion gateway is displayed', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
( useSelect as jest.Mock ).mockReturnValue( {
|
||||
displayable: true,
|
||||
recommendedPlugins: [
|
||||
{ title: 'test', slug: 'test', product: 'test' },
|
||||
{ title: 'test', id: 'test', plugins: [ 'test' ] },
|
||||
],
|
||||
} );
|
||||
const { container } = render(
|
||||
|
@ -297,7 +146,6 @@ describe( 'Payment recommendations', () => {
|
|||
it( 'should not render if there are no recommendedPlugins', () => {
|
||||
( isWCPaySupported as jest.Mock ).mockReturnValue( true );
|
||||
( useSelect as jest.Mock ).mockReturnValue( {
|
||||
displayable: true,
|
||||
recommendedPlugins: [],
|
||||
} );
|
||||
const { container } = render( <PaymentRecommendations /> );
|
||||
|
@ -321,19 +169,18 @@ describe( 'Payment recommendations', () => {
|
|||
installAndActivatePlugins: installAndActivateMock,
|
||||
} );
|
||||
( useSelect as jest.Mock ).mockReturnValue( {
|
||||
displayable: true,
|
||||
recommendedPlugins: [
|
||||
{
|
||||
title: 'test',
|
||||
slug: 'test',
|
||||
product: 'test-product',
|
||||
id: 'test',
|
||||
plugins: [ 'test-product' ],
|
||||
'button-text': 'install',
|
||||
'setup-link': '/wp-admin/random-link',
|
||||
},
|
||||
{
|
||||
title: 'another',
|
||||
slug: 'another',
|
||||
product: 'another-product',
|
||||
id: 'another',
|
||||
plugins: [ 'another-product' ],
|
||||
'button-text': 'install2',
|
||||
'setup-link': '/wp-admin/random-link',
|
||||
},
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
PaypalOnboardingStatus,
|
||||
PluginNames,
|
||||
SelectorKeysWithActions,
|
||||
RecommendedTypes,
|
||||
} from './types';
|
||||
|
||||
// Can be removed in WP 5.9, wp.data is supported in >5.7.
|
||||
|
@ -348,6 +349,36 @@ export function setRecommendedPlugins(
|
|||
};
|
||||
}
|
||||
|
||||
const SUPPORTED_TYPES = [ 'payments' ];
|
||||
export function* dismissRecommendedPlugins( type: RecommendedTypes ) {
|
||||
if ( ! SUPPORTED_TYPES.includes( type ) ) {
|
||||
return [];
|
||||
}
|
||||
const plugins: Plugin[] = yield resolveSelect(
|
||||
STORE_NAME,
|
||||
'getRecommendedPlugins',
|
||||
type
|
||||
);
|
||||
yield setRecommendedPlugins( type, [] );
|
||||
|
||||
let success: boolean;
|
||||
try {
|
||||
const url =
|
||||
WC_ADMIN_NAMESPACE + '/plugins/recommended-payment-plugins/dismiss';
|
||||
success = yield apiFetch( {
|
||||
path: url,
|
||||
method: 'POST',
|
||||
} );
|
||||
} catch ( error ) {
|
||||
success = false;
|
||||
}
|
||||
if ( ! success ) {
|
||||
// Reset recommended plugins
|
||||
yield setRecommendedPlugins( type, plugins );
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
export type Actions =
|
||||
| ReturnType< typeof updateActivePlugins >
|
||||
| ReturnType< typeof updateInstalledPlugins >
|
||||
|
@ -362,4 +393,5 @@ export type Actions =
|
|||
export type ActionDispatchers = {
|
||||
installJetpackAndConnect: typeof installJetpackAndConnect;
|
||||
installAndActivatePlugins: typeof installAndActivatePlugins;
|
||||
dismissRecommendedPlugins: typeof dismissRecommendedPlugins;
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Automattic\WooCommerce\Admin\API;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Onboarding;
|
||||
use Automattic\WooCommerce\Admin\PaymentPlugins;
|
||||
use Automattic\WooCommerce\Admin\PaymentMethodSuggestionsDataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||
use \Automattic\WooCommerce\Admin\Notes\InstallJPAndWCSPlugins;
|
||||
|
||||
|
@ -103,6 +103,19 @@ class Plugins extends \WC_REST_Data_Controller {
|
|||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/recommended-payment-plugins/dismiss',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'dismiss_recommended_payment_plugins' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
),
|
||||
'schema' => array( $this, 'get_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/connect-jetpack',
|
||||
|
@ -435,40 +448,23 @@ class Plugins extends \WC_REST_Data_Controller {
|
|||
* @return \WP_Error|\WP_HTTP_Response|\WP_REST_Response
|
||||
*/
|
||||
public function recommended_payment_plugins( $request ) {
|
||||
// Default to marketing category (if no category set).
|
||||
$all_plugins = PaymentPlugins::get_instance()->get_recommended_plugins();
|
||||
$valid_plugins = [];
|
||||
$per_page = $request->get_param( 'per_page' );
|
||||
// We currently only support English suggestions, unless otherwise provided in locale-data.
|
||||
$locale = get_locale();
|
||||
$suggestion_locales = array(
|
||||
'en_AU',
|
||||
'en_CA',
|
||||
'en_GB',
|
||||
'en_NZ',
|
||||
'en_US',
|
||||
'en_ZA',
|
||||
);
|
||||
|
||||
foreach ( $all_plugins as $plugin ) {
|
||||
if ( ! PluginsHelper::is_plugin_active( $plugin['product'] ) ) {
|
||||
if ( isset( $plugin['locale-data'] ) && isset( $plugin['locale-data'][ $locale ] ) ) {
|
||||
$locale_plugin = array_merge( $plugin, $plugin['locale-data'][ $locale ] );
|
||||
unset( $locale_plugin['locale-data'] );
|
||||
$valid_plugins[] = $locale_plugin;
|
||||
$suggestion_locales[] = $locale;
|
||||
} else {
|
||||
$valid_plugins[] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! in_array( $locale, $suggestion_locales, true ) ) {
|
||||
// If not a supported locale we return an empty array.
|
||||
if ( get_option( PaymentMethodSuggestionsDataSourcePoller::RECOMMENDED_PAYMENT_PLUGINS_DISMISS_OPTION, 'no' ) === 'yes' ) {
|
||||
return rest_ensure_response( array() );
|
||||
}
|
||||
$all_plugins = PaymentMethodSuggestionsDataSourcePoller::get_instance()->get_suggestions();
|
||||
$per_page = $request->get_param( 'per_page' );
|
||||
|
||||
return rest_ensure_response( array_slice( $valid_plugins, 0, $per_page ) );
|
||||
return rest_ensure_response( array_slice( $all_plugins, 0, $per_page ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses recommended payment plugins.
|
||||
*
|
||||
* @return \WP_Error|\WP_HTTP_Response|\WP_REST_Response
|
||||
*/
|
||||
public function dismiss_recommended_payment_plugins() {
|
||||
$success = update_option( PaymentMethodSuggestionsDataSourcePoller::RECOMMENDED_PAYMENT_PLUGINS_DISMISS_OPTION, 'yes' );
|
||||
return rest_ensure_response( $success );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,11 @@ abstract class DataSourcePoller {
|
|||
*/
|
||||
const FILTER_NAME = 'data_source_poller_data_sources';
|
||||
|
||||
/**
|
||||
* Name of data source specs filter.
|
||||
*/
|
||||
const FILTER_NAME_SPECS = 'data_source_poller_specs';
|
||||
|
||||
/**
|
||||
* Id of DataSourcePoller.
|
||||
*
|
||||
|
@ -105,6 +110,7 @@ abstract class DataSourcePoller {
|
|||
$this->read_specs_from_data_sources();
|
||||
$specs = get_transient( $this->args['transient_name'] );
|
||||
}
|
||||
$specs = apply_filters( self::FILTER_NAME_SPECS, $specs, $this->id );
|
||||
return false !== $specs ? $specs : array();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,10 @@ namespace Automattic\WooCommerce\Admin\Features\WcPayPromotion;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\Loader;
|
||||
use Automattic\WooCommerce\Admin\PaymentPlugins;
|
||||
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\EvaluateSuggestion;
|
||||
use Automattic\WooCommerce\Admin\PaymentMethodSuggestionsDataSourcePoller;
|
||||
|
||||
/**
|
||||
* WC Pay Promotion engine.
|
||||
|
@ -24,7 +25,7 @@ class Init {
|
|||
include_once __DIR__ . '/WCPaymentGatewayPreInstallWCPayPromotion.php';
|
||||
|
||||
add_action( 'change_locale', array( __CLASS__, 'delete_specs_transient' ) );
|
||||
add_filter( PaymentPlugins::FILTER_NAME, array( __CLASS__, 'possibly_filter_recommended_payment_gateways' ) );
|
||||
add_filter( DataSourcePoller::FILTER_NAME_SPECS, array( __CLASS__, 'possibly_filter_recommended_payment_gateways' ), 10, 2 );
|
||||
|
||||
if ( ! isset( $_GET['page'] ) || 'wc-settings' !== $_GET['page'] || ! isset( $_GET['tab'] ) || 'checkout' !== $_GET['tab'] ) { // phpcs:ignore WordPress.Security.NonceVerification
|
||||
return;
|
||||
|
@ -71,19 +72,20 @@ class Init {
|
|||
/**
|
||||
* Possibly filters out woocommerce-payments from recommended payment methods.
|
||||
*
|
||||
* @param array $payment_methods list of payment methods.
|
||||
* @param array $specs list of payment methods.
|
||||
* @param string $datasource_poller_id id of data source poller.
|
||||
* @return array list of payment method.
|
||||
*/
|
||||
public static function possibly_filter_recommended_payment_gateways( $payment_methods ) {
|
||||
if ( self::should_register_pre_install_wc_pay_promoted_gateway() ) {
|
||||
public static function possibly_filter_recommended_payment_gateways( $specs, $datasource_poller_id ) {
|
||||
if ( PaymentMethodSuggestionsDataSourcePoller::ID === $datasource_poller_id && self::should_register_pre_install_wc_pay_promoted_gateway() ) {
|
||||
return array_filter(
|
||||
$payment_methods,
|
||||
function( $payment_method ) {
|
||||
return 'woocommerce-payments' !== $payment_method['product'];
|
||||
$specs,
|
||||
function( $spec ) {
|
||||
return 'woocommerce-payments' !== $spec->plugins[0];
|
||||
}
|
||||
);
|
||||
}
|
||||
return $payment_methods;
|
||||
return $specs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\EvaluateSuggestion;
|
||||
|
||||
/**
|
||||
* Specs data source poller class for payment gateway suggestions.
|
||||
*/
|
||||
class PaymentMethodSuggestionsDataSourcePoller extends DataSourcePoller {
|
||||
|
||||
|
||||
const ID = 'payment_method_suggestions';
|
||||
|
||||
/**
|
||||
* Option name for dismissed payment method suggestions.
|
||||
*/
|
||||
const RECOMMENDED_PAYMENT_PLUGINS_DISMISS_OPTION = 'woocommerce_setting_payments_recommendations_hidden';
|
||||
|
||||
/**
|
||||
* Default data sources array.
|
||||
*/
|
||||
const DATA_SOURCES = array(
|
||||
'https://woocommerce.com/wp-json/wccom/payment-gateway-suggestions/1.0/payment-method/suggestions.json',
|
||||
);
|
||||
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var Analytics instance
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Get class instance.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! self::$instance ) {
|
||||
self::$instance = new self( self::ID, self::DATA_SOURCES );
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the payment method suggestions after validating the specs.
|
||||
*
|
||||
* @return array visible specs.
|
||||
*/
|
||||
public function get_suggestions() {
|
||||
if ( ! $this->allow_recommendations() ) {
|
||||
return array();
|
||||
}
|
||||
$suggestions = array();
|
||||
$specs = $this->get_specs_from_data_sources();
|
||||
|
||||
foreach ( $specs as $spec ) {
|
||||
$suggestion = EvaluateSuggestion::evaluate( $spec );
|
||||
$suggestions[] = $suggestion;
|
||||
}
|
||||
|
||||
return array_values(
|
||||
array_filter(
|
||||
$suggestions,
|
||||
function( $suggestion ) {
|
||||
return ! property_exists( $suggestion, 'is_visible' ) || $suggestion->is_visible;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should recommendations be displayed?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function allow_recommendations() {
|
||||
// Suggestions are only displayed if user can install plugins.
|
||||
if ( ! current_user_can( 'install_plugins' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suggestions may be disabled via a setting under Accounts & Privacy.
|
||||
if ( 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// User can disabled all suggestions via filter.
|
||||
return apply_filters( 'woocommerce_allow_payment_recommendations', true );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* WooCommerce Payment methods.
|
||||
* NOTE: DO NOT edit this file in WooCommerce core, this is generated from woocommerce-admin.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin;
|
||||
|
||||
/**
|
||||
* Contains backend logic for retrieving payment plugin recommendations.
|
||||
*/
|
||||
class PaymentPlugins {
|
||||
/**
|
||||
* Name of recommended plugins filter.
|
||||
*/
|
||||
const FILTER_NAME = 'woocommerce_admin_recommended_payment_plugins';
|
||||
|
||||
/**
|
||||
* Name of recommended plugins transient.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const RECOMMENDED_PLUGINS_TRANSIENT = 'wc_recommended_payment_plugins';
|
||||
|
||||
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var PaymentPlugins instance
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Get class instance.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load recommended payment plugins from WooCommerce.com
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_recommended_plugins() {
|
||||
if ( ! self::allow_recommendations() ) {
|
||||
return array();
|
||||
}
|
||||
$plugins_data = get_transient( self::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||
|
||||
if ( false === $plugins_data ) {
|
||||
include_once ABSPATH . '/wp-admin/includes/plugin-install.php';
|
||||
|
||||
$url = 'https://woocommerce.com/wp-json/wccom/marketplace-suggestions/1.0/payment-suggestions.json';
|
||||
$request = wp_safe_remote_get( $url );
|
||||
$plugins = [];
|
||||
|
||||
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
||||
$plugins = json_decode( $request['body'], true );
|
||||
}
|
||||
foreach ( $plugins as $key => $plugin ) {
|
||||
if ( ! array_key_exists( 'copy', $plugins[ $key ] ) ) {
|
||||
$api = plugins_api(
|
||||
'plugin_information',
|
||||
array(
|
||||
'slug' => $plugin['product'],
|
||||
'fields' => array(
|
||||
'short_description' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
if ( is_wp_error( $api ) ) {
|
||||
continue;
|
||||
}
|
||||
$plugins[ $key ]['copy'] = $api->short_description;
|
||||
}
|
||||
}
|
||||
|
||||
$plugins_data = array(
|
||||
'recommendations' => $plugins,
|
||||
'updated' => time(),
|
||||
);
|
||||
|
||||
set_transient(
|
||||
self::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||
$plugins_data,
|
||||
// Expire transient in 15 minutes if remote get failed.
|
||||
// Cache an empty result to avoid repeated failed requests.
|
||||
empty( $plugins ) ? 900 : 3 * DAY_IN_SECONDS
|
||||
);
|
||||
}
|
||||
|
||||
return apply_filters( self::FILTER_NAME, array_values( $plugins_data['recommendations'] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Should recommendations be displayed?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function allow_recommendations() {
|
||||
// Suggestions are only displayed if user can install plugins.
|
||||
if ( ! current_user_can( 'install_plugins' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suggestions may be disabled via a setting under Accounts & Privacy.
|
||||
if ( 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// User can disabled all suggestions via filter.
|
||||
return apply_filters( 'woocommerce_allow_payment_recommendations', true );
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use \Automattic\WooCommerce\Admin\API\Plugins;
|
||||
use Automattic\WooCommerce\Admin\PaymentMethodSuggestionsDataSourcePoller;
|
||||
|
||||
/**
|
||||
* WC Tests API Plugins
|
||||
|
@ -116,13 +117,11 @@ class WC_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
|
|||
public function test_get_recommended_payment_plugins() {
|
||||
wp_set_current_user( $this->user );
|
||||
set_transient(
|
||||
\Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||
'woocommerce_admin_' . PaymentMethodSuggestionsDataSourcePoller::ID . '_specs',
|
||||
array(
|
||||
'recommendations' => array(
|
||||
array(
|
||||
'product' => 'plugin',
|
||||
'title' => 'test',
|
||||
),
|
||||
(object) array(
|
||||
'plugins' => array( 'plugin' ),
|
||||
'title' => 'test',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
@ -132,71 +131,8 @@ class WC_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
|
|||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 1, count( $data ) );
|
||||
$this->assertEquals( 'plugin', $data[0]['product'] );
|
||||
delete_transient( \Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that recommended payment plugins with locale data.
|
||||
*/
|
||||
public function test_get_recommended_payment_plugins_with_locale() {
|
||||
wp_set_current_user( $this->user );
|
||||
add_filter( 'locale', array( $this, 'set_france_locale' ) );
|
||||
set_transient(
|
||||
\Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||
array(
|
||||
'recommendations' => array(
|
||||
array(
|
||||
'product' => 'plugin',
|
||||
'title' => 'test',
|
||||
'locale-data' => array(
|
||||
'fr_FR' => array(
|
||||
'title' => 'translated title',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint . '/recommended-payment-plugins' );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 1, count( $data ) );
|
||||
$this->assertEquals( 'plugin', $data[0]['product'] );
|
||||
$this->assertEquals( 'translated title', $data[0]['title'] );
|
||||
$this->assertEquals( false, isset( $data[0]['locale-data'] ) );
|
||||
delete_transient( \Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||
remove_filter( 'locale', array( $this, 'set_france_locale' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that recommended payment plugins with not default supported locale.
|
||||
*/
|
||||
public function test_get_recommended_payment_plugins_with_not_supported_locale() {
|
||||
wp_set_current_user( $this->user );
|
||||
add_filter( 'locale', array( $this, 'set_france_locale' ) );
|
||||
set_transient(
|
||||
\Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||
array(
|
||||
'recommendations' => array(
|
||||
array(
|
||||
'product' => 'plugin',
|
||||
'title' => 'test',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint . '/recommended-payment-plugins' );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
// Return nothing as default is only english locales.
|
||||
$this->assertEquals( 0, count( $data ) );
|
||||
delete_transient( \Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||
remove_filter( 'locale', array( $this, 'set_france_locale' ) );
|
||||
$this->assertEquals( 'plugin', $data[0]->plugins[0] );
|
||||
delete_transient( 'woocommerce_admin_' . PaymentMethodSuggestionsDataSourcePoller::ID . '_specs' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,14 +147,23 @@ class WC_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_get_recommended_payment_plugins_that_are_active() {
|
||||
wp_set_current_user( $this->user );
|
||||
update_option( 'active_plugins', array( 'facebook-for-woocommerce/facebook-for-woocommerce.php' ) );
|
||||
update_option( 'active_plugins', array( 'woocommerce-gateway-stripe/woocommerce-gateway-stripe.php' ) );
|
||||
set_transient(
|
||||
\Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||
'woocommerce_admin_' . PaymentMethodSuggestionsDataSourcePoller::ID . '_specs',
|
||||
array(
|
||||
'recommendations' => array(
|
||||
array(
|
||||
'product' => 'facebook-for-woocommerce',
|
||||
'title' => 'test',
|
||||
(object) array(
|
||||
'plugins' => array( 'woocommerce-gateway-stripe' ),
|
||||
'title' => 'test',
|
||||
'is_visible' => array(
|
||||
(object) array(
|
||||
'type' => 'not',
|
||||
'operand' => array(
|
||||
(object) array(
|
||||
'type' => 'plugins_activated',
|
||||
'plugins' => array( 'woocommerce-gateway-stripe' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -229,7 +174,50 @@ class WC_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
|
|||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 0, count( $data ) );
|
||||
delete_transient( \Automattic\WooCommerce\Admin\PaymentPlugins::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||
delete_transient( 'woocommerce_admin_' . PaymentMethodSuggestionsDataSourcePoller::ID . '_specs' );
|
||||
|
||||
delete_option( 'active_plugins' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that recommended payment plugins are not returned when active.
|
||||
*/
|
||||
public function test_plugins_when_dismissed_is_set_to_yes() {
|
||||
wp_set_current_user( $this->user );
|
||||
update_option( 'woocommerce_setting_payments_recommendations_hidden', 'yes' );
|
||||
set_transient(
|
||||
'woocommerce_admin_' . PaymentMethodSuggestionsDataSourcePoller::ID . '_specs',
|
||||
array(
|
||||
(object) array(
|
||||
'plugins' => array( 'plugin' ),
|
||||
'title' => 'test',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint . '/recommended-payment-plugins' );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 0, count( $data ) );
|
||||
delete_transient( 'woocommerce_admin_' . PaymentMethodSuggestionsDataSourcePoller::ID . '_specs' );
|
||||
delete_option( 'woocommerce_setting_payments_recommendations_hidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dismissing recommended payment plugins endpoint.
|
||||
*/
|
||||
public function test_dismiss_recommended_payment_plugins() {
|
||||
$this->assertEquals( 'no', get_option( 'woocommerce_setting_payments_recommendations_hidden', 'no' ) );
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$request = new WP_REST_Request( 'POST', $this->endpoint . '/recommended-payment-plugins/dismiss' );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( true, $data );
|
||||
|
||||
$this->assertEquals( 'yes', get_option( 'woocommerce_setting_payments_recommendations_hidden' ) );
|
||||
delete_option( 'woocommerce_setting_payments_recommendations_hidden' );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue