افزونه وبپی پرو

مشخصات مقاله:
بروزرسانی: شهریور ۱۴۰۴
وبپی پرو
فهرست مطالب

افزونه وبپی پرو

با افزونه WebP Free وبپی پرو، سرعت وب‌سایت خود را به طور چشمگیری افزایش دهید، سئوی تصاویر را بهبود بخشید و تجربه‌ی کاربری بهتری برای بازدیدکنندگان خود رقم بزنید. مدیریت و بهینه‌سازی تصاویر همزمان در اختیار شماست❤️‍🔥

امکانات افزونه وبپی پرو:

  • تبدیل آسان به فرمت WebP:

  • مدیریت هوشمند متن جایگزین (Alt Text):

  • داشبورد آماری و گزارش‌دهی دقیق:

  • کنترل کامل در دستان شما:

  • سازگاری و بهینه‌سازی: در بسته‌های کوچک انجام می‌شود.

افزونه وبپی پرو

ویژگی وبپی پرو Webp Pro

  • تبدیل آسان به فرمت WebP:

    کاهش حجم تصاویر بدون افت کیفیت با وبپی پرو.
  • افزایش چشمگیر سرعت بارگذاری صفحات.
  • بهبود رتبه سایت در موتورهای جستجو (SEO-friendly).
  • امکان تبدیل انتخابی تصاویر با یک کلیک.
  • مدیریت هوشمند متن جایگزین (Alt Text):

    بروزرسانی گروهی: به صورت خودکار برای تصاویری که متن جایگزین ندارند، Alt Text هوشمند تولید کنید.
  • ویرایش زنده: به راحتی و مستقیماً از داخل لیست تصاویر، متن‌های جایگزین را ویرایش نمایید.
  • بهبود سئو و دسترس‌پذیری: به موتورهای جستجو و کاربران کم‌توان کمک کنید تا محتوای تصویری شما را بهتر درک کنند.
  • داشبورد آماری و گزارش‌دهی دقیق:

    آمار جامع کتابخانه: گزارشی کامل از تعداد کل تصاویر، فرمت‌ها (JPG, PNG, WebP) و وضعیت متن‌های جایگزین دریافت کنید.
  • گزارش لحظه‌ای عملیات: تمام فعالیت‌های افزونه، از تبدیل تصاویر تا بروزرسانی‌ها، به صورت دقیق ثبت و نمایش داده می‌شود.
  • پاکسازی گزارشات: به راحتی و با یک کلیک، گزارشات وباگ ها رابا افزونه وبپی پرو  پاک کنید.
  • کنترل کامل در دستان شما:

    تنظیمات کیفیت: کیفیت تصاویر WebP خروجی را مطابق با نیاز خود تنظیم کنید (از ۱۰ تا ۱۰۰).
  • انتخاب فرمت‌ها: مشخص کنید کدام فرمت‌ها (JPG, PNG, JPEG) برای تبدیل در نظر گرفته شوند.
  • رابط کاربری ساده و جذاب: تمام امکانات در یک محیط کاربرپسند و تب‌بندی شده در دسترس شماست.
  • سازگاری و بهینه‌سازی:

    پاکسازی خودکار کش: پس از انجام عملیات مهم، کش افزونه‌های محبوب مانند WP Rocket و LiteSpeed به صورت خودکار پاک می‌شود تا تغییرات فوراً اعمال شوند.
  • پردازش دسته‌ای: برای جلوگیری از فشار به سرور، عملیات گروهی در بسته‌های کوچک انجام می‌شود.
کدهارا درون افزونه wp code بذارید-یک اسنیپت جدید PHPبسازید-اسم دلخواه و در نهایت کدها را کپی پیست کنید و ذخیره
<?php
/**
 * Plugin Name: WebP Free
 * Plugin URI:  https://mrbarati.com/forms/
 * Description: افزونه رایگان برای تبدیل تصاویر به فرمت WebP و مدیریت متن جایگزین با امکانات محدود.
 * Version:     0.0
 * Author:      مهندس براتی
 * Author URI:  https://mrbarati.com
 * License:     GPLv3
 * Requires at least: 6.0
 * Requires PHP: 7.4
 */

if (!defined('ABSPATH')) {
    exit;
}

final class WebP_Free {

    private static $instance = null;

    public static function instance() {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        $this->setup_hooks();
    }

    private function setup_hooks() {
        register_activation_hook(__FILE__, [__CLASS__, 'activate']);
        register_deactivation_hook(__FILE__, [__CLASS__, 'deactivate']);
        register_uninstall_hook(__FILE__, [__CLASS__, 'uninstall']);

        add_action('admin_menu', [$this, 'register_admin_menu']);
        add_filter('plugin_action_links_' . plugin_basename(__FILE__), [$this, 'add_settings_link']);
        add_action('admin_head-settings_page_webp-free', [$this, 'inject_admin_assets']);

        add_action('wp_ajax_webpfree_scan_images', [$this, 'ajax_scan_images']);
        add_action('wp_ajax_webpfree_update_images', [$this, 'ajax_update_images']);
        add_action('wp_ajax_webpfree_load_images_table', [$this, 'ajax_load_images_table']);
        add_action('wp_ajax_webpfree_save_alt_texts', [$this, 'ajax_save_alt_texts']);
        add_action('wp_ajax_webpfree_convert_to_webp', [$this, 'ajax_convert_to_webp']);
        add_action('wp_ajax_webpfree_save_settings', [$this, 'ajax_save_settings']);
        add_action('wp_ajax_webpfree_clear_logs', [$this, 'ajax_clear_logs']);
        add_action('wp_ajax_webpfree_refresh_nonce', [$this, 'ajax_refresh_nonce']);
        add_action('wp_ajax_webpfree_refresh_logs', [$this, 'ajax_refresh_logs']);

        add_filter('the_content', [$this, 'replace_images_with_webp_in_content']);
    }

    public static function activate() {
        if (!function_exists('wp_get_image_editor')) {
            wp_die('خطا: افزونه نیاز به تابع wp_get_image_editor دارد. لطفاً مطمئن شوید که کتابخانه GD یا Imagick روی سرور شما نصب است.');
        }
        add_option('webpfree_formats', ['jpeg', 'png', 'jpg']);
        add_option('webpfree_quality', 80);
        add_option('webpfree_logs', []);
    }

