افزونه مینی سئو
با افزونه مکمل سئو «مینی سئو»، تحلیلهای هوشمند و پیشنهادهای کاربردی را مستقیماً در صفحه ویرایش نوشته خود دریافت کنید و با اطمینان محتوایی تولید کنید که گوگل عاشق آن میشود.
دستیار هوشمند و مکمل برای افزونههای Rank Math و Yoast.
-
شکارچی جایگاه ویژه گوگل 🎯
با تحلیلگر AEO، مستقیم به بخش پاسخهای ویژه (Featured Snippets) بروید. -
پادشاه نتایج محلی شوید 👑
تحلیلگر GEO برای جذب مشتریان از شهر و منطقه خودتان. -
دو متخصص در یک افزونه ✌️
بهینهسازی همزمان برای پاسخگویی (AEO) و جستجوی محلی (GEO). -
چکلیست کاربردی، نه تئوری 📝
پیشنهادهای عملی و دقیق برای رفع سریع ایرادات سئوی محتوا. -
امتیازدهی آنی و هوشمند 📊
- سازگار با ووکامرس 🛒
- قیمت ۲۵۰/۰۰۰ تومان
- فعلا رایگانش کردم😊
- کدهارا درون افزونه wp code بذارید
- یک اسنیپت جدید PHPبسازید
- کدها راکپی پیست کنید.
/** * Plugin Name: مینی سئو * Plugin URI: https:/mrbarati.com/ * Description: تحلیلگر Aio و GEO، سازگار با Rank Math و Yoast SEO. مناسب برای نوشته، برگه و ووکامرس. * Version: 1.0.0 * Author: براتی طراح سایت * Author URI: https://mrbarati.com/ * License: GPL-2.0-or-later */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * اگر کلاس از قبل وجود دارد، دوباره تعریف نکن — مناسب برای WP Code / snippets */ if ( ! class_exists( 'Mini_SEO_Analyzor' ) ) : final class Mini_SEO_Analyzor { /** * Singleton instance * @var Mini_SEO_Analyzor|null */ private static $instance = null; /** * دریافت نمونه */ public static function instance() { if ( self::$instance === null ) { self::$instance = new self(); } return self::$instance; } /** * سازنده: ثبت هوکها */ private function __construct() { add_action( 'add_meta_boxes', [ $this, 'register_meta_box' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); add_action( 'wp_ajax_mini_seo_analyzor_run_analysis', [ $this, 'ajax_run_analysis' ] ); add_action( 'wp_ajax_mini_seo_analyzor_toggle_temp_disable', [ $this, 'ajax_toggle_temp_disable' ] ); add_action( 'save_post', [ $this, 'save_meta_box' ], 10, 2 ); add_action( 'admin_notices', [ $this, 'check_seo_plugins_notice' ] ); } /* ======================================================== * رندر متاباکس * ======================================================== */ public function register_meta_box(): void { $post_types = [ 'post', 'page', 'product' ]; add_meta_box( 'mini-seo-analyzor-box', __( 'تحلیلگر Aio و GEO', 'mini-seo-analyzor' ), [ $this, 'render_meta_box' ], $post_types, 'normal', 'high' ); } public function render_meta_box( $post ): void { $temp_disable = get_post_meta( $post->ID, '_mini_seo_analyzor_temp_disable', true ); $temp_disable = $temp_disable ? 1 : 0; $meta_nonce = wp_create_nonce( 'mini_seo_analyzor_meta_nonce' ); $provinces_json = wp_json_encode( $this->get_provinces_list() ); ?> <div class="mini-seo-analyzor-wrapper" data-post-id="<?php echo esc_attr( $post->ID ); ?>" data-temp-disable="<?php echo esc_attr( $temp_disable ); ?>" data-provinces="<?php echo esc_attr( $provinces_json ); ?>"> <div class="mini-seo-tabs"> <a href="#aio-panel" class="mini-seo-tab active" data-tab="aio-panel"><?php esc_html_e( 'تحلیل Aio', 'mini-seo-analyzor' ); ?></a> <a href="#geo-panel" class="mini-seo-tab" data-tab="geo-panel"><?php esc_html_e( 'تحلیل GEO', 'mini-seo-analyzor' ); ?></a> <a href="#aio-tutorial-panel" class="mini-seo-tab" data-tab="aio-tutorial-panel"><?php esc_html_e( 'راهنمای Aio', 'mini-seo-analyzor' ); ?></a> <a href="#geo-tutorial-panel" class="mini-seo-tab" data-tab="geo-tutorial-panel"><?php esc_html_e( 'راهنمای GEO', 'mini-seo-analyzor' ); ?></a> </div> <div id="aio-panel" class="mini-seo-panel active"> <div class="analysis-results"><div class="loading-message"><?php esc_html_e( 'برای شروع تحلیل، محتوا را ویرایش کنید...', 'mini-seo-analyzor' ); ?></div></div> </div> <div id="geo-panel" class="mini-seo-panel"> <div class="analysis-results"><div class="loading-message"><?php esc_html_e( 'در حال بارگذاری...', 'mini-seo-analyzor' ); ?></div></div> </div> <div id="aio-tutorial-panel" class="mini-seo-panel mini-seo-tutorial"> <?php echo $this->get_aio_tutorial_content(); ?> </div> <div id="geo-tutorial-panel" class="mini-seo-panel mini-seo-tutorial"> <?php echo $this->get_geo_tutorial_content(); ?> </div> <div class="mini-seo-controls" style="margin-top:12px;padding:12px;border:1px solid #e6e6e6;background:#fff;display:flex;align-items:center;gap:12px;"> <label style="display:flex;align-items:center;gap:10px;cursor:pointer;margin:0;"> <input type="checkbox" id="mini_seo_analyzor_temp_disable" <?php checked( $temp_disable, 1 ); ?> /> <span style="font-weight:600;"><?php esc_html_e( 'غیر فعال سازی موقت', 'mini-seo-analyzor' ); ?></span> </label> <span id="mini_seo_analyzor_status_badge" style="display:inline-block;padding:6px 10px;border-radius:14px;font-weight:700;color:#fff;font-size:13px;"> <?php if ( $temp_disable ) : ?> <span style="background:#c82333;padding:6px 10px;border-radius:14px;display:inline-block;"><?php esc_html_e( 'غیرفعال', 'mini-seo-analyzor' ); ?></span> <?php else : ?> <span style="background:#198754;padding:6px 10px;border-radius:14px;display:inline-block;"><?php esc_html_e( 'فعال', 'mini-seo-analyzor' ); ?></span> <?php endif; ?> </span> <span style="color:#666;font-size:13px;margin-left:auto;"><?php esc_html_e( '(اگر تیک زده شود، آنالیز خودکار متوقف میشود)', 'mini-seo-analyzor' ); ?></span> <input type="hidden" id="mini_seo_analyzor_meta_nonce" value="<?php echo esc_attr( $meta_nonce ); ?>" /> </div> </div> <?php } /* ======================================================== * enqueue CSS/JS * ======================================================== */ public function enqueue_assets( string $hook ): void { $screen = function_exists('get_current_screen') ? get_current_screen() : null; if ( ! $screen || ! in_array( $screen->post_type ?? '', [ 'post', 'page', 'product' ], true ) || ! in_array( $hook, [ 'post.php', 'post-new.php' ], true ) ) { return; } $css = ".mini-seo-tabs{display:flex;flex-wrap:wrap;border-bottom:2px solid #007cba;margin-bottom:0}.mini-seo-tab{padding:12px 18px;cursor:pointer;background:#f0f0f1;border:1px solid #ccc;border-bottom:none;margin-left:5px;font-weight:600;border-radius:8px 8px 0 0;position:relative;top:2px;transition:all .2s ease-in-out;text-decoration:none;color:#3c434a}.mini-seo-tab:hover{background:#e0e0e0}.mini-seo-tab.active{background:#007cba;color:#fff;border-color:#007cba}.mini-seo-panel{display:none;padding:25px;border:1px solid #ccc;border-top:none;background:#fff;clear:both}.mini-seo-panel.active{display:block}.mini-seo-panel .loading-message{padding:40px;text-align:center;color:#50575e;font-size:14px}.mini-seo-progress-bar{background-color:#e9ecef;border-radius:5px;overflow:hidden;margin:10px 0 25px;height:22px;direction:ltr;border:1px solid #ddd}.mini-seo-progress-bar-fill{height:100%;text-align:center;color:#fff;font-weight:700;font-size:13px;line-height:22px;transition:width .5s ease-in-out}.mini-seo-checklist{list-style:none;padding:0;margin:0}.mini-seo-checklist li{margin-bottom:14px;font-size:14px;padding-right:15px;border-right:4px solid;line-height:1.6}.mini-seo-checklist li.status-pass{border-color:#28a745}.mini-seo-checklist li.status-fail{border-color:#dc3545}.mini-seo-suggestion{font-size:13px;color:#50575e;margin:-8px 19px 15px 0;background:#f8f9fa;padding:10px;border-radius:4px;border:1px solid #e9ecef}.mini-seo-suggestion a{font-weight:700;text-decoration:none}.mini-seo-tutorial h4{font-size:16px;font-weight:700;border-bottom:2px solid #007cba;padding-bottom:5px;margin-top:25px;margin-bottom:15px}.mini-seo-tutorial p,.mini-seo-tutorial ul li{font-size:14px;line-height:1.8;color:#333}.mini-seo-tutorial code{background:#fffdf7;padding:3px 6px;border-radius:4px;font-size:15px;color:#b50000;border:1px solid #eee8d5;font-family:monospace}.mini-seo-tutorial strong{color:#005a87}"; wp_register_style( 'mini-seo-analyzor-style', false, [], '1.2.0' ); wp_enqueue_style( 'mini-seo-analyzor-style' ); wp_add_inline_style( 'mini-seo-analyzor-style', $css ); wp_register_script( 'mini-seo-analyzor-script', false, [ 'jquery' ], '1.2.0', true ); wp_enqueue_script( 'mini-seo-analyzor-script' ); $vars = [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'ajax_nonce' => wp_create_nonce( 'mini_seo_analyzor_ajax_nonce' ), ]; wp_localize_script( 'mini-seo-analyzor-script', 'mini_seo_analyzor_vars', $vars ); $js = <<<JS jQuery(document).ready(function($) { $('.mini-seo-tab').on('click', function(e) { e.preventDefault(); const tabId = $(this).data('tab'); $('.mini-seo-tab, .mini-seo-panel').removeClass('active'); $(this).addClass('active'); $('#' + tabId).addClass('active'); }); let analysisTimeout = null; const wrapper = $('.mini-seo-analyzor-wrapper'); const postId = parseInt(wrapper.data('post-id')) || 0; let tempDisable = wrapper.data('temp-disable') === 1 || wrapper.data('temp-disable') === '1'; function updateStatusBadge(state) { const badgeWrap = $('#mini_seo_analyzor_status_badge'); badgeWrap.empty(); if ( state ) { badgeWrap.append('<span style="background:#c82333;padding:6px 10px;border-radius:14px;display:inline-block;color:#fff;">غیرفعال</span>'); } else { badgeWrap.append('<span style="background:#198754;padding:6px 10px;border-radius:14px;display:inline-block;color:#fff;">فعال</span>'); } } function setTempDisableUI(state, options = {}) { tempDisable = !!state; wrapper.attr('data-temp-disable', tempDisable ? '1' : '0'); $('#mini_seo_analyzor_temp_disable').prop('checked', tempDisable); updateStatusBadge(tempDisable); if (tempDisable) { $('#aio-panel .analysis-results, #geo-panel .analysis-results').html('<div class="loading-message">تحلیل موقتاً غیرفعال است.</div>'); } else { if ( ! options.suppressPerform ) { performAnalysis(); } } } updateStatusBadge(tempDisable); function collectEditorData() { let postTitle = '', postContent = '', metaDesc = '', focusKeyword = ''; if (typeof wp !== 'undefined' && wp.data && wp.data.select) { try { const editor = wp.data.select('core/editor'); if ( editor && editor.getEditedPostAttribute ) { postTitle = editor.getEditedPostAttribute('title') || ''; postContent = editor.getEditedPostAttribute('content') || ''; } if ( wp.data.select('rank-math-analyzer') ) { const rankMathData = wp.data.select('rank-math-analyzer'); metaDesc = rankMathData.getMetaDescription ? rankMathData.getMetaDescription() : metaDesc; try { focusKeyword = rankMathData.getKeyword('primary')?.value || focusKeyword; } catch(e){} } else if ( wp.data.select('yoast-seo/editor') ) { const yoast = wp.data.select('yoast-seo/editor'); metaDesc = yoast.getSeoMeta ? (yoast.getSeoMeta()?.metadesc || '') : metaDesc; focusKeyword = yoast.getSeoMeta ? (yoast.getSeoMeta()?.focuskw || '') : focusKeyword; } } catch (ex) {} } if (!postTitle) postTitle = $('#title').val() || ''; if (!postContent) postContent = (typeof tinymce !== 'undefined' && tinymce.get('content')) ? tinymce.get('content').getContent() : $('#content').val() || ''; if (!metaDesc) metaDesc = $('#yoast_wpseo_metadesc').val() || $('textarea[name="rank_math_description"]').val() || ''; if (!focusKeyword) focusKeyword = $('#yoast_wpseo_focuskw').val() || $('input[name="rank_math_focus_keyword"]').val() || ''; return { postTitle, postContent, metaDesc, focusKeyword }; } function performAnalysis() { if ( tempDisable ) return; const loadingHtml = '<div class="loading-message">در حال تحلیل... لطفاً صبر کنید.</div>'; $('#aio-panel .analysis-results, #geo-panel .analysis-results').html(loadingHtml); if (!postId) return; const data = collectEditorData(); $.post(mini_seo_analyzor_vars.ajax_url, { action: 'mini_seo_analyzor_run_analysis', nonce: mini_seo_analyzor_vars.ajax_nonce, post_id: postId, title: data.postTitle, content: data.postContent, meta_description: data.metaDesc, focus_keyword: data.focusKeyword }, function(response) { if ( response && response.success ) { $('#aio-panel .analysis-results').html(response.data.aio_html); $('#geo-panel .analysis-results').html(response.data.geo_html); } else { const err = (response && response.data && response.data.message) ? response.data.message : 'یک خطای نامشخص رخ داد.'; $('#aio-panel .analysis-results, #geo-panel .analysis-results').html('<div class="loading-message" style="color:red;">' + err + '</div>'); } }).fail(function() { $('#aio-panel .analysis-results, #geo-panel .analysis-results').html('<div class="loading-message" style="color:red;">خطا در ارتباط با سرور.</div>'); }); } const debounceAnalysis = () => { clearTimeout(analysisTimeout); analysisTimeout = setTimeout(performAnalysis, 1500); }; if ( typeof wp !== 'undefined' && wp.data && wp.data.subscribe ) { wp.data.subscribe(debounceAnalysis); } else { $('#title, #content').on('input keyup', debounceAnalysis); if ( typeof tinymce !== 'undefined' && tinymce.get('content') ) { tinymce.get('content').on('keyup input', debounceAnalysis); } } setTimeout(function() { if ( ! tempDisable ) performAnalysis(); }, ۲۵۰۰); $('#mini_seo_analyzor_temp_disable').on('change', function() { const checked = $(this).is(':checked') ? 1 : 0; const prev = tempDisable ? 1 : 0; setTempDisableUI(checked, { suppressPerform: true }); $('#mini_seo_analyzor_temp_disable').prop('disabled', true); $.post(mini_seo_analyzor_vars.ajax_url, { action: 'mini_seo_analyzor_toggle_temp_disable', nonce: $('#mini_seo_analyzor_meta_nonce').val(), post_id: postId, value: checked }, function(res) { if ( res && res.success && typeof res.data.value !== 'undefined' ) { const saved = parseInt(res.data.value, 10) ? 1 : 0; setTempDisableUI(saved, { suppressPerform: true }); if ( saved === 0 ) { performAnalysis(); } } else { setTempDisableUI(prev, { suppressPerform: true }); alert('خطا در دریافت پاسخ سرور. وضعیت بازگردانده شد.'); } }).fail(function() { setTempDisableUI(prev, { suppressPerform: true }); alert('خطا در ذخیرهسازی وضعیت. دسترسی یا nonce بررسی شود.'); }).always(function() { $('#mini_seo_analyzor_temp_disable').prop('disabled', false); }); }); }); JS; wp_add_inline_script( 'mini-seo-analyzor-script', $js ); } /* ======================================================== * AJAX handlers * ======================================================== */ public function ajax_run_analysis(): void { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mini_seo_analyzor_ajax_nonce' ) ) { wp_send_json_error( [ 'message' => 'Nonce نامعتبر.' ], ۴۰۰ ); } $post_id = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : 0; if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) { wp_send_json_error( [ 'message' => 'دسترسی غیرمجاز.' ], ۴۰۳ ); } $title = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : ''; $content_html = isset( $_POST['content'] ) ? wp_kses_post( wp_unslash( $_POST['content'] ) ) : ''; $meta_desc = isset( $_POST['meta_description'] ) ? sanitize_text_field( wp_unslash( $_POST['meta_description'] ) ) : ''; $focus_keyword = isset( $_POST['focus_keyword'] ) ? sanitize_text_field( wp_unslash( $_POST['focus_keyword'] ) ) : ''; $content_text = wp_strip_all_tags( $content_html ); if ( empty( $focus_keyword ) ) $focus_keyword = $this->get_focus_keyword_from_meta( $post_id ); if ( empty( $meta_desc ) ) $meta_desc = $this->get_meta_description_from_meta( $post_id ); if ( empty( $focus_keyword ) ) { wp_send_json_error( [ 'message' => 'کلمه کلیدی اصلی تنظیم نشده است! لطفاً ابتدا کلمه کلیدی را در باکس افزونه Rank Math یا Yoast SEO وارد کنید.' ] ); } if ( get_post_meta( $post_id, '_mini_seo_analyzor_temp_disable', true ) ) { wp_send_json_error( [ 'message' => 'تحلیل به صورت موقت توسط کاربر غیرفعال شده است.' ] ); } $schema_info = $this->get_active_schema_info( $post_id ); $aio_html = $this->analyze_aio( $post_id, $title, $content_html, $content_text, $meta_desc, $focus_keyword, $schema_info ); $geo_html = $this->analyze_geo( $post_id, $content_html, $content_text, $title, $meta_desc, $schema_info ); wp_send_json_success( [ 'aio_html' => $aio_html, 'geo_html' => $geo_html ] ); } public function ajax_toggle_temp_disable(): void { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mini_seo_analyzor_meta_nonce' ) ) { wp_send_json_error( [ 'message' => 'Nonce نامعتبر.' ], ۴۰۰ ); } $post_id = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : 0; if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) { wp_send_json_error( [ 'message' => 'دسترسی غیرمجاز.' ], ۴۰۳ ); } $value = isset( $_POST['value'] ) ? intval( wp_unslash( $_POST['value'] ) ) : 0; $value = $value ? 1 : 0; if ( $value ) { update_post_meta( $post_id, '_mini_seo_analyzor_temp_disable', 1 ); } else { delete_post_meta( $post_id, '_mini_seo_analyzor_temp_disable' ); } if ( function_exists( 'clean_post_cache' ) ) { clean_post_cache( $post_id ); } wp_send_json_success( [ 'saved' => true, 'value' => $value ] ); } /* ======================================================== * ذخیره هنگام save_post (fallback) * ======================================================== */ public function save_meta_box( $post_id, $post ) { if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( ! current_user_can( 'edit_post', $post_id ) ) return; if ( isset( $_POST['mini_seo_analyzor_meta_nonce'] ) ) { $nonce = sanitize_text_field( wp_unslash( $_POST['mini_seo_analyzor_meta_nonce'] ) ); if ( ! wp_verify_nonce( $nonce, 'mini_seo_analyzor_meta_nonce' ) ) return; } if ( isset( $_POST['mini_seo_analyzor_temp_disable'] ) ) { $val = sanitize_text_field( wp_unslash( $_POST['mini_seo_analyzor_temp_disable'] ) ); if ( $val ) { update_post_meta( $post_id, '_mini_seo_analyzor_temp_disable', 1 ); } else { delete_post_meta( $post_id, '_mini_seo_analyzor_temp_disable' ); } } } /* ======================================================== * نوتیفیکیشن اگر Rank Math و Yoast نصب نبودند * ======================================================== */ public function check_seo_plugins_notice() { if ( ! is_admin() || ! current_user_can( 'edit_posts' ) ) return; $screen = function_exists('get_current_screen') ? get_current_screen() : null; if ( ! $screen || ! in_array( $screen->base ?? '', [ 'post', 'post-new' ], true ) ) return; if ( ! function_exists( 'is_plugin_active' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin.php'; } if ( ! is_plugin_active( 'seo-by-rank-math/rank-math.php' ) && ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) { echo '<div class="notice notice-warning is-dismissible"><p>⚠️ هیچ پلاگین سئوی اصلی (Rank Math یا Yoast SEO) فعال نیست. برخی از دادههای آنالیز Aio/GEO ممکن است کامل نباشند.</p></div>'; } } /* ======================================================== * توابع تحلیل (Aio / GEO) * ======================================================== */ private function analyze_aio( int $post_id, string $title, string $content_html, string $content_text, string $meta_desc, string $keyword, array $schema_info ): string { $score = 0; $checks = []; // کلمه کلیدی در عنوان: ۱۵ امتیاز if ( $this->keyword_exists_as_whole_word( $title, $keyword ) ) $score += 15; $checks[] = ['label' => 'کلمه کلیدی در عنوان', 'status' => $this->keyword_exists_as_whole_word( $title, $keyword ), 'suggestion' => 'کلمه کلیدی اصلی باید در عنوان صفحه وجود داشته باشد. بهتر است در ابتدای عنوان بیاید.']; // کلمه کلیدی در توضیحات متا: ۱۰ امتیاز if ( $this->keyword_exists_as_whole_word( $meta_desc, $keyword ) ) $score += 10; $checks[] = ['label' => 'کلمه کلیدی در توضیحات متا', 'status' => $this->keyword_exists_as_whole_word( $meta_desc, $keyword ), 'suggestion' => 'استفاده از کلمه کلیدی در توضیحات متا (Meta Description) برای افزایش نرخ کلیک در نتایج گوگل ضروری است.']; // وضعیت ایندکس: ۱۵ امتیاز $is_indexable = $this->is_post_indexable( $post_id ); if ( $is_indexable ) $score += 15; $checks[] = ['label' => 'وضعیت ایندکس: ' . ( $is_indexable ? 'ایندکس (Index)' : 'نوایندکس (NoIndex)' ), 'status' => $is_indexable, 'suggestion' => 'برای دیده شدن در گوگل، این صفحه باید قابل ایندکس باشد. تیک No Index را از تنظیمات سئو بردارید.']; // استفاده از H2 با کلمه کلیدی: ۱۰ امتیاز $has_h2_with_kw = (bool) preg_match( '/<h2[^>]*>.*' . preg_quote( $keyword, '/' ) . '.*<\/h2>/isu', $content_html ); if ( $has_h2_with_kw ) $score += 10; $checks[] = ['label' => 'استفاده از تگ H2 با کلمه کلیدی', 'status' => $has_h2_with_kw, 'suggestion' => 'کلمه کلیدی اصلی را در حداقل یکی از زیرعنوانهای H2 به کار ببرید تا ساختار محتوا برای گوگل واضحتر شود.']; // پیوندها: مجموعاً ۲۰ امتیاز (۱۰ برای داخلی، ۱۰ برای خارجی) $link_counts = $this->analyze_links_in_content( $content_html ); $total_links = $link_counts['internal'] + $link_counts['external']; if ( $link_counts['internal'] > 0 ) $score += 10; if ( $link_counts['external'] > 0 ) $score += 10; $link_status = $total_links > 0; $link_label = "پیوندها: {$total_links} | خارجی: {$link_counts['external']} | داخلی: {$link_counts['internal']}"; $suggestion = ''; if ( ! $link_status ) { // فقط اگر هیچ لینکی نباشد، این پیشنهاد نمایش داده میشود $suggestion = 'محتوای شما هیچ پیوندی ندارد. برای بهبود سئو، به صفحات دیگر سایت خود (لینک داخلی) و به سایتهای معتبر خارجی (لینک خارجی) ارجاع دهید.'; } elseif ( $link_counts['internal'] === 0 ) { // اگر لینک خارجی هست ولی داخلی نیست $suggestion = 'هیچ لینک داخلی یافت نشد. با لینک دادن به سایر نوشتههای مرتبط در سایت خود، به کاربران و گوگل در یافتن محتوای بیشتر کمک کنید.'; } elseif ( $link_counts['external'] === 0 ) { // اگر لینک داخلی هست ولی خارجی نیست $suggestion = 'هیچ لینک خارجی یافت نشد. ارجاع دادن به منابع معتبر خارجی میتواند اعتبار محتوای شما را نزد گوگل افزایش دهد.'; } $checks[] = ['label' => $link_label, 'status' => $link_status, 'suggestion' => $suggestion]; // کلمه کلیدی در محتوا: ۱۰ امتیاز $keyword_count = $this->count_keyword_as_whole_word( $content_text, $keyword ); if ( $keyword_count > 0 ) $score += 10; $checks[] = ['label' => "کلمه کلیدی در محتوا (تعداد: $keyword_count)", 'status' => $keyword_count > 0, 'suggestion' => 'حداقل ۱ بار از کلمه کلیدی در پاراگراف اول استفاده کنید. چگالی مناسب بین ۰.۵% تا ۱% است.']; // وجود اسکیما: ۱۰ امتیاز if ( $schema_info['found'] ) $score += 10; $checks[] = ['label' => 'وجود اسکیما (نوع: ' . esc_html($schema_info['type']) . ')', 'status' => $schema_info['found'], 'suggestion' => 'استفاده از نشانهگذاری اسکیمای ساختاریافته (مانند Article, FAQPage) به موتورهای جستجو کمک میکند محتوای شما را بهتر درک کنند.']; // کلمه کلیدی در متن Alt: 10 امتیاز $has_kw_in_alt = $this->check_keyword_in_image_alts( $post_id, $content_html, $keyword ); if ( $has_kw_in_alt ) $score += 10; $checks[] = ['label' => 'کلمه کلیدی در متن Alt تصاویر', 'status' => $has_kw_in_alt, 'suggestion' => 'برای بهینهسازی تصاویر، کلمه کلیدی را در متن جایگزین (Alt) حداقل یکی از تصاویر محتوا یا تصویر شاخص به کار ببرید.']; // مجموع کل امتیازات: ۱۰۰ return $this->render_progress_bar( 'امتیاز Aio', $score ) . $this->render_checklist( $checks ); } private function analyze_geo( int $post_id, string $content_html, string $content_text, string $title, string $meta_desc, array $schema_info ): string { $score = 0; $checks = []; $cities_pattern = 'تهران|اصفهان|شیراز|مشهد|تبریز|کرج|اهواز|قم|کرمانشاه|ارومیه|رشت|ساری|یزد|کرمان'; $full_text_for_city = $title . ' ' . $content_text . ' ' . $meta_desc; $has_city_in_content = (bool) preg_match( "/\b({$cities_pattern})\b/u", $full_text_for_city ); if ($has_city_in_content) $score += 25; $checks[] = ['label' => 'ذکر نام شهر در محتوا یا عنوان', 'status' => $has_city_in_content, 'suggestion' => 'نام شهر هدف (مثلاً تهران) را در عنوان، توضیحات متا یا متن اصلی ذکر کنید.']; $local_seo_info = $this->get_local_seo_nap_info(); $has_contact = !empty($local_seo_info['phone']) || !empty($local_seo_info['address']) || (bool) preg_match( '/(\d{8,11}|\b\d{3,4}-\d{7,8}\b)|(خیابان|بلوار|میدان|کوچه|پلاک)/u', $content_text ); if ($has_contact) $score += 20; $checks[] = ['label' => 'وجود شماره تماس یا بخشی از آدرس', 'status' => $has_contact, 'suggestion' => 'اطلاعات تماس (تلفن) و آدرس را در تنظیمات Local SEO افزونه سئو یا در محتوای صفحه وارد کنید.']; $has_map = (bool) preg_match( '/<iframe[^>]+src=[\'\"][^\'\"]*google\.com\/(maps)/i', $content_html ); if ($has_map) $score += 20; $checks[] = ['label' => 'جاسازی نقشه گوگل (Google Maps)', 'status' => $has_map, 'suggestion' => 'با قرار دادن نقشه گوگل در صفحه، موقعیت مکانی خود را به گوگل و کاربران به طور واضح نشان دهید.']; if ( $schema_info['is_local'] ) $score += 25; $checks[] = ['label' => 'استفاده از اسکیمای LocalBusiness', 'status' => $schema_info['is_local'], 'suggestion' => 'برای کسب و کارهای محلی، استفاده از اسکیمای LocalBusiness یا زیرمجموعههای آن برای نمایش در نتایج محلی گوگل حیاتی است.']; $has_city_in_alt = false; if (preg_match_all('/<img[^>]+alt=["\']([^"\']*)["\']/i', $content_html, $alt_matches)) { foreach ($alt_matches[1] as $alt_text) { if (preg_match("/\b({$cities_pattern})\b/u", $alt_text)) { $has_city_in_alt = true; break; } } } if($has_city_in_alt) $score += 10; $checks[] = ['label' => 'نام شهر در متن جایگزین (Alt) تصاویر', 'status' => $has_city_in_alt, 'suggestion' => 'نام شهر هدف را در متن جایگزین حداقل یکی از تصاویر صفحه به کار ببرید.']; return $this->render_progress_bar( 'امتیاز GEO', $score ) . $this->render_checklist( $checks ); } /* ======================================================== * توابع کمکی * ======================================================== */ private function get_active_schema_info( int $post_id ): array { $result = [ 'found' => false, 'type' => 'یافت نشد', 'is_local' => false ]; $found_types = []; if ( class_exists( '\RankMath' ) ) { $schemas = get_post_meta( $post_id, 'rank_math_schema', true ); if ( ! empty( $schemas ) && is_array( $schemas ) ) { foreach ( array_keys( $schemas ) as $schema_type ) { $found_types[] = ucfirst( $schema_type ); } } if ( empty( $found_types ) && class_exists('\RankMath\Helper') ) { $post_type = get_post_type( $post_id ); $default_schema = \RankMath\Helper::get_settings( "titles.pt_{$post_type}_default_schema_type" ); if ( ! empty( $default_schema ) ) { $found_types[] = ucfirst($default_schema); } elseif ( in_array($post_type, ['post', 'page'])) { $found_types[] = 'Article'; } elseif ( $post_type === 'product' ) { $found_types[] = 'Product'; } } } elseif ( function_exists( 'YoastSEO' ) ) { $page_type = get_post_meta( $post_id, '_yoast_wpseo_schema_page_type', true ); $article_type = get_post_meta( $post_id, '_yoast_wpseo_schema_article_type', true ); if ( ! empty( $article_type ) && $page_type === 'WebPage' ) { $found_types[] = $page_type; $found_types[] = $article_type; } elseif ( ! empty( $page_type ) ) { $found_types[] = $page_type; } elseif ( class_exists('WPSEO_Options') ){ $post_type = get_post_type($post_id); $options_key = 'schema-page-type-' . $post_type; $default_type = \WPSEO_Options::get( $options_key, 'WebPage' ); $found_types[] = $default_type; } } if ( ! empty( $found_types ) ) { $result['found'] = true; $unique_types = array_unique( array_filter( $found_types ) ); $result['type'] = implode( ', ', $unique_types ); foreach ( $unique_types as $type ) { if ( preg_match( '/(LocalBusiness|Restaurant|Store|ContactPage|AboutPage)/i', $type ) ) { $result['is_local'] = true; break; } } } return $result; } private function get_focus_keyword_from_meta( int $post_id ): string { $keyword = get_post_meta( $post_id, 'rank_math_focus_keyword', true ); if ( ! empty( $keyword ) ) { $keywords = explode( ',', $keyword ); return trim( $keywords[0] ); } $keyword = get_post_meta( $post_id, '_yoast_wpseo_focuskw', true ); if ( ! empty( $keyword ) ) { return trim( $keyword ); } return ''; } private function get_meta_description_from_meta( int $post_id ): string { $desc = get_post_meta( $post_id, 'rank_math_description', true ); if ( ! empty( $desc ) ) return trim( $desc ); $desc = get_post_meta( $post_id, '_yoast_wpseo_metadesc', true ); if ( ! empty( $desc ) ) return trim( $desc ); return ''; } private function keyword_exists_as_whole_word( string $haystack, string $needle ): bool { if ( empty( trim( $haystack ) ) || empty( trim( $needle ) ) ) return false; return preg_match( '/\b' . preg_quote( trim( $needle ), '/' ) . '\b/iu', $haystack ) === 1; } private function count_keyword_as_whole_word( string $haystack, string $needle ): int { if ( empty( trim( $haystack ) ) || empty( trim( $needle ) ) ) return 0; return preg_match_all( '/\b' . preg_quote( trim( $needle ), '/' ) . '\b/iu', $haystack ); } private function is_post_indexable( int $post_id ): bool { if ( class_exists( 'RankMath\Post' ) ) { $robots = \RankMath\Post::get_meta( 'robots', $post_id ); if ( is_array( $robots ) && in_array( 'noindex', $robots, true ) ) return false; } if ( get_post_meta( $post_id, '_yoast_wpseo_meta-robots-noindex', true ) === '1' ) return false; if ( '0' === get_option( 'blog_public' ) ) return false; return true; } private function analyze_links_in_content( string $html ): array { $counts = [ 'internal' => 0, 'external' => 0 ]; if ( empty( $html ) ) return $counts; $site_host = wp_parse_url( home_url(), PHP_URL_HOST ); if ( ! $site_host ) return $counts; $site_host = str_replace( 'www.', '', $site_host ); if ( ! class_exists('DOMDocument') ) return $counts; libxml_use_internal_errors( true ); $dom = new DOMDocument(); @$dom->loadHTML( mb_convert_encoding( $html, 'HTML-ENTITIES', 'UTF-8' ) ); libxml_clear_errors(); foreach ( $dom->getElementsByTagName('a') as $link ) { $href = $link->getAttribute('href'); if ( empty( $href ) || in_array( $href[0], [ '#', '?' ], true ) || strpos( $href, 'javascript:' ) === 0 || strpos($href, 'mailto:') === 0 ) continue; $host = wp_parse_url( $href, PHP_URL_HOST ); if ( empty( $host ) || str_replace( 'www.', '', $host ) === $site_host ) { $counts['internal']++; } else { $counts['external']++; } } return $counts; } private function check_keyword_in_image_alts( int $post_id, string $content_html, string $keyword ): bool { if ( preg_match_all( '/<img[^>]+alt=["\']([^"\']*)["\']/i', $content_html, $matches ) ) { foreach ( $matches[1] as $alt_text ) { if ( ! empty( $alt_text ) && $this->keyword_exists_as_whole_word( $alt_text, $keyword ) ) { return true; } } } if ( function_exists( 'has_post_thumbnail' ) && has_post_thumbnail( $post_id ) ) { $thumbnail_id = get_post_thumbnail_id( $post_id ); $featured_image_alt = get_post_meta( $thumbnail_id, '_wp_attachment_image_alt', true ); if ( ! empty( $featured_image_alt ) && $this->keyword_exists_as_whole_word( $featured_image_alt, $keyword ) ) { return true; } } return false; } private function get_local_seo_nap_info(): array { $nap = [ 'address' => '', 'phone' => '' ]; if ( function_exists( 'rank_math_get_option' ) ) { $nap['address'] = rank_math_get_option( 'local_seo_address' ); $nap['phone'] = rank_math_get_option( 'local_seo_phone' ); } if ( empty( $nap['address'] ) && class_exists( 'WPSEO_Options' ) ) { if ( is_plugin_active( 'wpseo-local/wpseo-local.php' ) ) { $options = get_option( 'wpseo_local' ); $nap['address'] = $options['location_address'] ?? ''; $nap['phone'] = $options['location_phone'] ?? ''; } } return $nap; } private function get_provinces_list(): array { return [ 'آذربایجان شرقی' => 'تبریز', 'آذربایجان غربی' => 'ارومیه', 'اردبیل' => 'اردبیل', 'اصفهان' => 'اصفهان', 'البرز' => 'کرج', 'ایلام' => 'ایلام', 'بوشهر' => 'بوشهر', 'تهران' => 'تهران', 'چهارمحال و بختیاری' => 'شهرکرد', 'خراسان رضوی' => 'مشهد', 'خراسان جنوبی' => 'بیرجند', 'خراسان شمالی' => 'بجنورد', 'خوزستان' => 'اهواز', 'زنجان' => 'زنجان', 'سمنان' => 'سمنان', 'سیستان و بلوچستان' => 'زاهدان', 'فارس' => 'شیراز', 'قزوین' => 'قزوین', 'قم' => 'قم', 'کردستان' => 'سنندج', 'کرمان' => 'کرمان', 'کرمانشاه' => 'کرمانشاه', 'کهگیلویه و بویراحمد' => 'یاسوج', 'گلستان' => 'گرگان', 'گیلان' => 'رشت', 'لرستان' => 'خرمآباد', 'مازندران' => 'ساری', 'مرکزی' => 'اراک', 'هرمزگان' => 'بندرعباس', 'همدان' => 'همدان', 'یزد' => 'یزد' ]; } private function render_progress_bar( string $label, int $score ): string { $score = min( 100, max( 0, $score ) ); $color = '#dc3545'; if ( $score >= 80 ) $color = '#198754'; elseif ( $score >= 50 ) $color = '#ffc107'; $text_color = ( $score < 50 && $score > 0 ) ? '#000' : '#fff'; return sprintf('<div><strong>%s: %d/100</strong></div><div class="mini-seo-progress-bar"><div class="mini-seo-progress-bar-fill" style="width:%d%%; background-color:%s; color:%s;">%d%%</div></div>', esc_html($label), $score, $score, esc_attr($color), esc_attr($text_color), $score); } private function render_checklist( array $checks ): string { $html = '<ul class="mini-seo-checklist">'; foreach ( $checks as $check ) { $status_class = $check['status'] ? 'status-pass' : 'status-fail'; $label_html = esc_html( $check['label'] ); $html .= sprintf( '<li class="%s">%s</li>', esc_attr( $status_class ), $label_html ); // پیشنهاد فقط در صورتی نمایش داده میشود که وضعیت Fail باشد و متنی برای پیشنهاد وجود داشته باشد if ( ! $check['status'] && ! empty( $check['suggestion'] ) ) { $suggestion_text = preg_replace('/(https?:\/\/[^\s]+)/', '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>', esc_html( $check['suggestion'] )); $html .= '<div class="mini-seo-suggestion">' . $suggestion_text . '</div>'; } } $html .= '</ul>'; return $html; } private function get_aio_tutorial_content(): string { return '<h4>راهنمای Aio (بهینهسازی برای موتور پاسخگو)</h4><p>هدف <strong>Aio</strong>، ارائه پاسخی مستقیم، سریع و دقیق به سوالات کاربران است. با رعایت این موارد، شانس خود را برای نمایش در بخش پاسخهای ویژه گوگل (Featured Snippets) و کسب رتبههای بهتر افزایش میدهید.</p><p><strong>۱. کلمه کلیدی در عنوان و توضیحات متا:</strong> کلمه کلیدی باید در مهمترین بخشهای صفحه یعنی عنوان و توضیحات متا وجود داشته باشد.</p><p><strong>۲. وضعیت ایندکس:</strong> مهمترین فاکتور فنی! اگر صفحه روی حالت <code>NoIndex</code> باشد، گوگل آن را در نتایج نمایش نخواهد داد.</p><p><strong>۳. استفاده از زیرعنوان H2 با کلمه کلیدی:</strong> برای مثال، اگر کلمه کلیدی شما <code>وردپرس</code> است، یک تگ H2 مانند <code><h2>وردپرس چیست؟</h2></code> تیک سبز را دریافت میکند.</p><p><strong>۴. لینکسازی داخلی و خارجی:</strong> با لینک دادن به صفحات مرتبط در سایت خودتان (داخلی) و به منابع معتبر دیگر (خارجی)، اعتبار صفحه را افزایش میدهید.</p><p><strong>۵. وجود کلمه کلیدی در محتوا:</strong> کلمه کلیدی باید به تعداد طبیعی و مناسب در متن تکرار شود. از تکرار بیش از حد خودداری کنید.</p><p><strong>۶. اسکیما (Schema):</strong> اگر صفحه شما به سوالات متداول پاسخ میدهد یا یک مقاله است، با استفاده از اسکیمای مناسب (مثل `FAQPage` یا `Article`) به گوگل کمک میکنید تا محتوای شما را بهعنوان پاسخ مستقیم نمایش دهد.</p><p><strong>۷. متن جایگزین (Alt) تصاویر:</strong> نوشتن متن جایگزین مناسب با کلمه کلیدی، به درک بهتر گوگل از محتوای تصویری و بهبود سئوی کلی صفحه کمک میکند.</p>'; } private function get_geo_tutorial_content(): string { return '<h4>راهنمای GEO (بهینهسازی برای جستجوی محلی)</h4><p>هدف <strong>GEO</strong>، کسب رتبه برای جستجوهایی است که به یک موقعیت مکانی خاص مرتبط هستند (مثلاً <code>رستوران در تهران</code>). این تکنیکها برای کسبوکارهای محلی حیاتی است.</p><p><strong>۱. ذکر نام شهر:</strong> نام شهر هدف خود را در عنوان، تیترها، متن اصلی و همچنین <strong>متن جایگزین (Alt) تصاویر</strong> به کار ببرید.</p><p><strong>۲. اطلاعات تماس و آدرس (NAP):</strong> درج اطلاعات نام (Name)، آدرس (Address) و شماره تلفن (Phone) یک سیگنال بسیار قوی برای سئوی محلی است.</p><p><strong>۳. جاسازی نقشه گوگل:</strong> قرار دادن نقشه گوگل در صفحه، موقعیت مکانی شما را به گوگل رسماً اعلام میکند.</p><p><strong>۴. استفاده از اسکیمای LocalBusiness:</strong> این یک زبان نشانهگذاری است که به گوگل کمک میکند کسبوکار محلی شما را عمیقتر درک کند. اگر کسبوکار محلی دارید، استفاده از این اسکیما یا انواع خاصتر آن (مثل <code>Restaurant</code>, <code>Store</code>, <code>Dentist</code>) <strong>بسیار ضروری</strong> است.</p>'; } } Mini_SEO_Analyzor::instance(); endif;
افزونه مینی سئو نسخه پرو
تحلیلگر سئو AIO: بهینهسازی برای موتورهای پاسخگو
با تحلیلگر AIO، محتوای خود را برای پاسخ مستقیم به نیاز کاربر و نمایش در بخش پاسخهای ویژه گوگل (Featured Snippets) بهینه کنید.
-
✅ بررسی کلمه کلیدی: حضور هوشمندانه کلمه کلیدی در عنوان، متا، تیتر H2 و متن اصلی.
-
✅ وضعیت ایندکس: اطمینان از اینکه صفحه شما توسط گوگل دیده میشود.
-
✅ لینکسازی هوشمند: تحلیل کامل لینکهای داخلی و خارجی برای افزایش اعتبار.
-
✅ قدرت اسکیما: بررسی وجود اسکیماهای ساختاریافته برای درک بهتر محتوا توسط گوگل.
-
✅ سئوی تصاویر: تحلیل متن جایگزین (Alt) تصاویر برای گرفتن ورودی از گوگل ایمیج.
تحلیلگر سئو GEO: پادشاهی در جستجوهای محلی
اگر کسبوکار محلی دارید، این بخش بلیط طلایی شما برای جذب مشتریان اطرافتان است.
-
✅ شناسایی نام شهر: بررسی هوشمند نام شهر هدف در عنوان، محتوا و تصاویر.
-
✅ اطلاعات تماس (NAP): تحلیل وجود آدرس و شماره تلفن به عنوان یک سیگنال قدرتمند محلی.
-
✅ نقشه گوگل: تشخیص وجود نقشه گوگل برای تثبیت موقعیت مکانی شما.
-
✅ اسکیمای محلی: بررسی تخصصی اسکیمای LocalBusiness برای درخشش در نتایج محلی.
تحلیلگر Pico: بهینهسازی تصاویر و مدیا
سرعت سایت و تجربه کاربری را با تحلیل دقیق رسانهها به سطح بالاتری ببرید.
-
✅ فرمت WebP: شناسایی تصاویر قدیمی و پیشنهاد فرمت مدرن WebP برای افزایش سرعت.
-
✅ متن جایگزین (Alt): شناسایی تصاویری که متن جایگزین ندارند تا هیچ فرصتی را از دست ندهید.
-
✅ حجم و ابعاد استاندارد: تشخیص تصاویر سنگین و بسیار عریض که سرعت سایت را کم میکنند.
-
✅ شناسایی ویدیو و صوت: امتیازدهی مثبت برای استفاده از ویدیو و پادکست جهت افزایش زمان ماندگاری کاربر.
سازگاری و یکپارچگی کامل
-
هماهنگ با غولها: کاملاً سازگار با افزونههای محبوب Rank Math و Yoast SEO.
-
پشتیبانی از ووکامرس: تحلیل دقیق و تخصصی صفحات محصولات فروشگاه شما.
-
مناسب برای همه: طراحی شده برای نوشتهها، برگهها و محصولات ووکامرس.
- سفارش خرید نسخه پرو⬇️
یک پاسخ
با رنک مث اوکیه!