WC_AJAX::shipping_providers_save_changes │ public static │ WC 10.7.0
Handle AJAX save for custom shipping providers (taxonomy-based).
Method of the class: WC_AJAX{}
No Hooks.
Returns
null. Nothing (null).
Usage
$result = WC_AJAX::shipping_providers_save_changes(): void;
Changelog
| Since 10.7.0 | Introduced. |
WC_AJAX::shipping_providers_save_changes() WC AJAX::shipping providers save changes code WC 10.8.1
public static function shipping_providers_save_changes(): void {
if ( ! \Automattic\WooCommerce\Utilities\FeaturesUtil::feature_is_enabled( 'fulfillments' ) ) {
wp_send_json_error( 'feature_disabled' );
}
if ( ! isset( $_POST['wc_shipping_providers_nonce'], $_POST['changes'] ) ) {
wp_send_json_error( 'missing_fields' );
}
if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_providers_nonce'] ), 'wc_shipping_providers_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
wp_send_json_error( 'bad_nonce' );
}
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_send_json_error( 'missing_capabilities' );
}
$taxonomy = 'wc_fulfillment_shipping_provider';
$changes = wp_unslash( $_POST['changes'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! is_array( $changes ) ) {
wp_send_json_error( 'invalid_changes' );
}
// Collect only built-in provider keys (class-based, not custom taxonomy providers).
$all_providers = \Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils::get_shipping_providers();
$built_in_keys = array();
foreach ( $all_providers as $provider ) {
if ( ! $provider instanceof \Automattic\WooCommerce\Admin\Features\Fulfillments\Providers\CustomShippingProvider ) {
$built_in_keys[] = $provider->get_key();
}
}
$reserved_slug_error = '';
foreach ( $changes as $term_id => $data ) {
if ( ! is_numeric( $term_id ) && ! isset( $data['newRow'] ) ) {
continue;
}
$term_id = absint( $term_id );
if ( isset( $data['deleted'] ) ) {
if ( isset( $data['newRow'] ) ) {
continue;
}
$term_to_delete = get_term( $term_id, $taxonomy );
if ( $term_to_delete instanceof \WP_Term && self::is_shipping_provider_in_use( $term_to_delete->slug ) ) {
$reserved_slug_error = sprintf(
/* translators: %s: provider name */
__( 'Cannot delete "%s" because it is used by existing fulfillments. Remove all fulfillments using this provider first.', 'woocommerce' ),
$term_to_delete->name
);
continue;
}
$delete_result = wp_delete_term( $term_id, $taxonomy );
if ( is_wp_error( $delete_result ) || false === $delete_result ) {
$reserved_slug_error = is_wp_error( $delete_result )
? $delete_result->get_error_message()
: __( 'Failed to delete the shipping provider.', 'woocommerce' );
}
continue;
}
$update_args = array();
if ( isset( $data['name'] ) && is_string( $data['name'] ) ) {
$update_args['name'] = sanitize_text_field( $data['name'] );
}
// Validate and set slug only on new rows. Slug is immutable after creation.
if ( isset( $data['newRow'] ) && isset( $data['slug'] ) && is_string( $data['slug'] ) && '' !== $data['slug'] ) {
$candidate_slug = sanitize_title( $data['slug'] );
if ( in_array( $candidate_slug, $built_in_keys, true ) ) {
$reserved_slug_error = sprintf(
/* translators: %s: slug value */
__( 'The slug "%s" is already used by a built-in shipping provider. Please choose a different slug.', 'woocommerce' ),
$candidate_slug
);
continue;
}
$update_args['slug'] = $candidate_slug;
}
// Validate tracking URL template: must be a valid http/https URL.
// null means "not submitted" (preserve existing), empty string means "clear".
$tracking_url_template = null;
if ( isset( $data['tracking_url_template'] ) && is_string( $data['tracking_url_template'] ) ) {
if ( '' === $data['tracking_url_template'] ) {
$tracking_url_template = '';
} else {
$testable_url = str_replace( '__PLACEHOLDER__', 'test', $data['tracking_url_template'] );
if ( filter_var( $testable_url, FILTER_VALIDATE_URL ) && preg_match( '#^https?://#i', $testable_url ) ) {
$tracking_url_template = esc_url_raw( $data['tracking_url_template'], array( 'http', 'https' ) );
} else {
$reserved_slug_error = __( 'The tracking URL template must be a valid HTTP or HTTPS URL.', 'woocommerce' );
}
}
}
// Validate icon URL: must be a valid http/https URL.
$icon_url = null;
if ( isset( $data['icon'] ) && is_string( $data['icon'] ) ) {
if ( '' === $data['icon'] ) {
$icon_url = '';
} elseif ( filter_var( $data['icon'], FILTER_VALIDATE_URL ) && preg_match( '#^https?://#i', $data['icon'] ) ) {
$icon_url = esc_url_raw( $data['icon'], array( 'http', 'https' ) );
} else {
$reserved_slug_error = __( 'The icon URL must be a valid HTTP or HTTPS URL.', 'woocommerce' );
}
}
if ( isset( $data['newRow'] ) ) {
$provider_name = strval( $update_args['name'] ?? '' );
$update_args = array_filter( $update_args );
if ( empty( $provider_name ) ) {
continue;
}
$inserted_term = wp_insert_term( $provider_name, $taxonomy, $update_args );
if ( is_wp_error( $inserted_term ) ) {
$reserved_slug_error = $inserted_term->get_error_message();
continue;
}
$term_id = $inserted_term['term_id'];
// Verify auto-generated slug doesn't collide with built-in keys.
$new_term = get_term( $term_id, $taxonomy );
if ( ! $new_term instanceof \WP_Term ) {
continue;
}
if ( in_array( $new_term->slug, $built_in_keys, true ) ) {
wp_delete_term( $term_id, $taxonomy );
$reserved_slug_error = sprintf(
/* translators: %s: provider name */
__( 'Could not create provider "%s" because its auto-generated slug conflicts with a built-in shipping provider. Please specify a different slug.', 'woocommerce' ),
$provider_name
);
continue;
}
} else {
$update_result = wp_update_term( $term_id, $taxonomy, $update_args );
if ( is_wp_error( $update_result ) ) {
$reserved_slug_error = $update_result->get_error_message();
continue;
}
}
if ( $term_id ) {
if ( null !== $tracking_url_template ) {
update_term_meta( $term_id, 'tracking_url_template', $tracking_url_template );
}
if ( null !== $icon_url ) {
update_term_meta( $term_id, 'icon', $icon_url );
}
}
}
$terms = get_terms(
array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
)
);
$shipping_providers = array();
if ( ! is_wp_error( $terms ) ) {
foreach ( $terms as $term ) {
$shipping_providers[] = array(
'term_id' => $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
'tracking_url_template' => get_term_meta( $term->term_id, 'tracking_url_template', true ),
'icon' => get_term_meta( $term->term_id, 'icon', true ),
);
}
}
$response = array(
'shipping_providers' => $shipping_providers,
);
if ( ! empty( $reserved_slug_error ) ) {
$response['error'] = $reserved_slug_error;
}
wp_send_json_success(
$response
);
}