Plugin Directory

Changeset 3788561


Ignore:
Timestamp:
11/06/2026 06:48:43 PM (18 hours ago)
Author:
afthemes
Message:

AI-powered image alt text generation integration

Location:
af-companion
Files:
2 added
15 edited

Legend:

Unmodified
Added
Removed
  • af-companion/trunk/af-companion.php

    r3785645 r3788561  
    33    Plugin Name: AF Companion
    44    Plugin URI: https://wordpress.org/plugins/af-companion/
    5     Description: The all-in-one performance and growth suite for WordPress. Instantly deploy expert-designed starter sites, optimize site speed with the Speed Booster engine, and scale your audience with integrated growth and diagnostic tools.
    6     Version: 3.0.0
     5    Description: Generate context-aware AI alt text, optimize WordPress performance, clean databases, monitor content and broken links, and manage site health.
     6    Version: 3.1.0
    77    Author: AF themes
    88    Author URI: https://www.afthemes.com
  • af-companion/trunk/assets/js/alt-manager.js

    r3785645 r3788561  
    11jQuery(document).ready(function($) {
     2
     3    // Model Selector Change Event
     4    $('#af_ai_model_select').on('change', function() {
     5        var selectedModel = $(this).val();
     6
     7        $.post(afAltData.ajax_url, {
     8            action: 'af_save_selected_ai_model',
     9            nonce: afAltData.nonce,
     10            model: selectedModel
     11        }, function(response) {
     12            if (response.success) {
     13                // Subtle visual feedback on dropdown change
     14                $('#af_ai_model_select').css('border-color', '#10b981').animate({ borderColor: '#cbd5e1' }, 1200);
     15            }
     16        });
     17    });
     18
     19    // 1. Manual Save Button Event
    220    $(document).on('click', '.af-save-alt-btn', function(e) {
    321        e.preventDefault();
    … …  
    2745                    $button.text('Saved ✓').css({'background': '#059669', 'color': '#fff', 'border-color': '#059669'});
    2846                    setTimeout(function() {
    29                         $button.prop('disabled', false).text('Save Alt').css({'background': '', 'color': '', 'border-color': ''});
     47                        $button.prop('disabled', false).text('Save').css({'background': '', 'color': '', 'border-color': ''});
    3048                    }, 1500);
    3149                } else {
    3250                    alert(response.data.message || 'Error updating alt text.');
    33                     $button.prop('disabled', false).text('Save Alt');
     51                    $button.prop('disabled', false).text('Save');
    3452                }
    3553            },
    3654            error: function() {
    3755                alert('Connection error. Please try again.');
    38                 $button.prop('disabled', false).text('Save Alt');
     56                $button.prop('disabled', false).text('Save');
    3957            }
    4058        });
    4159    });
     60
     61    // 2. Context AI Generation Event
     62    $(document).on('click', '.af-ai-alt-btn', function(e) {
     63        e.preventDefault();
     64        var $btn = $(this);
     65        var attachmentId = $btn.data('attachment-id');
     66        var $input = $('#alt-input-' + attachmentId);
     67        var originalHtml = $btn.html();
     68
     69        $('.af-ai-error-notice').remove();
     70
     71        $btn.prop('disabled', true).html('<span class="spinner is-active" style="float:none; margin:0 4px 0 0; width:14px; height:14px;"></span> Generating...');
     72
     73        $.post(afAltData.ajax_url, {
     74            action: 'af_alt_generate_ai',
     75            nonce: afAltData.nonce,
     76            attachment_id: attachmentId
     77        }, function(response) {
     78            $btn.prop('disabled', false).html(originalHtml);
     79
     80            if (response.success) {
     81                $input.val(response.data.alt_text);
     82                $input.css('border-color', '#10b981').animate({ borderColor: '#cbd5e1' }, 1500);
     83            } else {
     84                var errorMsg = response.data.message || 'AI generation failed.';
     85               
     86                if (errorMsg.indexOf('href=') !== -1) {
     87                    var $notice = $('<div class="notice notice-error af-ai-error-notice is-dismissible" style="margin: 15px 0; padding: 12px; border-left: 4px solid #dc2626;"><p style="margin:0; font-size: 13px;">' + errorMsg + '</p></div>');
     88                    $('.af-status-header').after($notice);
     89                } else {
     90                    alert('AI Notice: ' + errorMsg);
     91                }
     92            }
     93        }).fail(function() {
     94            $btn.prop('disabled', false).html(originalHtml);
     95            alert('Server communication error occurred.');
     96        });
     97    });
     98
    4299});
  • af-companion/trunk/inc/class-aftc-admin-header.php

    r3785645 r3788561  
    3333            'af-growth'             => array( 'label' => __( 'Growth Tools', 'af-companion' ), 'url' => admin_url( 'admin.php?page=af-growth' ) ),
    3434            'af-status'             => array( 'label' => __( 'System Status', 'af-companion' ), 'url' => admin_url( 'admin.php?page=af-status' ) ),
    35             'af-recommended-themes' => array( 'label' => __( 'Recommended Free Themes', 'af-companion' ), 'url' => admin_url( 'admin.php?page=af-recommended-themes' ) ),
     35            'af-recommended-themes' => array( 'label' => __( 'Free Themes', 'af-companion' ), 'url' => admin_url( 'admin.php?page=af-recommended-themes' ) ),
    3636        );
    3737        ?>
    … …  
    4848
    4949                <div class="af-app-actions">
    50                     <a href="https://afthemes.com/support/" target="_blank" rel="noopener noreferrer" class="button button-secondary af-app-btn-support">
     50                    <a href="https://afthemes.com/supports/" target="_blank" rel="noopener noreferrer" class="button button-secondary af-app-btn-support">
    5151                        <?php esc_html_e( 'Support', 'af-companion' ); ?>
    5252                    </a>
    5353                    <a href="https://afthemes.com/all-themes-plan/" target="_blank" rel="noopener noreferrer" class="button button-primary af-app-btn-pro">
    54                         <?php esc_html_e( 'Explore Pro', 'af-companion' ); ?>
     54                        <?php esc_html_e( 'Pro Themes & Plugins', 'af-companion' ); ?>
    5555                    </a>
    5656                </div>
  • af-companion/trunk/inc/class-aftc-alt-manager.php

    r3785645 r3788561  
    11<?php
    22/**
    3  * AF Alt Text Manager - Media Accessibility & Audit Engine
    4  *
    5  * Version: 1.0.1
    6  * Author: AF Themes
     3 * AF Companion - Centralized AI Settings & Alt Text Manager Engine
     4 *
     5 * @package           AF_Companion
     6 * @author            AF Themes
     7 * @license           GPL-2.0-or-later
     8 * @link              https://afthemes.com
     9 * @version           3.0.0
    710 */
    811
    912if ( ! defined( 'ABSPATH' ) ) {
    10     exit;
     13        exit; // Exit if accessed directly.
    1114}
    1215
     16/**
     17 * Main Alt Text Manager Administrative Controller Class
     18 */
    1319class AF_Alt_Text_Manager {
    1420
    15     public function __construct() {
    16         // Register top-level admin menu (bulletproof routing)
    17         add_action( 'admin_menu', array( $this, 'register_menu' ) );
    18 
    19         // AJAX Handlers for Inline Alt Text Updates
    20         add_action( 'wp_ajax_af_alt_quick_update', array( $this, 'ajax_quick_update' ) );
    21 
    22         // Enqueue Assets
    23         add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
    24     }
    25 
    26     /**
    27      * Register Top-Level Menu Page
    28      */
    29     public function register_menu() {
    30         add_menu_page(
    31             esc_html__( 'Alt Text Manager', 'af-companion' ),
    32             esc_html__( 'Alt Text Manager', 'af-companion' ),
    33             'upload_files',
    34             'af-alt-manager',
    35             array( $this, 'render_admin_page' ),
    36             'dashicons-format-image',
    37             35
    38         );
    39     }
    40 
    41     /**
    42      * Enqueue Styles & Scripts
    43      */
    44     public function enqueue_assets( $hook ) {
    45         if ( strpos( $hook, 'af-alt-manager' ) === false ) {
    46             return;
    47         }
    48 
    49         wp_enqueue_script(
    50             'af-alt-manager-js',
    51             AFTC_URL . '/assets/js/alt-manager.js',
    52             array( 'jquery' ),
    53             '1.0.1',
    54             true
    55         );
    56 
    57         wp_localize_script(
    58             'af-alt-manager-js',
    59             'afAltData',
    60             array(
    61                 'ajax_url' => admin_url( 'admin-ajax.php' ),
    62                 'nonce'    => wp_create_nonce( 'af_alt_nonce' ),
    63             )
    64         );
    65     }
    66 
    67     /**
    68      * Fast SQL Media Statistics Aggregation
    69      */
    70     private function get_alt_stats() {
    71         global $wpdb;
    72 
    73         $total = (int) $wpdb->get_var( "
    74             SELECT COUNT(ID) FROM {$wpdb->posts}
    75             WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%'
    76         " );
    77 
    78         if ( $total === 0 ) {
    79             return array( 'total' => 0, 'missing' => 0, 'valid' => 0 );
    80         }
    81 
    82         $missing = (int) $wpdb->get_var( "
    83             SELECT COUNT(p.ID)
    84             FROM {$wpdb->posts} p
    85             LEFT JOIN {$wpdb->postmeta} m ON (p.ID = m.post_id AND m.meta_key = '_wp_attachment_image_alt')
    86             WHERE p.post_type = 'attachment'
    87               AND p.post_mime_type LIKE 'image/%'
    88               AND (m.meta_value IS NULL OR TRIM(m.meta_value) = '')
    89         " );
    90 
    91         $missing = max( 0, $missing );
    92         $valid   = max( 0, $total - $missing ); // Fixed calculation glitch
    93 
    94         return array(
    95             'total'   => $total,
    96             'missing' => $missing,
    97             'valid'   => $valid,
    98         );
    99     }
    100 
    101     /**
    102      * Query Media Attachments Safely with Filters
    103      */
    104     private function get_media_attachments( $filter = 'all', $paged = 1, $per_page = 20 ) {
    105         $args = array(
    106             'post_type'      => 'attachment',
    107             'post_mime_type' => 'image',
    108             'post_status'    => 'inherit',
    109             'paged'          => $paged,
    110             'posts_per_page' => $per_page,
    111             'orderby'        => 'date',
    112             'order'          => 'DESC',
    113         );
    114 
    115         if ( $filter === 'missing' ) {
    116             $args['meta_query'] = array(
    117                 'relation' => 'OR',
    118                 array(
    119                     'key'     => '_wp_attachment_image_alt',
    120                     'compare' => 'NOT EXISTS',
    121                 ),
    122                 array(
    123                     'key'     => '_wp_attachment_image_alt',
    124                     'value'   => '',
    125                     'compare' => '=',
    126                 ),
    127             );
    128         } elseif ( $filter === 'valid' ) {
    129             $args['meta_query'] = array(
    130                 array(
    131                     'key'     => '_wp_attachment_image_alt',
    132                     'value'   => '',
    133                     'compare' => '!=',
    134                 ),
    135             );
    136         }
    137 
    138         return new WP_Query( $args );
    139     }
    140 
    141     /**
    142      * Main Administration View & Report Dashboard
    143      */
    144     public function render_admin_page() {
    145         if ( ! current_user_can( 'upload_files' ) ) {
    146             wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'af-companion' ) );
    147         }
    148 
    149         $filter       = isset( $_GET['alt_filter'] ) ? sanitize_key( $_GET['alt_filter'] ) : 'all';
    150         $current_page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1;
    151         $per_page     = 20;
    152 
    153         $stats = $this->get_alt_stats();
    154         $query = $this->get_media_attachments( $filter, $current_page, $per_page );
    155         ?>
    156         <?php AF_Admin_Header::render( 'af-alt-manager' ); ?>
    157         <div class="wrap af-status-container">
    158 
    159             <div class="af-status-header">
     21        public function __construct() {
     22                add_action( 'admin_menu', array( $this, 'register_menu' ) );
     23                add_action( 'wp_ajax_af_alt_quick_update', array( $this, 'ajax_quick_update' ) );
     24                add_action( 'wp_ajax_af_alt_generate_ai', array( $this, 'ajax_generate_ai_alt' ) );
     25                add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
     26        }
     27
     28        public function register_menu() {
     29                add_menu_page(
     30                        esc_html__( 'Alt Text Manager Powered by AI', 'af-companion' ),
     31                        esc_html__( 'AI Alt Text', 'af-companion' ),
     32                        'upload_files',
     33                        'af-alt-manager',
     34                        array( $this, 'render_admin_page' ),
     35                        'dashicons-format-image',
     36                        35
     37                );
     38        }
     39
     40        public function enqueue_assets( $hook ) {
     41                if ( false === strpos( $hook, 'af-alt-manager' ) ) {
     42                        return;
     43                }
     44
     45                wp_enqueue_script(
     46                        'af-alt-manager-js',
     47                        AFTC_URL . 'assets/js/alt-manager.js',
     48                        array( 'jquery' ),
     49                        '3.0.0',
     50                        true
     51                );
     52
     53                wp_localize_script(
     54                        'af-alt-manager-js',
     55                        'afAltData',
     56                        array(
     57                                'ajax_url' => admin_url( 'admin-ajax.php' ),
     58                                'nonce'    => wp_create_nonce( 'af_alt_nonce' ),
     59                        )
     60                );
     61        }
     62
     63        private function get_alt_stats() {
     64                global $wpdb;
     65
     66                $total = (int) $wpdb->get_var(
     67                        $wpdb->prepare(
     68                                "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_type = %s AND post_mime_type LIKE %s",
     69                                'attachment',
     70                                'image/%'
     71                        )
     72                );
     73
     74                if ( 0 === $total ) {
     75                        return array(
     76                                'total'   => 0,
     77                                'missing' => 0,
     78                                'valid'   => 0,
     79                        );
     80                }
     81
     82                $missing = (int) $wpdb->get_var(
     83                        $wpdb->prepare(
     84                                "SELECT COUNT(p.ID)
     85                                 FROM {$wpdb->posts} p
     86                                 LEFT JOIN {$wpdb->postmeta} m ON (p.ID = m.post_id AND m.meta_key = %s)
     87                                 WHERE p.post_type = %s
     88                                   AND p.post_mime_type LIKE %s
     89                                   AND (m.meta_value IS NULL OR TRIM(m.meta_value) = '')",
     90                                '_wp_attachment_image_alt',
     91                                'attachment',
     92                                'image/%'
     93                        )
     94                );
     95
     96                $missing = max( 0, $missing );
     97                $valid   = max( 0, $total - $missing );
     98
     99                return array(
     100                        'total'   => $total,
     101                        'missing' => $missing,
     102                        'valid'   => $valid,
     103                );
     104        }
     105
     106        private function get_media_attachments( $filter = 'all', $paged = 1, $per_page = 20 ) {
     107                $args = array(
     108                        'post_type'      => 'attachment',
     109                        'post_mime_type' => 'image',
     110                        'post_status'    => 'inherit',
     111                        'paged'          => absint( $paged ),
     112                        'posts_per_page' => absint( $per_page ),
     113                        'orderby'        => 'date',
     114                        'order'          => 'DESC',
     115                );
     116
     117                if ( 'missing' === $filter ) {
     118                        $args['meta_query'] = array(
     119                                'relation' => 'OR',
     120                                array(
     121                                        'key'     => '_wp_attachment_image_alt',
     122                                        'compare' => 'NOT EXISTS',
     123                                ),
     124                                array(
     125                                        'key'     => '_wp_attachment_image_alt',
     126                                        'value'   => '',
     127                                        'compare' => '=',
     128                                ),
     129                        );
     130                } elseif ( 'valid' === $filter ) {
     131                        $args['meta_query'] = array(
     132                                array(
     133                                        'key'     => '_wp_attachment_image_alt',
     134                                        'value'   => '',
     135                                        'compare' => '!=',
     136                                ),
     137                        );
     138                }
     139
     140                return new WP_Query( $args );
     141        }
     142
     143        public function render_admin_page() {
     144                if ( ! current_user_can( 'upload_files' ) ) {
     145                        wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'af-companion' ) );
     146                }
     147
     148                $filter       = isset( $_GET['alt_filter'] ) ? sanitize_key( $_GET['alt_filter'] ) : 'all';
     149                $current_page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1;
     150                $per_page     = 20;
     151
     152                $stats           = $this->get_alt_stats();
     153                $query           = $this->get_media_attachments( $filter, $current_page, $per_page );
     154                $is_ai_connected = AF_AI_Helper::is_connector_available();
     155                ?>
     156                <?php AF_Admin_Header::render( 'af-alt-manager' ); ?>
     157                <div class="wrap af-status-container">
     158                       
     159
     160                        <div class="af-status-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
     161                                <div class="af-status-header-wrap">
    160162                <div class="af-status-branding">
    161                     <h1><?php esc_html_e( 'Alt Text Manager', 'af-companion' ); ?></h1>
     163                    <h1><?php esc_html_e( 'AI Alt Text Manager', 'af-companion' ); ?></h1>
    162164                    <span class="af-badge-status"><?php esc_html_e( 'Media Accessibility', 'af-companion' ); ?></span>
    163165                </div>
    164166                <p class="af-subtitle"><?php esc_html_e( 'Audit your media library, identify images missing alternative text, and optimize web accessibility instantly.', 'af-companion' ); ?></p>
    165167            </div>
    166 
    167             <!-- Metrics Overview Cards -->
    168             <div class="af-cm-metrics">
    169                 <div class="af-cm-card">
    170                     <span class="af-card-num"><?php echo esc_html( number_format_i18n( $stats['total'] ) ); ?></span>
    171                     <span class="af-card-label"><?php esc_html_e( 'Total Images Scanned', 'af-companion' ); ?></span>
    172                 </div>
    173                 <div class="af-cm-card card-warning">
    174                     <span class="af-card-num"><?php echo esc_html( number_format_i18n( $stats['missing'] ) ); ?></span>
    175                     <span class="af-card-label"><?php esc_html_e( 'Missing Alt Text', 'af-companion' ); ?></span>
    176                 </div>
    177                 <div class="af-cm-card card-success">
    178                     <span class="af-card-num"><?php echo esc_html( number_format_i18n( $stats['valid'] ) ); ?></span>
    179                     <span class="af-card-label"><?php esc_html_e( 'Has Alt Text', 'af-companion' ); ?></span>
    180                 </div>
    181             </div>
    182 
    183             <!-- Toolbar Filter -->
    184             <div class="af-cm-toolbar">
    185                 <form method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>">
    186                     <input type="hidden" name="page" value="af-alt-manager" />
    187 
    188                     <label for="alt_filter"><?php esc_html_e( 'Filter Media:', 'af-companion' ); ?></label>
    189                     <select name="alt_filter" id="alt_filter">
    190                         <option value="all" <?php selected( $filter, 'all' ); ?>><?php esc_html_e( 'All Images', 'af-companion' ); ?></option>
    191                         <option value="missing" <?php selected( $filter, 'missing' ); ?>><?php esc_html_e( 'Missing Alt Text Only', 'af-companion' ); ?></option>
    192                         <option value="valid" <?php selected( $filter, 'valid' ); ?>><?php esc_html_e( 'Has Alt Text', 'af-companion' ); ?></option>
    193                     </select>
    194 
    195                     <button type="submit" class="button"><?php esc_html_e( 'Filter Audit', 'af-companion' ); ?></button>
    196                 </form>
    197             </div>
    198 
    199             <!-- Media Table -->
    200             <table class="wp-list-table widefat fixed striped af-cm-table">
    201                 <thead>
    202                     <tr>
    203                         <th class="column-thumbnail" style="width: 70px;"><?php esc_html_e( 'Image', 'af-companion' ); ?></th>
    204                         <th class="column-title"><?php esc_html_e( 'File & Filename', 'af-companion' ); ?></th>
    205                         <th class="column-alt" style="width: 45%;"><?php esc_html_e( 'Alternative Text (Alt)', 'af-companion' ); ?></th>
    206                         <th class="column-actions" style="width: 140px; text-align: right;"><?php esc_html_e( 'Quick Action', 'af-companion' ); ?></th>
    207                     </tr>
    208                 </thead>
    209                 <tbody>
    210                     <?php if ( $query->have_posts() ) : ?>
    211                         <?php while ( $query->have_posts() ) : $query->the_post();
    212                             $attachment_id = get_the_ID();
    213                             $alt_text      = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
    214                             $filename      = basename( get_attached_file( $attachment_id ) );
    215                            
    216                             // Try thumbnail first, fallback to full image URL if thumbnail file is missing on disk
    217                             $thumb_url = wp_get_attachment_image_url( $attachment_id, 'thumbnail' );
    218                             if ( ! $thumb_url ) {
    219                                 $thumb_url = wp_get_attachment_image_url( $attachment_id, 'full' );
    220                             }
    221                             $has_alt = ! empty( trim( $alt_text ) );
    222                             ?>
    223                             <tr>
    224                                 <td class="column-thumbnail">
    225                                     <?php if ( $thumb_url ) : ?>
    226                                         <img src="<?php echo esc_url( $thumb_url ); ?>" alt="" style="width: 48px; height: 48px; object-fit: cover; border-radius: 4px; border: 1px solid #cbd5e1;" />
    227                                     <?php else : ?>
    228                                         <span class="dashicons dashicons-format-image" style="font-size: 32px; color: #94a3b8;"></span>
    229                                     <?php endif; ?>
    230                                 </td>
    231                                 <td class="column-title">
    232                                     <strong><a href="<?php echo esc_url( get_edit_post_link( $attachment_id ) ); ?>" target="_blank"><?php echo esc_html( get_the_title() ); ?></a></strong>
    233                                     <div style="color: #64748b; font-size: 11px; margin-top: 2px;"><?php echo esc_html( $filename ); ?></div>
    234                                 </td>
    235                                 <td class="column-alt">
    236                                     <input type="text"
    237                                            id="alt-input-<?php echo esc_attr( $attachment_id ); ?>"
    238                                            value="<?php echo esc_attr( $alt_text ); ?>"
    239                                            placeholder="<?php esc_attr_e( 'Enter descriptive alternative text...', 'af-companion' ); ?>"
    240                                            style="width: 100%; padding: 6px 10px; border: 1px solid #cbd5e1; border-radius: 4px;" />
    241                                 </td>
    242                                 <td class="column-actions" style="text-align: right;">
    243                                     <button type="button"
    244                                             class="button button-small af-save-alt-btn"
    245                                             data-attachment-id="<?php echo esc_attr( $attachment_id ); ?>">
    246                                         <?php esc_html_e( 'Save Alt', 'af-companion' ); ?>
    247                                     </button>
    248                                 </td>
    249                             </tr>
    250                         <?php endwhile; wp_reset_postdata(); ?>
    251                     <?php else : ?>
    252                         <tr>
    253                             <td colspan="4"><?php esc_html_e( 'No images found matching your audit filter.', 'af-companion' ); ?></td>
    254                         </tr>
    255                     <?php endif; ?>
    256                 </tbody>
    257             </table>
    258 
    259             <!-- Pagination -->
    260             <?php
    261             $total_pages = $query->max_num_pages;
    262             if ( $total_pages > 1 ) :
    263                 ?>
    264                 <div class="af-cm-pagination">
    265                     <?php
    266                     echo paginate_links( array(
    267                         'base'      => add_query_arg( 'paged', '%#%' ),
    268                         'format'    => '',
    269                         'prev_text' => '&laquo;',
    270                         'next_text' => '&raquo;',
    271                         'total'     => $total_pages,
    272                         'current'   => $current_page,
    273                     ) );
    274                     ?>
    275                 </div>
    276             <?php endif; ?>
    277 
    278         </div>
    279         <?php
    280     }
    281 
    282     /**
    283      * AJAX Handler for Inline Alt Text Saving
    284      */
    285     public function ajax_quick_update() {
    286         check_ajax_referer( 'af_alt_nonce', 'nonce' );
    287 
    288         $attachment_id = isset( $_POST['attachment_id'] ) ? absint( $_POST['attachment_id'] ) : 0;
    289         $alt_text      = isset( $_POST['alt_text'] ) ? sanitize_text_field( $_POST['alt_text'] ) : '';
    290 
    291         if ( ! $attachment_id || ! current_user_can( 'upload_files', $attachment_id ) ) {
    292             wp_send_json_error( array( 'message' => esc_html__( 'Permission denied.', 'af-companion' ) ) );
    293         }
    294 
    295         update_post_meta( $attachment_id, '_wp_attachment_image_alt', $alt_text );
    296 
    297         wp_send_json_success( array(
    298             'message'  => esc_html__( 'Alt text updated.', 'af-companion' ),
    299             'alt_text' => $alt_text,
    300         ) );
    301     }
     168                                <div>
     169                                        <a href="<?php echo esc_url( admin_url( 'admin.php?page=af-ai-settings' ) ); ?>" class="button button-secondary">
     170                                                <span aria-hidden="true" style="vertical-align: middle; margin-top: 3px;"></span>
     171                                                <?php esc_html_e( 'AI Settings', 'af-companion' ); ?>
     172                                        </a>
     173                                </div>
     174                        </div>
     175
     176                        <!-- AI Status Banner -->
     177                        <div class="af-ai-status-banner" style="background: #fff; border: 1px solid #e2e8f0; border-left: 4px solid <?php echo $is_ai_connected ? '#10b981' : '#f59e0b'; ?>; border-radius: 8px; padding: 15px 20px; margin-bottom: 25px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
     178                                <div style="display: flex; align-items: center; gap: 12px;">
     179                                        <span class="dashicons dashicons-superhero" aria-hidden="true" style="font-size: 24px; width: 24px; height: 24px; color: <?php echo $is_ai_connected ? '#10b981' : '#f59e0b'; ?>;"></span>
     180                                        <div>
     181                                                <div style="font-weight: 700; font-size: 14px; color: #0f172a;">
     182                                                        <?php echo $is_ai_connected ? esc_html__( 'AI Connectors Active', 'af-companion' ) : esc_html__( 'AI Connector Not Configured', 'af-companion' ); ?>
     183                                                </div>
     184                                                <div style="font-size: 12px; color: #64748b; margin-top: 2px;">
     185                                                        <?php echo $is_ai_connected ? esc_html__( 'Using globally configured AI settings & preferences.', 'af-companion' ) : esc_html__( 'Connect an AI provider under Settings -> Connectors to unlock generation.', 'af-companion' ); ?>
     186                                                </div>
     187                                        </div>
     188                                </div>
     189                                <div>
     190                                        <a href="<?php echo esc_url( AF_AI_Helper::get_connector_setup_url() ); ?>" class="button button-secondary">
     191                                                <?php esc_html_e( 'Manage Connectors', 'af-companion' ); ?>
     192                                        </a>
     193                                </div>
     194                        </div>
     195
     196                        <!-- Metrics Overview Cards -->
     197                        <div class="af-cm-metrics" style="display: flex; gap: 15px; margin-bottom: 20px;">
     198                                <div class="af-cm-card" style="background: #fff; padding: 15px; border: 1px solid #ccd0d7; border-radius: 4px; flex: 1;">
     199                                        <span class="af-card-num" style="display: block; font-size: 20px; font-weight: bold;"><?php echo esc_html( number_format_i18n( $stats['total'] ) ); ?></span>
     200                                        <span class="af-card-label" style="color: #646970;"><?php esc_html_e( 'Total Images Scanned', 'af-companion' ); ?></span>
     201                                </div>
     202                                <div class="af-cm-card card-warning" style="background: #fff; padding: 15px; border: 1px solid #ccd0d7; border-radius: 4px; flex: 1;">
     203                                        <span class="af-card-num" style="display: block; font-size: 20px; font-weight: bold; color: #d63638;"><?php echo esc_html( number_format_i18n( $stats['missing'] ) ); ?></span>
     204                                        <span class="af-card-label" style="color: #646970;"><?php esc_html_e( 'Missing Alt Text', 'af-companion' ); ?></span>
     205                                </div>
     206                                <div class="af-cm-card card-success" style="background: #fff; padding: 15px; border: 1px solid #ccd0d7; border-radius: 4px; flex: 1;">
     207                                        <span class="af-card-num" style="display: block; font-size: 20px; font-weight: bold; color: #00a32a;"><?php echo esc_html( number_format_i18n( $stats['valid'] ) ); ?></span>
     208                                        <span class="af-card-label" style="color: #646970;"><?php esc_html_e( 'Has Alt Text', 'af-companion' ); ?></span>
     209                                </div>
     210                        </div>
     211
     212                        <!-- Toolbar Filter -->
     213                        <div class="af-cm-toolbar" style="margin-bottom: 15px;">
     214                                <form method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>">
     215                                        <input type="hidden" name="page" value="af-alt-manager" />
     216                                        <label for="alt_filter" style="margin-right: 5px;"><?php esc_html_e( 'Filter Media:', 'af-companion' ); ?></label>
     217                                        <select name="alt_filter" id="alt_filter">
     218                                                <option value="all" <?php selected( $filter, 'all' ); ?>><?php esc_html_e( 'All Images', 'af-companion' ); ?></option>
     219                                                <option value="missing" <?php selected( $filter, 'missing' ); ?>><?php esc_html_e( 'Missing Alt Text Only', 'af-companion' ); ?></option>
     220                                                <option value="valid" <?php selected( $filter, 'valid' ); ?>><?php esc_html_e( 'Has Alt Text', 'af-companion' ); ?></option>
     221                                        </select>
     222                                        <button type="submit" class="button"><?php esc_html_e( 'Filter Audit', 'af-companion' ); ?></button>
     223                                </form>
     224                        </div>
     225
     226                        <!-- Media Table -->
     227                        <table class="wp-list-table widefat fixed striped">
     228                                <thead>
     229                                        <tr>
     230                                                <th scope="col" style="width: 70px;"><?php esc_html_e( 'Image', 'af-companion' ); ?></th>
     231                                                <th scope="col"><?php esc_html_e( 'File & Context', 'af-companion' ); ?></th>
     232                                                <th scope="col" style="width: 42%;"><?php esc_html_e( 'Alternative Text (Alt)', 'af-companion' ); ?></th>
     233                                                <th scope="col" style="width: 150px; text-align: right;"><?php esc_html_e( 'Quick Action', 'af-companion' ); ?></th>
     234                                        </tr>
     235                                </thead>
     236                                <tbody>
     237                                        <?php if ( $query->have_posts() ) : ?>
     238                                                <?php
     239                                                while ( $query->have_posts() ) :
     240                                                        $query->the_post();
     241                                                        $attachment_id = get_the_ID();
     242                                                        $alt_text      = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
     243                                                        $filename      = basename( get_attached_file( $attachment_id ) );
     244
     245                                                        $parent_id    = wp_get_post_parent_id( $attachment_id );
     246                                                        $parent_title = $parent_id ? get_the_title( $parent_id ) : '';
     247                                                        $thumb_url    = wp_get_attachment_image_url( $attachment_id, 'thumbnail' );
     248                                                        if ( ! $thumb_url ) {
     249                                                                $thumb_url = wp_get_attachment_image_url( $attachment_id, 'full' );
     250                                                        }
     251                                                        ?>
     252                                                        <tr>
     253                                                                <td>
     254                                                                        <?php if ( $thumb_url ) : ?>
     255                                                                                <img src="<?php echo esc_url( $thumb_url ); ?>" alt="" style="width: 48px; height: 48px; object-fit: cover; border-radius: 4px; border: 1px solid #cbd5e1;" />
     256                                                                        <?php else : ?>
     257                                                                                <span class="dashicons dashicons-format-image" aria-hidden="true" style="font-size: 32px; color: #94a3b8;"></span>
     258                                                                        <?php endif; ?>
     259                                                                </td>
     260                                                                <td>
     261                                                                        <strong><a href="<?php echo esc_url( get_edit_post_link( $attachment_id ) ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( get_the_title() ); ?></a></strong>
     262                                                                        <div style="color: #64748b; font-size: 11px; margin-top: 2px;"><?php echo esc_html( $filename ); ?></div>
     263                                                                        <?php if ( ! empty( $parent_title ) ) : ?>
     264                                                                                <div style="color: #0284c7; font-size: 11px; margin-top: 2px;">
     265                                                                                        <span class="dashicons dashicons-media-text" aria-hidden="true" style="font-size: 12px; width: 12px; height: 12px; vertical-align: middle;"></span>
     266                                                                                        <?php echo esc_html( 'Parent: ' . $parent_title ); ?>
     267                                                                                </div>
     268                                                                        <?php endif; ?>
     269                                                                </td>
     270                                                                <td>
     271                                                                        <label for="alt-input-<?php echo esc_attr( $attachment_id ); ?>" class="screen-reader-text"><?php echo esc_html( sprintf( __( 'Alternative text for %s', 'af-companion' ), get_the_title() ) ); ?></label>
     272                                                                        <input type="text"
     273                                                                                   id="alt-input-<?php echo esc_attr( $attachment_id ); ?>"
     274                                                                                   value="<?php echo esc_attr( $alt_text ); ?>"
     275                                                                                   placeholder="<?php esc_attr_e( 'Enter descriptive alternative text...', 'af-companion' ); ?>"
     276                                                                                   style="width: 100%; padding: 6px 10px; border: 1px solid #cbd5e1; border-radius: 4px;" />
     277                                                                </td>
     278                                                                <td style="text-align: right; white-space: nowrap;">
     279                                                                        <button type="button"
     280                                                                                        class="button button-small af-ai-alt-btn"
     281                                                                                        data-attachment-id="<?php echo esc_attr( $attachment_id ); ?>"
     282                                                                                        style="color: #0284c7; border-color: #0284c7; margin-right: 4px;">
     283                                                                                <span class="dashicons dashicons-superhero" aria-hidden="true" style="font-size: 14px; vertical-align: middle; margin-top: 2px;"></span>
     284                                                                                <?php esc_html_e( 'Context AI', 'af-companion' ); ?>
     285                                                                        </button>
     286                                                                        <button type="button"
     287                                                                                        class="button button-small af-save-alt-btn"
     288                                                                                        data-attachment-id="<?php echo esc_attr( $attachment_id ); ?>">
     289                                                                                <?php esc_html_e( 'Save', 'af-companion' ); ?>
     290                                                                        </button>
     291                                                                </td>
     292                                                        </tr>
     293                                                <?php endwhile; wp_reset_postdata(); ?>
     294                                        <?php else : ?>
     295                                                <tr>
     296                                                        <td colspan="4"><?php esc_html_e( 'No images found matching your audit filter.', 'af-companion' ); ?></td>
     297                                                </tr>
     298                                        <?php endif; ?>
     299                                </tbody>
     300                        </table>
     301
     302                        <!-- Pagination -->
     303                        <?php
     304                        $total_pages = $query->max_num_pages;
     305                        if ( $total_pages > 1 ) :
     306                                ?>
     307                                <nav class="af-cm-pagination" aria-label="<?php esc_attr_e( 'Media audit pagination', 'af-companion' ); ?>" style="margin-top: 15px;">
     308                                        <?php
     309                                        echo paginate_links(
     310                                                array(
     311                                                        'base'      => add_query_arg( 'paged', '%#%' ),
     312                                                        'format'    => '',
     313                                                        'prev_text' => '&laquo;',
     314                                                        'next_text' => '&raquo;',
     315                                                        'total'     => $total_pages,
     316                                                        'current'   => $current_page,
     317                                                )
     318                                        );
     319                                        ?>
     320                                </nav>
     321                        <?php endif; ?>
     322
     323                </div>
     324                <?php
     325        }
     326
     327        public function ajax_quick_update() {
     328                check_ajax_referer( 'af_alt_nonce', 'nonce' );
     329
     330                $attachment_id = isset( $_POST['attachment_id'] ) ? absint( $_POST['attachment_id'] ) : 0;
     331                $alt_text      = isset( $_POST['alt_text'] ) ? sanitize_text_field( wp_unslash( $_POST['alt_text'] ) ) : '';
     332
     333                if ( ! $attachment_id || ! current_user_can( 'upload_files', $attachment_id ) ) {
     334                        wp_send_json_error( array( 'message' => esc_html__( 'Permission denied.', 'af-companion' ) ) );
     335                }
     336
     337                update_post_meta( $attachment_id, '_wp_attachment_image_alt', $alt_text );
     338
     339                wp_send_json_success(
     340                        array(
     341                                'message'  => esc_html__( 'Alt text updated.', 'af-companion' ),
     342                                'alt_text' => $alt_text,
     343                        )
     344                );
     345        }
     346
     347        public function ajax_generate_ai_alt() {
     348                check_ajax_referer( 'af_alt_nonce', 'nonce' );
     349
     350                $attachment_id = isset( $_POST['attachment_id'] ) ? absint( $_POST['attachment_id'] ) : 0;
     351
     352                if ( ! $attachment_id || ! current_user_can( 'upload_files', $attachment_id ) ) {
     353                        wp_send_json_error( array( 'message' => esc_html__( 'Permission denied.', 'af-companion' ) ) );
     354                }
     355
     356                if ( ! AF_AI_Helper::is_connector_available() ) {
     357                        wp_send_json_error(
     358                                array(
     359                                        'message' => sprintf(
     360                                                /* translators: %s: Connectors setup page URL */
     361                                                __( 'AI Connector not configured. Please set up your API keys in <a href="%s" target="_blank">Settings -> Connectors</a>.', 'af-companion' ),
     362                                                esc_url( AF_AI_Helper::get_connector_setup_url() )
     363                                        ),
     364                                )
     365                        );
     366                }
     367
     368                $settings     = AF_AI_Helper::get_settings();
     369                $parent_id    = wp_get_post_parent_id( $attachment_id );
     370                $parent_title = $parent_id ? get_the_title( $parent_id ) : '';
     371                $prompt       = ! empty( $settings['alt_prompt'] ) ? $settings['alt_prompt'] : AF_AI_Helper::get_default_settings()['alt_prompt'];
     372
     373                $result = AF_AI_Helper::generate(
     374                        $prompt,
     375                        array(
     376                                'attachment_id' => $attachment_id,
     377                                'parent_title'  => $parent_title,
     378                        )
     379                );
     380
     381                if ( is_wp_error( $result ) ) {
     382                        wp_send_json_error( array( 'message' => $result->get_error_message() ) );
     383                }
     384
     385                $clean_alt = trim( $result, " '\"" );
     386                $clean_alt = sanitize_text_field( $clean_alt );
     387
     388                update_post_meta( $attachment_id, '_wp_attachment_image_alt', $clean_alt );
     389
     390                wp_send_json_success(
     391                        array(
     392                                'message'  => esc_html__( 'Contextual AI alt text generated successfully!', 'af-companion' ),
     393                                'alt_text' => $clean_alt,
     394                        )
     395                );
     396        }
    302397}
     398// new AF_Alt_Text_Manager();
  • af-companion/trunk/inc/class-aftc-booster.php

    r3785645 r3788561  
    2323        require_once AFTC_PATH . 'inc/class-aftc-db-cleaner.php';       
    2424        require_once AFTC_PATH . 'inc/class-aftc-recommended-themes.php';       
     25        require_once AFTC_PATH . 'inc/ai/class-aftc-ai-helper.php';       
    2526
    2627        // Initialize them safely
    … …  
    3435        new AF_Database_Cleaner();
    3536        new AF_Recommended_Themes();
     37        // new AF_AI_Settings_Dashboard();
    3638    }
    3739}
  • af-companion/trunk/inc/demo-importer.php

    r3520356 r3788561  
    7979
    8080          if (!empty($related_free_theme)) {
    81            
     81
    8282            $freedemodataparse = $datajson['democontent'][$related_free_theme];
    8383            $freecurrent_demo = $freedemodataparse['data'];
    … …  
    235235      }
    236236    ?>
    237       <div id="templatespare-plugin-install-activate" data-class=<?php echo $class; ?> current-theme="af-companion" install=<?php echo json_encode($install); ?> activate=<?php echo json_encode($activate); ?> data-plugin-page='af-companion' message='<?php echo $message; ?>' ispro=''></div>
     237      <div id="templatespare-plugin-install-activate" data-class=<?php echo $class; ?> current-theme="af-templatespare" install=<?php echo json_encode($install); ?> activate=<?php echo json_encode($activate); ?> data-plugin-page='af-companion' message='<?php echo $message; ?>' ispro=''></div>
    238238<?php
    239239    }
  • af-companion/trunk/readme.txt

    r3785645 r3788561  
    1 === AF Companion – WordPress Performance, Maintenance & Site Health ===
     1=== AF Companion – AI Alt Text, Performance, Site Health & Maintenance ===
    22Contributors: afthemes
    3 Tags: performance, database, accessibility, broken-links, seo
     3Tags: ai, alt-text, performance, database, seo
    44Requires at least: 6.0
    55Tested up to: 7.1
    6 Stable tag: 3.0.0
     6Stable tag: 3.1.0
    77License: GPLv3 or later
    88License URI: https://www.gnu.org/licenses/gpl-3.0.html
    99
    10 Optimize WordPress performance, clean your database, audit image alt text, monitor content and links, and check site health.
     10Generate context-aware AI alt text, optimize WordPress performance, clean databases, monitor content and broken links, and manage site health.
    1111
    1212== Description ==
    1313
    14 = WordPress Performance, Maintenance, Content Audits & Site Health =
    15 
    16 **AF Companion** brings essential WordPress performance, maintenance, and website monitoring tools together in one dashboard. Optimize common WordPress settings, maintain your database, review website content, find missing image alternative text, monitor links, and check important server and WordPress health indicators.
    17 
    18 Whether you manage a blog, business website, online magazine, or publishing platform, AF Companion helps you take care of routine website maintenance without relying on a collection of separate utility plugins.
     14= AI Alt Text Generator, WordPress Performance & Website Maintenance =
     15
     16**AF Companion** brings AI-powered image alt text generation, WordPress performance optimization, database maintenance, content monitoring, and website health tools together in one dashboard.
     17
     18Generate descriptive image alternative text with AI using your connected WordPress AI provider. Choose an available AI model, customize your instructions, and use **Context AI** to analyze individual images with relevant website and content context.
     19
     20Beyond AI image alt text, AF Companion helps you maintain your WordPress website with performance controls, database cleanup, content monitoring, link monitoring, and server diagnostics.
    1921
    2022**Key features include:**
    2123
    22 * **Performance Optimization:** Control selected WordPress features and frontend optimizations, including Emojis, oEmbeds, XML-RPC, HTML minification, asynchronous JavaScript loading, Google Fonts display, and other asset settings.
    23 * **Database Maintenance:** Review database overhead and clean up selected revisions, expired transients, spam comments, and orphaned post metadata with dry-run scanning and batched deletion.
    24 * **Content Monitor:** Monitor website content and identify content that may need attention as part of your regular maintenance workflow.
    25 * **Alt Text Manager:** Audit your media library for images with missing alternative text and update image alt text.
    26 * **Link Monitor:** Check website link health and identify links that may need review.
    27 * **Website Diagnostics:** Check important WordPress and server components, including REST API availability, loopback requests, PHP configuration, scheduled tasks, and database information.
    28 * **SEO and Analytics Integrations:** Configure supported analytics, tracking, social metadata, schema, and webmaster verification settings.
    29 * **Legacy Demo Import:** Existing demo and manual import tools remain available for supported AF themes setup workflows.
    30 
    31 Manage these tools from the **AF Companion** dashboard in your WordPress administration area.
     24* **AI Alt Text Generator:** Generate descriptive, context-aware image alt text using AI models available through compatible WordPress AI Connectors.
     25* **Context AI:** Analyze an individual image and generate relevant alternative text using context such as your website name and the post or page associated with the image.
     26* **Custom AI Prompts:** Customize image analysis and alt text generation instructions from the AI Settings page.
     27* **AI Model Selection:** Choose an available model through your connected WordPress AI provider, including a model capable of image analysis.
     28* **Image Alt Text Audit:** Find media library images with missing alternative text and update their descriptions.
     29* **Performance Optimization:** Configure selected WordPress core features, frontend assets, and loading behavior.
     30* **Database Maintenance:** Review database overhead and clean selected revisions, expired transients, spam comments, and orphaned metadata.
     31* **Content Monitor:** Monitor website content and identify items that may need attention.
     32* **Link Monitor:** Review website link health and identify links that may need attention.
     33* **Website Health & Diagnostics:** Check important WordPress and server components.
     34* **SEO and Analytics Integrations:** Configure supported analytics, structured data, social metadata, and webmaster verification settings.
     35
     36Whether you manage a blog, business website, online magazine, or publishing platform, AF Companion helps you handle essential website maintenance from your WordPress dashboard.
    3237
    3338**Documentation:** https://docs.afthemes.com/
    … …  
    3540**Support:** https://afthemes.com/support/
    3641
    37 **AF themes:** https://afthemes.com/
     42**AF Themes:** https://afthemes.com/
     43
     44== AI Alt Text Generator ==
     45
     46= Generate Context-Aware AI Alt Text for WordPress Images =
     47
     48Writing descriptive alternative text for every image can take time, especially on content-heavy websites with large media libraries.
     49
     50AF Companion includes an AI-powered Alt Text Manager that analyzes images and helps generate relevant alternative text based on the image itself and its surrounding website context.
     51
     52Instead of relying only on generic image descriptions, use the **Context AI** action to generate alt text that better reflects how an image is used on your website.
     53
     54**AI-powered features**
     55
     56* **AI Image Analysis:** Use a compatible AI model to analyze an individual image and generate a descriptive alternative text suggestion.
     57* **Context AI Button:** Start AI image analysis directly from an individual image in the media management interface.
     58* **Website Context:** Use your website name and other available site information to help guide the generated description.
     59* **Linked Post Context:** Consider the post or page associated with an image when generating relevant alternative text.
     60* **Custom AI Prompts:** Configure your own instructions from the dedicated AI Settings page to guide the output.
     61* **AI Model Selection:** Select an available model through your connected WordPress AI provider.
     62* **Native WordPress AI Integration:** Use compatible WordPress AI Connectors instead of configuring a separate AI provider API key inside AF Companion.
     63
     64**How Context AI works**
     65
     661. Open your WordPress media on Alt Text Manager admin menu and select an image.
     672. Use the **Context AI** button available for the individual image.
     683. AF Companion analyzes the image and available website context, such as the website name and linked post or page.
     694. The connected AI model generates a relevant alternative text suggestion.
     705. Review the generated description and use it as appropriate for the image.
     71
     72**Customize your AI instructions**
     73
     74Open the **AI Settings** page to customize the prompt used for AI image analysis and alt text generation. Adapt the instructions to your website's subject, editorial style, terminology, and preferred description format.
     75
     76**Choose your AI model**
     77
     78AF Companion uses available models through compatible WordPress AI Connectors. Select a model supported by your connected provider. Image analysis requires a model that supports image input.
     79
     80AI provider availability and model options depend on your WordPress AI Connector configuration.
     81
     82== Image Alt Text Manager ==
     83
     84= Audit and Improve Image Alternative Text =
     85
     86Alongside AI generation, the Alt Text Manager helps you review existing media library images and identify missing alternative text.
     87
     88Features include:
     89
     90* Audit media library images for missing alternative text.
     91* Identify images that may need descriptive alt text.
     92* Update image alternative text from the management interface.
     93* Use AI-assisted image analysis to generate relevant descriptions.
     94* Customize AI generation instructions.
     95* Review AI-generated suggestions before using them.
     96
     97**Accessibility and image SEO**
     98
     99Alternative text helps people using screen readers understand meaningful images. It can also provide search engines with additional information about image content.
     100
     101Write descriptions that communicate the purpose or meaningful content of an image. Avoid adding unrelated keywords or repeating the same description across different images.
     102
     103Decorative images generally do not need descriptive alternative text. AI-generated descriptions should always be reviewed for accuracy and relevance before publication.
     104
     105An attachment's alt text and an image's rendered markup are not always the same. Images inserted through custom HTML, page builders, or other plugins may require separate review.
     106
     107== WordPress AI Connector Setup ==
     108
     109AI-powered image analysis requires a compatible WordPress AI Connector and an available model that supports image input.
     110
     1111. Configure an AI provider using the available WordPress AI Connector.
     1122. Make sure the provider has an available image-capable model.
     1133. Open AF Companion's **AI Settings** page.
     1144. Select an available AI model.
     1155. Customize the AI prompt to match your website and content requirements.
     1166. Open an image in the Alt Text Manager and use **Context AI** to generate an alt text suggestion.
     117
     118The available providers and models depend on the connectors installed and configured on your WordPress website. AI provider usage may be subject to the provider's own pricing, limits, terms, and privacy policies.
    38119
    39120== Performance Optimization ==
    … …  
    86167Use it as part of a regular editorial maintenance routine to help keep published pages and posts up to date.
    87168
    88 == Alt Text Manager ==
    89 
    90 Review image alternative text across your WordPress media library.
    91 
    92 The Alt Text Manager helps you:
    93 
    94 * Audit media library images for missing alternative text.
    95 * Identify images that may need descriptive alt text.
    96 * Update image alternative text from the management interface.
    97 
    98 Alternative text helps communicate the purpose or content of meaningful images to people using assistive technologies. Write descriptions that fit the image's context rather than adding keywords for search engines.
    99 
    100 An attachment's alt text and an image's rendered markup are not always the same. Images inserted through custom HTML, page builders, or other plugins may require separate review.
    101 
    102169== Link Monitor ==
    103170
    … …  
    169236== Legacy Demo Import Tools ==
    170237
    171 AF Companion retains its legacy demo and manual import functionality for supported AF themes workflows.
     238AF Companion retains its legacy demo and manual import functionality for supported AF Themes workflows.
    172239
    173240The manual import interface supports the following files:
    … …  
    1892565. Select the module you want to configure and review its available settings.
    190257
     258To use AI-powered alt text generation:
     259
     2601. Configure a compatible AI provider through WordPress AI Connectors.
     2612. Open the AF Companion AI Settings page.
     2623. Select an available image-capable model.
     2634. Customize your AI prompt.
     2645. Open an image in the Alt Text Manager and select **Context AI**.
     265
    191266Before enabling performance optimizations or running database maintenance, create a backup of your website.
    192267
    … …  
    195270= What is AF Companion? =
    196271
    197 AF Companion is a WordPress maintenance and optimization plugin. It includes performance controls, database maintenance, content monitoring, image alt text auditing, link monitoring, website diagnostics, and supported SEO and analytics integrations.
    198 
    199 = Where can I find the AF Companion dashboard? =
    200 
    201 After activating the plugin, open **AF Companion** from the WordPress administration menu. The dashboard provides access to its available modules and settings.
     272AF Companion is a WordPress performance, maintenance, and site health plugin. It includes an AI alt text generator, media library auditing, database maintenance, content monitoring, link monitoring, performance optimization, website diagnostics, and supported SEO and analytics integrations.
     273
     274= Does AF Companion include an AI alt text generator? =
     275
     276Yes. AF Companion includes an AI-powered Alt Text Manager that analyzes individual images and generates descriptive alternative text suggestions. It can use available website and linked post or page context to help make descriptions more relevant.
     277
     278= What is Context AI? =
     279
     280Context AI is an individual image analysis action in the Alt Text Manager. It analyzes an image and uses available website context, such as your website name and linked post or page, to generate a relevant alternative text suggestion.
     281
     282= How do I generate AI alt text for an image? =
     283
     284Open the image in your WordPress Alt Text Manager and use the **Context AI** button. AF Companion sends the image and available context to your selected AI model and returns an alternative text suggestion for you to review.
     285
     286= Which AI models and providers are supported? =
     287
     288AF Companion uses models available through compatible WordPress AI Connectors. The available providers and models depend on the connectors configured on your website. Choose a model that supports image input for AI image analysis.
     289
     290= Do I need to add a separate API key in AF Companion? =
     291
     292AF Companion uses compatible WordPress AI Connectors for provider access. Configure your AI provider through the available WordPress connector settings rather than entering a separate provider API key in the AF Companion AI Settings page.
     293
     294= Can I customize the AI prompt? =
     295
     296Yes. Open the AF Companion **AI Settings** page to customize the prompt used for image analysis and alt text generation. You can adapt the instructions to your website's subject, content, and preferred writing style.
     297
     298= Does Context AI use the content of my website? =
     299
     300Context AI can use available contextual information, including your website name and the post or page associated with an image, to help generate a relevant description. The image and selected context are processed by the connected AI provider.
     301
     302= Does AI automatically generate alt text for every image? =
     303
     304The Context AI feature provides an on-demand action for individual images. It does not mean that every image is automatically processed. Use the feature when you want an AI-generated suggestion for a particular image.
     305
     306= Should I review AI-generated alt text? =
     307
     308Yes. AI-generated descriptions are suggestions and may occasionally miss details or interpret an image incorrectly. Review each description before using it. Ensure the final alternative text accurately reflects the image and its purpose in the page.
     309
     310= Does AI-generated alt text improve image SEO? =
     311
     312Descriptive alternative text helps search engines understand meaningful image content and supports accessible website experiences. AI can help create relevant descriptions, but it does not guarantee higher search rankings or increased traffic.
     313
     314= Does the Alt Text Manager find images with missing alt text? =
     315
     316Yes. The Alt Text Manager audits your media library to identify images with missing alternative text and provides a way to update image alt text.
    202317
    203318= Can AF Companion help improve WordPress performance? =
    … …  
    215330Content Monitor provides tools for monitoring website content and identifying content that may need attention as part of your regular publishing and maintenance workflow.
    216331
    217 = How does the Alt Text Manager help with accessibility? =
    218 
    219 The Alt Text Manager audits your media library to identify images with missing alternative text and provides a way to update image alt text. Meaningful images should have descriptions appropriate to their context, while decorative images generally do not need descriptive alternative text.
    220 
    221332= Can AF Companion check broken links? =
    222333
    … …  
    241352= Does AF Companion still include demo import functionality? =
    242353
    243 Yes. Legacy demo and manual import tools remain available for supported AF themes workflows. The plugin's primary focus is now WordPress performance, maintenance, monitoring, and site health.
    244 
    245 = Is AF Companion suitable for websites that do not use AF themes? =
    246 
    247 Many of AF Companion's performance, maintenance, monitoring, and diagnostic tools are intended for general WordPress websites. Legacy demo import functionality is intended for compatible AF themes workflows.
     354Yes. Legacy demo and manual import tools remain available for supported AF Themes workflows. The plugin's primary focus is now AI-assisted image alt text, WordPress performance, maintenance, monitoring, and site health.
     355
     356= Is AF Companion suitable for websites that do not use AF Themes? =
     357
     358Many of AF Companion's performance, maintenance, monitoring, AI alt text, and diagnostic tools are intended for general WordPress websites. Legacy demo import functionality is intended for compatible AF Themes workflows.
    248359
    249360= Where can I get help with AF Companion? =
    … …  
    257368
    2583691. **AF Companion Dashboard:** Overview of the plugin's modules and administration navigation.
    259 2. **Performance Optimization:** Controls for selected WordPress core features and frontend optimization settings.
    260 3. **Database Maintenance:** Database overhead scanning and available cleanup operations.
    261 4. **Content Monitor:** Content monitoring interface for reviewing website content.
    262 5. **Alt Text Manager:** Media library audit showing images with missing alternative text.
    263 6. **Link Monitor:** Link monitoring interface showing website link health information.
    264 7. **SEO and Analytics Integrations:** Settings for supported analytics, structured data, social metadata, and webmaster verification.
    265 8. **Website Health & Diagnostics:** WordPress and server diagnostic information.
     3702. **AI Alt Text Manager:** Media library audit showing images with missing alternative text and available management actions.
     3713. **AI Settings:** Select an available AI model through WordPress AI Connectors and customize the AI prompt.
     3724. **Performance Optimization:** Controls for selected WordPress core features and frontend optimization settings.
     3735. **Database Maintenance:** Database overhead scanning and available cleanup operations.
     3746. **Content Monitor:** Content monitoring interface for reviewing website content.
     3757. **Link Monitor:** Link monitoring interface showing website link health information.
     3768. **SEO and Analytics Integrations:** Settings for supported analytics, structured data, social metadata, and webmaster verification.
     3779. **Website Health & Diagnostics:** WordPress and server diagnostic information.
     37810. **Recommended Free Themes for News, Magazines & Blogs:** Power your news, magazine, and blog sites with free WordPress themes engineered by AF themes.
    266379
    267380## AF themes
    … …  
    386499
    387500== Changelog ==
     501
     502## 3.1.0 - 07/11/2026
     503* Introduced AI-powered image alt text generation through compatible WordPress AI Connectors.
     504* Added Context AI actions for individual images to generate context-aware alternative text using image analysis and available website and linked content context.
     505* Added AI model selection and customizable prompts through the new AI Settings page.
     506* Added the Alt Text Manager for auditing media library images with missing alternative text.
    388507
    389508## 3.0.0 - 05/11/2026
Note: See TracChangeset for help on using the changeset viewer.