یکی از پرتکرارترین سناریوهایی که در پروژه‌های مشتریان با آن روبه‌رو می‌شوم این است: سایت، تیم چند‌نفره دارد، ولی همه با نقش «مدیر» کار می‌کنند. دلیلش همیشه هم یک چیز است: «وقت نداشتیم نقش‌های دقیق تعریف کنیم، پس همه را مدیر گذاشتیم تا کارها راه بیفتد.» مدتی بعد، وقتی مشکلی پیش می‌آید — یک کاربر تصادفاً افزونه‌ای را غیرفعال می‌کند، یا بدتر، اطلاعات حساس را می‌بیند — می‌فهمیم چقدر این تصمیم گران بوده. در پروژه‌ای که برای یک کلینیک پزشکی کار می‌کردم، مدیر فنی سایت را با هفت کاربر مختلف به من تحویل داد که همه‌شان نقش administrator داشتند. وقتی از او پرسیدم چرا، گفت که «منشی‌ها فقط باید نوبت‌ها را ببینند، ولی برایشان سخت بود که دسترسی‌ها را کم کنیم.» راه‌حل، یک اسنیپت کوچک بود که دسترسی‌های هر کاربر را در سطح کد محدود می‌کرد و به منشی‌ها فقط اجازهٔ مشاهدهٔ بخش نوبت‌ها را می‌داد. آن پروژه، باورِ رایجی را در ذهن من اصلاح کرد: محدود کردن دسترسی کاربران نه یک تصمیم انسانی دشوار، بلکه یک مسئلهٔ فنی است که با یک اسنیپت دقیق حل می‌شود. در این مقاله، همان مسیر را با هم مرور می‌کنیم: محدودسازی ورود به پیشخوان، مخفی‌سازی منوهای اضافی، محدودسازی ویرایش و حذف محتوا، و کنترل دقیق دسترسی براساس نقش و capability. اگر با مفهوم پایهٔ اسنیپت آشنا نیستید، پیش از ادامه قطعه کد وردپرس چیست و چگونه از آن استفاده کنیم نقطهٔ شروع مناسبی است.

چرا محدودسازی دسترسی، یک تصمیم امنیتی و تجربی است

محدود کردن دسترسی کاربران، در نگاه اول یک موضوع امنیتی به‌نظر می‌رسد؛ ولی در تجربهٔ من، به همان اندازه موضوعی دربارهٔ تجربهٔ کاربری هم است. سه دلیل که این دو بُعد را در تصمیم‌گیری‌های خودم کنار هم می‌گذارم:

دلیل اول: کاهش سطح حمله. هر کاربری که به بخش‌های کمتری دسترسی دارد، یک درِ کمتر برای ورود مهاجم است. اگر حساب یک کاربر کم‌دسترسی هک شود، مهاجم نمی‌تواند کارهای خطرناکی مثل نصب افزونه، تغییر تنظیمات یا حذف کاربران دیگر انجام دهد. این تفکر در مبانی راهنمای امنیت وردپرس برای مبتدیان با جزئیات آمده است.

دلیل دوم: کاهش خطای انسانی. در تجربهٔ من، بیشتر خرابی‌های تصادفی سایت (غیرفعال شدن یک افزونه، تغییر تنظیمات ناخواسته، حذف اشتباه یک برگه) از کاربران پر‌دسترسی آمده، نه از حملهٔ بیرونی. محدود کردن دسترسی، تعداد این خطاها را کاهش می‌دهد.

دلیل سوم: تمرکز کاری. کاربری که فقط با بخش‌های مرتبط با کارش مواجه می‌شود، سریع‌تر و دقیق‌تر کار می‌کند. در پروژه‌ای برای یک مجله، سردبیر محتوایی که در پیشخوان فقط بخش نوشته‌ها، دیدگاه‌ها و دسته‌بندی‌ها را می‌دید، زمان بازبینی روزانه‌اش حدود یک‌سوم کمتر از حالتی بود که منوی کامل مدیر را می‌دید.

