PaymentProviders::enhance_order_map() │ public │ WC 1.0
Enhance a payment providers order map.
If the payments providers order map is empty, it will be initialized with the current WC payment gateway ordering. If there are missing entries (registered payment gateways, suggestions, offline PMs, etc.), they will be added. Various rules will be enforced (e.g., offline PMs and their relation with the offline PMs group).
public function enhance_order_map( array $order_map ): array {
// We don't exclude shells here, because we need to get the order of all the registered payment gateways.
$payment_gateways = $this->get_payment_gateways( false );
// Make it a list keyed by the payment gateway ID.
$payment_gateways = array_combine(
array_map(
fn( $gateway ) => $gateway->id,
$payment_gateways
),
$payment_gateways
);
// Get the payment gateways order map.
$payment_gateways_order_map = array_flip( array_keys( $payment_gateways ) );
// Get the payment gateways to suggestions map.
$payment_gateways_to_suggestions_map = array_map(
fn( $gateway ) => $this->extension_suggestions->get_by_plugin_slug( Utils::normalize_plugin_slug( $this->get_payment_gateway_plugin_slug( $gateway ) ) ),
$payment_gateways
);
/*
* Initialize the order map with the current ordering.
*/
if ( empty( $order_map ) ) {
$order_map = $payment_gateways_order_map;
}
$order_map = Utils::order_map_normalize( $order_map );
$handled_suggestion_ids = array();
/*
* Go through the registered gateways and add any missing ones.
*/
// Use a map to keep track of the insertion offset for each suggestion ID.
// We need this so we can place multiple PGs matching a suggestion right after it but maintain their relative order.
$suggestion_order_map_id_to_offset_map = array();
foreach ( $payment_gateways_order_map as $id => $order ) {
if ( isset( $order_map[ $id ] ) ) {
continue;
}
// If there is a suggestion entry matching this payment gateway,
// we will add the payment gateway right after it so gateways pop-up in place of matching suggestions.
// We rely on suggestions and matching registered PGs being mutually exclusive in the UI.
if ( ! empty( $payment_gateways_to_suggestions_map[ $id ] ) ) {
$suggestion_id = $payment_gateways_to_suggestions_map[ $id ]['id'];
$suggestion_order_map_id = $this->get_suggestion_order_map_id( $suggestion_id );
if ( isset( $order_map[ $suggestion_order_map_id ] ) ) {
// Determine the offset for placing missing PGs after this suggestion.
if ( ! isset( $suggestion_order_map_id_to_offset_map[ $suggestion_order_map_id ] ) ) {
$suggestion_order_map_id_to_offset_map[ $suggestion_order_map_id ] = 0;
}
$suggestion_order_map_id_to_offset_map[ $suggestion_order_map_id ] += 1;
// Place the missing payment gateway right after the suggestion,
// with an offset to maintain relative order between multiple PGs matching the same suggestion.
$order_map = Utils::order_map_place_at_order(
$order_map,
$id,
$order_map[ $suggestion_order_map_id ] + $suggestion_order_map_id_to_offset_map[ $suggestion_order_map_id ]
);
// Remember that we handled this suggestion - don't worry about remembering it multiple times.
$handled_suggestion_ids[] = $suggestion_id;
continue;
}
}
// Add the missing payment gateway at the end.
$order_map[ $id ] = empty( $order_map ) ? 0 : max( $order_map ) + 1;
}
$handled_suggestion_ids = array_unique( $handled_suggestion_ids );
/*
* Place not yet handled suggestion entries right before their matching registered payment gateway IDs.
* This means that registered PGs already in the order map force the suggestions
* to be placed/moved right before them. We rely on suggestions and registered PGs being mutually exclusive.
*/
foreach ( array_keys( $order_map ) as $id ) {
// If the id is not of a payment gateway or there is no suggestion for this payment gateway, ignore it.
if ( ! array_key_exists( $id, $payment_gateways_to_suggestions_map ) ||
empty( $payment_gateways_to_suggestions_map[ $id ] )
) {
continue;
}
$suggestion = $payment_gateways_to_suggestions_map[ $id ];
// If the suggestion was already handled, skip it.
if ( in_array( $suggestion['id'], $handled_suggestion_ids, true ) ) {
continue;
}
// Place the suggestion at the same order as the payment gateway
// thus ensuring that the suggestion is placed right before the payment gateway.
$order_map = Utils::order_map_place_at_order(
$order_map,
$this->get_suggestion_order_map_id( $suggestion['id'] ),
$order_map[ $id ]
);
// Remember that we've handled this suggestion to avoid adding it multiple times.
// We only want to attach the suggestion to the first payment gateway that matches the plugin slug.
$handled_suggestion_ids[] = $suggestion['id'];
}
// Extract all the registered offline PMs and keep their order values.
$offline_methods = array_filter(
$order_map,
array( $this, 'is_offline_payment_method' ),
ARRAY_FILTER_USE_KEY
);
if ( ! empty( $offline_methods ) ) {
/*
* If the offline PMs group is missing, add it before the last offline PM.
*/
if ( ! array_key_exists( self::OFFLINE_METHODS_ORDERING_GROUP, $order_map ) ) {
$last_offline_method_order = max( $offline_methods );
$order_map = Utils::order_map_place_at_order( $order_map, self::OFFLINE_METHODS_ORDERING_GROUP, $last_offline_method_order );
}
/*
* Place all the offline PMs right after the offline PMs group entry.
*/
$target_order = $order_map[ self::OFFLINE_METHODS_ORDERING_GROUP ] + 1;
// Sort the offline PMs by their order.
asort( $offline_methods );
foreach ( $offline_methods as $offline_method => $order ) {
$order_map = Utils::order_map_place_at_order( $order_map, $offline_method, $target_order );
++$target_order;
}
}
return Utils::order_map_normalize( $order_map );
}