    public static function deactivate() {
        delete_option('webpfree_formats');
        delete_option('webpfree_quality');
        delete_option('webpfree_logs');
    }

    public static function uninstall() {
        global $wpdb;
        delete_option('webpfree_formats');
        delete_option('webpfree_quality');
        delete_option('webpfree_logs');
        $wpdb->delete($wpdb->postmeta, ['meta_key' => '_webp_converted_to']);
    }

    private function clear_caches() {
        if (function_exists('rocket_clean_domain')) {
            rocket_clean_domain();
        }
        if (class_exists('LiteSpeed_Cache')) {
            do_action('litespeed_purge_all');
        }
        wp_cache_flush();
    }

    private function add_log($message) {
        $logs = get_option('webpfree_logs', []);
        $new_log = [
            'message' => sanitize_text_field($message),
            'time'    => current_time('mysql')
        ];
        array_unshift($logs, $new_log);
        $logs = array_slice($logs, 0, 40);
        update_option('webpfree_logs', $logs);
    }

    public function add_settings_link($links) {
        $settings_link = '<a href="' . esc_url(admin_url('options-general.php?page=webp-free')) . '">تنظیمات</a>';
        array_unshift($links, $settings_link);
        return $links;
    }

    public function register_admin_menu() {
        add_options_page(
            'تنظیمات WebP Free',
            'WebP Free',
            'manage_options',
            'webp-free',
            [$this, 'render_settings_page']
        );
    }

    public function inject_admin_assets() {
        $this->embed_css();
        $this->embed_js();
    }