محدود کردن دسترسی، هم برای سایت امن‌تر است و هم برای کاربر راحت‌تر. هر دسترسی که حذف می‌کنید، یک تصمیم کمتر برای کاربر و یک ریسک کمتر برای سایت است.

سه لایهٔ محدودسازی دسترسی که باید از هم تفکیک شوند

در تجربهٔ خودم، محدودسازی دسترسی به سه لایهٔ متفاوت تقسیم می‌شود که هرکدام ابزار فنی متفاوتی می‌خواهند. تفکیک این سه، اولین قدم در طراحی درست است:

لایهٔ اول: لایهٔ نقش و capability

این لایه، پایه‌ای‌ترین سطح محدودسازی است. در این لایه، شما تعریف می‌کنید که هر نقش چه capabilityهایی دارد و کاربران با چه نقشی وارد سایت می‌شوند. اصلاح در این لایه، پایدارترین راه محدودسازی است ولی نیاز به دانش قبلی دربارهٔ ساختار نقش‌ها دارد. توضیح کامل این موضوع در توابع وردپرس برای مدیریت نقش‌ها و دسترسی‌ها و نمونهٔ عملی آن در قطعه کد افزودن نقش کاربری جدید وردپرس آمده است.

لایهٔ دوم: لایهٔ رابط کاربری

این لایه، دربارهٔ چیزی است که کاربر در پیشخوان می‌بیند. حتی اگر کاربر از نظر فنی به بخشی دسترسی داشته باشد، می‌توانید آن را از دید او پنهان کنید. مثال: پنهان کردن منوی «افزونه‌ها» از یک کاربری که نظری نمی‌تواند تغییرات ایجاد کند. این لایه، تجربهٔ کاربری را بهبود می‌دهد ولی به‌تنهایی امنیت را تضمین نمی‌کند. توضیح تکمیلی در قطعه کد مخفی کردن منوی مدیریت وردپرس آمده است.

لایهٔ سوم: لایهٔ منطقی

این لایه، دربارهٔ کنترل رفتار کاربر در لحظهٔ اجرای عملیات است. حتی اگر کاربری به منویی دسترسی پیدا کند، می‌توانید در کد سفارشی خودتان بررسی کنید که آیا اجازهٔ انجام عملیات مورد نظر را دارد یا نه. این لایه، مکمل دو لایهٔ قبلی است و در سناریوهایی که دسترسی‌ها پیچیده‌اند، ضروری می‌شود. اصول این لایه در هوک‌های وردپرس و افزایش امنیت کد آمده است.

در پروژه‌های خودم، همیشه هر سه لایه را در نظر می‌گیرم، ولی تأکید اصلی روی لایهٔ اول است. بدون اصلاح نقش و capability، دو لایهٔ دیگر بیشتر شبیه تزئین هستند تا امنیت واقعی.

محدودسازی ورود به پیشخوان برای نقش‌های غیرمدیر

پرکاربردترین نیاز در محدودسازی دسترسی، جلوگیری از ورود نقش‌های غیرمدیر به پیشخوان است. مثلاً در سایتی که مشتریان فقط برای خرید ثبت‌نام کرده‌اند، نیازی نیست به پیشخوان دسترسی داشته باشند. الگوی استاندارد این کار:

/**
 * Snippet: Block non-admin users from accessing wp-admin.
 *
 * @since 2026-09-16
 * @author WordPressKar
 *
 * Purpose: Restrict wp-admin access to administrators and editors.
 * Location: mu-plugins directory or child theme functions.php.
 */

add_action( 'init', 'wphk_restrict_admin_access' );

function wphk_restrict_admin_access() {
    if ( ! is_user_logged_in() ) {
        return;
    }

    if ( wp_doing_ajax() ) {
        return;
    }

    if ( ! is_admin() ) {
        return;
    }

    $user = wp_get_current_user();

    if ( ! $user instanceof WP_User ) {
        return;
    }

    $allowed_roles = array( 'administrator', 'editor' );
    if ( array_intersect( $allowed_roles, (array) $user->roles ) ) {
        return;
    }

    wp_safe_redirect( home_url( '/' ) );
    exit;
}

