= 200 && $status < 300 ) { return null; } $body = json_decode( wp_remote_retrieve_body( $response ), true ); $detail = ''; if ( is_array( $body ) ) { // Try each common error-message field. foreach ( [ 'detail', 'message', 'error' ] as $key ) { if ( ! empty( $body[ $key ] ) && is_string( $body[ $key ] ) ) { $detail = $body[ $key ]; break; } } } $message = $service . ': '; if ( 401 === $status || 403 === $status ) { $message .= __( 'authentication failed — check your API key.', 'generateblocks-pro' ); } elseif ( 429 === $status ) { $retry_after = wp_remote_retrieve_header( $response, 'retry-after' ); $message .= __( 'rate limit exceeded.', 'generateblocks-pro' ); if ( $retry_after ) { $message .= ' ' . sprintf( /* translators: %s: seconds */ __( 'Retry after %s seconds.', 'generateblocks-pro' ), sanitize_text_field( (string) $retry_after ) ); } } elseif ( $status >= 500 ) { $message .= __( 'provider error — try again later.', 'generateblocks-pro' ); } elseif ( $detail ) { $message .= sanitize_text_field( $detail ); } else { $message .= sprintf( /* translators: %d: HTTP status code */ __( 'unexpected response (HTTP %d).', 'generateblocks-pro' ), $status ); } return new WP_Error( 'provider_error', $message, [ 'status' => $status ] ); } /** * Normalize a submitted field value for provider payloads. * * Form fields can produce scalar values or arrays (for example checkbox * groups). Provider merge/custom-field APIs expect strings, so flatten arrays * consistently and reject objects or nested non-scalar array values. * * @param mixed $value Submitted value. * @return string */ public static function normalize_field_value( $value ) { if ( is_array( $value ) ) { $parts = []; foreach ( $value as $part ) { if ( is_scalar( $part ) ) { $parts[] = (string) $part; } } $value = implode( ', ', $parts ); } if ( is_object( $value ) ) { return ''; } return trim( (string) $value ); } }