Merge branch 'trunk' into update/admin-docs

This commit is contained in:
Chi-Hsuan Huang 2022-04-15 11:53:08 +08:00 committed by GitHub
commit 3ead227cdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 613 additions and 252 deletions

View File

@ -4,6 +4,8 @@
- Update test for payment task. #32467
- Increase timeout threshold for payment task. #32605
# 1.0.0
- Add returned type annotations and remove unused vars. #8020

View File

@ -21,8 +21,10 @@ export class PaymentsSetup extends BasePage {
await waitForElementByText( 'h1', 'Set up payments' );
}
async closeHelpModal(): Promise< void > {
await this.clickButtonWithText( 'Got it' );
async possiblyCloseHelpModal(): Promise< void > {
try {
await this.clickButtonWithText( 'Got it' );
} catch ( e ) {}
}
async showOtherPaymentMethods(): Promise< void > {
@ -32,6 +34,7 @@ export class PaymentsSetup extends BasePage {
`${ selector }[aria-expanded=false]`
);
await toggleButton?.click();
await waitForElementByText( 'h2', 'Offline payment methods' );
}
async goToPaymentMethodSetup(

View File

@ -48,12 +48,13 @@ const testAdminPaymentSetupTask = () => {
it( 'Can visit the payment setup task from the homescreen if the setup wizard has been skipped', async () => {
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.closeHelpModal();
await paymentsSetup.possiblyCloseHelpModal();
await paymentsSetup.isDisplayed();
} );
it( 'Saving valid bank account transfer details enables the payment method', async () => {
it.skip( 'Saving valid bank account transfer details enables the payment method', async () => {
await paymentsSetup.showOtherPaymentMethods();
await waitForTimeout( 500 );
await paymentsSetup.goToPaymentMethodSetup( 'bacs' );
await bankTransferSetup.saveAccountDetails( {
accountNumber: '1234',
@ -63,23 +64,25 @@ const testAdminPaymentSetupTask = () => {
iban: '12 3456 7890',
swiftCode: 'ABBA',
} );
await waitForTimeout( 1000 );
await waitForTimeout( 1500 );
expect( await settings.paymentMethodIsEnabled( 'bacs' ) ).toBe(
true
);
await homeScreen.navigate();
} );
it( 'Enabling cash on delivery enables the payment method', async () => {
it.skip( 'Enabling cash on delivery enables the payment method', async () => {
await settings.cleanPaymentMethods();
await homeScreen.navigate();
await homeScreen.isDisplayed();
await waitForTimeout( 1000 );
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.possiblyCloseHelpModal();
await paymentsSetup.isDisplayed();
await paymentsSetup.showOtherPaymentMethods();
await waitForTimeout( 500 );
await paymentsSetup.enableCashOnDelivery();
await waitForTimeout( 1000 );
await waitForTimeout( 1500 );
expect( await settings.paymentMethodIsEnabled( 'cod' ) ).toBe(
true
);

View File

@ -3,6 +3,7 @@
- Fix documentation for `TableCard` component
- Update dependency `@wordpress/hooks` to ^3.5.0
- Update dependency `@wordpress/icons` to ^8.1.0
- Add `className` prop for Pill component. #32605
# 10.0.0
- Replace deprecated wp.compose.withState with wp.element.useState. #8338

View File

@ -2,16 +2,17 @@
* External dependencies
*/
import { createElement } from '@wordpress/element';
import classnames from 'classnames';
/**
* Internal dependencies
*/
import { Text } from '../experimental';
export function Pill( { children } ) {
export function Pill( { children, className } ) {
return (
<Text
className="woocommerce-pill"
className={ classnames( 'woocommerce-pill', className ) }
variant="caption"
as="span"
size="12"

View File

@ -6,7 +6,9 @@ import { useEffect, useLayoutEffect, useRef } from '@wordpress/element';
import classnames from 'classnames';
import { decodeEntities } from '@wordpress/html-entities';
import { getSetting } from '@woocommerce/settings';
import { ONBOARDING_STORE_NAME } from '@woocommerce/data';
import { Text, useSlot } from '@woocommerce/experimental';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -93,12 +95,18 @@ export const Header = ( { sections, isEmbedded = false, query } ) => {
}
}, [ isEmbedded, sections, siteTitle ] );
const tasksReminderFeature =
window.wcAdminFeatures[ 'tasklist-setup-experiment-1' ];
const { hasTasksReminderFeature } = useSelect( ( select ) => {
const taskLists = select( ONBOARDING_STORE_NAME ).getTaskLists();
return {
hasTasksReminderFeature: taskLists.some(
( list ) => list.id === 'setup_experiment_1'
),
};
} );
return (
<div className={ className } ref={ headerElement }>
{ tasksReminderFeature && (
{ hasTasksReminderFeature && (
<TasksReminderBar
pageTitle={ pageTitle }
updateBodyMargin={ updateBodyMargin }

View File

@ -49,5 +49,6 @@ $progress-complete-color: #007cba;
.woocommerce-card__menu {
position: absolute;
right: 0;
top: 7px;
}
}

View File

@ -76,7 +76,7 @@ export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
return __( 'You are almost there', 'woocommerce' );
}, [ completedCount, hasVisitedTasks ] );
if ( loading || completedCount === tasksCount ) {
if ( loading ) {
return null;
}
@ -90,22 +90,26 @@ export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
<h1 className="woocommerce-task-progress-header__title">
{ progressTitle }
</h1>
<p>
{ sprintf(
/* translators: 1: completed tasks, 2: total tasks */
__(
'Follow these steps to start selling quickly. %1$d out of %2$d complete.',
'woocommerce'
),
completedCount,
tasksCount
) }
</p>
<progress
className="woocommerce-task-progress-header__progress-bar"
max={ tasksCount }
value={ completedCount || 0 }
/>
{ completedCount !== tasksCount ? (
<>
<p>
{ sprintf(
/* translators: 1: completed tasks, 2: total tasks */
__(
'Follow these steps to start selling quickly. %1$d out of %2$d complete.',
'woocommerce'
),
completedCount,
tasksCount
) }
</p>
<progress
className="woocommerce-task-progress-header__progress-bar"
max={ tasksCount }
value={ completedCount || 0 }
/>
</>
) : null }
</div>
</div>
);

View File

@ -25,6 +25,7 @@ export const Action = ( {
onSetUp = () => {},
onSetupCallback,
setupButtonText = __( 'Get started', 'woocommerce' ),
externalLink = null,
} ) => {
const [ isBusy, setIsBusy ] = useState( false );
@ -41,6 +42,11 @@ export const Action = ( {
selected: getPluginTrackKey( id ),
} );
if ( ! hasPlugins && externalLink ) {
window.location.href = externalLink;
return;
}
if ( onSetupCallback ) {
setIsBusy( true );
await new Promise( onSetupCallback )
@ -84,17 +90,19 @@ export const Action = ( {
</Button>
);
const EnableButton = () => (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce' ) }
</Button>
);
if ( ! hasSetup ) {
if ( ! isEnabled ) {
return (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce' ) }
</Button>
);
return <EnableButton />;
}
return <ManageButton />;
@ -110,6 +118,10 @@ export const Action = ( {
}
if ( ! needsSetup ) {
if ( ! isEnabled ) {
return <EnableButton />;
}
return <ManageButton />;
}

View File

@ -4,8 +4,10 @@
import classnames from 'classnames';
import { Fragment } from '@wordpress/element';
import { CardBody, CardMedia, CardDivider } from '@wordpress/components';
import { RecommendedRibbon, SetupRequired } from '@woocommerce/onboarding';
import { SetupRequired } from '@woocommerce/onboarding';
import { Pill } from '@woocommerce/components';
import { Text, useSlot } from '@woocommerce/experimental';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
@ -15,7 +17,7 @@ import './List.scss';
export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
const {
image,
image_72x72: image72x72,
content,
id,
plugins = [],
@ -27,6 +29,7 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
requiredSettings,
settingsUrl: manageUrl,
is_local_partner: isLocalPartner,
external_link: externalLink,
} = paymentGateway;
const connectSlot = useSlot(
@ -39,9 +42,9 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
Boolean( setupSlot?.fills?.length );
const hasSetup = Boolean(
plugins.length || requiredSettings.length || hasFills
plugins.length || requiredSettings.length || hasFills || externalLink
);
const showRecommendedRibbon = isRecommended && needsSetup;
const showRecommended = isRecommended && needsSetup;
const classes = classnames(
'woocommerce-task-payment',
@ -57,14 +60,20 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
className={ classes }
>
<CardMedia isBorderless>
<img src={ image } alt={ title } />
<img src={ image72x72 } alt={ title } />
</CardMedia>
<div className="woocommerce-task-payment__description">
{ showRecommendedRibbon && (
<RecommendedRibbon isLocalPartner={ isLocalPartner } />
) }
<Text as="h3" className="woocommerce-task-payment__title">
{ title }
<span>{ title }</span>
{ showRecommended && (
<Pill
className={ ! isLocalPartner && 'pill-green' }
>
{ isLocalPartner
? __( 'Local Partner', 'woocommerce' )
: __( 'Recommended', 'woocommerce' ) }
</Pill>
) }
{ isInstalled && needsSetup && !! plugins.length && (
<SetupRequired />
) }
@ -85,6 +94,7 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
isRecommended={ isRecommended }
isLoading={ loading }
markConfigured={ markConfigured }
externalLink={ externalLink }
/>
</div>
</CardBody>

View File

@ -42,6 +42,15 @@
color: $studio-gray-80;
margin-top: 0;
margin-bottom: $gap-smaller;
.woocommerce-pill {
margin-left: 8px;
&.pill-green {
color: #008a20;
border-color: #008a20;
}
}
}
.woocommerce-task-payment__content {

View File

@ -138,7 +138,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
expect( queryByText( 'Recommended' ) ).not.toBeInTheDocument();
} );
it( 'should display Manage button if not enabled and does have setup', () => {
it( 'should display Manage button if enabled and does have setup', () => {
const props = {
...defaultProps,
paymentGateways: [
@ -180,6 +180,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
...mockGateway,
plugins: [ 'nope' ],
needsSetup: false,
enabled: true,
},
],
};

View File

@ -7,12 +7,14 @@ import {
OPTIONS_STORE_NAME,
ONBOARDING_STORE_NAME,
PAYMENT_GATEWAYS_STORE_NAME,
SETTINGS_STORE_NAME,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useMemo, useCallback, useEffect } from '@wordpress/element';
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { getNewPath } from '@woocommerce/navigation';
import { getAdminLink } from '@woocommerce/settings';
import { Button } from '@wordpress/components';
import ExternalIcon from 'gridicons/dist/external';
@ -24,15 +26,25 @@ import { Setup, Placeholder as SetupPlaceholder } from './components/Setup';
import { Toggle } from './components/Toggle/Toggle';
import { WCPaySuggestion } from './components/WCPay';
import { getPluginSlug } from '~/utils';
import { getCountryCode } from '~/dashboard/utils';
import './plugins/Bacs';
import './payment-gateway-suggestions.scss';
const SEE_MORE_LINK =
'https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations';
const comparePaymentGatewaysByPriority = ( a, b ) =>
a.recommendation_priority - b.recommendation_priority;
const isGatewayWCPay = ( gateway ) =>
gateway.plugins?.length === 1 &&
gateway.plugins[ 0 ] === 'woocommerce-payments';
const isGatewayOtherCategory = ( gateway, countryCode ) =>
gateway.category_other &&
gateway.category_other.indexOf( countryCode ) !== -1;
const isGatewayAdditionalCategory = ( gateway, countryCode ) =>
gateway.category_additional &&
gateway.category_additional.indexOf( countryCode ) !== -1;
export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
const { updatePaymentGateway } = useDispatch( PAYMENT_GATEWAYS_STORE_NAME );
const {
@ -40,7 +52,10 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
paymentGatewaySuggestions,
installedPaymentGateways,
isResolving,
countryCode,
} = useSelect( ( select ) => {
const { getSettings } = select( SETTINGS_STORE_NAME );
const { general: settings = {} } = getSettings( 'general' );
return {
getPaymentGateway: select( PAYMENT_GATEWAYS_STORE_NAME )
.getPaymentGateway,
@ -54,6 +69,7 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
paymentGatewaySuggestions: select(
ONBOARDING_STORE_NAME
).getPaymentGatewaySuggestions(),
countryCode: getCountryCode( settings.woocommerce_default_country ),
};
}, [] );
@ -185,6 +201,27 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
return gateway;
}, [ isResolving, query, paymentGateways ] );
const isWCPayOrOtherCategoryDoneSetup = useMemo( () => {
for ( const [ , gateway ] of paymentGateways.entries() ) {
if ( ! gateway.installed || gateway.needsSetup ) {
continue;
}
if ( isGatewayWCPay( gateway ) ) {
return true;
}
if ( isGatewayOtherCategory( gateway, countryCode ) ) {
return true;
}
}
return false;
}, [ countryCode, paymentGateways ] );
const isWCPaySupported =
Array.from( paymentGateways.values() ).findIndex( isGatewayWCPay ) !==
-1;
const [ wcPayGateway, offlineGateways, additionalGateways ] = useMemo(
() =>
Array.from( paymentGateways.values() )
@ -206,14 +243,32 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
// WCPay is handled separately when not installed and configured
if (
gateway.plugins?.length === 1 &&
gateway.plugins[ 0 ] === 'woocommerce-payments' &&
isGatewayWCPay( gateway ) &&
! ( gateway.installed && ! gateway.needsSetup )
) {
wcPay.push( gateway );
} else if ( gateway.is_offline ) {
offline.push( gateway );
} else {
} else if ( gateway.enabled ) {
// Enabled gateways should be ignored.
} else if ( isWCPayOrOtherCategoryDoneSetup ) {
// If WCPay or "other" gateway is enabled in an WCPay-eligible country, only
// allow to list "additional" gateways.
if (
isGatewayAdditionalCategory(
gateway,
countryCode
)
) {
additional.push( gateway );
}
} else if ( ! isWCPaySupported ) {
// When WCPay-ineligible, just show all gateways.
additional.push( gateway );
} else if (
isGatewayOtherCategory( gateway, countryCode )
) {
// When nothing is set up and eligible for WCPay, only show "other" gateways.
additional.push( gateway );
}
@ -221,11 +276,14 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
},
[ [], [], [] ]
),
[ paymentGateways ]
[
countryCode,
isWCPaySupported,
isWCPayOrOtherCategoryDoneSetup,
paymentGateways,
]
);
const isEligibleWCPay = !! wcPayGateway.length;
const trackSeeMore = () => {
recordEvent( 'tasklist_payment_see_more', {} );
};
@ -254,23 +312,26 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
const additionalSection = !! additionalGateways.length && (
<List
heading={
isEligibleWCPay
? null
: __( 'Choose a payment provider', 'woocommerce' )
! wcPayGateway.length &&
__( 'Choose a payment provider', 'woocommerce' )
}
recommendation={ recommendation }
paymentGateways={ additionalGateways }
markConfigured={ markConfigured }
footerLink={
<Button
href={ SEE_MORE_LINK }
target="_blank"
onClick={ trackSeeMore }
isTertiary
>
{ __( 'See more', 'woocommerce' ) }
<ExternalIcon size={ 18 } />
</Button>
! isWCPayOrOtherCategoryDoneSetup && (
<Button
href={ getAdminLink(
'admin.php?page=wc-addons&section=payment-gateways'
) }
target="_blank"
onClick={ trackSeeMore }
isTertiary
>
{ __( 'See more', 'woocommerce' ) }
<ExternalIcon size={ 18 } />
</Button>
)
}
></List>
);
@ -288,7 +349,7 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
<div className="woocommerce-task-payments">
{ ! paymentGateways.size && <ListPlaceholder /> }
{ isEligibleWCPay ? (
{ wcPayGateway.length ? (
<>
<WCPaySuggestion paymentGateway={ wcPayGateway[ 0 ] } />
<Toggle

View File

@ -46,6 +46,10 @@
.components-card__divider:last-child {
display: none;
}
.woocommerce-task-payment-wcpay {
margin-bottom: 0;
}
}
// @todo This can be migrated into the PaymentMethod component once the payment-gateway-suggestions feature is enabled.

View File

@ -31,6 +31,8 @@ const paymentGatewaySuggestions = [
plugins: [ 'woocommerce-gateway-stripe' ],
is_visible: true,
recommendation_priority: 3,
category_other: [ 'US' ],
category_additional: [],
},
{
id: 'ppcp-gateway',
@ -41,6 +43,8 @@ const paymentGatewaySuggestions = [
'http://localhost:8888/wp-content/plugins/woocommerce/assets/images/paypal.png',
plugins: [ 'woocommerce-paypal-payments' ],
is_visible: true,
category_other: [ 'US' ],
category_additional: [ 'US' ],
},
{
id: 'cod',
@ -82,6 +86,8 @@ const paymentGatewaySuggestions = [
'http://localhost:8888/wp-content/plugins/woocommerce-admin/images/onboarding/eway.png',
plugins: [ 'woocommerce-gateway-eway' ],
is_visible: true,
category_other: [ 'US' ],
category_additional: [ 'US' ],
},
];
@ -140,7 +146,7 @@ describe( 'PaymentGatewaySuggestions', () => {
);
const paymentTitleElements = container.querySelectorAll(
'.woocommerce-task-payment__title'
'.woocommerce-task-payment__title > span:first-child'
);
const paymentTitles = Array.from( paymentTitleElements ).map(
@ -212,6 +218,49 @@ describe( 'PaymentGatewaySuggestions', () => {
expect( getByText( 'Finish setup' ) ).toBeInTheDocument();
} );
test( 'should show "category_additional" gateways only after WCPay is set up', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [
{
id: 'woocommerce_payments',
title: 'WooCommerce Payments',
plugins: [ 'woocommerce-payments' ],
is_visible: true,
needs_setup: false,
},
],
countryCode: 'US',
} ) );
const { container } = render(
<PaymentGatewaySuggestions
onComplete={ onComplete }
query={ query }
/>
);
const paymentTitleElements = container.querySelectorAll(
'.woocommerce-task-payment__title'
);
const paymentTitles = Array.from( paymentTitleElements ).map(
( e ) => e.textContent
);
expect( paymentTitles ).toEqual( [
'PayPal Payments',
'Eway',
'Cash on delivery',
'Direct bank transfer',
] );
} );
test( 'should record event correctly when finish setup is clicked', () => {
const onComplete = jest.fn();
const query = {};
@ -254,6 +303,7 @@ describe( 'PaymentGatewaySuggestions', () => {
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [],
countryCode: 'US',
} ) );
render(
@ -266,13 +316,16 @@ describe( 'PaymentGatewaySuggestions', () => {
fireEvent.click( screen.getByText( 'Other payment methods' ) );
// By default it's hidden, so when toggle it shows.
expect( recordEvent ).toHaveBeenCalledWith(
// Second call after "tasklist_payments_options".
expect(
recordEvent.mock.calls[ recordEvent.mock.calls.length - 1 ]
).toEqual( [
'tasklist_payment_show_toggle',
{
toggle: 'show',
payment_method_count: paymentGatewaySuggestions.length - 1, // Minus one for WCPay since it's not counted in "other payment methods".
}
);
},
] );
} );
test( 'should record event correctly when see more is clicked', () => {
@ -283,6 +336,7 @@ describe( 'PaymentGatewaySuggestions', () => {
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [],
countryCode: 'US',
} ) );
render(
@ -294,10 +348,8 @@ describe( 'PaymentGatewaySuggestions', () => {
fireEvent.click( screen.getByText( 'Other payment methods' ) );
fireEvent.click( screen.getByText( 'See more' ) );
expect( recordEvent ).toHaveBeenCalledWith(
'tasklist_payment_see_more',
{}
);
expect(
recordEvent.mock.calls[ recordEvent.mock.calls.length - 1 ]
).toEqual( [ 'tasklist_payment_see_more', {} ] );
} );
} );

View File

@ -14,6 +14,7 @@ import { getAdminLink } from '@woocommerce/settings';
import { close as closeIcon } from '@wordpress/icons';
import interpolateComponents from '@automattic/interpolate-components';
import { useEffect } from '@wordpress/element';
import { getQuery } from '@woocommerce/navigation';
/**
* Internal dependencies
@ -27,7 +28,7 @@ type ReminderBarProps = {
};
type ReminderTextProps = {
remainingCount: number;
remainingCount: number | null;
};
const REMINDER_BAR_HIDDEN_OPTION = 'woocommerce_task_list_reminder_bar_hidden';
@ -66,7 +67,6 @@ const ReminderText: React.FC< ReminderTextProps > = ( { remainingCount } ) => {
export const TasksReminderBar: React.FC< ReminderBarProps > = ( {
taskListId = 'setup_experiment_1',
pageTitle,
updateBodyMargin,
} ) => {
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
@ -119,13 +119,18 @@ export const TasksReminderBar: React.FC< ReminderBarProps > = ( {
};
} );
const isHomescreen =
getQuery().page && getQuery().page === 'wc-admin' && ! getQuery().path;
const isActiveTaskPage = Boolean( getQuery().wc_onboarding_active_task );
const hideReminderBar =
loading ||
taskListHidden ||
taskListComplete ||
reminderBarHidden ||
completedTasksCount === 0 ||
[ 'Home', 'Shipping', 'Tax', 'Payments' ].includes( pageTitle );
isHomescreen ||
isActiveTaskPage;
useEffect( () => {
updateBodyMargin();

View File

@ -23,6 +23,7 @@ import { SectionedTaskList } from '../two-column-tasks/sectioned-task-list';
import TwoColumnTaskListPlaceholder from '../two-column-tasks/placeholder';
import '../two-column-tasks/style.scss';
import { getAdminSetting } from '~/utils/admin-settings';
import { SectionedTaskListPlaceholder } from '~/two-column-tasks/sectioned-task-list-placeholder';
export type TasksProps = {
query: { task?: string };
@ -45,6 +46,8 @@ function getTaskListPlaceholderComponent(
switch ( taskListId ) {
case 'setup_experiment_1':
return TwoColumnTaskListPlaceholder;
case 'setup_experiment_2':
return SectionedTaskListPlaceholder;
default:
return TasksPlaceholder;
}

View File

@ -0,0 +1,75 @@
/**
* Internal dependencies
*/
import './style.scss';
type TasksPlaceholderProps = {
numTasks?: number;
query: {
task?: string;
};
};
const SectionedTaskListPlaceholder: React.FC< TasksPlaceholderProps > = (
props
) => {
const { numTasks = 3 } = props;
return (
<div
className={
'woocommerce-task-dashboard__container woocommerce-sectioned-task-list'
}
>
<div className="components-card is-size-large woocommerce-task-card woocommerce-homescreen-card is-loading ">
<div className="components-card__header is-size-medium">
<div className="wooocommerce-task-card__header">
<div className="is-placeholder"> </div>
</div>
</div>
<ul className="woocommerce-experimental-list">
{ Array.from( new Array( numTasks ) ).map( ( v, i ) => (
<li
tabIndex={ i }
key={ i }
className="woocommerce-experimental-list__item woocommerce-task-list__item"
>
<div className="woocommerce-task-list__item-before">
<div className="is-placeholder"></div>
</div>
<div className="woocommerce-task-list__item-text">
<div className="components-truncate components-text is-placeholder"></div>
</div>
</li>
) ) }
</ul>
</div>
<div className="is-loading components-panel__body woocommerce-task-card">
<div className="components-panel__body-title">
<div className="components-button components-panel__body-toggle">
<div className="woocommerce-task-list__item-text">
<div className="components-truncate components-text is-placeholder"></div>
</div>
<div className="woocommerce-task-list__item-after">
<div className="is-placeholder"></div>
</div>
</div>
</div>
</div>
<div className="is-loading components-panel__body woocommerce-task-card">
<div className="components-panel__body-title">
<div className="components-button components-panel__body-toggle">
<div className="woocommerce-task-list__item-text">
<div className="components-truncate components-text is-placeholder"></div>
</div>
<div className="woocommerce-task-list__item-after">
<div className="is-placeholder"></div>
</div>
</div>
</div>
</div>
</div>
);
};
export { SectionedTaskListPlaceholder };

View File

@ -63,7 +63,9 @@
pointer-events: none;
}
&:not(.is-complete) .woocommerce-task-list__item-before .woocommerce-task__icon {
&:not(.is-complete)
.woocommerce-task-list__item-before
.woocommerce-task__icon {
border-color: $gray-300;
}
}
@ -89,4 +91,31 @@
}
}
}
> .is-loading {
border: none;
margin-bottom: 8px;
.woocommerce-task-list__item .woocommerce-task-list__item-before {
padding: 0 0 0 $gap-large;
}
&.components-panel__body .components-panel__body-title .woocommerce-task-list__item-text {
width: 50%;
.is-placeholder {
width: 100%;
}
}
&.components-panel__body .woocommerce-task-list__item-after {
margin-left: $gap;
.is-placeholder {
height: 24px;
width: 24px;
border-radius: 50%;
}
}
}
}

View File

@ -35,7 +35,7 @@ const PanelBodyWithUpdatedType = PanelBody as React.ComponentType< PanelBodyProp
export const SectionedTaskList: React.FC< TaskListProps > = ( {
query,
id,
eventName,
eventPrefix,
tasks,
keepCompletedTaskList,
isComplete,
@ -66,7 +66,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
return;
}
recordEvent( `${ eventName }_view`, {
recordEvent( `${ eventPrefix }view`, {
number_tasks: visibleTasks.length,
store_connected: profileItems.wccom_connected,
} );
@ -122,7 +122,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
}
const trackClick = ( task: TaskType ) => {
recordEvent( `${ eventName }_click`, {
recordEvent( `${ eventPrefix }_click`, {
task_name: task.id,
} );
};
@ -182,10 +182,34 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
opened={ openPanel === section.id }
onToggle={ ( isOpen: boolean ) => {
if ( ! isOpen && openPanel === section.id ) {
recordEvent(
`${ eventPrefix }section_closed`,
{
id: section.id,
all: true,
}
);
setOpenPanel( null );
} else {
if ( openPanel ) {
recordEvent(
`${ eventPrefix }section_closed`,
{
id: openPanel,
all: false,
}
);
}
setOpenPanel( section.id );
}
if ( isOpen ) {
recordEvent(
`${ eventPrefix }section_opened`,
{
id: section.id,
}
);
}
} }
initialOpen={ false }
>

View File

@ -1,14 +1,14 @@
# Feature Flags
Features inside the `woocommerce-admin` repository can be in various states of completeness. In addition to the development copy of `woocommerce-admin`, feature plugin versions are bundled, and code is merged to WooCommerce core. To provide a way for improved control over how these features are released in these different environments, `woocommerce-admin` has a system for feature flags.
Features inside the `woocommerce` repository can be in various states of completeness. To provide a way for improved control over how these features are released in these different environments, `woocommerce` has a system for feature flags.
We currently support the following environments:
| Environment | Description |
|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| development | Development - All features should be enabled in development. These flags are also used in both JS and PHP tests. Ran using `pnpm start`. |
| plugin | Plugin - A packaged release of the featured plugin, for GitHub WordPress.org. | |
| core | Core - assets/files ready and stable enough for core merge. Ran using `pnpm pack`. (@todo).
| development | Development - All features should be enabled in development. These flags are also used in both JS and PHP tests. Ran using `pnpm start`. | |
| core | Core - assets/files ready and stable enough. Ran using `pnpm build` & `pnpm pack`.
## Adding a new flag

View File

@ -11,7 +11,7 @@
"scripts": {
"analyze": "cross-env NODE_ENV=production ANALYZE=true webpack",
"prebuild": "pnpm run install-if-deps-outdated",
"build": "pnpm run build:feature-config && cross-env NODE_ENV=production webpack",
"build": "WC_ADMIN_PHASE=core pnpm run build:feature-config && cross-env NODE_ENV=production WC_ADMIN_PHASE=core webpack",
"build-storybook": "build-storybook -c ./storybook/.storybook",
"build:feature-config": "php ../woocommerce/bin/generate-feature-config.php",
"build:packages": "cross-env NODE_ENV=production pnpm run:packages -- build",

View File

@ -8,14 +8,13 @@
/**
* Get phase for feature flags
* - development: All features should be enabled in development.
* - plugin: For the standalone feature plugin, for GitHub and WordPress.org.
* - core: Stable features for WooCommerce core merge.
*/
$phase = getenv( 'WC_ADMIN_PHASE' );
if ( ! in_array( $phase, array( 'development', 'plugin', 'core' ), true ) ) {
$phase = 'plugin'; // Default to plugin when running `pnpm run build`.
if ( ! in_array( $phase, array( 'development', 'core' ), true ) ) {
$phase = 'core'; // Default to core when running `pnpm run build`.
}
$config_json = file_get_contents( __DIR__ . '/../client/admin/config/' . $phase . '.json' );
$config = json_decode( $config_json );

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Remove Pinterest extension from OBW #32626

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fixing bug in which tasks reminder bar was displayed on product screens

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Added a temporary filter to patch the WCA JS packages i18n json files #32603

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Don't include draft orders in reports

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Pass `WC_ADMIN_PHASE=core` to build commands & remove "plugin" env

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Revert back menu position to floats as string for WP compatibility.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Update payment gateway logic in payment task

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Update payment method link to the internal extension marketplace

View File

@ -20,8 +20,6 @@
"store-alerts": true,
"transient-notices": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
"tasklist-setup-experiment-1": false,
"tasklist-setup-experiment-2": false
"wc-pay-welcome-page": true
}
}

View File

@ -20,8 +20,6 @@
"store-alerts": true,
"transient-notices": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
"tasklist-setup-experiment-1": false,
"tasklist-setup-experiment-2": false
"wc-pay-welcome-page": true
}
}

View File

@ -1,27 +0,0 @@
{
"features": {
"activity-panels": true,
"analytics": true,
"coupons": true,
"customer-effort-score-tracks": true,
"homescreen": true,
"marketing": true,
"minified-js": true,
"mobile-app-banner": true,
"navigation": true,
"onboarding": true,
"onboarding-tasks": true,
"remote-inbox-notifications": true,
"remote-free-extensions": true,
"payment-gateway-suggestions": true,
"settings": false,
"shipping-label-banner": true,
"subscriptions": true,
"store-alerts": true,
"transient-notices": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
"tasklist-setup-experiment-1": false,
"tasklist-setup-experiment-2": false
}
}

View File

@ -61,7 +61,7 @@ class WC_Admin_Menus {
$menu[] = array( '', 'read', 'separator-woocommerce', '', 'wp-menu-separator woocommerce' ); // WPCS: override ok.
}
add_menu_page( __( 'WooCommerce', 'woocommerce' ), __( 'WooCommerce', 'woocommerce' ), 'edit_others_shop_orders', 'woocommerce', null, $woocommerce_icon, 55 );
add_menu_page( __( 'WooCommerce', 'woocommerce' ), __( 'WooCommerce', 'woocommerce' ), 'edit_others_shop_orders', 'woocommerce', null, $woocommerce_icon, '55.5' );
add_submenu_page( 'edit.php?post_type=product', __( 'Attributes', 'woocommerce' ), __( 'Attributes', 'woocommerce' ), 'manage_product_terms', 'product_attributes', array( $this, 'attributes_page' ) );
}
@ -73,7 +73,7 @@ class WC_Admin_Menus {
if ( self::can_view_woocommerce_menu_item() ) {
add_submenu_page( 'woocommerce', __( 'Reports', 'woocommerce' ), __( 'Reports', 'woocommerce' ), 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ) );
} else {
add_menu_page( __( 'Sales reports', 'woocommerce' ), __( 'Sales reports', 'woocommerce' ), 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ), 'dashicons-chart-bar', 56 );
add_menu_page( __( 'Sales reports', 'woocommerce' ), __( 'Sales reports', 'woocommerce' ), 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ), 'dashicons-chart-bar', '55.6' );
}
}

View File

@ -209,13 +209,13 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
* See https://github.com/woocommerce/woocommerce/issues/32130 for more details.
*/
if ( WooCommercePayments::is_supported() ) {
$columns_count = count( $columns );
$columns_count = count( $columns );
$link_text = __( 'Other payment methods', 'woocommerce' );
$external_link_icon = '<svg style="margin-left: 4px" class="gridicon gridicons-external needs-offset" height="18" width="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>';
echo '<tr>';
// phpcs:ignore -- ignoring the error since the value is harded.
echo "<td style='border-top: 1px solid #c3c4c7; background-color: #fff' colspan='{$columns_count}'>";
echo "<a id='settings-other-payment-methods' href='https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations' target='_blank' class='components-button is-tertiary'>";
echo "<a id='settings-other-payment-methods' href='" . esc_url( admin_url( 'admin.php?page=wc-addons&section=payment-gateways' ) ) . "' target='_blank' class='components-button is-tertiary'>";
// phpcs:ignore
echo $link_text;
// phpcs:ignore

View File

@ -15,7 +15,7 @@
"preinstall": "npx only-allow pnpm",
"build": "./bin/build-zip.sh",
"build:feature-config": "php bin/generate-feature-config.php",
"build:core": "pnpm run build:feature-config && pnpm nx build woocommerce-admin && pnpm nx build woocommerce-legacy-assets && pnpm run makepot",
"build:core": "WC_ADMIN_PHASE=core pnpm run build:feature-config && pnpm nx build woocommerce-admin && pnpm nx build woocommerce-legacy-assets && pnpm run makepot",
"build:zip": "pnpm run build",
"lint:js": "eslint assets/js --ext=js",
"docker:down": "pnpx wc-e2e docker:down",

View File

@ -397,7 +397,6 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
'creative-mail-by-constant-contact',
'facebook-for-woocommerce',
'google-listings-and-ads',
'pinterest-for-woocommerce',
'mailpoet',
),
'type' => 'string',

View File

@ -577,7 +577,7 @@ class DataStore extends SqlQuery {
*/
protected static function get_excluded_report_order_statuses() {
$excluded_statuses = \WC_Admin_Settings::get_option( 'woocommerce_excluded_report_order_statuses', array( 'pending', 'failed', 'cancelled' ) );
$excluded_statuses = array_merge( array( 'trash' ), array_map( 'esc_sql', $excluded_statuses ) );
$excluded_statuses = array_merge( array( 'auto-draft', 'trash' ), array_map( 'esc_sql', $excluded_statuses ) );
return apply_filters( 'woocommerce_analytics_excluded_order_statuses', $excluded_statuses );
}

View File

@ -73,6 +73,33 @@ class TaskLists {
add_filter( 'woocommerce_admin_shared_settings', array( __CLASS__, 'task_list_preloaded_settings' ), 20 );
}
/**
* Check if an experiment is the treatment or control.
*
* @param string $name Name prefix of experiment.
* @return bool
*/
public static function is_experiment_treatment( $name ) {
$anon_id = isset( $_COOKIE['tk_ai'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['tk_ai'] ) ) : '';
$allow_tracking = 'yes' === get_option( 'woocommerce_allow_tracking' );
$abtest = new \WooCommerce\Admin\Experimental_Abtest(
$anon_id,
'woocommerce',
$allow_tracking
);
$date = new \DateTime();
$date->setTimeZone( new \DateTimeZone( 'UTC' ) );
$experiment_name = sprintf(
'%s_%s_%s',
$name,
$date->format( 'Y' ),
$date->format( 'm' )
);
return $abtest->get_variation( $experiment_name ) === 'treatment';
}
/**
* Initialize default lists.
*/
@ -93,7 +120,8 @@ class TaskLists {
'Appearance',
),
'event_prefix' => 'tasklist_',
'visible' => ! Features::is_enabled( 'tasklist-setup-experiment-1' ) && ! Features::is_enabled( 'tasklist-setup-experiment-2' ),
'visible' => ! self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_1' )
&& ! self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_2' ),
)
);
@ -117,7 +145,7 @@ class TaskLists {
'options' => array(
'use_completed_title' => true,
),
'visible' => Features::is_enabled( 'tasklist-setup-experiment-1' ),
'visible' => self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_1' ),
)
);
@ -138,7 +166,8 @@ class TaskLists {
'Appearance',
),
'event_prefix' => 'tasklist_',
'visible' => Features::is_enabled( 'tasklist-setup-experiment-2' ),
'visible' => self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_2' )
&& ! self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_1' ),
'options' => array(
'use_completed_title' => true,
),

View File

@ -25,161 +25,114 @@ class DefaultPaymentGateways {
'id' => 'payfast',
'title' => __( 'PayFast', 'woocommerce' ),
'content' => __( 'The PayFast extension for WooCommerce enables you to accept payments by Credit Card and EFT via one of South Africas most popular payment gateways. No setup fees or monthly subscription costs. Selecting this extension will configure your store to use South African rands as the selected currency.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/payfast.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payfast.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/payfast.png',
'plugins' => array( 'woocommerce-payfast-gateway' ),
'is_visible' => array(
(object) array(
'type' => 'base_location_country',
'value' => 'ZA',
'operation' => '=',
),
self::get_rules_for_countries( array( 'ZA', 'GH', 'NG' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'ZA', 'GH', 'NG' ),
'category_additional' => array(),
),
array(
'id' => 'stripe',
'title' => __( ' Stripe', 'woocommerce' ),
'content' => __( 'Accept debit and credit cards in 135+ currencies, methods such as Alipay, and one-touch checkout with Apple Pay.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/stripe.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/stripe.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/stripe.png',
'plugins' => array( 'woocommerce-gateway-stripe' ),
'is_visible' => array(
// https://stripe.com/global.
self::get_rules_for_countries(
array(
'AU',
'AT',
'BE',
'BG',
'BR',
'CA',
'CY',
'CZ',
'DK',
'EE',
'FI',
'FR',
'DE',
'GR',
'HK',
'IN',
'IE',
'IT',
'JP',
'LV',
'LT',
'LU',
'MY',
'MT',
'MX',
'NL',
'NZ',
'NO',
'PL',
'PT',
'RO',
'SG',
'SK',
'SI',
'ES',
'SE',
'CH',
'GB',
'US',
'PR',
)
array( 'AU', 'AT', 'BE', 'BG', 'BR', 'CA', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HK', 'IN', 'IE', 'IT', 'JP', 'LV', 'LT', 'LU', 'MY', 'MT', 'MX', 'NL', 'NZ', 'NO', 'PL', 'PT', 'RO', 'SG', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB', 'US', 'PR', 'HU', 'SL', 'ID', 'MY', 'SI', 'PR' )
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'AU', 'AT', 'BE', 'BG', 'BR', 'CA', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HK', 'IN', 'IE', 'IT', 'JP', 'LV', 'LT', 'LU', 'MY', 'MT', 'MX', 'NL', 'NZ', 'NO', 'PL', 'PT', 'RO', 'SG', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB', 'US', 'PR', 'HU', 'SL', 'ID', 'MY', 'SI', 'PR' ),
'category_additional' => array(),
'recommendation_priority' => 3,
),
array(
'id' => 'paystack',
'title' => __( 'Paystack', 'woocommerce' ),
'content' => __( 'Paystack helps African merchants accept one-time and recurring payments online with a modern, safe, and secure payment gateway.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/paystack.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/paystack.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/paystack.png',
'plugins' => array( 'woo-paystack' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'ZA', 'GH', 'NG' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'ZA', 'GH', 'NG' ),
'category_additional' => array(),
),
array(
'id' => 'kco',
'title' => __( 'Klarna Checkout', 'woocommerce' ),
'content' => __( 'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/klarna.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/klarna-black.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/klarna.png',
'plugins' => array( 'klarna-checkout-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'SE', 'FI', 'NO' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'SE', 'FI', 'NO' ),
'category_additional' => array(),
),
array(
'id' => 'klarna_payments',
'title' => __( 'Klarna Payments', 'woocommerce' ),
'content' => __( 'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/klarna.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/klarna-black.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/klarna.png',
'plugins' => array( 'klarna-payments-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries(
array(
'DK',
'DE',
'AT',
'NL',
'CH',
'BE',
'SP',
'PL',
'FR',
'IT',
'GB',
)
array( 'US', 'CA', 'DK', 'DE', 'AT', 'NL', 'CH', 'BE', 'SP', 'PL', 'FR', 'IT', 'GB', 'ES', 'FI', 'NO', 'SE', 'ES', 'FI', 'NO', 'SE' )
),
self::get_rules_for_cbd( false ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA', 'DK', 'DE', 'AT', 'NL', 'CH', 'BE', 'SP', 'PL', 'FR', 'IT', 'GB', 'ES', 'FI', 'NO', 'SE', 'ES', 'FI', 'NO', 'SE' ),
),
array(
'id' => 'mollie_wc_gateway_banktransfer',
'title' => __( 'Mollie', 'woocommerce' ),
'content' => __( 'Effortless payments by Mollie: Offer global and local payment methods, get onboarded in minutes, and supported in your language.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/mollie.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/mollie.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/mollie.png',
'plugins' => array( 'mollie-payments-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries(
array(
'FR',
'DE',
'GB',
'AT',
'CH',
'ES',
'IT',
'PL',
'FI',
'NL',
'BE',
)
array( 'FR', 'DE', 'GB', 'AT', 'CH', 'ES', 'IT', 'PL', 'FI', 'NL', 'BE' )
),
),
'category_other' => array( 'FR', 'DE', 'GB', 'AT', 'CH', 'ES', 'IT', 'PL', 'FI', 'NL', 'BE' ),
'category_additional' => array(),
),
array(
'id' => 'woo-mercado-pago-custom',
'title' => __( 'Mercado Pago Checkout Pro & Custom', 'woocommerce' ),
'content' => __( 'Accept credit and debit cards, offline (cash or bank transfer) and logged-in payments with money in Mercado Pago. Safe and secure payments with the leading payment processor in LATAM.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/mercadopago.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/mercadopago.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/mercadopago.png',
'plugins' => array( 'woocommerce-mercadopago' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ) ),
),
'recommendation_priority' => 2,
'is_local_partner' => true,
'category_other' => array( 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ),
'category_additional' => array(),
),
array(
'id' => 'ppcp-gateway',
'title' => __( 'PayPal Payments', 'woocommerce' ),
'content' => __( "Safe and secure payments using credit cards or your customer's PayPal account.", 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/paypal.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/paypal.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/paypal.png',
'plugins' => array( 'woocommerce-paypal-payments' ),
'is_visible' => array(
(object) array(
@ -189,12 +142,15 @@ class DefaultPaymentGateways {
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'US', 'CA', 'AT', 'BE', 'BG', 'HR', 'CH', 'CY', 'CZ', 'DK', 'EE', 'ES', 'FI', 'FR', 'DE', 'GB', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SL', 'SE', 'MX', 'BR', 'AR', 'CL', 'CO', 'EC', 'PE', 'UY', 'VE', 'AU', 'NZ', 'HK', 'JP', 'SG', 'CN', 'ID', 'ZA', 'NG', 'GH' ),
'category_additional' => array( 'US', 'CA', 'AT', 'BE', 'BG', 'HR', 'CH', 'CY', 'CZ', 'DK', 'EE', 'ES', 'FI', 'FR', 'DE', 'GB', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SL', 'SE', 'MX', 'BR', 'AR', 'CL', 'CO', 'EC', 'PE', 'UY', 'VE', 'AU', 'NZ', 'HK', 'JP', 'SG', 'CN', 'ID', 'IN', 'ZA', 'NG', 'GH' ),
),
array(
'id' => 'cod',
'title' => __( 'Cash on delivery', 'woocommerce' ),
'content' => __( 'Take payments in cash upon delivery.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/cod.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/cod.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/cod.png',
'is_visible' => array(
self::get_rules_for_cbd( false ),
),
@ -204,7 +160,8 @@ class DefaultPaymentGateways {
'id' => 'bacs',
'title' => __( 'Direct bank transfer', 'woocommerce' ),
'content' => __( 'Take payments via bank transfer.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/bacs.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/bacs.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/bacs.png',
'is_visible' => array(
self::get_rules_for_cbd( false ),
),
@ -218,6 +175,7 @@ class DefaultPaymentGateways {
'woocommerce'
),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'plugins' => array( 'woocommerce-payments' ),
'description' => 'With WooCommerce Payments, you can securely accept major cards, Apple Pay, and payments in over 100 currencies. Track cash flow and manage recurring revenue directly from your stores dashboard - with no setup costs or monthly fees.',
'is_visible' => array(
@ -260,6 +218,7 @@ class DefaultPaymentGateways {
'woocommerce'
),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'plugins' => array( 'woocommerce-payments' ),
'description' => 'With WooCommerce Payments, you can securely accept major cards, Apple Pay, and payments in over 100 currencies. Track cash flow and manage recurring revenue directly from your stores dashboard - with no setup costs or monthly fees.',
'is_visible' => array(
@ -294,6 +253,7 @@ class DefaultPaymentGateways {
'woocommerce'
),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'plugins' => array( 'woocommerce-payments' ),
'description' => 'With WooCommerce Payments, you can securely accept major cards, Apple Pay, and payments in over 100 currencies with no setup costs or monthly fees and you can now accept in-person payments with the Woo mobile app.',
'is_visible' => array(
@ -324,7 +284,8 @@ class DefaultPaymentGateways {
'id' => 'razorpay',
'title' => __( 'Razorpay', 'woocommerce' ),
'content' => __( 'The official Razorpay extension for WooCommerce allows you to accept credit cards, debit cards, netbanking, wallet, and UPI payments.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/razorpay.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/razorpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/razorpay.png',
'plugins' => array( 'woo-razorpay' ),
'is_visible' => array(
(object) array(
@ -334,12 +295,15 @@ class DefaultPaymentGateways {
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'IN' ),
'category_additional' => array(),
),
array(
'id' => 'payubiz',
'title' => __( 'PayU for WooCommerce', 'woocommerce' ),
'content' => __( 'Enable PayUs exclusive plugin for WooCommerce to start accepting payments in 100+ payment methods available in India including credit cards, debit cards, UPI, & more!', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/payu.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/payu.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/payu.png',
'plugins' => array( 'payu-india' ),
'is_visible' => array(
(object) array(
@ -349,23 +313,29 @@ class DefaultPaymentGateways {
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'IN' ),
'category_additional' => array(),
),
array(
'id' => 'eway',
'title' => __( 'Eway', 'woocommerce' ),
'content' => __( 'The Eway extension for WooCommerce allows you to take credit card payments directly on your store without redirecting your customers to a third party site to make payment.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/eway.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/eway.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/eway.png',
'plugins' => array( 'woocommerce-gateway-eway' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'AU', 'NZ' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'AU', 'NZ' ),
'category_additional' => array(),
),
array(
'id' => 'square_credit_card',
'title' => __( 'Square', 'woocommerce' ),
'content' => __( 'Securely accept credit and debit cards with one low rate, no surprise fees (custom rates available). Sell online and in store and track sales and inventory in one place.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/square.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/square-black.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/square.png',
'plugins' => array( 'woocommerce-square' ),
'is_visible' => array(
(object) array(
@ -376,12 +346,54 @@ class DefaultPaymentGateways {
self::get_rules_for_cbd( true ),
),
array(
self::get_rules_for_countries( array( 'US', 'CA', 'JP', 'GB', 'AU', 'IE', 'FR', 'ES' ) ),
self::get_rules_for_countries( array( 'US', 'CA', 'JP', 'GB', 'AU', 'IE', 'FR', 'ES', 'FI' ) ),
self::get_rules_for_selling_venues( array( 'brick-mortar', 'brick-mortar-other' ) ),
),
),
),
),
'category_other' => array( 'US', 'CA', 'JP', 'GB', 'AU', 'IE', 'FR', 'ES', 'FI' ),
'category_additional' => array(),
),
array(
'id' => 'afterpay',
'title' => __( 'Afterpay', 'woocommerce' ),
'content' => __( 'Afterpay allows customers to receive products immediately and pay for purchases over four installments, always interest-free.', 'woocommerce' ),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/afterpay.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/afterpay.png',
'plugins' => array( 'afterpay-gateway-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'US', 'CA' ) ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA' ),
),
array(
'id' => 'amazon_payments_advanced',
'title' => __( 'Amazon Pay', 'woocommerce' ),
'content' => __( 'Enable a familiar, fast checkout for hundreds of millions of active Amazon customers globally.', 'woocommerce' ),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/amazonpay.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/amazonpay.png',
'plugins' => array( 'woocommerce-gateway-amazon-payments-advanced' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'US', 'CA' ) ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA' ),
),
array(
'id' => 'affirm',
'title' => __( 'Affirm', 'woocommerce' ),
'content' => __( 'Affirms tailored Buy Now Pay Later programs remove price as a barrier, turning browsers into buyers, increasing average order value, and expanding your customer base.', 'woocommerce' ),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/affirm.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/affirm.png',
'plugins' => array(),
'external_link' => 'https://woocommerce.com/products/woocommerce-gateway-affirm',
'is_visible' => array(
self::get_rules_for_countries( array( 'US', 'CA' ) ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA' ),
),
);
}

View File

@ -36,7 +36,6 @@ class DefaultFreeExtensions {
'plugins' => [
self::get_plugin( 'mailpoet' ),
self::get_plugin( 'google-listings-and-ads' ),
self::get_plugin( 'pinterest-for-woocommerce' ),
],
],
[
@ -53,7 +52,7 @@ class DefaultFreeExtensions {
'title' => __( 'Grow your store', 'woocommerce' ),
'plugins' => [
self::get_plugin( 'google-listings-and-ads:alt' ),
self::get_plugin( 'pinterest-for-woocommerce:alt' ),
self::get_plugin( 'pinterest-for-woocommerce' ),
],
],
];
@ -100,30 +99,7 @@ class DefaultFreeExtensions {
'manage_url' => 'admin.php?page=wc-admin&path=%2Fgoogle%2Fstart',
'is_built_by_wc' => true,
],
'pinterest-for-woocommerce' => [
'name' => __( 'Pinterest for WooCommerce', 'woocommerce' ),
'description' => sprintf(
/* translators: 1: opening product link tag. 2: closing link tag */
__( 'Inspire shoppers with %1$sPinterest for WooCommerce%2$s', 'woocommerce' ),
'<a href="https://woocommerce.com/products/pinterest-for-woocommerce" target="_blank">',
'</a>'
),
'image_url' => plugins_url( '/assets/images/onboarding/pinterest.png', WC_PLUGIN_FILE ),
'manage_url' => 'admin.php?page=pinterest-for-woocommerce',
'is_visible' => [
[
'type' => 'not',
'operand' => [
[
'type' => 'plugins_activated',
'plugins' => [ 'pinterest-for-woocommerce' ],
],
],
],
],
'is_built_by_wc' => false,
],
'pinterest-for-woocommerce:alt' => [
'pinterest-for-woocommerce' => [
'name' => __( 'Pinterest for WooCommerce', 'woocommerce' ),
'description' => __( 'Get your products in front of Pinterest users searching for ideas and things to buy. Get started with Pinterest and make your entire product catalog browsable.', 'woocommerce' ),
'image_url' => plugins_url( '/assets/images/onboarding/pinterest.png', WC_PLUGIN_FILE ),

View File

@ -43,8 +43,40 @@ class Translations {
// Handler for WooCommerce and WooCommerce Admin plugin activation.
add_action( 'woocommerce_activated_plugin', array( $this, 'potentially_generate_translation_strings' ) );
add_action( 'activated_plugin', array( $this, 'potentially_generate_translation_strings' ) );
// Adding this filter to adjust the path after woocommerce-admin was merged into woocommerce core.
// Remove after the translations strings have been updated to the new path (probably woocommerce 6.6).
add_filter( 'load_script_textdomain_relative_path', array( $this, 'adjust_script_path' ), 10, 2 );
}
/**
* This filter is temporarily used to produce the correct i18n paths as they were moved in WC 6.5.
*
* @param string $relative Relative path to the script.
* @param string $src The script's source URL.
*/
public function adjust_script_path( $relative, $src ) {
// only rewrite the path if the translation file is from the old woocommerce-admin dist folder.
if ( false === strpos( $relative, 'assets/client/admin' ) ) {
return $relative;
}
// translation filenames are always based on the unminified path.
if ( substr( $relative, -7 ) === '.min.js' ) {
$relative = substr( $relative, 0, -7 ) . '.js';
}
$file_base = 'woocommerce-' . determine_locale(); // e.g woocommerce-fr_FR.
$md5_filename = $file_base . '-' . md5( $relative ) . '.json';
$languages_path = WP_LANG_DIR . '/plugins/'; // get path to translations folder.
if ( ! is_readable( $languages_path . $md5_filename ) ) {
return str_replace( 'assets/client/admin', 'packages/woocommerce-admin/dist', $relative );
} else {
return $relative;
}
}
/**
* Generate a filename to cache translations from JS chunks.
*
@ -101,8 +133,13 @@ class Translations {
// Only combine "app" files (not scripts registered with WP).
if (
// paths for woocommerce < 6.5. can be removed from 6.6 onwards or when i18n json file names are updated.
false === strpos( $reference_file, 'dist/chunks/' ) &&
false === strpos( $reference_file, 'dist/app/index.js' )
false === strpos( $reference_file, 'dist/app/index.js' ) &&
// paths for woocommerce >= 6.5 (post-merge of woocommerce-admin).
false === strpos( $reference_file, 'assets/admin/app/index.js' ) &&
false === strpos( $reference_file, 'assets/admin/chunks/' )
) {
continue;
}