پنج نکتهٔ کلیدی در این نمونه. اول، بررسی is_user_logged_in در ابتدا که از اجرای این منطق برای کاربران مهمان جلوگیری می‌کند. دوم، بررسی wp_doing_ajax که از قطع کردن درخواست‌های AJAX کاربران جلوگیری می‌کند؛ بدون این شرط، کاربران غیرمجاز که در front-end از AJAX استفاده می‌کنند با خطای ۳۰۱ مواجه می‌شوند. سوم، بررسی is_admin که تضمین می‌کند این محدودسازی فقط در پیشخوان اجرا می‌شود. چهارم، استفاده از array_intersect برای بررسی نقش‌ها؛ این رویکرد با کاربرانی که چند نقش دارند هم کار می‌کند. پنجم، استفاده از wp_safe_redirect به‌جای wp_redirect که امنیت بیشتری دارد و جلوی ریدایرکت به دامنه‌های خارجی را می‌گیرد. نحوۀ دقیق این توابع در توابع وردپرس برای کار با کاربران آمده است.

یک نکتهٔ عملی: اگر می‌خواهید کاربران غیرمجاز به‌جای ریدایرکت، به صفحهٔ پروفایل خودشان هدایت شوند، می‌توانید مقدار home_url( '/' ) را با admin_url( 'profile.php' ) جایگزین کنید. در پروژه‌های سامانه‌های عضویتی، این رویکرد تجربهٔ کاربری بهتری می‌سازد.

مخفی‌سازی منوهای اضافی در پیشخوان

در لایهٔ دوم، می‌خواهیم منوهایی که کاربر به آن‌ها نیازی ندارد را از دید او پنهان کنیم. هوک مناسب برای این کار، admin_menu با اولویت بالا است:

add_action( 'admin_menu', 'wphk_hide_admin_menus', 999 );

function wphk_hide_admin_menus() {
    if ( current_user_can( 'manage_options' ) ) {
        return;
    }

    remove_menu_page( 'tools.php' );
    remove_menu_page( 'edit-comments.php' );
    remove_menu_page( 'plugins.php' );
    remove_menu_page( 'themes.php' );

    // برای کاربران غیرمدیر، منوی کاربران را هم پنهان می‌کنیم
    if ( ! current_user_can( 'list_users' ) ) {
        remove_menu_page( 'users.php' );
    }
}

پنج نکتهٔ کلیدی در این نمونه. اول، استفاده از اولویت ۹۹۹ که تضمین می‌کند این تابع بعد از ثبت همهٔ منوها اجرا می‌شود؛ بدون این اولویت، ممکن است برخی منوها دوباره ظاهر شوند. توضیح کامل این مفهوم در Priority در هوک‌های وردپرس چیست آمده است. دوم، بررسی current_user_can( "manage_options" ) در ابتدا که به مدیران اجازه می‌دهد همهٔ منوها را ببینند. سوم، حذف تدریجی منوهای مختلف براساس نیاز، نه یک‌جا و براساس حدس. چهارم، بررسی دقیق‌تر دسترسی برای منوهایی مثل «کاربران» که ممکن است برخی نقش‌ها هم به آن نیاز داشته باشند. پنجم، توجه به این نکته که remove_menu_page فقط منو را از دید پنهان می‌کند؛ اگر کاربر آدرس مستقیم منو را وارد کند، همچنان می‌تواند به آن دسترسی پیدا کند — این موضوع در بخش محدودسازی منطقی حل می‌شود. الگوهای مشابه در مهم‌ترین Action Hook های وردپرس آمده است.

محدودسازی ویرایش و حذف محتوا براساس نویسنده

در لایهٔ سوم، حتی اگر کاربر به فهرست نوشته‌ها دسترسی داشته باشد، می‌خواهیم مطمئن شویم که فقط می‌تواند نوشته‌های خودش را ویرایش و حذف کند. این کار با فیلتر map_meta_cap انجام می‌شود:

add_filter( 'map_meta_cap', 'wphk_limit_edit_to_own_posts', 10, 4 );

