modify the request arguments before the call * - aish_http_retry_codes -> which HTTP status codes trigger a retry * - aish_http_retries -> number of extra attempts (default 1) * - aish_http_result -> inspect or modify the final result */ if ( ! function_exists( 'aish_http_json' ) ) { function aish_http_json( string $url, array $payload = [], string $method = 'POST', array $extra = [] ) { $base = [ 'headers' => [ 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'User-Agent' => 'AI Snippet SEO Helper/' . ( defined( 'AISH_VERSION' ) ? AISH_VERSION : '1.x' ), ], 'body' => wp_json_encode( $payload ), 'timeout' => 25, 'httpversion' => '1.1', 'sslverify' => true, 'redirection' => 2, ]; $args = array_replace_recursive( $base, $extra ); $args = apply_filters( 'aish_http_args', $args, $url, $payload, $method ); $do = ( strtoupper( $method ) === 'GET' ) ? 'wp_remote_get' : 'wp_remote_post'; $retry_codes = apply_filters( 'aish_http_retry_codes', [ 429, 500, 502, 503, 504, 520, 521, 522 ] ); $max_retries = (int) apply_filters( 'aish_http_retries', 1 ); $attempt = 0; $res = null; while ( true ) { $res = $do( $url, $args ); if ( ! is_wp_error( $res ) ) { $code = (int) wp_remote_retrieve_response_code( $res ); if ( ! in_array( $code, $retry_codes, true ) ) { break; } if ( $attempt >= $max_retries ) { break; } usleep( 200000 * ( $attempt + 1 ) ); $attempt++; continue; } // WP_Error: retry only on transient network errors $msg = implode( '; ', $res->get_error_messages() ); $transient_err = ( stripos( $msg, 'timed out' ) !== false ) || ( stripos( $msg, 'cURL error 28' ) !== false ) || ( stripos( $msg, 'Could not resolve' ) !== false ) || ( stripos( $msg, 'cURL error 6' ) !== false ); if ( $transient_err && $attempt < $max_retries ) { usleep( 200000 * ( $attempt + 1 ) ); $attempt++; continue; } // No retry available, or attempts exhausted break; } return apply_filters( 'aish_http_result', $res, $url, $payload, $method, $args, $attempt ); } }