    private function embed_css() {
        ?>
        <style>
            .rtl .nav-tab-wrapper { 
                margin-bottom: 20px; 
                background: linear-gradient(135deg, #2271b1 0%, #1a5d93 100%); 
                padding: 5px; 
                border-radius: 8px; 
                box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            }
            .rtl .nav-tab { 
                background: #fff; 
                color: #004aad; 
                border: none; 
                margin: 5px; 
                padding: 10px 20px; 
                border-radius: 5px; 
                transition: all 0.3s ease; 
                font-weight: bold; 
                font-size: 16px;
            }
            .rtl .nav-tab:hover, .rtl .nav-tab.nav-tab-active { 
                background: #004aad; 
                color: #fff; 
            }
            .rtl .tab-content { 
                display: none; 
                padding: 25px; 
                background: #fff; 
                border: 1px solid #c3c4c7; 
                border-top: 0; 
                border-radius: 0 0 8px 8px; 
                box-shadow: 0 2px 5px rgba(0,0,0,0.1);
                font-size: 15px;
            }
            .rtl .tab-content.active { display: block; }
            .rtl .tab-content h2 { 
                color: #004aad; 
                font-weight: bold; 
                font-size: 21px; 
            }
            .rtl .tab-content p, .rtl .tab-content li { 
                font-size: 15px; 
                line-height: 1.8; 
                color: #333;
            }
            .rtl .result-container, .rtl .log-box { margin-top: 20px; }
            .rtl .actions-bar { margin-bottom: 15px; display: flex; gap: 10px; align-items: center; }
            .rtl #webp-image-list, .rtl .widefat { margin-top: 20px; }
            .rtl #webp-image-list th.check-column { padding: 8px 0; }
            .rtl #webp-image-list td, .rtl #webp-image-list th { vertical-align: middle; }
            .rtl #webp-image-list tbody tr { height: 70px; }
            .rtl #webp-image-list img { max-height: 60px; width: auto; max-width: 100%; border-radius: 3px; box-shadow: 0 0 5px rgba(0,0,0,0.1); }
            .rtl td.editable-alt { cursor: pointer; position: relative; padding: 8px; }
            .rtl .alt-text-input { display: none; width: calc(100% - 110px); padding: 5px; vertical-align: middle; }
            .rtl .save-single-alt { display: none; background-color: #4CAF50; color: #fff; border: none; border-radius: 3px; padding: 5px 10px; cursor: pointer; margin-right: 5px; vertical-align: middle; }
            .rtl .cancel-single-alt { display: none; background-color: #FF0000; color: #fff; border: none; border-radius: 3px; padding: 5px 10px; cursor: pointer; margin-right: 5px; vertical-align: middle; }
            .rtl .max-ten-warning { color: #FF0000; }

            #webpfree-toast-container { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; width: 380px; max-width: 90%; }
            .ir-toast { font-family: inherit; font-size: 15px; background-color: #fff; color: #1d2327; padding: 20px; margin-bottom: 10px; border-right-width: 5px; border-right-style: solid; border-radius: 4px; box-shadow: 0 5px 25px rgba(0,0,0,0.2); display: flex; align-items: flex-start; gap: 12px; opacity: 0; transform: scale(0.9); transition: all 0.3s ease-out; }
            .ir-toast.show { opacity: 1; transform: scale(1); }
            .ir-toast .ir-toast-icon { font-size: 20px; line-height: 1.4; }
            .ir-toast .ir-toast-message { flex-grow: 1; line-height: 1.6; }
            .ir-toast .ir-toast-message b { font-weight: 600; }
            .ir-toast .ir-toast-close { background: none; border: none; font-size: 22px; cursor: pointer; color: #777; padding: 0 5px; }
            .ir-toast.success { border-right-color: #4CAF50; }
            .ir-toast.success .ir-toast-icon { color: #4CAF50; }
            .ir-toast.error { border-right-color: #F44336; }
            .ir-toast.error .ir-toast-icon { color: #F44336; }

            #log-container { max-height: 400px; overflow-y: auto; background: #f9f9f9; border: 1px solid #ddd; padding: 10px; }
            #log-container ul { margin: 0; padding: 0; list-style: none; }
            #log-container li { background: #fff; border-bottom: 1px solid #eee; padding: 8px 12px; font-size: 15px; display: flex; justify-content: space-between; align-items: center; }
            #log-container li:last-child { border-bottom: none; }
            #log-container li::before { content: counters(item, ".") ". "; counter-increment: item; margin-left: 10px; }
            .log-time { color: #777; font-size: 14px; }

            #help h3 { margin-top: 25px; border-bottom: 2px solid #004aad; padding-bottom: 5px; color: #004aad; font-size: 20px; }
            #help p { line-height: 1.7; }
            #webp-pro-btn { display: inline-block; padding: 15px 30px; font-size: 15px; font-weight: bold; background-color: #2271b1; color: #fff; text-decoration: none; border-radius: 5px; margin-top: 20px; margin-left: 10px; }
            #webp-pro-btn:hover { background-color: #1a5d93; }

            .progress-container { margin-top: 15px; display: none; }
            .progress-bar { width: 100%; background-color: #f3f3f3; border-radius: 5px; overflow: hidden; }
            .progress-bar-fill { height: 20px; background-color: #4CAF50; width: 0%; transition: width 0.3s ease-in-out; }
            .progress-text { margin-top: 5px; font-size: 15px; color: #333; }

            #image-table-container > p { color: #FF0000; font-weight: bold; font-size: 15px; }
            .rtl td.editable-alt[title] { color: #FF0000; font-weight: bold; }
        </style>
        <?php
    }

    private function embed_js() {
        $localized_data = [
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce('webpfree_nonce'),
            'i18n'    => [
                'loading' => 'در حال بارگذاری...',
                'error' => 'یک خطای غیرمنتظره رخ داد!',
                'saving' => 'در حال ذخیره...',
                'scan' => 'اسکن و نمایش گزارشات',
                'scanning' => 'در حال اسکن...',
                'startUpdate' => 'شروع بروزرسانی گروهی',
                'updating' => 'در حال پردازش...',
                'convertingSelected' => 'تبدیل منتخب به WebP',
                'converting' => 'در حال تبدیل...',
                'saveAltChanges' => 'OK',
                'cancelAltChanges' => 'Noki',
                'clearing' => 'در حال پاکسازی...',
                'progress' => 'پیشرفت: %s%% (پردازش %s از %s تصویر)'
            ]
        ];
        ?>
        <script>
        jQuery(document).ready(function($) {
            let webpFree = <?php echo wp_json_encode($localized_data); ?>;
            const i18n = webpFree.i18n;

            function showToast(message, isSuccess = true, duration = 4000) {
                const container = $('#webpfree-toast-container');
                if (container.length === 0) {
                    $('body').append('<div id="webpfree-toast-container"></div>');
                }
                const icon = isSuccess ? '✔' : '✖';
                const toastClass = isSuccess ? 'success' : 'error';
                const toast = $(`<div class="ir-toast ${toastClass}"><span class="ir-toast-icon">${icon}</span><div class="ir-toast-message">${message}</div><button class="ir-toast-close" title="بستن">×</button></div>`);
                $('#webpfree-toast-container').append(toast);
                setTimeout(() => { toast.addClass('show'); }, 100);
                const autoClose = setTimeout(() => { toast.removeClass('show').on('transitionend', () => toast.remove()); }, duration);
                toast.find('.ir-toast-close').on('click', () => {
                    clearTimeout(autoClose);
                    toast.removeClass('show').on('transitionend', () => toast.remove());
                });
            }

            async function refreshNonce() {
                try {
                    const response = await $.post(webpFree.ajaxurl, { action: 'webpfree_refresh_nonce' });
                    if (response.success && response.data.new_nonce) {
                        webpFree.nonce = response.data.new_nonce;
                        return true;
                    }
                } catch (e) {
                    console.error('Nonce refresh failed:', e);
                    showToast(i18n.error, false);
                }
                return false;
            }

            $('.nav-tab').on('click', function(e) {
                e.preventDefault();
                const target = $(this).attr('href');
                $('.nav-tab').removeClass('nav-tab-active');
                $(this).addClass('nav-tab-active');
                $('.tab-content').removeClass('active');
                $(target).addClass('active');

                if (target === '#webp') {
                    loadImagesTable();
                    showToast('نسخه رایگان: محدود به نمایش و تبدیل ۱۴ تصویر.', true, 4000);
                } else if (target === '#update') {
                    showToast('نسخه رایگان: محدود به بروزرسانی ۱۴ تصویر.', true, 4000);
                } else if (target === '#logs') {
                    $('#log-container').html('<p>برای مشاهده گزارشات، دکمه اسکن را کلیک کنید.</p>');
                    showToast('نسخه رایگان: گزارشات عملیات اخیر.', true, 4000);
                } else if (target === '#stats') {
                    scanImages();
                    showToast('نسخه رایگان: نمایش آمار تصاویر.', true, 4000);
                } else {
                    showToast('نسخه رایگان: امکانات محدود.', true, 4000);
                }
            });

            if (window.location.hash && $('.nav-tab[href="' + window.location.hash + '"]').length) {
                $('.nav-tab[href="' + window.location.hash + '"]').trigger('click');
            } else {
                $('.nav-tab-wrapper a:first').trigger('click');
            }

            function scanImages() {
                $('#stats-table-container').html('<p>' + i18n.loading + '</p>');
                $.post(webpFree.ajaxurl, { action: 'webpfree_scan_images', nonce: webpFree.nonce })
                    .done(res => {
                        if (res.success) {
                            $('#stats-table-container').html(res.data.table);
                        } else {
                            showToast(res.data.message || i18n.error, false);
                        }
                    })
                    .fail(() => showToast(i18n.error, false));
            }

            $('#scan-images').on('click', function() {
                const btn = $(this).prop('disabled', true).text(i18n.scanning);
                scanImages();
                btn.prop('disabled', false).text(i18n.scan);
            });

            function refreshLogs() {
                $('#log-container').html('<p>' + i18n.loading + '</p>');
                $.post(webpFree.ajaxurl, { action: 'webpfree_refresh_logs', nonce: webpFree.nonce })
                    .done(res => {
                        if (res.success) {
                            $('#log-container').html(res.data.logs);
                            showToast('گزارشات با موفقیت بارگذاری شد.', true);
                        } else {
                            showToast(res.data.message || i18n.error, false);
                        }
                    })
                    .fail(() => showToast(i18n.error, false));
            }

            $('#scan-logs').on('click', function() {
                const btn = $(this).prop('disabled', true).text(i18n.scanning);
                refreshLogs();
                btn.prop('disabled', false).text(i18n.scan);
            });

            $('#start-processing').on('click', async function() {
                if (!await refreshNonce()) return;
                const btn = $(this).prop('disabled', true).text(i18n.updating);
                const batchSize = 14;
                const progressContainer = $('#progress-container');
                const progressBar = progressContainer.find('.progress-bar-fill');
                const progressText = progressContainer.find('.progress-text');

                progressContainer.show();

                let totalImages = 0;
                try {
                    const countResponse = await $.post(webpFree.ajaxurl, {
                        action: 'webpfree_scan_images',
                        nonce: webpFree.nonce,
                        count_only: true
                    });
                    if (countResponse.success && countResponse.data.total_without_alt) {
                        totalImages = Math.min(countResponse.data.total_without_alt, 14);
                    } else {
                        showToast(i18n.error, false);
                        btn.prop('disabled', false).text(i18n.startUpdate);
                        progressContainer.hide();
                        return;
                    }
                } catch (e) {
                    showToast(i18n.error, false);
                    btn.prop('disabled', false).text(i18n.startUpdate);
                    progressContainer.hide();
                    return;
                }

                let processed = 0;
                let updatedCount = 0;

                async function processBatch(offset) {
                    try {
                        const response = await $.post(webpFree.ajaxurl, {
                            action: 'webpfree_update_images',
                            nonce: webpFree.nonce,
                            offset: offset,
                            limit: batchSize
                        });
                        if (response.success) {
                            processed += response.data.processed;
                            updatedCount += response.data.updated;
                            const percentage = Math.min((processed / totalImages) * 100, 100).toFixed(1);
                            progressBar.css('width', percentage + '%');
                            progressText.text(i18n.progress.replace('%s', percentage).replace('%s', processed).replace('%s', totalImages));

                            if (processed < totalImages && processed < 14) {
                                await processBatch(offset + batchSize);
                            } else {
                                showToast(`بروزرسانی گروهی: ${updatedCount} متن جایگزین بروزرسانی شد.`, true);
                                btn.prop('disabled', false).text(i18n.startUpdate);
                                progressContainer.hide();
                            }
                        } else {
                            showToast(response.data.message || i18n.error, false);
                            btn.prop('disabled', false).text(i18n.startUpdate);
                            progressContainer.hide();
                        }
                    } catch (e) {
                        showToast(i18n.error, false);
                        btn.prop('disabled', false).text(i18n.startUpdate);
                        progressContainer.hide();
                    }
                }

                await processBatch(0);
            });

            function loadImagesTable() {
                $('#image-table-container').html('<p>' + i18n.loading + '</p>');
                $.post(webpFree.ajaxurl, {
                    action: 'webpfree_load_images_table',
                    nonce: webpFree.nonce
                })
                    .done(res => {
                        if (res.success) {
                            $('#image-table-container').html(res.data.table);
                        } else {
                            showToast(res.data.message || i18n.error, false);
                        }
                    })
                    .fail(() => showToast(i18n.error, false));
            }

            $('#image-table-container').on('change', '#select-all-images', function() {
                $('#image-table-container .image-select').prop('checked', this.checked).trigger('change');
            });

            $('#image-table-container').on('change', '.image-select', function() {
                $('#convert-webp').prop('disabled', $('#image-table-container .image-select:checked').length === 0);
            });

            $('#image-table-container').on('dblclick', '.editable-alt', function() {
                const cell = $(this);
                cell.find('.alt-text-display').hide();
                cell.find('.alt-text-input, .save-single-alt, .cancel-single-alt').show();
                cell.find('.alt-text-input').focus().data('original-value', cell.find('.alt-text-input').val());
            });

            $('#image-table-container').on('click', '.save-single-alt', async function() {
                if (!await refreshNonce()) return;
                const btn = $(this);
                const cell = btn.closest('.editable-alt');
                const input = cell.find('.alt-text-input');
                const display = cell.find('.alt-text-display');
                const imageId = cell.closest('tr').data('id');
                const newText = input.val();
                btn.text('...').prop('disabled', true);
                const updateData = { id: imageId, text: newText };
                $.post(webpFree.ajaxurl, {
                    action: 'webpfree_save_alt_texts',
                    nonce: webpFree.nonce,
                    updates: [updateData]
                })
                    .done(res => {
                        if (res.success) {
                            display.text(newText);
                            showToast(res.data.message, true);
                        } else {
                            showToast(res.data.message || i18n.error, false);
                        }
                    })
                    .fail(() => showToast(i18n.error, false))
                    .always(() => {
                        input.hide();
                        btn.hide().text(i18n.saveAltChanges).prop('disabled', false);
                        cell.find('.cancel-single-alt').hide();
                        display.show();
                    });
            });

            $('#image-table-container').on('click', '.cancel-single-alt', function() {
                const cell = $(this).closest('.editable-alt');
                const input = cell.find('.alt-text-input');
                const display = cell.find('.alt-text-display');
                input.val(input.data('original-value')).hide();
                $(this).hide();
                cell.find('.save-single-alt').hide();
                display.show();
            });

            $('#convert-webp').on('click', async function() {
                if (!await refreshNonce()) return;
                const btn = $(this);
                const imageIds = $('#image-table-container .image-select:checked').map((_, el) => $(el).val()).get();
                if (imageIds.length > 0) {
                    btn.prop('disabled', true).text(i18n.converting);
                    $.post(webpFree.ajaxurl, {
                        action: 'webpfree_convert_to_webp',
                        nonce: webpFree.nonce,
                        image_ids: imageIds
                    })
                        .done(res => {
                            if (res.success) {
                                loadImagesTable();
                                $.post(webpFree.ajaxurl, { action: 'webpfree_clear_caches', nonce: webpFree.nonce });
                            }
                            showToast(res.data.message, res.success);
                        })
                        .fail(() => showToast(i18n.error, false))
                        .always(() => {
                            btn.prop('disabled', false).text(i18n.convertingSelected);
                            if ($('#select-all-images').length) $('#select-all-images').prop('checked', false);
                            $('#convert-webp').prop('disabled', true);
                        });
                }
            });

            $('#save-settings').on('click', async function() {
                if (!await refreshNonce()) return;
                const btn = $(this).prop('disabled', true).text(i18n.saving);
                $.post(webpFree.ajaxurl, {
                    action: 'webpfree_save_settings',
                    nonce: webpFree.nonce,
                    settings: $('#bulk-webp-settings').serialize()
                })
                    .done(res => {
                        if (res.success) {
                            $.post(webpFree.ajaxurl, { action: 'webpfree_clear_caches', nonce: webpFree.nonce });
                        }
                        showToast(res.data.message, res.success);
                    })
                    .fail(() => showToast(i18n.error, false))
                    .always(() => btn.prop('disabled', false).text('ذخیره تنظیمات'));
            });

            $('#clear-logs-btn').on('click', async function() {
                if (!await refreshNonce()) return;
                if (!confirm('آیا از پاک کردن تمام گزارشات مطمئن هستید؟ این عمل غیرقابل بازگشت است.')) return;
                const btn = $(this).prop('disabled', true).text(i18n.clearing);
                $.post(webpFree.ajaxurl, { action: 'webpfree_clear_logs', nonce: webpFree.nonce })
                    .done(res => {
                        if (res.success) $('#log-container').html('<p>گزارشات با موفقیت پاک شدند.</p>');
                        showToast(res.data.message, res.success);
                    })
                    .fail(() => showToast(i18n.error, false))
                    .always(() => btn.prop('disabled', false).text('پاک کردن همه گزارشات'));
            });
        });
        </script>
        <?php
    }

    public function render_settings_page() {
        $formats = get_option('webpfree_formats', ['jpeg', 'png', 'jpg']);
        $quality = get_option('webpfree_quality', 80);
        ?>
        <div class="wrap">
            <div id="webpfree-toast-container"></div>
            <h1>تنظیمات WebP Free</h1>
            <h2 class="nav-tab-wrapper">
                <a href="#stats" class="nav-tab">آمار</a>
                <a href="#update" class="nav-tab">بروزرسانی گروهی</a>
                <a href="#webp" class="nav-tab">تبدیل به WebP</a>
                <a href="#bulk-webp" class="nav-tab">تنظیمات</a>
                <a href="#logs" class="nav-tab">گزارشات</a>
                <a href="#help" class="nav-tab">راهنما</a>
            </h2>
            <div id="stats" class="tab-content">
                <h2>آمار کتابخانه رسانه</h2>
                <button id="scan-images" class="button button-primary" aria-label="اسکن و نمایش آمار تصاویر">اسکن و نمایش آمار</button>
                <div id="stats-table-container" class="result-container"></div>
            </div>
            <div id="update" class="tab-content">
                <h2>بروزرسانی خودکار متن جایگزین</h2>
                <p>این عملیات تصاویر فاقد متن جایگزین را در بسته‌های کوچک پردازش می‌کند و پیشرفت با نوار پیشرفت نمایش داده می‌شود: نکته: خطای غیرمنتظره یعنی عکسی بدون متن جایگزین ندارید و این به معنای خطای سیستمی نیست!</p>
                <button id="start-processing" class="button button-primary" aria-label="شروع بروزرسانی گروهی متن‌های جایگزین">شروع بروزرسانی گروهی</button>
                <div id="progress-container" class="progress-container">
                    <div class="progress-bar">
                        <div class="progress-bar-fill"></div>
                    </div>
                    <div class="progress-text">پیشرفت: ۰٪ (پردازش ۰ از ۰ تصویر)</div>
                </div>
            </div>
            <div id="webp" class="tab-content">
                <h2>تبدیل انتخابی به WebP و ویرایش متن جایگزین</h2>
                <div class="notice notice-warning inline"><p><strong>هشدار:</strong> برای جلوگیری از فشار به سرور، توصیه می‌شود هر بار <span class="max-ten-warning">حداکثر ۱۰</span> تصویر را برای تبدیل انتخاب کنید.</p></div>
                <div class="actions-bar"><button id="convert-webp" class="button button-primary" disabled aria-label="تبدیل تصاویر انتخاب‌شده به فرمت WebP">تبدیل منتخب به WebP</button></div>
                <div id="image-table-container"></div>
            </div>
            <div id="bulk-webp" class="tab-content">
                <h2>تنظیمات تبدیل WebP</h2>
                <form id="bulk-webp-settings">
                    <table class="form-table">
                        <tr>
                            <th scope="row"><label for="quality">کیفیت تصویر:</label></th>
                            <td>
                                <input type="number" id="quality" name="quality" value="<?php echo esc_attr($quality); ?>" min="10" max="100" class="small-text" />
                                <p class="description">این عدد، درصد کیفیت تصویر خروجی را تعیین می‌کند (بین ۱۰ تا ۱۰۰). عدد کمتر به معنای حجم پایین‌تر و کیفیت کمتر است. مقدار پیشنهادی برای تعادل بین حجم و کیفیت، ۸۰ است.</p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row">فرمت‌های قابل تبدیل:</th>
                            <td>
                                <fieldset>
                                    <label><input type="checkbox" name="formats[]" value="jpeg" <?php checked(in_array('jpeg', $formats)); ?>> JPEG</label>
                                    <label><input type="checkbox" name="formats[]" value="jpg" <?php checked(in_array('jpg', $formats)); ?>> JPG</label>
                                    <label><input type="checkbox" name="formats[]" value="png" <?php checked(in_array('png', $formats)); ?>> PNG</label>
                                </fieldset>
                            </td>
                        </tr>
                    </table>
                    <p class="submit"><button type="button" id="save-settings" class="button button-secondary" aria-label="ذخیره تنظیمات افزونه">ذخیره تنظیمات</button></p>
                </form>
            </div>
            <div id="logs" class="tab-content">
                <h2>گزارش عملیات</h2>
                <p>برای مشاهده گزارشات، دکمه "اسکن و نمایش گزارشات" را کلیک کنید.</p>
                <div class="actions-bar">
                    <button id="scan-logs" class="button button-primary" aria-label="اسکن و نمایش گزارشات عملیات">اسکن و نمایش گزارشات</button>
                    <button id="clear-logs-btn" class="button button-danger" aria-label="پاک کردن تمام گزارشات">پاک کردن همه گزارشات</button>
                </div>
                <div id="log-container" class="result-container"></div>
            </div>
            <div id="help" class="tab-content">
                <h2>راهنمای جامع افزونه</h2>
                <p>این افزونه ابزاری قدرتمند برای بهینه‌سازی تصاویر سایت شما از طریق مدیریت متن جایگزین و تبدیل آن‌ها به فرمت مدرن WebP است.</p>
                <a href="https://mrbarati.com/webp-pro/" id="webp-pro-btn" target="_blank" rel="noopener" aria-label="خرید نسخه Webp Pro">خرید نسخه Webp Pro</a>
                <h3>تب آمار</h3>
                <p>این بخش یک نمای کلی از وضعیت تصاویر کتابخانه رسانه شما ارائه می‌دهد. با کلیک روی دکمه "اسکن"، می‌توانید آماری دقیق از تعداد کل تصاویر، تعداد تصاویر JPG و PNG، تعداد تصاویر WebP و وضعیت متن‌های جایگزین (alt) مشاهده کنید.</p>
                <h3>تب بروزرسانی گروهی</h3>
                <p>این ابزار تصاویر فاقد متن جایگزین را تا سقف ۱۴ تصویر پردازش می‌کند. متن جایگزین بر اساس اولویت (عنوان نوشته، عنوان تصویر، نام فایل) تولید می‌شود.</p>
                <h3>تب تبدیل به WebP</h3>
                <p>تا ۱۴ تصویر JPG و PNG نمایش داده می‌شود. می‌توانید تصاویر را انتخاب کرده، متن جایگزین را ویرایش کنید و آن‌ها را به WebP تبدیل کنید.</p>
                <h3>تب تنظیمات</h3>
                <p>کیفیت تصویر WebP و فرمت‌های قابل تبدیل را می‌توانید تنظیم کنید.</p>
                <h3>تب گزارشات</h3>
                <p>تمام عملیات مهم با تاریخ و زمان در اینجا ثبت می‌شود.</p>
            </div>
        </div>
        <?php
    }

    public function ajax_scan_images() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        global $wpdb;
        $total_images = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%'");
        $jpeg_images = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'attachment' AND (post_mime_type = 'image/jpeg' OR post_mime_type = 'image/jpg')");
        $png_images = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_mime_type = 'image/png'");
        $webp_images = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_mime_type = 'image/webp'");
        $images_with_alt = (int) $wpdb->get_var("SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id WHERE p.post_type = 'attachment' AND p.post_mime_type LIKE 'image/%' AND pm.meta_key = '_wp_attachment_image_alt' AND pm.meta_value != ''");
        $images_without_alt = $total_images - $images_with_alt;

        if (isset($_POST['count_only']) && $_POST['count_only']) {
            wp_send_json_success(['total_without_alt' => $images_without_alt]);
        }

        $percent_with_alt = ($total_images > 0) ? round(($images_with_alt / $total_images) * 100, 1) : 0;
        $percent_without_alt = ($total_images > 0) ? 100 - $percent_with_alt : 0;

        ob_start();
        ?>
        <table class="widefat striped">
            <thead>
                <tr>
                    <th>معیار</th>
                    <th>تعداد</th>
                    <th>درصد</th>
                </tr>
            </thead>
            <tbody>
                <tr><td>کل تصاویر کتابخانه</td><td><?php echo esc_html(number_format_i18n($total_images)); ?></td><td>۱۰۰٪</td></tr>
                <tr><td>تعداد تصاویر JPG/JPEG</td><td><?php echo esc_html(number_format_i18n($jpeg_images)); ?></td><td>-</td></tr>
                <tr><td>تعداد تصاویر PNG</td><td><?php echo esc_html(number_format_i18n($png_images)); ?></td><td>-</td></tr>
                <tr><td>تعداد تصاویر WebP</td><td><?php echo esc_html(number_format_i18n($webp_images)); ?></td><td>-</td></tr>
                <tr><td>تصاویر دارای متن جایگزین</td><td><?php echo esc_html(number_format_i18n($images_with_alt)); ?></td><td><?php echo esc_html($percent_with_alt); ?>٪</td></tr>
                <tr><td>تصاویر بدون متن جایگزین</td><td><?php echo esc_html(number_format_i18n($images_without_alt)); ?></td><td><?php echo esc_html($percent_without_alt); ?>٪</td></tr>
            </tbody>
        </table>
        <?php
        wp_send_json_success(['table' => ob_get_clean()]);
    }

    public function ajax_refresh_logs() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        $logs = get_option('webpfree_logs', []);
        ob_start();
        if (empty($logs)) {
            echo '<p>هیچ گزارشی یافت نشد.</p>';
        } else {
            ?>
            <ul style="counter-reset: item;">
                <?php foreach ($logs as $log) : ?>
                    <li>
                        <span class="log-message"><?php echo esc_html($log['message']); ?></span>
                        <span class="log-time"><?php echo esc_html(wp_date('Y/m/d H:i:s', strtotime($log['time']))); ?></span>
                    </li>
                <?php endforeach; ?>
            </ul>
            <?php
        }
        wp_send_json_success(['logs' => ob_get_clean()]);
    }

    public function ajax_update_images() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        global $wpdb;
        $offset = isset($_POST['offset']) ? max(0, intval($_POST['offset'])) : 0;
        $limit = min(14, max(1, isset($_POST['limit']) ? intval($_POST['limit']) : 14));

        $images = $wpdb->get_results($wpdb->prepare(
            "SELECT p.ID, p.post_parent, p.post_title, p.guid 
             FROM {$wpdb->posts} p 
             LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_wp_attachment_image_alt' 
             WHERE p.post_type = 'attachment' 
             AND p.post_mime_type LIKE 'image/%%' 
             AND (pm.meta_value IS NULL OR pm.meta_value = '') 
             LIMIT %d OFFSET %d",
            $limit, $offset
        ));

        if (empty($images)) {
            wp_send_json_success([
                'message' => 'هیچ تصویری برای بروزرسانی یافت نشد.',
                'processed' => 0,
                'updated' => 0
            ]);
            return;
        }

        $updated_count = 0;
        foreach ($images as $image) {
            $alt_text = '';
            if ($image->post_parent > 0) {
                $alt_text = get_the_title($image->post_parent);
            }
            if (empty(trim($alt_text))) {
                $alt_text = $image->post_title;
            }
            if (empty(trim($alt_text))) {
                $alt_text = pathinfo($image->guid, PATHINFO_FILENAME);
            }
            $alt_text = ucwords(str_replace(['-', '_'], ' ', $alt_text));
            if (update_post_meta($image->ID, '_wp_attachment_image_alt', sanitize_text_field($alt_text))) {
                $updated_count++;
            }
        }

        if ($updated_count > 0) {
            $this->add_log(sprintf('بروزرسانی گروهی: %s متن جایگزین بروزرسانی شد.', number_format_i18n($updated_count)));
            $this->clear_caches();
        }

        wp_send_json_success([
            'message' => sprintf('%s تصویر با موفقیت بروزرسانی شد.', number_format_i18n($updated_count)),
            'processed' => count($images),
            'updated' => $updated_count
        ]);
    }

    public function ajax_load_images_table() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        $query_args = [
            'post_type' => 'attachment',
            'post_status' => 'inherit',
            'posts_per_page' => 14,
            'post_mime_type' => ['image/jpeg', 'image/png', 'image/jpg'],
            'meta_query' => [
                [
                    'key' => '_webp_converted_to',
                    'compare' => 'NOT EXISTS',
                ],
            ],
            'orderby' => 'date',
            'order' => 'DESC',
        ];

        $query = new WP_Query($query_args);

        ob_start();
        if ($query->have_posts()) {
            ?>
            <table class="widefat striped" id="webp-image-list">
                <thead>
                    <tr>
                        <th class="check-column"><input type="checkbox" id="select-all-images"></th>
                        <th>پیش‌نمایش</th>
                        <th>نام فایل</th>
                        <th>متن جایگزین (دوبار کلیک کنید برای ویرایش)</th>
                        <th>حجم (KB)</th>
                    </tr>
                </thead>
                <tbody>
                    <?php
                    while ($query->have_posts()) : $query->the_post();
                        $image_id = get_the_ID();
                        $file_path = get_attached_file($image_id);
                        $size_kb = (file_exists($file_path)) ? round(filesize($file_path) / 1024, 1) : '-';
                        $alt_text = get_post_meta($image_id, '_wp_attachment_image_alt', true);
                        $filename = wp_basename(get_the_guid());
                        $display_filename = (mb_strlen($filename) > 22) ? mb_substr($filename, 0, 22) . '...' : $filename;
                        ?>
                        <tr data-id="<?php echo esc_attr($image_id); ?>">
                            <th class="check-column"><input type="checkbox" class="image-select" value="<?php echo esc_attr($image_id); ?>"></th>
                            <td><?php echo wp_get_attachment_image($image_id, [60, 60], true); ?></td>
                            <td title="<?php echo esc_attr($filename); ?>"><?php echo esc_html($display_filename); ?></td>
                            <td class="editable-alt" title="دوبار کلیک کنید برای ویرایش">
                                <span class="alt-text-display"><?php echo esc_html($alt_text); ?></span>
                                <input type="text" class="alt-text-input" value="<?php echo esc_attr($alt_text); ?>">
                                <button class="save-single-alt">OK</button>
                                <button class="cancel-single-alt">Noki</button>
                            </td>
                            <td><?php echo esc_html($size_kb); ?></td>
                        </tr>
                    <?php
                    endwhile;
                    wp_reset_postdata();
                    ?>
                </tbody>
            </table>
            <?php
        } else {
            ?>
            <div class="notice notice-info inline">
                <p>تبریک! تمام تصاویر واجد شرایط به فرمت WebP تبدیل شده‌اند.</p>
            </div>
            <?php
        }
        wp_send_json_success(['table' => ob_get_clean()]);
    }

    public function ajax_save_alt_texts() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }
        if (!isset($_POST['updates']) || !is_array($_POST['updates'])) {
            wp_send_json_error(['message' => 'داده‌های نامعتبر.']);
        }

        $updates = (array) $_POST['updates'];
        $updated_count = 0;

        foreach ($updates as $update) {
            $image_id = isset($update['id']) ? intval($update['id']) : 0;
            $alt_text = isset($update['text']) ? sanitize_text_field(wp_unslash($update['text'])) : '';
            if ($image_id > 0 && current_user_can('edit_post', $image_id)) {
                if (update_post_meta($image_id, '_wp_attachment_image_alt', $alt_text)) {
                    $updated_count++;
                    $this->add_log(sprintf('متن جایگزین برای تصویر ID %d به "%s" تغییر یافت.', $image_id, $alt_text));
                    $this->clear_caches();
                }
            }
        }

        if ($updated_count > 0) {
            wp_send_json_success(['message' => sprintf('متن جایگزین برای %s تصویر ذخیره شد.', number_format_i18n($updated_count))]);
        } else {
            wp_send_json_error(['message' => 'هیچ تغییری برای ذخیره وجود نداشت.']);
        }
    }

    public function ajax_convert_to_webp() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        $image_ids = isset($_POST['image_ids']) ? array_map('intval', (array) $_POST['image_ids']) : [];
        if (empty($image_ids)) {
            wp_send_json_error(['message' => 'هیچ تصویری برای تبدیل انتخاب نشده است.']);
        }

        $success_count = 0;
        $failed_count = 0;

        foreach ($image_ids as $image_id) {
            $result = $this->convert_and_create_webp_attachment($image_id);
            if ($result) {
                $success_count++;
            } else {
                $failed_count++;
            }
        }

        $message = sprintf(
            'عملیات انجام شد: <br><b>موفق:</b> %s تصویر <br><b>ناموفق:</b> %s تصویر',
            number_format_i18n($success_count),
            number_format_i18n($failed_count)
        );

        if ($success_count > 0) {
            $this->add_log(sprintf('تبدیل گروهی: %d تصویر به WebP تبدیل شد.', $success_count));
            $this->clear_caches();
        }

        wp_send_json_success(['message' => $message]);
    }

    public function ajax_save_settings() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        $settings = [];
        if (isset($_POST['settings'])) {
            parse_str($_POST['settings'], $settings);
        }

        $quality = isset($settings['quality']) ? absint($settings['quality']) : 80;
        $formats = isset($settings['formats']) && is_array($settings['formats']) ? array_map('sanitize_text_field', $settings['formats']) : [];

        if ($quality < 10 || $quality > 100) {
            wp_send_json_error(['message' => 'کیفیت تصویر باید بین ۱۰ تا ۱۰۰ باشد.']);
            return;
        }

        if (empty($formats)) {
            wp_send_json_error(['message' => 'حداقل یک فرمت باید انتخاب شود.']);
            return;
        }

        update_option('webpfree_quality', $quality);
        update_option('webpfree_formats', $formats);

        $this->add_log('تنظیمات افزونه ذخیره شد.');
        $this->clear_caches();
        wp_send_json_success(['message' => 'تنظیمات با موفقیت ذخیره شد.']);
    }

    public function ajax_clear_logs() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        delete_option('webpfree_logs');
        wp_send_json_success(['message' => 'تمام گزارشات با موفقیت پاک شدند.']);
    }

    public function ajax_clear_caches() {
        check_ajax_referer('webpfree_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'دسترسی مجاز نیست.']);
        }

        $this->clear_caches();
        wp_send_json_success(['message' => 'کش‌ها با موفقیت پاک شدند.']);
    }

    public function ajax_refresh_nonce() {
        if (!current_user_can('manage_options')) {
            wp_send_json_error();
        }

        wp_send_json_success(['new_nonce' => wp_create_nonce('webpfree_nonce')]);
    }

    private function convert_and_create_webp_attachment($original_attachment_id) {
        if (!function_exists('wp_get_image_editor') || !function_exists('wp_generate_attachment_metadata') || !function_exists('wp_insert_attachment')) {
            $this->add_log(sprintf('خطا: توابع مورد نیاز برای تبدیل تصویر ID %d در دسترس نیست.', $original_attachment_id));
            return false;
        }

        $original_file_path = get_attached_file($original_attachment_id);
        if (!$original_file_path || !file_exists($original_file_path)) {
            $this->add_log(sprintf('خطا: فایل تصویر ID %d یافت نشد.', $original_attachment_id));
            return false;
        }

        $editor = wp_get_image_editor($original_file_path);
        if (is_wp_error($editor)) {
            $this->add_log(sprintf('خطا: ویرایشگر تصویر برای ID %d با خطا مواجه شد: %s', $original_attachment_id, $editor->get_error_message()));
            return false;
        }

        $editor->set_quality(get_option('webpfree_quality', 80));
        $webp_saved = $editor->save($editor->generate_filename('webp'), 'image/webp');

        if (is_wp_error($webp_saved) || !isset($webp_saved['path'])) {
            $this->add_log(sprintf('خطا: ذخیره تصویر WebP برای ID %d با خطا مواجه شد: %s', $original_attachment_id, is_wp_error($webp_saved) ? $webp_saved->get_error_message() : 'خطای ناشناخته'));
            return false;
        }

        $webp_path = $webp_saved['path'];
        $original_post = get_post($original_attachment_id);
        $attachment_data = [
            'post_mime_type' => $webp_saved['mime-type'],
            'post_title'     => $original_post->post_title . ' (WebP)',
            'post_content'   => $original_post->post_content,
            'post_status'    => 'inherit'
        ];

        $webp_attachment_id = wp_insert_attachment($attachment_data, $webp_path, 0, true);
        if (is_wp_error($webp_attachment_id)) {
            @unlink($webp_path);
            $this->add_log(sprintf('خطا: ایجاد پیوست WebP برای تصویر ID %d با خطا مواجه شد: %s', $original_attachment_id, $webp_attachment_id->get_error_message()));
            return false;
        }

        if (file_exists(ABSPATH . 'wp-admin/includes/image.php')) {
            require_once ABSPATH . 'wp-admin/includes/image.php';
            wp_update_attachment_metadata($webp_attachment_id, wp_generate_attachment_metadata($webp_attachment_id, $webp_path));
        }

        $original_alt = get_post_meta($original_attachment_id, '_wp_attachment_image_alt', true);
        if (!empty($original_alt)) {
            update_post_meta($webp_attachment_id, '_wp_attachment_image_alt', $original_alt);
        }

        update_post_meta($original_attachment_id, '_webp_converted_to', $webp_attachment_id);
        $this->add_log(sprintf('تصویر "%s" (ID: %d) به WebP (ID: %d) تبدیل شد.', $original_post->post_title, $original_attachment_id, $webp_attachment_id));

        return true;
    }

    public function replace_images_with_webp_in_content($content) {
        if (is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) {
            return $content;
        }

        preg_match_all('/<img[^>]+>/i', $content, $matches);
        if (empty($matches[0])) {
            return $content;
        }

        foreach ($matches[0] as $img_tag) {
            $original_id = 0;
            if (preg_match('/wp-image-([0-9]+)/i', $img_tag, $class_id_match)) {
                $original_id = intval($class_id_match[1]);
            } else if (preg_match('/src="([^"]+)"/i', $img_tag, $src_match)) {
                $original_id = attachment_url_to_postid($src_match[1]);
            }

            if (!$original_id) {
                continue;
            }

            $webp_id = get_post_meta($original_id, '_webp_converted_to', true);
            if (!empty($webp_id) && get_post($webp_id)) {
                preg_match('/class="([^"]+)"/', $img_tag, $class_match);
                $classes = isset($class_match[1]) ? $class_match[1] : '';
                $size = 'full';
                if (preg_match('/size-([a-zA-Z0-9_-]+)/', $classes, $size_match)) {
                    $size = $size_match[1];
                }
                $webp_url = wp_get_attachment_image_url($webp_id, $size);
                $alt_text = get_post_meta($original_id, '_wp_attachment_image_alt', true);
                $new_tag = sprintf(
                    '<picture><source type="image/webp" srcset="%s"><img src="%s" alt="%s" class="%s"></picture>',
                    esc_url($webp_url),
                    esc_url(wp_get_attachment_image_url($original_id, $size)),
                    esc_attr($alt_text),
                    esc_attr($classes)
                );
                if ($new_tag) {
                    $content = str_replace($img_tag, $new_tag, $content);
                }
            }
        }

        return $content;
    }
}

WebP_Free::instance();
سفارش خرید نسخه پرو⬇️
خدمات پشتیبانی سایت وردپرسی
بعد از تکمیل فرم وبررسی اولیه باشما تماس می گیرم
۴/۵ - (۸ امتیاز)
Telegram
WhatsApp
Email
LinkedIn
پشتیبان سایت

یک پاسخ

دیدگاهتان را بنویسید

یک × چهار =