function wphk_limit_edit_to_own_posts( $caps, $cap, $user_id, $args ) {
    if ( ! in_array( $cap, array( 'edit_post', 'delete_post' ), true ) ) {
        return $caps;
    }

    if ( empty( $args[0] ) ) {
        return $caps;
    }

    $post = get_post( $args[0] );
    if ( ! $post instanceof WP_Post ) {
        return $caps;
    }

    // برای نقش‌های ویرایشگر و مدیر، محدودیت اعمال نمی‌شود
    $user = get_userdata( $user_id );
    if ( $user && array_intersect( array( 'administrator', 'editor' ), (array) $user->roles ) ) {
        return $caps;
    }

    if ( (int) $post->post_author !== (int) $user_id ) {
        return array( 'do_not_allow' );
    }

    return $caps;
}

چهار نکتهٔ کلیدی در این الگو. اول، استفاده از فیلتر map_meta_cap که در لحظهٔ بررسی capabilityهای مرتبط با متادیتای یک شیء خاص (مثل نوشتهٔ خاص) اجرا می‌شود. دوم، بررسی دقیق instanceof WP_Post که در سناریوهای نادر از خطا جلوگیری می‌کند. سوم، بازگرداندن آرایهٔ array( "do_not_allow" ) که به وردپرس می‌گوید این capability را رد کند. چهارم، بررسی نقش کاربر برای اینکه مدیران و ویرایشگرها از این محدودیت معاف باشند. توضیح تفصیلی این فیلتر در توابع وردپرس برای مدیریت نقش‌ها و دسترسی‌ها آمده است.

یک هشدار: این فیلتر قدرتمند است و می‌تواند روی بخش‌های مختلف پیشخوان و front-end اثر بگذارد. پیش از اعمال، در محیط استجینگ تست کنید و اطمینان پیدا کنید که وردپرس، افزونه‌ها و قالب به‌درستی با محدودیت جدید کار می‌کنند. اصول کار در محیط استجینگ در بهترین روش تست قالب وردپرس پیش از انتشار سایت آمده است.

محدودسازی ابزارک‌ها و اطلاعات پیشخوان

یکی از کم‌توجه‌ترین بخش‌های محدودسازی، اطلاعاتی است که در صفحهٔ پیشخوان (Dashboard) نمایش داده می‌شود. وردپرس به‌طور پیش‌فرض ابزارک‌هایی مثل «اخبار وردپرس»، «فعالیت» و «بازار» را نشان می‌دهد که برای کاربران غیرمدیر بی‌معنی و گاهی نگران‌کننده است. الگوی حذف این ابزارک‌ها:

add_action( 'wp_dashboard_setup', 'wphk_custom_dashboard_for_users' );

function wphk_custom_dashboard_for_users() {
    if ( current_user_can( 'manage_options' ) ) {
        return;
    }

    remove_meta_box( 'dashboard_primary', 'dashboard', 'side' );
    remove_meta_box( 'dashboard_secondary', 'dashboard', 'side' );
    remove_meta_box( 'dashboard_quick_press', 'dashboard', 'side' );
    remove_meta_box( 'dashboard_right_now', 'dashboard', 'normal' );
    remove_meta_box( 'dashboard_activity', 'dashboard', 'normal' );

    // افزودن یک ابزارک ساده خوش‌آمدگویی به‌جای ابزارک‌های حذف‌شده
    wp_add_dashboard_widget(
        'wphk_welcome_widget',
        'خوش آمدید',
        'wphk_render_welcome_widget'
    );
}

function wphk_render_welcome_widget() {
    $user = wp_get_current_user();
    if ( ! $user instanceof WP_User ) {
        return;
    }
    echo '<p>' . esc_html( $user->display_name ) . ' عزیز، به پنل مدیریت خوش آمدید.</p>';
}

سه نکتهٔ کلیدی در این الگو. اول، استفاده از هوک wp_dashboard_setup که نقطهٔ استاندارد مدیریت ابزارک‌های پیشخوان است. دوم، بررسی دسترسی مدیر در ابتدا که اجازه می‌دهد مدیران همهٔ ابزارک‌ها را ببینند. سوم، استفاده از wp_add_dashboard_widget برای افزودن یک ابزارک خوش‌آمدگویی که تجربهٔ کاربری را انسانی‌تر می‌کند. یک نکتهٔ ظریف: اگر می‌خواهید ترتیب ابزارک‌ها را تغییر دهید، از فیلتر dashboard_glance_items یا توابع مشابه استفاده کنید. الگوهای مشابه در قطعه کد افزودن ستون سفارشی به مدیریت وردپرس آمده است.

محدودسازی تلاش‌های ورود

محدودسازی دسترسی فقط به پیشخوان محدود نمی‌شود؛ یکی از مهم‌ترین لایه‌های امنیتی، محدود کردن تعداد تلاش‌های ورود ناموفق است. اگر یک کاربر (یا مهاجم) بتواند بی‌نهایت بار رمز را امتحان کند، هر رمزی قابل شکستن است. الگوی پایه با هوک wp_login_failed:

add_action( 'wp_login_failed', 'wphk_count_failed_login' );

function wphk_count_failed_login( $username ) {
    $ip  = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : '';
    $key = 'wphk_failed_' . md5( $username . '|' . $ip );

    $attempts = (int) get_transient( $key );
    $attempts++;

    set_transient( $key, $attempts, 15 * MINUTE_IN_SECONDS );

    if ( $attempts >= 5 ) {
        // ثبت رویداد و رد ورودهای بعدی
        error_log( sprintf( 'WPHK: brute-force suspected for %s from %s', $username, $ip ) );
    }
}

و برای اعمال محدودیت در زمان ورود، از هوک wp_authenticate استفاده می‌کنیم:

add_action( 'wp_authenticate', 'wphk_block_excessive_attempts', 30, 2 );

function wphk_block_excessive_attempts( $username, $password ) {
    $ip  = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : '';
    $key = 'wphk_failed_' . md5( $username . '|' . $ip );

    $attempts = (int) get_transient( $key );

    if ( $attempts >= 5 ) {
        wp_die(
            'تعداد تلاش‌های ناموفق بیش از حد مجاز است. لطفاً ۱۵ دقیقه دیگر امتحان کنید.',
            'دسترسی موقتاً محدود شده',
            array( 'response' => 429 )
        );
    }
}

چهار نکتهٔ کلیدی در این الگو. اول، استفاده از transient برای شمارش تلاش‌ها که با پایان زمان، خودکار پاک می‌شود. دوم، ترکیب نام کاربری و IP در کلید که هم جلوی حمله به یک کاربر خاص را می‌گیرد و هم جلوی حمله از یک IP خاص. سوم، استفاده از کد پاسخ HTTP 429 (Too Many Requests) که پیام واضحی به ابزارهای پایش می‌دهد. چهارم، اولویت ۳۰ در هوک wp_authenticate که بعد از سایر بررسی‌ها اجرا می‌شود. تحلیل جامع این حوزه در جلوگیری از حملات Brute Force در وردپرس آمده است.

تفکیک نقش از capability در محدودسازی

یکی از پرتکرارترین اشتباهات در محدودسازی دسترسی، چک کردن نقش به‌جای capability است. این اشتباه، در ظاهر ساده به‌نظر می‌رسد ولی در بلندمدت مشکلات جدی می‌سازد. سه دلیل:

دلیل اول: انعطاف‌پذیری. اگر کد شما فقط نقش editor را چک کند، هر نقشی که روزی capabilityهای مشابه داشته باشد، دسترسی نخواهد داشت. بررسی capability، به نقش‌های جدید اجازه می‌دهد بدون تغییر کد، به‌درستی کار کنند.

دلیل دوم: نقش‌های ترکیبی. یک کاربر می‌تواند چند نقش داشته باشد. اگر کد شما فقط نقش editor را چک کند، کاربری که هم editor است و هم author، در برخی موارد به‌درستی تشخیص داده نمی‌شود.

