get_total_images(); $images_with_alt = $this->get_images_with_alt(); $images_missing_alt = $total_images - $images_with_alt; $coverage_percentage = ($total_images > 0) ? ($images_with_alt / $total_images) * 100 : 0; return array( 'total_images' => $total_images, 'images_with_alt' => $images_with_alt, 'images_missing_alt' => $images_missing_alt, 'coverage_percentage' => $coverage_percentage, 'missing_product_images' => $this->get_missing_product_images(), 'missing_featured_images' => $this->get_missing_featured_images(), 'missing_content_images' => $this->get_missing_content_images(), // New item 'missing_blog_images' => $this->get_missing_blog_images(), // New item 'monthly_stats' => $this->get_monthly_stats(), ); } /** * Retrieves the total number of images * * @return int Total number of images * * @since 1.0.0 */ private function get_total_images() { $cache_key = 'aiimatg_total_images_count'; $count = wp_cache_get($cache_key); if (false === $count) { $image_query = new WP_Query(array( 'post_type' => 'attachment', 'post_mime_type' => 'image', 'post_status' => 'inherit', 'posts_per_page' => -1, 'fields' => 'ids' )); $count = $image_query->found_posts; wp_cache_set($cache_key, $count, 'aiimatg_plugin', HOUR_IN_SECONDS); } return (int) $count; } /** * Retrieves the number of images with alt text * * @return int Number of images with alt text * * @since 1.0.0 */ private function get_images_with_alt() { $cache_key = 'aiimatg_images_with_alt_count'; $count = wp_cache_get($cache_key); if (false === $count) { $query_args = array( 'post_type' => 'attachment', 'post_mime_type' => 'image', 'post_status' => 'inherit', 'posts_per_page' => -1, 'fields' => 'ids', 'meta_key' => '_wp_attachment_image_alt', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => '', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'meta_compare' => '!=' ); $image_query = new WP_Query($query_args); $count = $image_query->found_posts; wp_cache_set($cache_key, $count, 'aiimatg_plugin', HOUR_IN_SECONDS); } return (int) $count; } /** * Retrieves the number of missing product images * * @return int Number of missing product images * * @since 1.0.0 */ private function get_missing_product_images() { $cache_key = 'aiimatg_missing_product_images_count'; $count = wp_cache_get($cache_key); if (false === $count) { if (!class_exists('WooCommerce')) { return 0; } $query_args = array( 'post_type' => 'product', 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'relation' => 'AND', array( 'key' => '_product_image_gallery', 'compare' => 'EXISTS' ) ) ); $product_query = new WP_Query($query_args); $missing_count = 0; if ($product_query->have_posts()) { foreach ($product_query->posts as $product_id) { $image_ids = array(); $featured_image_id = get_post_thumbnail_id($product_id); if ($featured_image_id) { $image_ids[] = $featured_image_id; } $gallery_image_ids = get_post_meta($product_id, '_product_image_gallery', true); if (!empty($gallery_image_ids)) { $gallery_image_ids = explode(',', $gallery_image_ids); $image_ids = array_merge($image_ids, $gallery_image_ids); } foreach ($image_ids as $image_id) { $alt_text = get_post_meta($image_id, '_wp_attachment_image_alt', true); if (empty($alt_text)) { $missing_count++; } } } } $count = $missing_count; wp_cache_set($cache_key, $count, 'aiimatg_plugin', HOUR_IN_SECONDS); } return (int) $count; } /** * Retrieves the number of missing featured images * * @return int Number of missing featured images * * @since 1.0.0 */ private function get_missing_featured_images() { $cache_key = 'aiimatg_missing_featured_images_count'; $count = wp_cache_get($cache_key); if (false === $count) { $query_args = array( 'post_type' => array('post', 'page', 'product'), 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'relation' => 'AND', array( 'key' => '_thumbnail_id', 'compare' => 'EXISTS' ) ) ); $featured_query = new WP_Query($query_args); $missing_count = 0; if ($featured_query->have_posts()) { foreach ($featured_query->posts as $post_id) { $featured_image_id = get_post_thumbnail_id($post_id); if ($featured_image_id) { $alt_text = get_post_meta($featured_image_id, '_wp_attachment_image_alt', true); if (empty($alt_text)) { $missing_count++; } } } } $count = $missing_count; wp_cache_set($cache_key, $count, 'aiimatg_plugin', HOUR_IN_SECONDS); } return (int) $count; } /** * Retrieves the number of missing content images * * @return int Number of missing content images * * @since 1.0.0 */ private function get_missing_content_images() { $cache_key = 'aiimatg_missing_content_images_count'; $count = wp_cache_get($cache_key); if (false === $count) { $query_args = array( 'post_type' => array('post', 'page'), 'posts_per_page' => -1, 'fields' => 'ids' ); $content_query = new WP_Query($query_args); $missing_count = 0; if ($content_query->have_posts()) { foreach ($content_query->posts as $post_id) { $post = get_post($post_id); $image_ids = $this->image_ids_from_content($post->post_content); foreach ($image_ids as $image_id) { $alt_text = get_post_meta($image_id, '_wp_attachment_image_alt', true); if (empty($alt_text)) { $missing_count++; } } } } $count = $missing_count; wp_cache_set($cache_key, $count, 'aiimatg_plugin', HOUR_IN_SECONDS); } return (int) $count; } /** * Retrieves the number of missing blog images * * @return int Number of missing blog images * * @since 1.0.0 */ private function get_missing_blog_images() { $cache_key = 'aiimatg_missing_blog_images_count'; $count = wp_cache_get($cache_key); if (false === $count) { $query_args = array( 'post_type' => 'post', 'posts_per_page' => -1, 'fields' => 'ids' ); $blog_query = new WP_Query($query_args); $missing_count = 0; if ($blog_query->have_posts()) { foreach ($blog_query->posts as $post_id) { // Get post content $post = get_post($post_id); $image_ids = $this->image_ids_from_content($post->post_content); foreach ($image_ids as $image_id) { $alt_text = get_post_meta($image_id, '_wp_attachment_image_alt', true); if (empty($alt_text)) { $missing_count++; } } } } $count = $missing_count; wp_cache_set($cache_key, $count, 'aiimatg_plugin', HOUR_IN_SECONDS); } return (int) $count; } /** * Calculate quality score for a single alt text * * @param string $alt_text The alt text to analyze * @param array $seo_keywords Array of SEO keywords * @return int Quality score (0-100) */ private function calculate_alt_text_quality_score($alt_text, $seo_keywords = array()) { $score = 70; $length = strlen($alt_text); if ($length < 20) { $score -= 20; } elseif ($length > 125) { $score -= 10; } elseif ($length >= 40 && $length <= 80) { $score += 10; // Bonus for ideal length } $descriptive_words = array('showing', 'displaying', 'contains', 'features', 'depicts', 'illustrates'); foreach ($descriptive_words as $word) { if (stripos($alt_text, $word) !== false) { $score += 5; break; } } if (!empty($seo_keywords)) { foreach ($seo_keywords as $keyword) { if (stripos($alt_text, $keyword) !== false) { $score += 15; break; } } } return max(0, min(100, $score)); } /** * Retrieves monthly statistics for alt text generation * * @return array Monthly statistics * * @since 1.0.0 */ private function get_monthly_stats() { $cache_key = 'aiimatg_monthly_stats'; $monthly_stats = wp_cache_get($cache_key); if (false === $monthly_stats) { $query_args = array( 'post_type' => 'attachment', 'post_mime_type' => 'image', 'posts_per_page' => -1, 'fields' => 'ids', 'meta_key' => '_wp_attachment_image_alt', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => '', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'meta_compare' => '!=' ); $images_query = new WP_Query($query_args); $monthly_stats = array(); if ($images_query->have_posts()) { $monthly_data = array(); foreach ($images_query->posts as $image) { $month = gmdate('Y-m', strtotime($image->post_modified)); $alt_text = get_post_meta($image->ID, '_wp_attachment_image_alt', true); if (!isset($monthly_data[$month])) { $monthly_data[$month] = array( 'total_generated' => 0, 'total_length' => 0 ); } $monthly_data[$month]['total_generated']++; $monthly_data[$month]['total_length'] += strlen($alt_text); } foreach ($monthly_data as $month => $data) { $monthly_stats[] = (object) array( 'month' => $month, 'total_generated' => $data['total_generated'], 'avg_length' => round($data['total_length'] / $data['total_generated'], 2) ); } usort($monthly_stats, function($a, $b) { return strcmp($b->month, $a->month); }); $monthly_stats = array_slice($monthly_stats, 0, 12); } wp_cache_set($cache_key, $monthly_stats, 'aiimatg_plugin', HOUR_IN_SECONDS); } return $monthly_stats; } /** * Generates CSV from analytics data * * @param array $data Analytics data * * @return string CSV content * * @since 1.0.0 */ private function generate_csv($data) { $csv = "Metric,Value\n"; foreach ($data as $key => $value) { $csv .= sprintf("%s,%s\n", str_replace('_', ' ', ucfirst($key)), $value); } return $csv; } /** * Enqueues analytics assets * * @param string $hook Current admin page hook * * @return void * * @since 1.0.0 */ public function enqueue_analytics_assets($hook) { if (strpos($hook, 'aiimatg-analytics') !== false) { // Enqueue CSS files wp_enqueue_style('aiimatg-analytics-css', AIIMATG_PLUGIN_URL . 'assets/css/analytics.css', array(), AIIMATG_PLUGIN_VERSION); wp_enqueue_style('aiimatg-animations-css', AIIMATG_PLUGIN_URL . 'assets/css/animations.css', array(), AIIMATG_PLUGIN_VERSION); // Enqueue analytics script wp_enqueue_script('aiimatg-analytics-js', AIIMATG_PLUGIN_URL . 'assets/js/analytics.js', array('jquery'), AIIMATG_PLUGIN_VERSION, true); } } /** * Internal method for logging messages only when debugging is enabled * * @param string $message The message to log * @return void */ private function aiimatg_log($message) { if (defined('WP_DEBUG') && WP_DEBUG) { // Use structured logging if (function_exists('aiimatg_log')) { aiimatg_log($message, 'debug'); } } } /** * Extracts image IDs from content * * @param string $content Content to extract image IDs from * * @return array Array of image IDs * * @since 1.0.0 */ private function image_ids_from_content($content) { $image_ids = array(); $patterns = array( '/wp-image-(\d+)/', // WordPress default '/attachment_(\d+)/', // Some themes/plugins '/class="[^"]*wp-image-(\d+)[^"]*"/', // Class-based '/id="[^"]*attachment-(\d+)[^"]*"/' // ID-based ); foreach ($patterns as $pattern) { preg_match_all($pattern, $content, $matches); if (!empty($matches[1])) { $image_ids = array_merge($image_ids, $matches[1]); } } return array_map('intval', array_unique($image_ids)); } }