settings = $settings; $this->log_manager = new AITM_Log_Manager(); $generation_method = $settings['generation_method'] ?? 'first_content_image'; if ( $generation_method === 'ai_generation' ) { require_once AITM_PLUGIN_DIR . '/includes/class-ai-image-generator.php'; try { $this->ai_generator = new AITM_AI_Image_Generator( $settings ); } catch ( Exception $e ) { // If AI generator fails to initialize, fall back to content image finder $min_width = $settings['min_image_width'] ?? 0; $min_height = $settings['min_image_height'] ?? 0; $this->image_finder = new AITM_Content_Image_Finder( $min_width, $min_height ); } } else { $min_width = $settings['min_image_width'] ?? 0; $min_height = $settings['min_image_height'] ?? 0; $this->image_finder = new AITM_Content_Image_Finder( $min_width, $min_height ); } } /** * Generate thumbnail for post * * @param int $post_id Post ID. * @return array Result data. */ public function generate_for_post( $post_id ) { $post = get_post( $post_id ); if ( ! $post ) { return array( 'success' => false, 'message' => __( 'Post not found', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => '', ); } // Check if post already has thumbnail $overwrite_existing = $this->settings['overwrite_existing'] ?? false; if ( ! $overwrite_existing && has_post_thumbnail( $post_id ) ) { return array( 'success' => false, 'message' => __( 'Post already has thumbnail', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, ); } // Choose generation method $generation_method = $this->settings['generation_method'] ?? 'first_content_image'; switch ( $generation_method ) { case 'ai_generation': if ( isset( $this->ai_generator ) ) { return $this->generate_with_ai( $post_id, $post ); } break; case 'generate_from_title': return $this->generate_from_title( $post_id, $post ); case 'search_or_generate': $result = $this->generate_from_content( $post_id, $post ); if ( ! $result['success'] ) { return $this->generate_from_title( $post_id, $post ); } return $result; case 'use_default_image': $result = $this->generate_from_content( $post_id, $post ); if ( ! $result['success'] ) { return $this->use_default_image( $post_id, $post ); } return $result; } // Fallback to default method return $this->generate_from_content( $post_id, $post ); } /** * Generate thumbnail from content image * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @return array Result data. */ private function generate_from_content( $post_id, $post ) { // Find image in content $image = $this->image_finder->find_first_image( $post_id ); if ( ! $image ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => __( 'No suitable image found in content', 'ai-thumbnails-maker' ), 'type' => 'first_content_image', 'image_size' => '', ) ); return array( 'success' => false, 'message' => __( 'No suitable image found in content', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'first_content_image', ); } // Get attachment ID $attachment_id = $this->image_finder->get_thumbnail_id( $image ); if ( ! $attachment_id ) { $image_url = $image['url'] ?? ''; // Check if URL is local $is_local = $this->is_local_url( $image_url ); if ( $is_local ) { // Local URL but attachment not found - skip with error $error_message = __( 'Attachment not found in database (ID from tag does not match attachment or not found)', 'ai-thumbnails-maker' ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => $error_message, 'type' => 'first_content_image', 'image_size' => '', ) ); return array( 'success' => false, 'message' => $error_message, 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'first_content_image', ); } // Попытка скачать внешнее изображение, если включено в настройках $download_remote = $this->settings['download_remote_images'] ?? false; if ( ! $download_remote ) { $this->log_manager->write( 'info', sprintf( 'External image found but download_remote_images is disabled (%s)', $image_url ) ); } elseif ( ! $this->is_http_image_url( $image_url ) ) { $this->log_manager->write( 'info', sprintf( 'Image URL is not HTTP(S), cannot download (%s)', $image_url ) ); } else { $downloaded_id = $this->download_external_image_to_media( $image_url, $post_id ); if ( $downloaded_id ) { $attachment_id = $downloaded_id; } } if ( ! $attachment_id ) { $error_message = $download_remote ? __( 'Failed to download external image', 'ai-thumbnails-maker' ) : __( 'Image found but it is hosted on a remote server and cannot be set as featured image because "Download Remote Images" option is disabled', 'ai-thumbnails-maker' ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => $error_message, 'type' => 'first_content_image', 'image_size' => '', ) ); return array( 'success' => false, 'message' => $error_message, 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'first_content_image', ); } } // Check if attachment is actually an image if ( ! wp_attachment_is_image( $attachment_id ) ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => __( 'Attachment is not an image', 'ai-thumbnails-maker' ), 'type' => 'first_content_image', 'image_size' => '', ) ); return array( 'success' => false, 'message' => __( 'Attachment is not an image', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'first_content_image', ); } // Check image size requirements if ( ! $this->image_finder->check_image_size( $attachment_id ) ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => __( 'Image does not meet size requirements', 'ai-thumbnails-maker' ), 'type' => 'first_content_image', 'image_size' => '', ) ); return array( 'success' => false, 'message' => __( 'Image does not meet size requirements', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'first_content_image', ); } // Set as featured image // If overwrite_existing is enabled, delete current thumbnail first if ( $overwrite_existing && has_post_thumbnail( $post_id ) ) { delete_post_thumbnail( $post_id ); } $result = set_post_thumbnail( $post_id, $attachment_id ); if ( $result || get_post_thumbnail_id( $post_id ) == $attachment_id ) { $metadata = wp_get_attachment_metadata( $attachment_id ); $image_size = ''; if ( isset( $metadata['width'], $metadata['height'] ) ) { $width = $metadata['width']; $height = $metadata['height']; // Get file size $file_path = get_attached_file( $attachment_id ); $file_size = ''; if ( $file_path && file_exists( $file_path ) ) { $size_bytes = filesize( $file_path ); $file_size = size_format( $size_bytes, 2 ); } $image_size = $width . 'x' . $height; if ( $file_size ) { $image_size .= ' (' . $file_size . ')'; } } $thumbnail_url = wp_get_attachment_image_url( $attachment_id, 'thumbnail' ); $full_image_url = wp_get_attachment_image_url( $attachment_id, 'full' ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => true, 'message' => __( 'Thumbnail generated successfully', 'ai-thumbnails-maker' ), 'type' => 'first_content_image', 'image_size' => $image_size, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $attachment_id, ) ); return array( 'success' => true, 'message' => __( 'Thumbnail generated successfully', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $attachment_id, 'image_size' => $image_size, 'type' => 'first_content_image', ); } $reason = $this->get_set_thumbnail_error_reason( $post, $attachment_id ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set thumbnail: %s', 'ai-thumbnails-maker' ), $reason ), 'type' => 'first_content_image', 'image_size' => '', ) ); return array( 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set thumbnail: %s', 'ai-thumbnails-maker' ), $reason ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'first_content_image', ); } /** * Generate thumbnail using AI * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @return array Result data. */ private function generate_with_ai( $post_id, $post ) { try { $attachment_id = $this->ai_generator->generate_for_post( $post_id ); if ( ! $attachment_id ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => __( 'Failed to generate AI image', 'ai-thumbnails-maker' ), 'type' => 'ai_generation', 'image_size' => '', ) ); return array( 'success' => false, 'message' => __( 'Failed to generate AI image', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'ai_generation', ); } // Get image metadata $metadata = wp_get_attachment_metadata( $attachment_id ); $image_size = ''; if ( isset( $metadata['width'], $metadata['height'] ) ) { $width = $metadata['width']; $height = $metadata['height']; // Get file size $file_path = get_attached_file( $attachment_id ); $file_size = ''; if ( $file_path && file_exists( $file_path ) ) { $size_bytes = filesize( $file_path ); $file_size = size_format( $size_bytes, 2 ); } $image_size = $width . 'x' . $height; if ( $file_size ) { $image_size .= ' (' . $file_size . ')'; } } // Set thumbnail $overwrite_existing = $this->settings['overwrite_existing'] ?? false; if ( $overwrite_existing && has_post_thumbnail( $post_id ) ) { delete_post_thumbnail( $post_id ); } $result = set_post_thumbnail( $post_id, $attachment_id ); if ( $result || get_post_thumbnail_id( $post_id ) == $attachment_id ) { $thumbnail_url = wp_get_attachment_image_url( $attachment_id, 'thumbnail' ); $full_image_url = wp_get_attachment_image_url( $attachment_id, 'full' ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => true, 'message' => __( 'AI image generated successfully', 'ai-thumbnails-maker' ), 'type' => 'ai_generation', 'image_size' => $image_size, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $attachment_id, ) ); return array( 'success' => true, 'message' => __( 'AI image generated successfully', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $attachment_id, 'image_size' => $image_size, 'type' => 'ai_generation', ); } else { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set thumbnail: %s', 'ai-thumbnails-maker' ), $this->get_set_thumbnail_error_reason( $post, $attachment_id ) ), 'type' => 'ai_generation', 'image_size' => '', ) ); return array( 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set thumbnail: %s', 'ai-thumbnails-maker' ), $this->get_set_thumbnail_error_reason( $post, $attachment_id ) ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'ai_generation', ); } } catch ( Exception $e ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => $e->getMessage(), 'type' => 'ai_generation', 'image_size' => '', ) ); return array( 'success' => false, 'message' => $e->getMessage(), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'ai_generation', ); } } /** * Add entry to generation log * * @param array $log_entry Log entry data. */ private function add_to_log( $log_entry ) { $level = isset( $log_entry['success'] ) && $log_entry['success'] ? 'success' : 'error'; $message = sprintf( 'Post: %s (ID: %d) | %s | Type: %s', $log_entry['post_title'] ?? 'Unknown', $log_entry['post_id'] ?? 0, $log_entry['message'] ?? 'No message', $log_entry['type'] ?? 'unknown' ); $context = array(); if ( isset( $log_entry['image_size'] ) && ! empty( $log_entry['image_size'] ) ) { $context['image_size'] = $log_entry['image_size']; } $this->log_manager->write( $level, $message, $context ); } /** * Build human-readable reason why set_post_thumbnail might fail * * @param WP_Post $post Post object. * @param int $attachment_id Attachment ID. * @return string Reason string. */ private function get_set_thumbnail_error_reason( $post, $attachment_id ) { if ( ! $post || ! isset( $post->post_type ) ) { return __( 'Invalid post', 'ai-thumbnails-maker' ); } if ( ! post_type_supports( $post->post_type, 'thumbnail' ) ) { /* translators: %s: Post type name */ return sprintf( __( 'Post type "%s" does not support featured images', 'ai-thumbnails-maker' ), $post->post_type ); } $attachment = get_post( $attachment_id ); if ( ! $attachment ) { return __( 'Attachment not found', 'ai-thumbnails-maker' ); } $file_path = get_attached_file( $attachment_id ); if ( empty( $file_path ) || ! file_exists( $file_path ) ) { return __( 'Image file is missing on the server', 'ai-thumbnails-maker' ); } // DB/meta update failed and thumbnail ID did not change. return __( 'database/meta update failed', 'ai-thumbnails-maker' ); } /** * Check if URL is http/https and looks like an image URL * * @param string $url URL. * @return bool */ private function is_http_image_url( $url ) { if ( empty( $url ) ) { return false; } $valid = wp_http_validate_url( $url ); if ( ! $valid ) { return false; } $parts = wp_parse_url( $url ); if ( empty( $parts['scheme'] ) || ! in_array( strtolower( $parts['scheme'] ), array( 'http', 'https' ), true ) ) { return false; } return true; } /** * Check if URL belongs to current site * * @param string $url URL to check. * @return bool True if URL is local. */ private function is_local_url( $url ) { if ( empty( $url ) ) { return false; } // Parse URL $parsed_url = wp_parse_url( $url ); if ( ! $parsed_url || ! isset( $parsed_url['host'] ) ) { // Relative URL - consider as local if ( strpos( $url, '/' ) === 0 || strpos( $url, 'wp-content' ) !== false ) { return true; } return false; } $url_host = strtolower( $parsed_url['host'] ); // Get site URLs $home_url = wp_parse_url( home_url() ); $site_url = wp_parse_url( site_url() ); $home_host = isset( $home_url['host'] ) ? strtolower( $home_url['host'] ) : ''; $site_host = isset( $site_url['host'] ) ? strtolower( $site_url['host'] ) : ''; // Check if host matches if ( $url_host === $home_host || $url_host === $site_host ) { return true; } // Check for localhost variations $localhost_patterns = array( 'localhost', '127.0.0.1', '::1' ); $is_localhost = false; foreach ( $localhost_patterns as $pattern ) { if ( strpos( $url_host, $pattern ) !== false ) { $is_localhost = true; break; } } // If both are localhost (even with different ports), consider as local if ( $is_localhost ) { foreach ( $localhost_patterns as $pattern ) { if ( strpos( $home_host, $pattern ) !== false || strpos( $site_host, $pattern ) !== false ) { return true; } } } return false; } /** * Securely download external image and add to Media Library * * @param string $url Image URL. * @param int $post_id Post ID to attach to. * @return int Attachment ID or 0 */ private function download_external_image_to_media( $url, $post_id ) { if ( ! $this->is_http_image_url( $url ) ) { $this->log_manager->write( 'debug', sprintf( 'External image download skipped: not a valid HTTP(S) URL (%s)', $url ) ); return 0; } // Проверяем, не загружали ли уже это изображение ранее $existing_id = $this->find_attachment_by_source_url( $url ); if ( $existing_id ) { $this->log_manager->write( 'debug', sprintf( 'External image already downloaded: using existing attachment ID %d (%s)', $existing_id, $url ) ); return $existing_id; } $this->log_manager->write( 'debug', sprintf( 'Attempting to download external image: %s', $url ) ); $head = wp_remote_head( $url, array( 'timeout' => 10, 'redirection' => 5 ) ); if ( is_wp_error( $head ) ) { $this->log_manager->write( 'error', sprintf( 'Failed to fetch remote image headers: %s (%s)', $head->get_error_message(), $url ) ); return 0; } $code = (int) wp_remote_retrieve_response_code( $head ); if ( $code < 200 || $code >= 400 ) { $this->log_manager->write( 'error', sprintf( 'Remote image returned HTTP %d (%s)', $code, $url ) ); return 0; } $content_type = wp_remote_retrieve_header( $head, 'content-type' ); if ( empty( $content_type ) || strpos( strtolower( $content_type ), 'image/' ) !== 0 ) { $this->log_manager->write( 'error', sprintf( 'Remote file is not an image (Content-Type: %s) (%s)', $content_type ?: 'unknown', $url ) ); return 0; } $max_bytes = (int) apply_filters( 'aitm_max_remote_image_size', 15 * 1024 * 1024 ); // 15 MB $content_length = (int) wp_remote_retrieve_header( $head, 'content-length' ); if ( $content_length > 0 && $content_length > $max_bytes ) { $this->log_manager->write( 'error', sprintf( 'Remote image too large: %s (max: %s) (%s)', size_format( $content_length ), size_format( $max_bytes ), $url ) ); return 0; } require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $tmp = download_url( $url, 30 ); if ( is_wp_error( $tmp ) ) { $this->log_manager->write( 'error', sprintf( 'Failed to download remote image: %s (%s)', $tmp->get_error_message(), $url ) ); return 0; } $path = wp_parse_url( $url, PHP_URL_PATH ); $basename = $path ? basename( $path ) : 'image'; $check = wp_check_filetype_and_ext( $tmp, $basename ); $mime_type = $check['type'] ?? ''; if ( empty( $mime_type ) || strpos( strtolower( $mime_type ), 'image/' ) !== 0 ) { $this->log_manager->write( 'error', sprintf( 'Downloaded file is not a valid image (MIME: %s) (%s)', $mime_type ?: 'unknown', $url ) ); wp_delete_file( $tmp ); return 0; } $file_array = array( 'name' => $basename, 'tmp_name' => $tmp, ); $attachment_id = media_handle_sideload( $file_array, $post_id ); if ( is_wp_error( $attachment_id ) ) { $this->log_manager->write( 'error', sprintf( 'Failed to create attachment: %s (%s)', $attachment_id->get_error_message(), $url ) ); wp_delete_file( $tmp ); return 0; } $this->log_manager->write( 'success', sprintf( 'External image downloaded successfully: attachment ID %d (%s)', $attachment_id, $url ) ); // Сохраняем исходный URL в мета для предотвращения дубликатов update_post_meta( $attachment_id, '_aitm_source_url', esc_url_raw( $url ) ); $file_path = get_attached_file( $attachment_id ); if ( $file_path && file_exists( $file_path ) ) { $metadata = wp_generate_attachment_metadata( $attachment_id, $file_path ); if ( ! empty( $metadata ) ) { wp_update_attachment_metadata( $attachment_id, $metadata ); } } return (int) $attachment_id; } /** * Find attachment by source URL in meta * * @param string $url Source URL. * @return int Attachment ID or 0 */ private function find_attachment_by_source_url( $url ) { global $wpdb; if ( empty( $url ) ) { return 0; } // Нормализуем URL для поиска $normalized_url = esc_url_raw( $url ); // Проверяем кеш $cache_key = 'aitm_src_' . md5( $normalized_url ); $cached_id = wp_cache_get( $cache_key, 'aitm' ); if ( false !== $cached_id ) { // Проверяем, что attachment ещё существует if ( $cached_id > 0 && get_post( $cached_id ) ) { return (int) $cached_id; } // Если не существует, удаляем из кеша wp_cache_delete( $cache_key, 'aitm' ); } // Быстрый поиск через индексированный запрос по meta_key + meta_value // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $attachment_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_aitm_source_url' AND meta_value = %s LIMIT 1", $normalized_url ) ); if ( $attachment_id ) { $attachment_id = (int) $attachment_id; // Проверяем, что это действительно attachment и он существует $post = get_post( $attachment_id ); if ( $post && $post->post_type === 'attachment' ) { // Кешируем на 1 час wp_cache_set( $cache_key, $attachment_id, 'aitm', 3600 ); return $attachment_id; } } // Кешируем отрицательный результат на 5 минут wp_cache_set( $cache_key, 0, 'aitm', 300 ); return 0; } /** * Generate thumbnail from title * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @return array Result data. */ private function generate_from_title( $post_id, $post ) { require_once AITM_PLUGIN_DIR . '/includes/class-title-image-generator.php'; try { $title_generator = new AITM_Title_Image_Generator( $this->settings ); $attachment_id = $title_generator->generate_for_post( $post_id ); if ( ! $attachment_id ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => __( 'Failed to generate title image', 'ai-thumbnails-maker' ), 'type' => 'generate_from_title', 'image_size' => '', ) ); return array( 'success' => false, 'message' => __( 'Failed to generate title image', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'generate_from_title', ); } // Get image metadata $metadata = wp_get_attachment_metadata( $attachment_id ); $image_size = ''; if ( isset( $metadata['width'], $metadata['height'] ) ) { $width = $metadata['width']; $height = $metadata['height']; // Get file size $file_path = get_attached_file( $attachment_id ); $file_size = ''; if ( $file_path && file_exists( $file_path ) ) { $size_bytes = filesize( $file_path ); $file_size = size_format( $size_bytes, 2 ); } $image_size = $width . 'x' . $height; if ( $file_size ) { $image_size .= ' (' . $file_size . ')'; } } // Set thumbnail $overwrite_existing = $this->settings['overwrite_existing'] ?? false; if ( $overwrite_existing && has_post_thumbnail( $post_id ) ) { delete_post_thumbnail( $post_id ); } $result = set_post_thumbnail( $post_id, $attachment_id ); if ( $result || get_post_thumbnail_id( $post_id ) == $attachment_id ) { $thumbnail_url = wp_get_attachment_image_url( $attachment_id, 'thumbnail' ); $full_image_url = wp_get_attachment_image_url( $attachment_id, 'full' ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => true, 'message' => __( 'Title image generated successfully', 'ai-thumbnails-maker' ), 'type' => 'generate_from_title', 'image_size' => $image_size, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $attachment_id, ) ); return array( 'success' => true, 'message' => __( 'Title image generated successfully', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $attachment_id, 'image_size' => $image_size, 'type' => 'generate_from_title', ); } $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set thumbnail: %s', 'ai-thumbnails-maker' ), $this->get_set_thumbnail_error_reason( $post, $attachment_id ) ), 'type' => 'generate_from_title', 'image_size' => '', ) ); return array( 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set thumbnail: %s', 'ai-thumbnails-maker' ), $this->get_set_thumbnail_error_reason( $post, $attachment_id ) ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'generate_from_title', ); } catch ( Exception $e ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => $e->getMessage(), 'type' => 'generate_from_title', 'image_size' => '', ) ); return array( 'success' => false, 'message' => $e->getMessage(), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'generate_from_title', ); } } /** * Use default image as thumbnail * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @return array Result data. */ private function use_default_image( $post_id, $post ) { $default_image_id = $this->settings['default_image_id'] ?? 0; if ( ! $default_image_id || ! wp_attachment_is_image( $default_image_id ) ) { $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, 'message' => __( 'No default image configured or image not found', 'ai-thumbnails-maker' ), 'type' => 'use_default_image', 'image_size' => '', ) ); return array( 'success' => false, 'message' => __( 'No default image configured or image not found', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'use_default_image', ); } // Get image metadata $metadata = wp_get_attachment_metadata( $default_image_id ); $image_size = ''; if ( isset( $metadata['width'], $metadata['height'] ) ) { $width = $metadata['width']; $height = $metadata['height']; // Get file size $file_path = get_attached_file( $default_image_id ); $file_size = ''; if ( $file_path && file_exists( $file_path ) ) { $size_bytes = filesize( $file_path ); $file_size = size_format( $size_bytes, 2 ); } $image_size = $width . 'x' . $height; if ( $file_size ) { $image_size .= ' (' . $file_size . ')'; } } // Set thumbnail $overwrite_existing = $this->settings['overwrite_existing'] ?? false; if ( $overwrite_existing && has_post_thumbnail( $post_id ) ) { delete_post_thumbnail( $post_id ); } $result = set_post_thumbnail( $post_id, $default_image_id ); if ( $result || get_post_thumbnail_id( $post_id ) == $default_image_id ) { $thumbnail_url = wp_get_attachment_image_url( $default_image_id, 'thumbnail' ); $full_image_url = wp_get_attachment_image_url( $default_image_id, 'full' ); $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => true, 'message' => __( 'Default image set successfully', 'ai-thumbnails-maker' ), 'type' => 'use_default_image', 'image_size' => $image_size, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $default_image_id, ) ); return array( 'success' => true, 'message' => __( 'Default image set successfully', 'ai-thumbnails-maker' ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'thumbnail_url' => $thumbnail_url, 'full_image_url' => $full_image_url, 'thumbnail_id' => $default_image_id, 'image_size' => $image_size, 'type' => 'use_default_image', ); } $this->add_to_log( array( 'post_id' => $post_id, 'post_title' => $post->post_title, 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set default image: %s', 'ai-thumbnails-maker' ), $this->get_set_thumbnail_error_reason( $post, $default_image_id ) ), 'type' => 'use_default_image', 'image_size' => '', ) ); return array( 'success' => false, /* translators: %s: Error reason */ 'message' => sprintf( __( 'Failed to set default image: %s', 'ai-thumbnails-maker' ), $this->get_set_thumbnail_error_reason( $post, $default_image_id ) ), 'post_id' => $post_id, 'post_title' => $post->post_title, 'type' => 'use_default_image', ); } /** * Get statistics * * @param string $post_type Post type. * @return array Statistics data. */ public function get_statistics( $post_type = 'post' ) { // Посты с превью $with_thumbnail = new WP_Query( array( 'post_type' => $post_type, 'post_status' => 'publish', 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( array( 'key' => '_thumbnail_id', 'compare' => 'EXISTS', ), ), ) ); // Посты без превью $without_thumbnail = new WP_Query( array( 'post_type' => $post_type, 'post_status' => 'publish', 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( array( 'key' => '_thumbnail_id', 'compare' => 'NOT EXISTS', ), ), ) ); $with_count = $with_thumbnail->found_posts; $without_count = $without_thumbnail->found_posts; $total = $with_count + $without_count; $percentage = $total > 0 ? round( ( $with_count / $total ) * 100 ) : 0; return array( 'with_thumbnail' => $with_count, 'without_thumbnail' => $without_count, 'total' => $total, 'percentage' => $percentage, ); } }