دلیل سوم: هماهنگی با اکوسیستم. افزونه‌های دیگر روی همان capabilityها کار می‌کنند. اگر شما هم به همان استاندارد وفادار باشید، افزونه‌های دیگر بدون تعارض با کد شما کار می‌کنند.

سناریونادرستدرست
بررسی دسترسی به ویرایش نوشتهin_array( 'editor', $user->roles )current_user_can( 'edit_posts' )
بررسی دسترسی به تنظیماتin_array( 'administrator', $user->roles )current_user_can( 'manage_options' )
بررسی دسترسی به مدیریت کاربرانچک کردن نام نقشcurrent_user_can( 'list_users' )
بررسی دسترسی به مدیریت سفارش‌های ووکامرسچک کردن نقش shop_managercurrent_user_can( 'manage_woocommerce' )

قاعدهٔ طلایی من در این حوزه: هرگز نام نقش را در کد چک نکنید؛ همیشه از current_user_can با نام capability استفاده کنید. این تصمیم کوچک، در بلندمدت انعطاف‌پذیری و پایداری کد شما را چند برابر می‌کند. توضیح تفصیلی این تفاوت در توابع وردپرس برای مدیریت نقش‌ها و دسترسی‌ها و احراز هویت چیست و چه انواعی دارد آمده است.

محدودسازی محتوای front-end براساس نقش

محدودسازی دسترسی، فقط به پیشخوان محدود نمی‌شود. در سایت‌های عضویت‌محور، بخش‌هایی از محتوای front-end باید فقط برای اعضا یا کاربران با نقش خاص نمایش داده شود. دو الگوی رایج:

الگوی اول: محدودسازی نمایش بخشی از محتوا

add_filter( 'the_content', 'wphk_restrict_content_by_role' );

function wphk_restrict_content_by_role( $content ) {
    if ( ! is_singular( 'post' ) ) {
        return $content;
    }

    if ( ! current_user_can( 'read' ) ) {
        return '<p class="wphk-restricted">برای مشاهدهٔ این محتوا لطفاً وارد حساب کاربری خود شوید.</p>';
    }

    if ( ! current_user_can( 'edit_posts' ) ) {
        // کاربر عادی: نمایش بخش اول محتوا
        return wp_trim_words( $content, 100, ' … ' );
    }

    return $content;
}

سه نکتهٔ کلیدی: اول، استفاده از current_user_can( 'read' ) که همهٔ کاربران لاگین‌کرده را شناسایی می‌کند. دوم، استفاده از current_user_can( 'edit_posts' ) که کاربران با دسترسی ویرایش (مثل نویسندگان و بالاتر) را از محدودیت معاف می‌کند. سوم، برش متن با wp_trim_words که روش استاندارد وردپرس برای این کار است. الگوهای مشابه برای محدودسازی محتوا در توابع وردپرس برای دریافت اطلاعات نوشته آمده است.

الگوی دوم: محدودسازی دانلود فایل

add_action( 'template_redirect', 'wphk_protect_download_links' );

function wphk_protect_download_links() {
    if ( ! is_singular( 'post' ) ) {
        return;
    }

    if ( ! current_user_can( 'read' ) ) {
        wp_safe_redirect( wp_login_url( get_permalink() ) );
        exit;
    }
}

دو نکتهٔ کلیدی: اول، استفاده از template_redirect که پیش از رندر قالب اجرا می‌شود و اجازه می‌دهد کاربر را قبل از نمایش محتوا به صفحهٔ ورود هدایت کنید. دوم، استفاده از wp_login_url که کاربر را پس از ورود به همان صفحه برمی‌گرداند. مبانی این الگو در امن‌سازی لاگین ادمین در وردپرس و فعال‌سازی 2FA برای کاربران وردپرس آمده است.

محل درست قرارگیری این اسنیپت

مانند همهٔ اسنیپت‌های وردپرس، محل قرارگیری این کد هم تصمیم مهمی است. سه گزینه پیش روی شماست:

