mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-07 19:54:15 +08:00
Merge pull request #3139 from woocommerce/PCP-4244-add-logic-and-ui-visuals-for-conditional-disabled-state-for-payment-methods
Payment Methods: Add Dependency-Based Status Sync (4244)
This commit is contained in:
commit
8f9e305fa7
17 changed files with 748 additions and 112 deletions
|
@ -82,3 +82,85 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disabled state styling.
|
||||||
|
.ppcp--method-item--disabled {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
// Apply grayscale and disable interactions.
|
||||||
|
.ppcp--method-inner {
|
||||||
|
opacity: 0.7;
|
||||||
|
filter: grayscale(1);
|
||||||
|
pointer-events: none;
|
||||||
|
transition: filter 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override text colors.
|
||||||
|
.ppcp--method-title {
|
||||||
|
color: $color-gray-700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp--method-description p {
|
||||||
|
color: $color-gray-500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp--method-disabled-message {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-5px);
|
||||||
|
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style all buttons and toggle controls.
|
||||||
|
.components-button,
|
||||||
|
.components-form-toggle {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hover state - only blur the inner content.
|
||||||
|
&:hover {
|
||||||
|
.ppcp--method-inner {
|
||||||
|
filter: blur(2px) grayscale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp--method-disabled-message {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled overlay.
|
||||||
|
.ppcp--method-disabled-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba($color-white, 0.4);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 50;
|
||||||
|
border-radius: var(--container-border-radius);
|
||||||
|
pointer-events: auto;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp--method-item--disabled:hover .ppcp--method-disabled-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp--method-disabled-message {
|
||||||
|
padding: 14px 18px;
|
||||||
|
text-align: center;
|
||||||
|
@include font(13, 20, 500);
|
||||||
|
color: $color-text-tertiary;
|
||||||
|
position: relative;
|
||||||
|
z-index: 51;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ const PaymentMethodItemBlock = ( {
|
||||||
onTriggerModal,
|
onTriggerModal,
|
||||||
onSelect,
|
onSelect,
|
||||||
isSelected,
|
isSelected,
|
||||||
|
isDisabled,
|
||||||
|
disabledMessage,
|
||||||
} ) => {
|
} ) => {
|
||||||
const { activeHighlight, setActiveHighlight } = useActiveHighlight();
|
const { activeHighlight, setActiveHighlight } = useActiveHighlight();
|
||||||
const isHighlighted = activeHighlight === paymentMethod.id;
|
const isHighlighted = activeHighlight === paymentMethod.id;
|
||||||
|
@ -31,9 +33,16 @@ const PaymentMethodItemBlock = ( {
|
||||||
id={ paymentMethod.id }
|
id={ paymentMethod.id }
|
||||||
className={ `ppcp--method-item ${
|
className={ `ppcp--method-item ${
|
||||||
isHighlighted ? 'ppcp-highlight' : ''
|
isHighlighted ? 'ppcp-highlight' : ''
|
||||||
}` }
|
} ${ isDisabled ? 'ppcp--method-item--disabled' : '' }` }
|
||||||
separatorAndGap={ false }
|
separatorAndGap={ false }
|
||||||
>
|
>
|
||||||
|
{ isDisabled && (
|
||||||
|
<div className="ppcp--method-disabled-overlay">
|
||||||
|
<p className="ppcp--method-disabled-message">
|
||||||
|
{ disabledMessage }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
<div className="ppcp--method-inner">
|
<div className="ppcp--method-inner">
|
||||||
<div className="ppcp--method-title-wrapper">
|
<div className="ppcp--method-title-wrapper">
|
||||||
{ paymentMethod?.icon && (
|
{ paymentMethod?.icon && (
|
||||||
|
|
|
@ -19,12 +19,14 @@ const PaymentMethodsBlock = ( { paymentMethods = [], onTriggerModal } ) => {
|
||||||
<SettingsBlock className="ppcp--grid ppcp-r-settings-block__payment-methods">
|
<SettingsBlock className="ppcp--grid ppcp-r-settings-block__payment-methods">
|
||||||
{ paymentMethods
|
{ paymentMethods
|
||||||
// Remove empty/invalid payment method entries.
|
// Remove empty/invalid payment method entries.
|
||||||
.filter( ( m ) => m.id )
|
.filter( ( m ) => m && m.id )
|
||||||
.map( ( paymentMethod ) => (
|
.map( ( paymentMethod ) => (
|
||||||
<PaymentMethodItemBlock
|
<PaymentMethodItemBlock
|
||||||
key={ paymentMethod.id }
|
key={ paymentMethod.id }
|
||||||
paymentMethod={ paymentMethod }
|
paymentMethod={ paymentMethod }
|
||||||
isSelected={ paymentMethod.enabled }
|
isSelected={ paymentMethod.enabled }
|
||||||
|
isDisabled={ paymentMethod.isDisabled }
|
||||||
|
disabledMessage={ paymentMethod.disabledMessage }
|
||||||
onSelect={ ( checked ) =>
|
onSelect={ ( checked ) =>
|
||||||
handleSelect( paymentMethod.id, checked )
|
handleSelect( paymentMethod.id, checked )
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { createInterpolateElement } from '@wordpress/element';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { scrollAndHighlight } from '../../../../../utils/scrollAndHighlight';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to display a payment method dependency message
|
||||||
|
*
|
||||||
|
* @param {Object} props - Component props
|
||||||
|
* @param {string} props.parentId - ID of the parent payment method
|
||||||
|
* @param {string} props.parentName - Display name of the parent payment method
|
||||||
|
* @return {JSX.Element} The formatted message with link
|
||||||
|
*/
|
||||||
|
const DependencyMessage = ( { parentId, parentName } ) => {
|
||||||
|
// Using WordPress createInterpolateElement with proper React elements
|
||||||
|
return createInterpolateElement(
|
||||||
|
/* translators: %s: payment method name */
|
||||||
|
__(
|
||||||
|
'This payment method requires <methodLink /> to be enabled.',
|
||||||
|
'woocommerce-paypal-payments'
|
||||||
|
),
|
||||||
|
{
|
||||||
|
methodLink: (
|
||||||
|
<strong>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
onClick={ ( e ) => {
|
||||||
|
e.preventDefault();
|
||||||
|
scrollAndHighlight( parentId );
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
{ parentName }
|
||||||
|
</a>
|
||||||
|
</strong>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DependencyMessage;
|
|
@ -0,0 +1,71 @@
|
||||||
|
import SettingsCard from '../../../../ReusableComponents/SettingsCard';
|
||||||
|
import { PaymentMethodsBlock } from '../../../../ReusableComponents/SettingsBlocks';
|
||||||
|
import usePaymentDependencyState from '../../../../../hooks/usePaymentDependencyState';
|
||||||
|
import DependencyMessage from './DependencyMessage';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a payment method card with dependency handling
|
||||||
|
*
|
||||||
|
* @param {Object} props - Component props
|
||||||
|
* @param {string} props.id - Unique identifier for the card
|
||||||
|
* @param {string} props.title - Title of the payment method card
|
||||||
|
* @param {string} props.description - Description of the payment method
|
||||||
|
* @param {string} props.icon - Icon path for the payment method
|
||||||
|
* @param {Array} props.methods - List of payment methods to display
|
||||||
|
* @param {Object} props.methodsMap - Map of all payment methods by ID
|
||||||
|
* @param {Function} props.onTriggerModal - Callback when a method is clicked
|
||||||
|
* @param {boolean} props.isDisabled - Whether the entire card is disabled
|
||||||
|
* @param {(string|JSX.Element)} props.disabledMessage - Message to show when disabled
|
||||||
|
* @return {JSX.Element} The rendered component
|
||||||
|
*/
|
||||||
|
const PaymentMethodCard = ( {
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
icon,
|
||||||
|
methods,
|
||||||
|
methodsMap = {},
|
||||||
|
onTriggerModal,
|
||||||
|
isDisabled = false,
|
||||||
|
disabledMessage,
|
||||||
|
} ) => {
|
||||||
|
const dependencyState = usePaymentDependencyState( methods, methodsMap );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsCard
|
||||||
|
id={ id }
|
||||||
|
title={ title }
|
||||||
|
description={ description }
|
||||||
|
icon={ icon }
|
||||||
|
contentContainer={ false }
|
||||||
|
>
|
||||||
|
<PaymentMethodsBlock
|
||||||
|
paymentMethods={ methods.map( ( method ) => {
|
||||||
|
const dependency = dependencyState[ method.id ];
|
||||||
|
|
||||||
|
const dependencyMessage = dependency ? (
|
||||||
|
<DependencyMessage
|
||||||
|
parentId={ dependency.parentId }
|
||||||
|
parentName={ dependency.parentName }
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...method,
|
||||||
|
isDisabled:
|
||||||
|
method.isDisabled ||
|
||||||
|
isDisabled ||
|
||||||
|
Boolean( dependency?.isDisabled ),
|
||||||
|
disabledMessage:
|
||||||
|
method.disabledMessage ||
|
||||||
|
dependencyMessage ||
|
||||||
|
disabledMessage,
|
||||||
|
};
|
||||||
|
} ) }
|
||||||
|
onTriggerModal={ onTriggerModal }
|
||||||
|
/>
|
||||||
|
</SettingsCard>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaymentMethodCard;
|
|
@ -1,17 +1,23 @@
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useCallback } from '@wordpress/element';
|
import { useCallback } from '@wordpress/element';
|
||||||
|
|
||||||
import SettingsCard from '../../../ReusableComponents/SettingsCard';
|
|
||||||
import { PaymentMethodsBlock } from '../../../ReusableComponents/SettingsBlocks';
|
|
||||||
import { CommonHooks, OnboardingHooks, PaymentHooks } from '../../../../data';
|
import { CommonHooks, OnboardingHooks, PaymentHooks } from '../../../../data';
|
||||||
import { useActiveModal } from '../../../../data/common/hooks';
|
import { useActiveModal } from '../../../../data/common/hooks';
|
||||||
import Modal from '../Components/Payment/Modal';
|
import Modal from '../Components/Payment/Modal';
|
||||||
|
import PaymentMethodCard from '../Components/Payment/PaymentMethodCard';
|
||||||
|
|
||||||
const TabPaymentMethods = () => {
|
const TabPaymentMethods = () => {
|
||||||
const methods = PaymentHooks.usePaymentMethods();
|
const methods = PaymentHooks.usePaymentMethods();
|
||||||
const { setPersistent, changePaymentSettings } = PaymentHooks.useStore();
|
const store = PaymentHooks.useStore();
|
||||||
|
const { setPersistent, changePaymentSettings } = store;
|
||||||
const { activeModal, setActiveModal } = useActiveModal();
|
const { activeModal, setActiveModal } = useActiveModal();
|
||||||
|
|
||||||
|
// Get all methods as a map for dependency checking
|
||||||
|
const methodsMap = {};
|
||||||
|
methods.all.forEach( ( method ) => {
|
||||||
|
methodsMap[ method.id ] = method;
|
||||||
|
} );
|
||||||
|
|
||||||
const getActiveMethod = () => {
|
const getActiveMethod = () => {
|
||||||
if ( ! activeModal ) {
|
if ( ! activeModal ) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -60,6 +66,7 @@ const TabPaymentMethods = () => {
|
||||||
icon="icon-checkout-standard.svg"
|
icon="icon-checkout-standard.svg"
|
||||||
methods={ methods.paypal }
|
methods={ methods.paypal }
|
||||||
onTriggerModal={ setActiveModal }
|
onTriggerModal={ setActiveModal }
|
||||||
|
methodsMap={ methodsMap }
|
||||||
/>
|
/>
|
||||||
{ merchant.isBusinessSeller && canUseCardPayments && (
|
{ merchant.isBusinessSeller && canUseCardPayments && (
|
||||||
<PaymentMethodCard
|
<PaymentMethodCard
|
||||||
|
@ -75,6 +82,7 @@ const TabPaymentMethods = () => {
|
||||||
icon="icon-checkout-online-methods.svg"
|
icon="icon-checkout-online-methods.svg"
|
||||||
methods={ methods.cardPayment }
|
methods={ methods.cardPayment }
|
||||||
onTriggerModal={ setActiveModal }
|
onTriggerModal={ setActiveModal }
|
||||||
|
methodsMap={ methodsMap }
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
<PaymentMethodCard
|
<PaymentMethodCard
|
||||||
|
@ -90,6 +98,7 @@ const TabPaymentMethods = () => {
|
||||||
icon="icon-checkout-alternative-methods.svg"
|
icon="icon-checkout-alternative-methods.svg"
|
||||||
methods={ methods.apm }
|
methods={ methods.apm }
|
||||||
onTriggerModal={ setActiveModal }
|
onTriggerModal={ setActiveModal }
|
||||||
|
methodsMap={ methodsMap }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{ activeModal && (
|
{ activeModal && (
|
||||||
|
@ -104,25 +113,3 @@ const TabPaymentMethods = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TabPaymentMethods;
|
export default TabPaymentMethods;
|
||||||
|
|
||||||
const PaymentMethodCard = ( {
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
icon,
|
|
||||||
methods,
|
|
||||||
onTriggerModal,
|
|
||||||
} ) => (
|
|
||||||
<SettingsCard
|
|
||||||
id={ id }
|
|
||||||
title={ title }
|
|
||||||
description={ description }
|
|
||||||
icon={ icon }
|
|
||||||
contentContainer={ false }
|
|
||||||
>
|
|
||||||
<PaymentMethodsBlock
|
|
||||||
paymentMethods={ methods }
|
|
||||||
onTriggerModal={ onTriggerModal }
|
|
||||||
/>
|
|
||||||
</SettingsCard>
|
|
||||||
);
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
export default {
|
export default {
|
||||||
// Transient data.
|
// Transient data.
|
||||||
SET_TRANSIENT: 'PAYMENT:SET_TRANSIENT',
|
SET_TRANSIENT: 'PAYMENT:SET_TRANSIENT',
|
||||||
|
SET_DISABLED_BY_DEPENDENCY: 'PAYMENT:SET_DISABLED_BY_DEPENDENCY',
|
||||||
|
RESTORE_DEPENDENCY_STATE: 'PAYMENT:RESTORE_DEPENDENCY_STATE',
|
||||||
|
|
||||||
// Persistent data.
|
// Persistent data.
|
||||||
SET_PERSISTENT: 'PAYMENT:SET_PERSISTENT',
|
SET_PERSISTENT: 'PAYMENT:SET_PERSISTENT',
|
||||||
|
|
|
@ -7,6 +7,7 @@ import * as actions from './actions';
|
||||||
import * as hooks from './hooks';
|
import * as hooks from './hooks';
|
||||||
import * as resolvers from './resolvers';
|
import * as resolvers from './resolvers';
|
||||||
import { initTodoSync } from '../sync/todo-state-sync';
|
import { initTodoSync } from '../sync/todo-state-sync';
|
||||||
|
import { initPaymentDependencySync } from '../sync/payment-methods-sync';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes and registers the settings store with WordPress data layer.
|
* Initializes and registers the settings store with WordPress data layer.
|
||||||
|
@ -24,9 +25,12 @@ export const initStore = () => {
|
||||||
|
|
||||||
register( store );
|
register( store );
|
||||||
|
|
||||||
// Initialize todo sync after store registration. Potentially should be moved elsewhere.
|
// Initialize todo sync after store registration.
|
||||||
initTodoSync();
|
initTodoSync();
|
||||||
|
|
||||||
|
// Initialize payment method dependency sync.
|
||||||
|
initPaymentDependencySync();
|
||||||
|
|
||||||
return Boolean( wp.data.select( STORE_NAME ) );
|
return Boolean( wp.data.select( STORE_NAME ) );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,56 @@ const reducer = createReducer( defaultTransient, defaultPersistent, {
|
||||||
|
|
||||||
[ ACTION_TYPES.HYDRATE ]: ( state, payload ) =>
|
[ ACTION_TYPES.HYDRATE ]: ( state, payload ) =>
|
||||||
changePersistent( state, payload.data ),
|
changePersistent( state, payload.data ),
|
||||||
|
|
||||||
|
[ ACTION_TYPES.SET_DISABLED_BY_DEPENDENCY ]: ( state, payload ) => {
|
||||||
|
const { methodId } = payload;
|
||||||
|
const method = state.data[ methodId ];
|
||||||
|
|
||||||
|
if ( ! method ) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new state with the method disabled due to dependency
|
||||||
|
const updatedData = {
|
||||||
|
...state.data,
|
||||||
|
[ methodId ]: {
|
||||||
|
...method,
|
||||||
|
enabled: false,
|
||||||
|
_disabledByDependency: true,
|
||||||
|
_originalState: method.enabled,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
data: updatedData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
[ ACTION_TYPES.RESTORE_DEPENDENCY_STATE ]: ( state, payload ) => {
|
||||||
|
const { methodId } = payload;
|
||||||
|
const method = state.data[ methodId ];
|
||||||
|
|
||||||
|
if ( ! method || ! method._disabledByDependency ) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the method to its original state
|
||||||
|
const updatedData = {
|
||||||
|
...state.data,
|
||||||
|
[ methodId ]: {
|
||||||
|
...method,
|
||||||
|
enabled: method._originalState === true,
|
||||||
|
_disabledByDependency: false,
|
||||||
|
_originalState: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
data: updatedData,
|
||||||
|
};
|
||||||
|
},
|
||||||
} );
|
} );
|
||||||
|
|
||||||
export default reducer;
|
export default reducer;
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
import { subscribe, select } from '@wordpress/data';
|
||||||
|
|
||||||
|
// Store name
|
||||||
|
const PAYMENT_STORE = 'wc/paypal/payment';
|
||||||
|
|
||||||
|
// Track original states of dependent methods
|
||||||
|
const originalStates = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize payment method dependency synchronization
|
||||||
|
*/
|
||||||
|
export const initPaymentDependencySync = () => {
|
||||||
|
let previousPaymentState = null;
|
||||||
|
let isProcessing = false;
|
||||||
|
|
||||||
|
const unsubscribe = subscribe( () => {
|
||||||
|
if ( isProcessing ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isProcessing = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const paymentHooks = select( PAYMENT_STORE );
|
||||||
|
if ( ! paymentHooks ) {
|
||||||
|
isProcessing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const methods = paymentHooks.persistentData();
|
||||||
|
if ( ! methods ) {
|
||||||
|
isProcessing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! previousPaymentState ) {
|
||||||
|
previousPaymentState = { ...methods };
|
||||||
|
isProcessing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const changedMethods = Object.keys( methods )
|
||||||
|
.filter(
|
||||||
|
( key ) =>
|
||||||
|
key !== '__meta' &&
|
||||||
|
methods[ key ] &&
|
||||||
|
previousPaymentState[ key ]
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
( methodId ) =>
|
||||||
|
methods[ methodId ].enabled !==
|
||||||
|
previousPaymentState[ methodId ].enabled
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( changedMethods.length > 0 ) {
|
||||||
|
changedMethods.forEach( ( changedId ) => {
|
||||||
|
const isNowEnabled = methods[ changedId ].enabled;
|
||||||
|
|
||||||
|
const dependents = Object.entries( methods )
|
||||||
|
.filter(
|
||||||
|
( [ key, method ] ) =>
|
||||||
|
key !== '__meta' &&
|
||||||
|
method &&
|
||||||
|
method.depends_on &&
|
||||||
|
method.depends_on.includes( changedId )
|
||||||
|
)
|
||||||
|
.map( ( [ key ] ) => key );
|
||||||
|
|
||||||
|
if ( dependents.length > 0 ) {
|
||||||
|
if ( ! isNowEnabled ) {
|
||||||
|
handleDisableDependents( dependents, methods );
|
||||||
|
} else {
|
||||||
|
handleRestoreDependents( dependents, methods );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPaymentState = { ...methods };
|
||||||
|
} catch ( error ) {
|
||||||
|
// Keep error handling without the console.error
|
||||||
|
} finally {
|
||||||
|
isProcessing = false;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDisableDependents = ( dependentIds, methods ) => {
|
||||||
|
dependentIds.forEach( ( methodId ) => {
|
||||||
|
if ( methods[ methodId ] ) {
|
||||||
|
if ( ! ( methodId in originalStates ) ) {
|
||||||
|
originalStates[ methodId ] = methods[ methodId ].enabled;
|
||||||
|
}
|
||||||
|
methods[ methodId ].enabled = false;
|
||||||
|
methods[ methodId ].isDisabled = true;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRestoreDependents = ( dependentIds, methods ) => {
|
||||||
|
dependentIds.forEach( ( methodId ) => {
|
||||||
|
if (
|
||||||
|
methods[ methodId ] &&
|
||||||
|
methodId in originalStates &&
|
||||||
|
checkAllDependenciesSatisfied( methodId, methods )
|
||||||
|
) {
|
||||||
|
methods[ methodId ].enabled = originalStates[ methodId ];
|
||||||
|
methods[ methodId ].isDisabled = false;
|
||||||
|
delete originalStates[ methodId ];
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkAllDependenciesSatisfied = ( methodId, methods ) => {
|
||||||
|
const method = methods[ methodId ];
|
||||||
|
if ( ! method || ! method.depends_on ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! method.depends_on.some( ( parentId ) => {
|
||||||
|
const parent = methods[ parentId ];
|
||||||
|
return ! parent || parent.enabled === false;
|
||||||
|
} );
|
||||||
|
};
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the display name for a parent payment method
|
||||||
|
*
|
||||||
|
* @param {string} parentId - ID of the parent payment method
|
||||||
|
* @param {Object} methodsMap - Map of all payment methods by ID
|
||||||
|
* @return {string} The display name to use for the parent method
|
||||||
|
*/
|
||||||
|
const getParentMethodName = ( parentId, methodsMap ) => {
|
||||||
|
const parentMethod = methodsMap[ parentId ];
|
||||||
|
return parentMethod
|
||||||
|
? parentMethod.itemTitle || parentMethod.title || ''
|
||||||
|
: '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds disabled parent dependencies for a method
|
||||||
|
*
|
||||||
|
* @param {Object} method - The payment method to check
|
||||||
|
* @param {Object} methodsMap - Map of all payment methods by ID
|
||||||
|
* @return {Array} List of disabled parent IDs, empty if none
|
||||||
|
*/
|
||||||
|
const findDisabledParents = ( method, methodsMap ) => {
|
||||||
|
if ( ! method.depends_on?.length && ! method._disabledByDependency ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parents = method.depends_on || [];
|
||||||
|
|
||||||
|
return parents.filter( ( parentId ) => {
|
||||||
|
const parent = methodsMap[ parentId ];
|
||||||
|
return parent && ! parent.enabled;
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook to handle payment method dependencies
|
||||||
|
*
|
||||||
|
* @param {Array} methods - List of payment methods
|
||||||
|
* @param {Object} methodsMap - Map of payment methods by ID
|
||||||
|
* @return {Object} Dependency state object with methods that should be disabled
|
||||||
|
*/
|
||||||
|
const usePaymentDependencyState = ( methods, methodsMap ) => {
|
||||||
|
return useSelect(
|
||||||
|
( select ) => {
|
||||||
|
const paymentStore = select( 'wc/paypal/payment' );
|
||||||
|
if ( ! paymentStore ) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {};
|
||||||
|
|
||||||
|
methods.forEach( ( method ) => {
|
||||||
|
const disabledParents = findDisabledParents(
|
||||||
|
method,
|
||||||
|
methodsMap
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( disabledParents.length > 0 ) {
|
||||||
|
const parentId = disabledParents[ 0 ];
|
||||||
|
const parentName = getParentMethodName(
|
||||||
|
parentId,
|
||||||
|
methodsMap
|
||||||
|
);
|
||||||
|
|
||||||
|
result[ method.id ] = {
|
||||||
|
isDisabled: true,
|
||||||
|
parentId,
|
||||||
|
parentName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
[ methods, methodsMap ]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default usePaymentDependencyState;
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* Scroll to a specific element and highlight it
|
||||||
|
*
|
||||||
|
* @param {string} elementId - ID of the element to scroll to
|
||||||
|
* @param {boolean} [highlight=true] - Whether to highlight the element
|
||||||
|
* @return {Promise} - Resolves when scroll and highlight are complete
|
||||||
|
*/
|
||||||
|
export const scrollAndHighlight = ( elementId, highlight = true ) => {
|
||||||
|
return new Promise( ( resolve ) => {
|
||||||
|
const scrollTarget = document.getElementById( elementId );
|
||||||
|
|
||||||
|
if ( scrollTarget ) {
|
||||||
|
const navContainer = document.querySelector(
|
||||||
|
'.ppcp-r-navigation-container'
|
||||||
|
);
|
||||||
|
const navHeight = navContainer ? navContainer.offsetHeight : 0;
|
||||||
|
|
||||||
|
// Get the current scroll position and element's position relative to viewport
|
||||||
|
const rect = scrollTarget.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Calculate the final position with offset
|
||||||
|
const scrollPosition =
|
||||||
|
rect.top + window.scrollY - ( navHeight + 55 );
|
||||||
|
|
||||||
|
window.scrollTo( {
|
||||||
|
top: scrollPosition,
|
||||||
|
behavior: 'smooth',
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Add highlight if requested
|
||||||
|
if ( highlight ) {
|
||||||
|
scrollTarget.classList.add( 'ppcp-highlight' );
|
||||||
|
|
||||||
|
// Remove highlight after animation
|
||||||
|
setTimeout( () => {
|
||||||
|
scrollTarget.classList.remove( 'ppcp-highlight' );
|
||||||
|
}, 2000 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve after scroll animation
|
||||||
|
setTimeout( resolve, 300 );
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`Failed to scroll: Element with ID "${ elementId }" not found`
|
||||||
|
);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
};
|
|
@ -7,6 +7,8 @@ export const TAB_IDS = {
|
||||||
PAY_LATER_MESSAGING: 'tab-panel-0-pay-later-messaging',
|
PAY_LATER_MESSAGING: 'tab-panel-0-pay-later-messaging',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
import { scrollAndHighlight } from './scrollAndHighlight';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select a tab by simulating a click event and scroll to specified element,
|
* Select a tab by simulating a click event and scroll to specified element,
|
||||||
* accounting for navigation container height
|
* accounting for navigation container height
|
||||||
|
@ -23,40 +25,8 @@ export const selectTab = ( tabId, scrollToId ) => {
|
||||||
if ( tab ) {
|
if ( tab ) {
|
||||||
tab.click();
|
tab.click();
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
const scrollTarget = scrollToId
|
const targetId = scrollToId || 'ppcp-settings-container';
|
||||||
? document.getElementById( scrollToId )
|
scrollAndHighlight( targetId, false ).then( resolve );
|
||||||
: document.getElementById( 'ppcp-settings-container' );
|
|
||||||
|
|
||||||
if ( scrollTarget ) {
|
|
||||||
const navContainer = document.querySelector(
|
|
||||||
'.ppcp-r-navigation-container'
|
|
||||||
);
|
|
||||||
const navHeight = navContainer
|
|
||||||
? navContainer.offsetHeight
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
// Get the current scroll position and element's position relative to viewport
|
|
||||||
const rect = scrollTarget.getBoundingClientRect();
|
|
||||||
|
|
||||||
// Calculate the final position with offset
|
|
||||||
const scrollPosition =
|
|
||||||
rect.top + window.scrollY - ( navHeight + 55 );
|
|
||||||
|
|
||||||
window.scrollTo( {
|
|
||||||
top: scrollPosition,
|
|
||||||
behavior: 'smooth',
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Resolve after scroll animation
|
|
||||||
setTimeout( resolve, 300 );
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
`Failed to scroll: Element with ID "${
|
|
||||||
scrollToId || 'ppcp-settings-container'
|
|
||||||
}" not found`
|
|
||||||
);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}, 100 );
|
}, 100 );
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Settings;
|
||||||
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||||
use WooCommerce\PayPalCommerce\Settings\Ajax\SwitchSettingsUiEndpoint;
|
use WooCommerce\PayPalCommerce\Settings\Ajax\SwitchSettingsUiEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Settings\Data\Definition\PaymentMethodsDependenciesDefinition;
|
||||||
use WooCommerce\PayPalCommerce\Settings\Data\GeneralSettings;
|
use WooCommerce\PayPalCommerce\Settings\Data\GeneralSettings;
|
||||||
use WooCommerce\PayPalCommerce\Settings\Data\OnboardingProfile;
|
use WooCommerce\PayPalCommerce\Settings\Data\OnboardingProfile;
|
||||||
use WooCommerce\PayPalCommerce\Settings\Data\PaymentSettings;
|
use WooCommerce\PayPalCommerce\Settings\Data\PaymentSettings;
|
||||||
|
@ -46,7 +47,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\ConnectionState;
|
use WooCommerce\PayPalCommerce\WcGateway\Helper\ConnectionState;
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'settings.url' => static function ( ContainerInterface $container ) : string {
|
'settings.url' => static function ( ContainerInterface $container ) : string {
|
||||||
/**
|
/**
|
||||||
* The path cannot be false.
|
* The path cannot be false.
|
||||||
*
|
*
|
||||||
|
@ -57,7 +58,7 @@ return array(
|
||||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.onboarding' => static function ( ContainerInterface $container ) : OnboardingProfile {
|
'settings.data.onboarding' => static function ( ContainerInterface $container ) : OnboardingProfile {
|
||||||
$can_use_casual_selling = $container->get( 'settings.casual-selling.eligible' );
|
$can_use_casual_selling = $container->get( 'settings.casual-selling.eligible' );
|
||||||
$can_use_vaulting = $container->has( 'save-payment-methods.eligible' ) && $container->get( 'save-payment-methods.eligible' );
|
$can_use_vaulting = $container->has( 'save-payment-methods.eligible' ) && $container->get( 'save-payment-methods.eligible' );
|
||||||
$can_use_card_payments = $container->has( 'card-fields.eligible' ) && $container->get( 'card-fields.eligible' );
|
$can_use_card_payments = $container->has( 'card-fields.eligible' ) && $container->get( 'card-fields.eligible' );
|
||||||
|
@ -77,27 +78,27 @@ return array(
|
||||||
$can_use_subscriptions
|
$can_use_subscriptions
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.general' => static function ( ContainerInterface $container ) : GeneralSettings {
|
'settings.data.general' => static function ( ContainerInterface $container ) : GeneralSettings {
|
||||||
return new GeneralSettings(
|
return new GeneralSettings(
|
||||||
$container->get( 'api.shop.country' ),
|
$container->get( 'api.shop.country' ),
|
||||||
$container->get( 'api.shop.currency.getter' )->get(),
|
$container->get( 'api.shop.currency.getter' )->get(),
|
||||||
$container->get( 'wcgateway.is-send-only-country' )
|
$container->get( 'wcgateway.is-send-only-country' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.styling' => static function ( ContainerInterface $container ) : StylingSettings {
|
'settings.data.styling' => static function ( ContainerInterface $container ) : StylingSettings {
|
||||||
return new StylingSettings(
|
return new StylingSettings(
|
||||||
$container->get( 'settings.service.sanitizer' )
|
$container->get( 'settings.service.sanitizer' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.payment' => static function ( ContainerInterface $container ) : PaymentSettings {
|
'settings.data.payment' => static function ( ContainerInterface $container ) : PaymentSettings {
|
||||||
return new PaymentSettings();
|
return new PaymentSettings();
|
||||||
},
|
},
|
||||||
'settings.data.settings' => static function ( ContainerInterface $container ) : SettingsModel {
|
'settings.data.settings' => static function ( ContainerInterface $container ) : SettingsModel {
|
||||||
return new SettingsModel(
|
return new SettingsModel(
|
||||||
$container->get( 'settings.service.sanitizer' )
|
$container->get( 'settings.service.sanitizer' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.paylater-messaging' => static function ( ContainerInterface $container ) : array {
|
'settings.data.paylater-messaging' => static function ( ContainerInterface $container ) : array {
|
||||||
// TODO: Create an AbstractDataModel wrapper for this configuration!
|
// TODO: Create an AbstractDataModel wrapper for this configuration!
|
||||||
|
|
||||||
$config_factors = $container->get( 'paylater-configurator.factory.config' );
|
$config_factors = $container->get( 'paylater-configurator.factory.config' );
|
||||||
|
@ -121,7 +122,7 @@ return array(
|
||||||
* (onboarding/connected) and connection-aware environment checks.
|
* (onboarding/connected) and connection-aware environment checks.
|
||||||
* This is the preferred solution to check environment and connection state.
|
* This is the preferred solution to check environment and connection state.
|
||||||
*/
|
*/
|
||||||
'settings.connection-state' => static function ( ContainerInterface $container ) : ConnectionState {
|
'settings.connection-state' => static function ( ContainerInterface $container ) : ConnectionState {
|
||||||
$data = $container->get( 'settings.data.general' );
|
$data = $container->get( 'settings.data.general' );
|
||||||
assert( $data instanceof GeneralSettings );
|
assert( $data instanceof GeneralSettings );
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ return array(
|
||||||
|
|
||||||
return new ConnectionState( $is_connected, $environment );
|
return new ConnectionState( $is_connected, $environment );
|
||||||
},
|
},
|
||||||
'settings.environment' => static function ( ContainerInterface $container ) : Environment {
|
'settings.environment' => static function ( ContainerInterface $container ) : Environment {
|
||||||
// We should remove this service in favor of directly using `settings.connection-state`.
|
// We should remove this service in favor of directly using `settings.connection-state`.
|
||||||
$state = $container->get( 'settings.connection-state' );
|
$state = $container->get( 'settings.connection-state' );
|
||||||
assert( $state instanceof ConnectionState );
|
assert( $state instanceof ConnectionState );
|
||||||
|
@ -140,7 +141,7 @@ return array(
|
||||||
/**
|
/**
|
||||||
* Checks if valid merchant connection details are stored in the DB.
|
* Checks if valid merchant connection details are stored in the DB.
|
||||||
*/
|
*/
|
||||||
'settings.flag.is-connected' => static function ( ContainerInterface $container ) : bool {
|
'settings.flag.is-connected' => static function ( ContainerInterface $container ) : bool {
|
||||||
/*
|
/*
|
||||||
* This service only resolves the connection status once per request.
|
* This service only resolves the connection status once per request.
|
||||||
* We should remove this service in favor of directly using `settings.connection-state`.
|
* We should remove this service in favor of directly using `settings.connection-state`.
|
||||||
|
@ -153,7 +154,7 @@ return array(
|
||||||
/**
|
/**
|
||||||
* Checks if the merchant is connected to a sandbox environment.
|
* Checks if the merchant is connected to a sandbox environment.
|
||||||
*/
|
*/
|
||||||
'settings.flag.is-sandbox' => static function ( ContainerInterface $container ) : bool {
|
'settings.flag.is-sandbox' => static function ( ContainerInterface $container ) : bool {
|
||||||
/*
|
/*
|
||||||
* This service only resolves the sandbox flag once per request.
|
* This service only resolves the sandbox flag once per request.
|
||||||
* We should remove this service in favor of directly using `settings.connection-state`.
|
* We should remove this service in favor of directly using `settings.connection-state`.
|
||||||
|
@ -163,61 +164,61 @@ return array(
|
||||||
|
|
||||||
return $state->is_sandbox();
|
return $state->is_sandbox();
|
||||||
},
|
},
|
||||||
'settings.rest.onboarding' => static function ( ContainerInterface $container ) : OnboardingRestEndpoint {
|
'settings.rest.onboarding' => static function ( ContainerInterface $container ) : OnboardingRestEndpoint {
|
||||||
return new OnboardingRestEndpoint( $container->get( 'settings.data.onboarding' ) );
|
return new OnboardingRestEndpoint( $container->get( 'settings.data.onboarding' ) );
|
||||||
},
|
},
|
||||||
'settings.rest.common' => static function ( ContainerInterface $container ) : CommonRestEndpoint {
|
'settings.rest.common' => static function ( ContainerInterface $container ) : CommonRestEndpoint {
|
||||||
return new CommonRestEndpoint( $container->get( 'settings.data.general' ) );
|
return new CommonRestEndpoint( $container->get( 'settings.data.general' ) );
|
||||||
},
|
},
|
||||||
'settings.rest.payment' => static function ( ContainerInterface $container ) : PaymentRestEndpoint {
|
'settings.rest.payment' => static function ( ContainerInterface $container ) : PaymentRestEndpoint {
|
||||||
return new PaymentRestEndpoint(
|
return new PaymentRestEndpoint(
|
||||||
$container->get( 'settings.data.payment' ),
|
$container->get( 'settings.data.payment' ),
|
||||||
$container->get( 'settings.data.definition.methods' )
|
$container->get( 'settings.data.definition.methods' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.styling' => static function ( ContainerInterface $container ) : StylingRestEndpoint {
|
'settings.rest.styling' => static function ( ContainerInterface $container ) : StylingRestEndpoint {
|
||||||
return new StylingRestEndpoint(
|
return new StylingRestEndpoint(
|
||||||
$container->get( 'settings.data.styling' ),
|
$container->get( 'settings.data.styling' ),
|
||||||
$container->get( 'settings.service.sanitizer' )
|
$container->get( 'settings.service.sanitizer' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.refresh_feature_status' => static function ( ContainerInterface $container ) : RefreshFeatureStatusEndpoint {
|
'settings.rest.refresh_feature_status' => static function ( ContainerInterface $container ) : RefreshFeatureStatusEndpoint {
|
||||||
return new RefreshFeatureStatusEndpoint(
|
return new RefreshFeatureStatusEndpoint(
|
||||||
$container->get( 'wcgateway.settings' ),
|
$container->get( 'wcgateway.settings' ),
|
||||||
new Cache( 'ppcp-timeout' ),
|
new Cache( 'ppcp-timeout' ),
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.authentication' => static function ( ContainerInterface $container ) : AuthenticationRestEndpoint {
|
'settings.rest.authentication' => static function ( ContainerInterface $container ) : AuthenticationRestEndpoint {
|
||||||
return new AuthenticationRestEndpoint(
|
return new AuthenticationRestEndpoint(
|
||||||
$container->get( 'settings.service.authentication_manager' ),
|
$container->get( 'settings.service.authentication_manager' ),
|
||||||
$container->get( 'settings.service.data-manager' )
|
$container->get( 'settings.service.data-manager' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.login_link' => static function ( ContainerInterface $container ) : LoginLinkRestEndpoint {
|
'settings.rest.login_link' => static function ( ContainerInterface $container ) : LoginLinkRestEndpoint {
|
||||||
return new LoginLinkRestEndpoint(
|
return new LoginLinkRestEndpoint(
|
||||||
$container->get( 'settings.service.connection-url-generator' ),
|
$container->get( 'settings.service.connection-url-generator' ),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.webhooks' => static function ( ContainerInterface $container ) : WebhookSettingsEndpoint {
|
'settings.rest.webhooks' => static function ( ContainerInterface $container ) : WebhookSettingsEndpoint {
|
||||||
return new WebhookSettingsEndpoint(
|
return new WebhookSettingsEndpoint(
|
||||||
$container->get( 'api.endpoint.webhook' ),
|
$container->get( 'api.endpoint.webhook' ),
|
||||||
$container->get( 'webhook.registrar' ),
|
$container->get( 'webhook.registrar' ),
|
||||||
$container->get( 'webhook.status.simulation' )
|
$container->get( 'webhook.status.simulation' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.pay_later_messaging' => static function ( ContainerInterface $container ) : PayLaterMessagingEndpoint {
|
'settings.rest.pay_later_messaging' => static function ( ContainerInterface $container ) : PayLaterMessagingEndpoint {
|
||||||
return new PayLaterMessagingEndpoint(
|
return new PayLaterMessagingEndpoint(
|
||||||
$container->get( 'wcgateway.settings' ),
|
$container->get( 'wcgateway.settings' ),
|
||||||
$container->get( 'paylater-configurator.endpoint.save-config' )
|
$container->get( 'paylater-configurator.endpoint.save-config' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.settings' => static function ( ContainerInterface $container ) : SettingsRestEndpoint {
|
'settings.rest.settings' => static function ( ContainerInterface $container ) : SettingsRestEndpoint {
|
||||||
return new SettingsRestEndpoint(
|
return new SettingsRestEndpoint(
|
||||||
$container->get( 'settings.data.settings' )
|
$container->get( 'settings.data.settings' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.casual-selling.supported-countries' => static function ( ContainerInterface $container ) : array {
|
'settings.casual-selling.supported-countries' => static function ( ContainerInterface $container ) : array {
|
||||||
return array(
|
return array(
|
||||||
'AR',
|
'AR',
|
||||||
'AU',
|
'AU',
|
||||||
|
@ -267,13 +268,13 @@ return array(
|
||||||
'VN',
|
'VN',
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.casual-selling.eligible' => static function ( ContainerInterface $container ) : bool {
|
'settings.casual-selling.eligible' => static function ( ContainerInterface $container ) : bool {
|
||||||
$country = $container->get( 'api.shop.country' );
|
$country = $container->get( 'api.shop.country' );
|
||||||
$eligible_countries = $container->get( 'settings.casual-selling.supported-countries' );
|
$eligible_countries = $container->get( 'settings.casual-selling.supported-countries' );
|
||||||
|
|
||||||
return in_array( $country, $eligible_countries, true );
|
return in_array( $country, $eligible_countries, true );
|
||||||
},
|
},
|
||||||
'settings.handler.connection-listener' => static function ( ContainerInterface $container ) : ConnectionListener {
|
'settings.handler.connection-listener' => static function ( ContainerInterface $container ) : ConnectionListener {
|
||||||
$page_id = $container->has( 'wcgateway.current-ppcp-settings-page-id' ) ? $container->get( 'wcgateway.current-ppcp-settings-page-id' ) : '';
|
$page_id = $container->has( 'wcgateway.current-ppcp-settings-page-id' ) ? $container->get( 'wcgateway.current-ppcp-settings-page-id' ) : '';
|
||||||
|
|
||||||
return new ConnectionListener(
|
return new ConnectionListener(
|
||||||
|
@ -284,16 +285,16 @@ return array(
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.signup-link-cache' => static function ( ContainerInterface $container ) : Cache {
|
'settings.service.signup-link-cache' => static function ( ContainerInterface $container ) : Cache {
|
||||||
return new Cache( 'ppcp-paypal-signup-link' );
|
return new Cache( 'ppcp-paypal-signup-link' );
|
||||||
},
|
},
|
||||||
'settings.service.onboarding-url-manager' => static function ( ContainerInterface $container ) : OnboardingUrlManager {
|
'settings.service.onboarding-url-manager' => static function ( ContainerInterface $container ) : OnboardingUrlManager {
|
||||||
return new OnboardingUrlManager(
|
return new OnboardingUrlManager(
|
||||||
$container->get( 'settings.service.signup-link-cache' ),
|
$container->get( 'settings.service.signup-link-cache' ),
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.connection-url-generator' => static function ( ContainerInterface $container ) : ConnectionUrlGenerator {
|
'settings.service.connection-url-generator' => static function ( ContainerInterface $container ) : ConnectionUrlGenerator {
|
||||||
return new ConnectionUrlGenerator(
|
return new ConnectionUrlGenerator(
|
||||||
$container->get( 'api.env.endpoint.partner-referrals' ),
|
$container->get( 'api.env.endpoint.partner-referrals' ),
|
||||||
$container->get( 'api.repository.partner-referrals-data' ),
|
$container->get( 'api.repository.partner-referrals-data' ),
|
||||||
|
@ -301,7 +302,7 @@ return array(
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.authentication_manager' => static function ( ContainerInterface $container ) : AuthenticationManager {
|
'settings.service.authentication_manager' => static function ( ContainerInterface $container ) : AuthenticationManager {
|
||||||
return new AuthenticationManager(
|
return new AuthenticationManager(
|
||||||
$container->get( 'settings.data.general' ),
|
$container->get( 'settings.data.general' ),
|
||||||
$container->get( 'api.env.paypal-host' ),
|
$container->get( 'api.env.paypal-host' ),
|
||||||
|
@ -312,10 +313,10 @@ return array(
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.sanitizer' => static function ( ContainerInterface $container ) : DataSanitizer {
|
'settings.service.sanitizer' => static function ( ContainerInterface $container ) : DataSanitizer {
|
||||||
return new DataSanitizer();
|
return new DataSanitizer();
|
||||||
},
|
},
|
||||||
'settings.service.data-manager' => static function ( ContainerInterface $container ) : SettingsDataManager {
|
'settings.service.data-manager' => static function ( ContainerInterface $container ) : SettingsDataManager {
|
||||||
return new SettingsDataManager(
|
return new SettingsDataManager(
|
||||||
$container->get( 'settings.data.definition.methods' ),
|
$container->get( 'settings.data.definition.methods' ),
|
||||||
$container->get( 'settings.data.onboarding' ),
|
$container->get( 'settings.data.onboarding' ),
|
||||||
|
@ -327,7 +328,7 @@ return array(
|
||||||
$container->get( 'settings.data.todos' ),
|
$container->get( 'settings.data.todos' ),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.ajax.switch_ui' => static function ( ContainerInterface $container ) : SwitchSettingsUiEndpoint {
|
'settings.ajax.switch_ui' => static function ( ContainerInterface $container ) : SwitchSettingsUiEndpoint {
|
||||||
return new SwitchSettingsUiEndpoint(
|
return new SwitchSettingsUiEndpoint(
|
||||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||||
$container->get( 'button.request-data' ),
|
$container->get( 'button.request-data' ),
|
||||||
|
@ -335,7 +336,7 @@ return array(
|
||||||
$container->get( 'api.merchant_id' ) !== ''
|
$container->get( 'api.merchant_id' ) !== ''
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.rest.todos' => static function ( ContainerInterface $container ) : TodosRestEndpoint {
|
'settings.rest.todos' => static function ( ContainerInterface $container ) : TodosRestEndpoint {
|
||||||
return new TodosRestEndpoint(
|
return new TodosRestEndpoint(
|
||||||
$container->get( 'settings.data.todos' ),
|
$container->get( 'settings.data.todos' ),
|
||||||
$container->get( 'settings.data.definition.todos' ),
|
$container->get( 'settings.data.definition.todos' ),
|
||||||
|
@ -343,22 +344,26 @@ return array(
|
||||||
$container->get( 'settings.service.todos_sorting' )
|
$container->get( 'settings.service.todos_sorting' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.todos' => static function ( ContainerInterface $container ) : TodosModel {
|
'settings.data.todos' => static function ( ContainerInterface $container ) : TodosModel {
|
||||||
return new TodosModel();
|
return new TodosModel();
|
||||||
},
|
},
|
||||||
'settings.data.definition.todos' => static function ( ContainerInterface $container ) : TodosDefinition {
|
'settings.data.definition.todos' => static function ( ContainerInterface $container ) : TodosDefinition {
|
||||||
return new TodosDefinition(
|
return new TodosDefinition(
|
||||||
$container->get( 'settings.service.todos_eligibilities' ),
|
$container->get( 'settings.service.todos_eligibilities' ),
|
||||||
$container->get( 'settings.data.general' ),
|
$container->get( 'settings.data.general' ),
|
||||||
$container->get( 'wc-subscriptions.helper' )
|
$container->get( 'wc-subscriptions.helper' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.data.definition.methods' => static function ( ContainerInterface $container ) : PaymentMethodsDefinition {
|
'settings.data.definition.methods' => static function ( ContainerInterface $container ) : PaymentMethodsDefinition {
|
||||||
return new PaymentMethodsDefinition(
|
return new PaymentMethodsDefinition(
|
||||||
$container->get( 'settings.data.payment' ),
|
$container->get( 'settings.data.payment' ),
|
||||||
|
$container->get( 'settings.data.definition.method_dependencies' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.pay_later_status' => static function ( ContainerInterface $container ) : array {
|
'settings.data.definition.method_dependencies' => static function ( ContainerInterface $container ) : PaymentMethodsDependenciesDefinition {
|
||||||
|
return new PaymentMethodsDependenciesDefinition();
|
||||||
|
},
|
||||||
|
'settings.service.pay_later_status' => static function ( ContainerInterface $container ) : array {
|
||||||
$pay_later_endpoint = $container->get( 'settings.rest.pay_later_messaging' );
|
$pay_later_endpoint = $container->get( 'settings.rest.pay_later_messaging' );
|
||||||
$pay_later_settings = $pay_later_endpoint->get_details()->get_data();
|
$pay_later_settings = $pay_later_endpoint->get_details()->get_data();
|
||||||
|
|
||||||
|
@ -379,7 +384,7 @@ return array(
|
||||||
'is_enabled_for_any_location' => $is_pay_later_messaging_enabled_for_any_location,
|
'is_enabled_for_any_location' => $is_pay_later_messaging_enabled_for_any_location,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.button_locations' => static function ( ContainerInterface $container ) : array {
|
'settings.service.button_locations' => static function ( ContainerInterface $container ) : array {
|
||||||
$styling_endpoint = $container->get( 'settings.rest.styling' );
|
$styling_endpoint = $container->get( 'settings.rest.styling' );
|
||||||
$styling_data = $styling_endpoint->get_details()->get_data()['data'];
|
$styling_data = $styling_endpoint->get_details()->get_data()['data'];
|
||||||
|
|
||||||
|
@ -389,7 +394,7 @@ return array(
|
||||||
'product_enabled' => $styling_data['product']->enabled ?? false,
|
'product_enabled' => $styling_data['product']->enabled ?? false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.gateways_status' => static function ( ContainerInterface $container ) : array {
|
'settings.service.gateways_status' => static function ( ContainerInterface $container ) : array {
|
||||||
$payment_endpoint = $container->get( 'settings.rest.payment' );
|
$payment_endpoint = $container->get( 'settings.rest.payment' );
|
||||||
$settings = $payment_endpoint->get_details()->get_data();
|
$settings = $payment_endpoint->get_details()->get_data();
|
||||||
|
|
||||||
|
@ -400,7 +405,7 @@ return array(
|
||||||
'card-button' => $settings['data']['ppcp-card-button-gateway']['enabled'] ?? false,
|
'card-button' => $settings['data']['ppcp-card-button-gateway']['enabled'] ?? false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.merchant_capabilities' => static function ( ContainerInterface $container ) : array {
|
'settings.service.merchant_capabilities' => static function ( ContainerInterface $container ) : array {
|
||||||
$features = apply_filters(
|
$features = apply_filters(
|
||||||
'woocommerce_paypal_payments_rest_common_merchant_features',
|
'woocommerce_paypal_payments_rest_common_merchant_features',
|
||||||
array()
|
array()
|
||||||
|
@ -416,7 +421,7 @@ return array(
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
'settings.service.todos_eligibilities' => static function ( ContainerInterface $container ) : TodosEligibilityService {
|
'settings.service.todos_eligibilities' => static function ( ContainerInterface $container ) : TodosEligibilityService {
|
||||||
$pay_later_service = $container->get( 'settings.service.pay_later_status' );
|
$pay_later_service = $container->get( 'settings.service.pay_later_status' );
|
||||||
$pay_later_statuses = $pay_later_service['statuses'];
|
$pay_later_statuses = $pay_later_service['statuses'];
|
||||||
$is_pay_later_messaging_enabled_for_any_location = $pay_later_service['is_enabled_for_any_location'];
|
$is_pay_later_messaging_enabled_for_any_location = $pay_later_service['is_enabled_for_any_location'];
|
||||||
|
@ -473,7 +478,7 @@ return array(
|
||||||
$container->get( 'googlepay.eligible' ) && $capabilities['google_pay'] && ! $gateways['google_pay'],
|
$container->get( 'googlepay.eligible' ) && $capabilities['google_pay'] && ! $gateways['google_pay'],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'settings.service.todos_sorting' => static function ( ContainerInterface $container ) : TodosSortingAndFilteringService {
|
'settings.service.todos_sorting' => static function ( ContainerInterface $container ) : TodosSortingAndFilteringService {
|
||||||
return new TodosSortingAndFilteringService(
|
return new TodosSortingAndFilteringService(
|
||||||
$container->get( 'settings.data.todos' )
|
$container->get( 'settings.data.todos' )
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* PayPal Commerce Todos Definitions
|
* Payment Methods Definitions
|
||||||
*
|
*
|
||||||
* @package WooCommerce\PayPalCommerce\Settings\Data\Definition
|
* @package WooCommerce\PayPalCommerce\Settings\Data\Definition
|
||||||
*/
|
*/
|
||||||
|
@ -40,6 +40,13 @@ class PaymentMethodsDefinition {
|
||||||
*/
|
*/
|
||||||
private PaymentSettings $settings;
|
private PaymentSettings $settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment method dependencies definition.
|
||||||
|
*
|
||||||
|
* @var PaymentMethodsDependenciesDefinition
|
||||||
|
*/
|
||||||
|
private PaymentMethodsDependenciesDefinition $dependencies_definition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of WooCommerce payment gateways.
|
* List of WooCommerce payment gateways.
|
||||||
*
|
*
|
||||||
|
@ -50,10 +57,15 @@ class PaymentMethodsDefinition {
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param PaymentSettings $settings Payment methods data model.
|
* @param PaymentSettings $settings Payment methods data model.
|
||||||
|
* @param PaymentMethodsDependenciesDefinition $dependencies_definition Payment dependencies definition.
|
||||||
*/
|
*/
|
||||||
public function __construct( PaymentSettings $settings ) {
|
public function __construct(
|
||||||
$this->settings = $settings;
|
PaymentSettings $settings,
|
||||||
|
PaymentMethodsDependenciesDefinition $dependencies_definition
|
||||||
|
) {
|
||||||
|
$this->settings = $settings;
|
||||||
|
$this->dependencies_definition = $dependencies_definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,15 +85,30 @@ class PaymentMethodsDefinition {
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
foreach ( $all_methods as $method ) {
|
foreach ( $all_methods as $method ) {
|
||||||
$result[ $method['id'] ] = $this->build_method_definition(
|
$method_id = $method['id'];
|
||||||
$method['id'],
|
|
||||||
|
// Add dependency info if applicable.
|
||||||
|
$depends_on = $this->dependencies_definition->get_parent_methods( $method_id );
|
||||||
|
if ( ! empty( $depends_on ) ) {
|
||||||
|
$method['depends_on'] = $depends_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[ $method_id ] = $this->build_method_definition(
|
||||||
|
$method_id,
|
||||||
$method['title'],
|
$method['title'],
|
||||||
$method['description'],
|
$method['description'],
|
||||||
$method['icon'],
|
$method['icon'],
|
||||||
$method['fields'] ?? array()
|
$method['fields'] ?? array(),
|
||||||
|
$depends_on
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add dependency maps to metadata.
|
||||||
|
$result['__meta'] = array(
|
||||||
|
'dependencies' => $this->dependencies_definition->get_dependencies(),
|
||||||
|
'dependents' => $this->dependencies_definition->get_dependents_map(),
|
||||||
|
);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,14 +122,15 @@ class PaymentMethodsDefinition {
|
||||||
* @param string $icon Admin-side icon of the payment method.
|
* @param string $icon Admin-side icon of the payment method.
|
||||||
* @param array|false $fields Optional. Additional fields to display in the edit modal.
|
* @param array|false $fields Optional. Additional fields to display in the edit modal.
|
||||||
* Setting this to false omits all fields.
|
* Setting this to false omits all fields.
|
||||||
|
* @param array $depends_on Optional. IDs of payment methods that this depends on.
|
||||||
* @return array Payment method definition.
|
* @return array Payment method definition.
|
||||||
*/
|
*/
|
||||||
private function build_method_definition(
|
private function build_method_definition(
|
||||||
string $gateway_id,
|
string $gateway_id,
|
||||||
string $title,
|
string $title,
|
||||||
string $description,
|
string $description,
|
||||||
string $icon,
|
string $icon, $fields = array(),
|
||||||
$fields = array()
|
array $depends_on = array()
|
||||||
) : array {
|
) : array {
|
||||||
$gateway = $this->wc_gateways[ $gateway_id ] ?? null;
|
$gateway = $this->wc_gateways[ $gateway_id ] ?? null;
|
||||||
|
|
||||||
|
@ -119,6 +147,11 @@ class PaymentMethodsDefinition {
|
||||||
'itemDescription' => $description,
|
'itemDescription' => $description,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Add dependency information if provided - ensure it's included directly in the config.
|
||||||
|
if ( ! empty( $depends_on ) ) {
|
||||||
|
$config['depends_on'] = $depends_on;
|
||||||
|
}
|
||||||
|
|
||||||
if ( is_array( $fields ) ) {
|
if ( is_array( $fields ) ) {
|
||||||
$config['fields'] = array_merge(
|
$config['fields'] = array_merge(
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Payment Methods Dependencies Definition
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Settings\Data\Definition
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare( strict_types = 1 );
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Settings\Data\Definition;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\Applepay\ApplePayGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\BancontactGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\BlikGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\EPSGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\IDealGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\MultibancoGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\MyBankGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\P24Gateway;
|
||||||
|
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\TrustlyGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PaymentMethodsDependenciesDefinition
|
||||||
|
*
|
||||||
|
* Defines dependency relationships between payment methods.
|
||||||
|
*/
|
||||||
|
class PaymentMethodsDependenciesDefinition {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all payment method dependencies
|
||||||
|
*
|
||||||
|
* Maps dependent method ID => array of parent method IDs.
|
||||||
|
* A dependent method is disabled if ANY of its required parents is disabled.
|
||||||
|
*
|
||||||
|
* @return array The dependency relationships between payment methods
|
||||||
|
*/
|
||||||
|
public function get_dependencies(): array {
|
||||||
|
$dependencies = array(
|
||||||
|
CardButtonGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
CreditCardGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
AxoGateway::ID => array( PayPalGateway::ID, CreditCardGateway::ID ),
|
||||||
|
ApplePayGateway::ID => array( PayPalGateway::ID, CreditCardGateway::ID ),
|
||||||
|
GooglePayGateway::ID => array( PayPalGateway::ID, CreditCardGateway::ID ),
|
||||||
|
BancontactGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
BlikGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
EPSGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
IDealGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
MultibancoGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
MyBankGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
P24Gateway::ID => array( PayPalGateway::ID ),
|
||||||
|
TrustlyGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
PayUponInvoiceGateway::ID => array( PayPalGateway::ID ),
|
||||||
|
OXXO::ID => array( PayPalGateway::ID ),
|
||||||
|
'venmo' => array( PayPalGateway::ID ),
|
||||||
|
'pay-later' => array( PayPalGateway::ID ),
|
||||||
|
);
|
||||||
|
|
||||||
|
return apply_filters(
|
||||||
|
'woocommerce_paypal_payments_payment_method_dependencies',
|
||||||
|
$dependencies
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mapping from parent methods to their dependent methods
|
||||||
|
*
|
||||||
|
* @return array Parent-to-child dependency map
|
||||||
|
*/
|
||||||
|
public function get_dependents_map(): array {
|
||||||
|
$result = array();
|
||||||
|
$dependencies = $this->get_dependencies();
|
||||||
|
|
||||||
|
foreach ( $dependencies as $child_id => $parent_ids ) {
|
||||||
|
foreach ( $parent_ids as $parent_id ) {
|
||||||
|
if ( ! isset( $result[ $parent_id ] ) ) {
|
||||||
|
$result[ $parent_id ] = array();
|
||||||
|
}
|
||||||
|
$result[ $parent_id ][] = $child_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all parent methods that a method depends on
|
||||||
|
*
|
||||||
|
* @param string $method_id Method ID to check.
|
||||||
|
* @return array Array of parent method IDs
|
||||||
|
*/
|
||||||
|
public function get_parent_methods( string $method_id ): array {
|
||||||
|
return $this->get_dependencies()[ $method_id ] ?? array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get methods that depend on a parent method
|
||||||
|
*
|
||||||
|
* @param string $parent_id Parent method ID.
|
||||||
|
* @return array Array of dependent method IDs
|
||||||
|
*/
|
||||||
|
public function get_dependent_methods( string $parent_id ): array {
|
||||||
|
return $this->get_dependents_map()[ $parent_id ] ?? array();
|
||||||
|
}
|
||||||
|
}
|
|
@ -150,7 +150,17 @@ class PaymentRestEndpoint extends RestEndpoint {
|
||||||
$gateway_settings = array();
|
$gateway_settings = array();
|
||||||
$all_methods = $this->gateways();
|
$all_methods = $this->gateways();
|
||||||
|
|
||||||
|
// First extract __meta if present.
|
||||||
|
if ( isset( $all_methods['__meta'] ) ) {
|
||||||
|
$gateway_settings['__meta'] = $all_methods['__meta'];
|
||||||
|
}
|
||||||
|
|
||||||
foreach ( $all_methods as $key => $method ) {
|
foreach ( $all_methods as $key => $method ) {
|
||||||
|
// Skip the __meta key as we've already handled it.
|
||||||
|
if ( $key === '__meta' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$gateway_settings[ $key ] = array(
|
$gateway_settings[ $key ] = array(
|
||||||
'id' => $method['id'],
|
'id' => $method['id'],
|
||||||
'title' => $method['title'],
|
'title' => $method['title'],
|
||||||
|
@ -164,6 +174,11 @@ class PaymentRestEndpoint extends RestEndpoint {
|
||||||
if ( isset( $method['fields'] ) ) {
|
if ( isset( $method['fields'] ) ) {
|
||||||
$gateway_settings[ $key ]['fields'] = $method['fields'];
|
$gateway_settings[ $key ]['fields'] = $method['fields'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preserve dependency information.
|
||||||
|
if ( isset( $method['depends_on'] ) ) {
|
||||||
|
$gateway_settings[ $key ]['depends_on'] = $method['depends_on'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$gateway_settings['paypalShowLogo'] = $this->settings->get_paypal_show_logo();
|
$gateway_settings['paypalShowLogo'] = $this->settings->get_paypal_show_logo();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue