'Bearer ' . $api_key, 'Content-Type' => 'application/json', ]; $body = [ 'model' => $model, 'messages' => [ [ 'role' => 'user', 'content' => [ ['type' => 'text', 'text' => $prompt], ['type' => 'image_url', 'image_url' => [ 'url' => $image_data_uri ]] ] ] ] ]; $response = wp_remote_post($api_url, [ 'headers' => $headers, 'body' => json_encode($body), 'timeout' => $timeout, ]); $generated = ''; $api_response_json = null; $json_fields = null; if (!is_wp_error($response) && !empty($response['body'])) { $api_response_json = json_decode($response['body'], true); if (!empty($api_response_json['choices'][0]['message']['content'])) { // Raw content from the model $raw_content = trim($api_response_json['choices'][0]['message']['content']); $raw_content = trim($raw_content, "\"' \t\n\r\0\x0B"); // Try to interpret the content itself as JSON containing "alt_text" $json_fields = json_decode($raw_content, true); if (json_last_error() !== JSON_ERROR_NONE || ! is_array($json_fields) || empty($json_fields['alt_text'])) { // Backwards-compatible behavior: treat the content as plain alt text $json_fields['alt_text'] = $raw_content; } } elseif ( isset( $api_response_json['error'] ) ) { if (AIT_IAT_Settings::get('enable_debug_mode')) { error_log( '[AI Image Alt Text] OpenAI API error: ' . $api_response_json['error']['code'] . ' - ' . $api_response_json['error']['message'] ); } } } else { if (AIT_IAT_Settings::get('enable_debug_mode')) { error_log('[AI Image Alt Text] OpenAI API error: ' . print_r($response, true)); } return $alt; } if ($max_length && strlen($json_fields['alt_text']) > $max_length) { $json_fields['alt_text'] = mb_substr($json_fields['alt_text'], 0, $max_length); } $json_fields['alt_text'] = $prefix . $json_fields['alt_text'] . $suffix; $json_fields['alt_text'] = apply_filters('ait_iat_after_generate_alt_text', $json_fields['alt_text'], $attachment_id, $api_response_json); $accept = apply_filters('ait_iat_should_accept_alt', true, $json_fields['alt_text'], $attachment_id); if ( $accept && $json_fields['alt_text'] ) { self::record_generation(); } return ( $accept && ! empty( $json_fields['alt_text'] ) ) ? $json_fields : $alt; } public static function is_monthly_limit_exceeded() { $timestamps = get_option('ait_iat_generation_timestamps', []); $cutoff = time() - (30 * DAY_IN_SECONDS); // Keep only timestamps from the last 30 days $timestamps = array_filter($timestamps, function($t) use ($cutoff) { return $t >= $cutoff; }); // Save cleaned list update_option('ait_iat_generation_timestamps', $timestamps); $limit = apply_filters( 'ait_iat/generation_limit', 25 ); return count($timestamps) >= $limit; } public static function record_generation() { $timestamps = get_option('ait_iat_generation_timestamps', []); $timestamps[] = time(); update_option('ait_iat_generation_timestamps', $timestamps); } /** * Rename an attachment's main file using a new filename slug. * * @param int $attachment_id Attachment ID. * @param string $new_slug New filename slug (without extension). * @return string|null New basename (e.g. "my-file-name.jpg") on success, null on failure. */ public static function maybe_rename_attachment_file( $attachment_id, $new_slug ) { $new_slug = sanitize_title( $new_slug ); if ( ! $attachment_id || ! $new_slug ) { return null; } $old_path = get_attached_file( $attachment_id ); if ( ! $old_path || ! file_exists( $old_path ) ) { return null; } $pathinfo = pathinfo( $old_path ); $dir = $pathinfo['dirname']; $ext = isset( $pathinfo['extension'] ) ? $pathinfo['extension'] : ''; $old_base = $pathinfo['basename']; // Build new basename and make sure it's unique within the directory. $proposed_basename = $new_slug . ( $ext ? '.' . $ext : '' ); $new_basename = wp_unique_filename( $dir, $proposed_basename ); $new_path = trailingslashit( $dir ) . $new_basename; // Actually move the main file. if ( ! @rename( $old_path, $new_path ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged return null; } // Update attached file path. update_attached_file( $attachment_id, $new_path ); // Update attachment metadata to reflect the new main file path. $meta = wp_get_attachment_metadata( $attachment_id ); if ( ! empty( $meta ) && is_array( $meta ) && ! empty( $meta['file'] ) ) { // $meta['file'] is a path relative to uploads base dir, like "2025/12/old-name.jpg". $upload_dir = wp_get_upload_dir(); if ( ! empty( $upload_dir['basedir'] ) && is_string( $upload_dir['basedir'] ) ) { $uploads_basedir = trailingslashit( $upload_dir['basedir'] ); // Derive the relative directory from the old meta file. $meta_pathinfo = pathinfo( $meta['file'] ); $rel_dir = ! empty( $meta_pathinfo['dirname'] ) && '.' !== $meta_pathinfo['dirname'] ? trailingslashit( $meta_pathinfo['dirname'] ) : ''; $meta['file'] = $rel_dir . $new_basename; wp_update_attachment_metadata( $attachment_id, $meta ); } } return $new_basename; } }