گزینهٔ اول: افزونهٔ اختصاصی یا mu-plugins. محدودسازی دسترسی، بخشی از ساختار امنیتی سایت است و باید مستقل از قالب زندگی کند. اگر با ساختار افزونهٔ اختصاصی آشنا نیستید، کدنویسی اختصاصی برای افزونه وردپرس و ساختار فایل‌های یک افزونه استاندارد وردپرس مراجع کاملی هستند.

گزینهٔ دوم: چایلد تم. اگر پروژهٔ شما ساده است و افزونهٔ اختصاصی ندارید، چایلد تم گزینهٔ قابل‌قبولی است؛ ولی توجه داشته باشید که در تعویض قالب، این کد از بین می‌رود و ممکن است کسی متوجه نشود. تفاوت‌ها و کاربردهای چایلد تم در قالب وردپرس چایلد چیست و چه زمانی به آن نیاز داریم آمده است.

گزینهٔ سوم: افزونهٔ مدیریت اسنیپت. اگر می‌خواهید سریع شروع کنید، این گزینه سبک‌ترین راه است. ولی برای اسنیپت‌های مرتبط با امنیت، ترجیح می‌دهم کد را در کنترل کامل داشته باشم. اگر این گزینه را انتخاب کردید، چگونه قطعه کد وردپرس را ایمن اجرا کنیم نکات ایمنی مهمی دارد.

الگوی عملی من در پروژه‌های خودم: تمام کدهای مرتبط با محدودسازی دسترسی را در یک افزونهٔ اختصاصی به نام «wphk-access-control» نگه می‌دارم که هم محدودسازی پیشخوان را در خود دارد، هم محدودسازی محتوا. این ساختار، در پروژه‌های چندساله، پایداری و مستندسازی را تضمین می‌کند. برای دیدن فهرست گسترده‌تری از اسنیپت‌های کاربردی، بهترین قطعه کدهای کاربردی وردپرس برای سایت‌ها مرجع خوبی است.

اشتباهات رایج در محدودسازی دسترسی

در بازبینی سایت‌های مختلف، شش اشتباه تکراری در این حوزه دیده‌ام که هرکدام درس‌آموز است:

اشتباهپیامد واقعیاصلاح
چک کردن نقش به‌جای capabilityکاربران با نقش ترکیبی به‌درستی شناسایی نمی‌شونداستفاده از current_user_can با capability
نبود بررسی wp_doing_ajax در محدودسازی پیشخوانقطع شدن درخواست‌های AJAX کاربرانافزودن شرط AJAX در ابتدای تابع
استفاده از wp_redirect به‌جای wp_safe_redirectریسک ریدایرکت به دامنه‌های خارجیاستفاده از wp_safe_redirect
نبود شرط is_admin در محدودسازی منطقیاثر ناخواسته بر front-endبررسی دقیق محیط اجرا
اعمال محدودیت برای همه به‌جای نقش‌های خاصمدیر سایت هم محدود می‌شودبررسی current_user_can قبل از اعمال محدودیت
نبود پیشوند اختصاصی در نام توابعتعارض با افزونه‌های دیگرپیشوند یکتا مثل wphk_

هرکدام از این اشتباهات را در پروژه‌ای دیده‌ام و همه‌شان در چند دقیقه اصلاح‌شدنی هستند. برای مرور عمومی این نوع خطاها، اشتباهات رایج هنگام استفاده از قطعه کد وردپرس و اشتباهات رایج امنیتی وردپرس مراجع جامعی هستند.

دو پروندهٔ واقعی از پروژه‌ها

برای این‌که این اصول در عمل روشن‌تر شوند، دو پروندهٔ واقعی از تجربهٔ خودم را مرور می‌کنم — بدون جزئیات هویتی، ولی با ساختار دقیق مشکل و راه‌حل.

پروندهٔ اول: کلینیکی که با یک اسنیپت، منشی‌ها را از منوی مدیر نجات داد

همان پروژهٔ ابتدای مقاله. مدیر فنی سایت، همهٔ کاربران را با نقش administrator تعریف کرده بود تا کارها سریع راه بیفتد. نتیجه: منشی‌ها که فقط باید نوبت‌ها را مدیریت می‌کردند، به همه بخش‌های سایت دسترسی داشتند. راه‌حل: تعریف نقش سفارشی wphk_receptionist با capabilityهای محدود، انتقال منشی‌ها به این نقش، و افزودن اسنیپت wp_dashboard_setup برای پنهان کردن ابزارک‌های غیرمرتبط. نتیجه: تجربهٔ کاری منشی‌ها بهبود یافت و در یک ماه، هیچ خطای تصادفی از سمت آن‌ها گزارش نشد. تحلیل تفصیلی این نوع بهینه‌سازی در راهنمای امنیت وردپرس برای مبتدیان آمده است.

پروندهٔ دوم: مجله‌ای که با محدودسازی محتوا، از نشت اطلاعات جلوگیری کرد

در یک مجله آنلاین، تیم تحریریه از نقش editor استفاده می‌کرد و در همان زمان، پیش‌نویس‌های تأییدنشده در فهرست نوشته‌ها برای همه قابل مشاهده بود. راه‌حل: افزودن اسنیپت map_meta_cap برای محدودسازی ویرایش و حذف به نویسنده، و افزودن اسنیپت نمایش شرطی محتوا برای پیش‌نویس‌ها. نتیجه: پیش‌نویس‌ها فقط برای نویسنده و سردبیر قابل مشاهده شد، و اصلاح اشتباهات بین نویسنده‌ها بدون تداخل انجام شد. تجربهٔ مشابه در حوزهٔ محتوا در قطعه کد مخفی کردن منوی مدیریت وردپرس آمده است.

این دو پرونده، نکتهٔ مشترک دارند: محدودسازی دسترسی، وقتی درست انجام شود، هم امنیت را می‌سازد و هم تجربهٔ کاربری را بهبود می‌دهد. تفاوت بین سایتی که همه‌چیز را به همه می‌دهد و سایتی که ساختار دقیق دسترسی‌ها را دارد، در همین تصمیم‌های کوچک شکل می‌گیرد.

مسیر پیشنهادی و نتیجه

قطعه کد محدود کردن دسترسی کاربران وردپرس، یکی از پرتکرارترین و در عین حال مهم‌ترین اسنیپت‌های امنیتی و تجربی است. سه لایهٔ اصلی این کار: لایهٔ نقش و capability (پایه)، لایهٔ رابط کاربری (پنهان‌سازی منوها)، و لایهٔ منطقی (کنترل در لحظهٔ اجرا). چهار حوزهٔ اصلی که در این مقاله پوشش دادیم: محدودسازی ورود به پیشخوان، مخفی‌سازی منوهای اضافی، محدودسازی ویرایش و حذف محتوا، و محدودسازی محتوای front-end. سه ملاحظهٔ کلیدی (چک capability به‌جای نقش، بررسی wp_doing_ajax در محدودسازی پیشخوان، پرهیز از wp_redirect به‌جای wp_safe_redirect) در همهٔ اسنیپت‌های این حوزه باید رعایت شوند. و محل درست این اسنیپت، افزونهٔ اختصاصی یا mu-plugins است، نه فایل قالب والد.

گام بعدی عملی که پیشنهاد می‌کنم: در همین امروز، فهرست کاربران سایت خود را باز کنید و ببینید هر کاربر چه دسترسی‌هایی دارد. اگر بیش از نیمی از کاربران دسترسی مدیر دارند، احتمالاً می‌توانید دسترسی‌ها را محدودتر کنید. یکی از اسنیپت‌های این مقاله را در محیط استجینگ اعمال کنید و تفاوت تجربهٔ کاربری و پایداری را با دقت ببینید. اگر تجربه‌ای با محدودسازی دسترسی داشته‌اید — به‌ویژه اگر در پروژه‌ای روش تمیزی برای ترکیب نقش سفارشی و محدودسازی منطقی پیدا کرده‌اید — برای من جالب است بدانید چطور حلش کردید. تجربهٔ خودتان را در دیدگاه‌ها بنویسید؛ به‌ویژه اگر اسنیپت مکمل دیگری برای محدودسازی می‌شناسید که برای خواننده‌های بعدی مفید است. 🔐