شبی که سه هزار لینک شکست و یک تابع نجات داد

پاییز ۱۳۹۹، یک سایت خبری با ده سال آرشیو را برای مهاجرت به ساختار URL جدید تحویل گرفتم. مدیر سایت می‌خواست پیوندهای یکتا از /?p=123 به /news/2020/05/title/ تغییر کند. من بدون ریدایرکت، ساختار را عوض کردم. صبح روز بعد، گزارش Search Console آمد: سه هزار و دویست خطای ۴۰۴ در یک شب. رتبه سایت در یک هفته، بیست درصد افت کرد. آن روز فهمیدم ریدایرکت، یک «تنظیم» نیست؛ یک بیمه‌نامه است که اگر نخریده باشید، هزینه‌اش را با رتبه و ترافیک می‌دهید. این مقاله، تجربه‌ام از کار با توابع ریدایرکت وردپرس در پروژه‌های واقعی است — نه فهرست توابع، بلکه پروتکل عملیاتی.

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

ریدایرکت در وردپرس: کجای معماری است؟

ریدایرکت، هدایت خودکار کاربر و ربات از یک URL به URL دیگر است. در معماری وردپرس، سه سطح برای ریدایرکت وجود دارد: سطح سرور (فایل .htaccess یا کانفیگ Nginx)، سطح وردپرس (توابع wp_redirect و wp_safe_redirect)، و سطح افزونه (افزونه‌های اختصاصی ریدایرکت). تشخیص این سه سطح، اولین گام تصمیم درست است. برای ریدایرکت‌های سراسری مثل HTTP به HTTPS، سطح سرور بهترین گزینه است چون قبل از اجرای PHP اتفاق می‌افتد. برای ریدایرکت‌های محتوایی و پویا، سطح وردپرس انتخاب درست است. مباحث پایه در وردپرس چیست و ساختار هسته وردپرس آمده است.

ریدایرکت در سطح سرور، مثل تغییر مسیر یک خیابان است؛ ریدایرکت در سطح وردپرس، مثل گذاشتن یک تابلوی راهنما در میدان اصلی. اولی سریع‌تر است، دومی انعطاف‌پذیرتر.

wp_redirect: تابع پایه ریدایرکت در وردپرس

تابع اصلی ریدایرکت در وردپرس، wp_redirect است:

wp_redirect( $location, $status = 302, $x_redirect_by = 'WordPress' );
exit;

سه نکته حیاتی: یک — exit بعد از ریدایرکت: فراموش کردن exit یکی از شایع‌ترین باگ‌های امنیتی است. بدون آن، ادامه اجرای کد رخ می‌دهد و کاربر ممکن است محتوای محرمانه‌ای را که بعد از ریدایرکت تولید شده ببیند. دو — کد وضعیت: پیش‌فرض ۳۰۲ است که برای ریدایرکت موقت مناسب است؛ برای انتقال دائمی، ۳۰۱ بدهید. سه — هدرها: این تابع باید قبل از هر خروجی HTML فراخوانی شود، وگرنه با خطای headers already sent مواجه می‌شوید. الگوی صحیح:

function my_plugin_redirect_old_post() {
    if ( ! is_singular( 'post' ) ) {
        return;
    }
    $post_id = get_the_ID();
    $redirect = get_post_meta( $post_id, '_redirect_to', true );
    if ( $redirect ) {
        wp_redirect( esc_url_raw( $redirect ), 301 );
        exit;
    }
}
add_action( 'template_redirect', 'my_plugin_redirect_old_post' );

نکته مهم در انتخاب hook: template_redirect بعد از تشخیص نوع صفحه اجرا می‌شود ولی قبل از خروجی HTML. اگر در init استفاده کنید، توابع شرطی مثل is_singular کار نمی‌کنند. راهنمای کامل hookها در هوک‌های وردپرس و نحوه استفاده از add_action.

wp_safe_redirect: نسخه امن ریدایرکت

از وردپرس ۵.۱، تابع wp_safe_redirect اضافه شد که همان کار wp_redirect را می‌کند ولی URL را با allowlist مقایسه می‌کند:

wp_safe_redirect( $location, $status = 302, $x_redirect_by = 'WordPress' );
exit;

تفاوت کلیدی: wp_safe_redirect فقط به دامنه‌های مجاز (host فعلی سایت، دامنه‌های ثبت‌شده در allowed_redirect_hosts) ریدایرکت می‌کند. اگر مقصد در allowlist نباشد، به fallback یعنی wp-admin ریدایرکت می‌شود. این ویژگی، حمله Open Redirect را دفع می‌کند — حملاتی که کاربر را با URL معتبر سایت شما به سایت مخرب می‌فرستند. توصیه من در پروژه‌های واقعی: همیشه از wp_safe_redirect استفاده کنید، مگر با دلیل روشن. فقط در مواردی که مقصد یک دامنه بیرونی مشخص و مورد اعتماد است، از wp_redirect استفاده کنید. مثال:

// نامناسب - خطر Open Redirect
$redirect_to = $_GET['redirect_to'];
wp_redirect( $redirect_to );
exit;

// مناسب
$redirect_to = isset( $_GET['redirect_to'] ) ? esc_url_raw( $_GET['redirect_to'] ) : home_url( '/' );
wp_safe_redirect( $redirect_to );
exit;

مباحث امنیتی ریدایرکت در PHP امن در وردپرس و حمله CSRF آمده است. یک تجربه میدانی: در پروژه‌ای، فرم ورود سفارشی داشتیم که پس از لاگین، کاربر را به $_GET['redirect_to'] می‌فرستاد. یک محقق امنیتی، حمله Open Redirect را کشف کرد که می‌توانست کاربران را پس از ورود به سایت فیشینگ هدایت کند. تغییر به wp_safe_redirect در دو خط کد، این حفره را بست.

کدهای وضعیت ریدایرکت: ۳۰۱، ۳۰۲، ۳۰۷ و ۳۰۸

انتخاب کد وضعیت، تصمیم سئویی مهمی است که در سئو تکنیکال چیست به آن پرداخته‌ام. فهرست کدهایی که در وردپرس به‌کار می‌آید:

کدنامکاربردانتقال اعتبار
301Moved Permanentlyتغییر دائمی URL، مهاجرت دامنه، تغییر ساختار پیوندبله
302Found (Temporary)هدایت موقت، کمپین، نگهداریخیر
307Temporary Redirectمثل ۳۰۲ با حفظ متد HTTPخیر
308Permanent Redirectمثل ۳۰۱ با حفظ متد HTTPبله
410Goneمحتوای حذف‌شده دائمی، بدون جانشینخیر

نکته عملی: در ۹۰٪ پروژه‌ها، از ۳۰۱ استفاده می‌کنید. برای فرم‌های POST که بعد از پرداخت به صفحه تشکر می‌روند، اگر می‌خواهید متد POST حفظ شود، ۳۰۷ یا ۳۰۸ انتخاب درست است — ولی این سناریو در وردپرس کمتر پیش می‌آید. اشتباه رایج: استفاده از ۳۰۲ برای تغییر ساختار URL که باعث می‌شود گوگل اعتبار را منتقل نکند و افت رتبه رخ دهد. راهنمای کامل تفاوت‌ها و تأثیرشان بر رتبه در ساختار URL و سئو و سئو تکنیکال از خزش تا ایندکس.

پروتکل تغییر ساختار URL بدون افت رتبه

شش گام عملی که در پروژه‌های واقعی اجرا می‌کنم:

  1. نقشه URLهای قدیم به جدید: پیش از تغییر، فهرست کامل URLهای قدیم را از sitemap یا Search Console استخراج کنید و برای هرکدام، مقصد جدید را تعریف کنید.
  2. پیاده‌سازی ریدایرکت ۳۰۱: با استفاده از افزونه (برای مبتدی) یا کد اختصاصی (برای حرفه‌ای).
  3. تست روی محیط آزمایشی: قبل از اعمال روی سایت زنده، همه ریدایرکت‌ها را تست کنید. الگوی تست در بهترین روش تست وردپرس.
  4. اعمال روی Production در ساعت کم‌ترافیک: با بکاپ کامل و آمادگی بازگشت.
  5. ارسال sitemap جدید: به Search Console اعلام کنید که ساختار تغییر کرده است.
  6. پایش هفته اول: روزانه گزارش Coverage را چک کنید. اگر ۴۰۴ یا خطای خزش زیاد شد، سریعاً اصلاح کنید.

یک درس از همان پروژه پاییز ۱۳۹۹: قبل از تغییر ساختار URL، حتماً نقشه کامل را آماده کنید. من آن روز بدون نقشه شروع کردم و سه هزار لینک شکسته را بعداً دستی رفع کردم. این پنج روز کار اضافه، با یک روز آماده‌سازی قابل پیشگیری بود. پروتکل کامل تغییر در تغییر امن قالب وردپرس و رفع خطای لینک‌های وردپرس آمده است.

حلقه ریدایرکت: چرا رخ می‌دهد و چگونه رفع می‌شود؟

حلقه ریدایرکت (ERR_TOO_MANY_REDIRECTS)، وقتی رخ می‌دهد که زنجیره‌ای از ریدایرکت‌ها به هیچ نتیجه‌ای نرسد. چهار علت شایع:

  • علت اول، تعارض ریدایرکت‌های متناقض: URL A به B و B به A ریدایرکت می‌شود.
  • علت دوم، تناقض در HTTP/HTTPS: یک ریدایرکت HTTPS به HTTP و در جای دیگر HTTP به HTTPS.
  • علت سوم، تنظیم اشتباه WordPress Address و Site Address: در «تنظیمات ← همگانی» دو URL متفاوت تنظیم شده.
  • علت چهارم، تعارض بین ریدایرکت افزونه و ریدایرکت سرور: یکی به A می‌فرستد، دیگری به B.

روش عیب‌یابی: در Chrome، سربرگ Network را باز کنید، گزینه Preserve log را فعال کنید و URL را باز کنید. زنجیره ریدایرکت‌ها را خواهید دید. سپس با حذف تدریجی قواعد، مقصر را پیدا کنید. راهنمای گام‌به‌گام در رفع حلقه ریدایرکت وردپرس. یک تجربه میدانی: در پروژه‌ای، حلقه ریدایرکت از تعارض افزونه SSL و ریدایرکت HTTPS در .htaccess ایجاد شده بود. یکی به https://site.com و دیگری به http://www.site.com می‌فرستاد. با حذف قاعده دوم از .htaccess، مشکل حل شد.

ریدایرکت در فرم‌ها و پرداخت

در فرم‌ها و جریان پرداخت، ریدایرکت نقش کلیدی دارد. الگوهای رایج:

// پس از ارسال موفق فرم
$redirect_url = add_query_arg( 'status', 'success', get_permalink( $thank_you_page_id ) );
wp_safe_redirect( $redirect_url );
exit;

// پس از خطای اعتبارسنجی، بازگشت به فرم با پارامتر خطا
$redirect_url = add_query_arg( 'error', 'invalid_email', wp_get_referer() );
wp_safe_redirect( $redirect_url );
exit;

نکته امنیتی حیاتی: قبل از ریدایرکت در فرم‌ها، حتماً nonce و بررسی دسترسی انجام دهید. راهنمای کامل در نانس وردپرس و پیاده‌سازی نانس در فرم‌ها. در فروشگاه‌های ووکامرس، ریدایرکت‌ها بخشی از جریان پرداخت هستند — از صفحه محصول به سبد، از سبد به درگاه، از درگاه به صفحه تشکر. راهنمای تکمیلی در تنظیم روش‌های پرداخت ووکامرس و سفارشی‌سازی سبد و تسویه‌حساب ووکامرس. یک نکته میدانی: در پروژه‌ای، مشتری از ریدایرکت ناموفق پس از پرداخت شکایت داشت. علت: افزونه درگاه پرداخت، کاربر را به home_url() ریدایرکت می‌کرد ولی صفحه تشکر با query parameter خاصی نمایش داده می‌شد. راه‌حل: استفاده از add_query_arg برای ساخت URL کامل.

ریدایرکت در مهاجرت دامنه

مهاجرت دامنه، بزرگ‌ترین آزمون ریدایرکت است. سه لایه ریدایرکت باید هم‌راستا باشند:

  1. لایه اول، ریدایرکت دامنه قدیم به جدید: در سطح DNS یا .htaccess. همه درخواست‌های دامنه قدیم باید به دامنه جدید ریدایرکت شوند، با حفظ مسیر.
  2. لایه دوم، ریدایرکت www به non-www: اگر سایت جدید با site.com شروع می‌شود، باید www.site.com هم به آن ریدایرکت شود.
  3. لایه سوم، ریدایرکت HTTP به HTTPS: اگر SSL جدید فعال شده، همه درخواست‌های HTTP باید به HTTPS ریدایرکت شوند.

الگوی .htaccess کامل برای مهاجرت دامنه:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^oldsite\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.oldsite\.com$
RewriteRule ^(.*)$ https://newsite.com/$1 [R=301,L]

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

راهنمای کامل در راهنمای انتخاب هاست و امن‌سازی wp-config. یک تجربه میدانی: در پروژه‌ای، پس از مهاجرت، سایت به http://www.newsite.com ریدایرکت می‌شد نه https://newsite.com. علت: ترتیب قواعد .htaccess اشتباه بود. با قرار دادن قاعده HTTPS بالاتر، مشکل حل شد. ترتیب قواعد .htaccess، در پروژه‌های واقعی یکی از شایع‌ترین منابع باگ است.

ریدایرکت با افزونه در برابر کد اختصاصی

انتخاب بین افزونه و کد، تصمیم معماری است. مزایای افزونه: رابط گرافیکی، لاگ خودکار ۴۰۴، امکان import/export قواعد، مناسب تیم‌های غیرفنی. مزایای کد اختصاصی: کنترل کامل، بدون سربار، امکان منطق پیچیده، مناسب تیم فنی. راهنمای مقایسه افزونه‌های معتبر در افزونه‌های ریدایرکت وردپرس و بررسی افزونه Redirection. توصیه من در پروژه‌های متوسط: افزونه برای مدیریت + کد اختصاصی برای منطق‌های خاص. در پروژه‌های بزرگ: کد اختصاصی برای همه، با لاگ اختصاصی. اصول کدنویسی این لایه در اصول کدنویسی تمیز و استانداردهای کدنویسی وردپرس آمده است.

ریدایرکت و سئو: نکات ظریف

ریدایرکت فقط یک انتقال فنی نیست؛ یک عملیات سئویی است. پنج نکته که در پروژه‌های واقعی دیده‌ام:

  1. زنجیره ریدایرکت نسازید: A به B، B به C. گوگل تمام زنجیره را طی می‌کند ولی اعتبار را کاهش می‌دهد. همیشه A را مستقیم به C بفرستید.
  2. محتوای صفحه قدیم و جدید، یکسان باشد: ریدایرکت به صفحه‌ای نامرتبط، تجربه بد و سیگنال منفی است. راهنمای محتوا در سئو چیست.
  3. روی ریدایرکت‌های بلندمدت، ۳۰۱ بگذارید: ۳۰۲ برای انتقال دائمی، اعتبار را منتقل نمی‌کند.
  4. لینک‌های داخلی را به‌روز کنید: به‌جای تکیه همیشگی بر ریدایرکت، لینک‌های داخلی را مستقیم به URL جدید تغییر دهید. راهنمای لینک داخلی در سئوی درون‌صفحه.
  5. sitemap را به‌روز کنید: sitemap باید URLهای جدید را نشان دهد، نه قدیم. راهنما در سئو تکنیکال چیست.

یک نکته عملی که در پروژه‌های بزرگ ارزش زیادی دارد: پیش از مهاجرت، تمام لینک‌های داخلی به صفحات مهم را در یک فایل استخراج کنید. بعد از مهاجرت، آن‌ها را مستقیم به URL جدید تغییر دهید. این کار، در طول سه ماه، ۲۰ تا ۳۰ درصد بار ریدایرکت را کم می‌کند و سرعت سایت را بهبود می‌دهد. مسیر کامل تحلیل لینک داخلی در توابع کوئری سفارشی و بهینه‌سازی کوئری‌ها.

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

در وردپرس مالتی‌سایت و نصب‌های زیرپوشه، ریدایرکت پیچیدگی‌های خاص خودش را دارد. در مالتی‌سایت، ریدایرکت‌های سطح شبکه با network_site_url و network_home_url ساخته می‌شوند؛ در سطح هر سایت، با home_url و site_url. راهنمای تفصیلی در وردپرس مالتی‌سایت و توابع لینک و URL. در نصب زیرپوشه (مثلاً site.com/blog/)، ریدایرکت‌ها باید مسیر را شامل شوند. اشتباه رایج: استفاده از wp_safe_redirect( '/' ) که به ریشه دامنه می‌فرستد نه ریشه زیرپوشه. الگوی صحیح: wp_safe_redirect( home_url( '/' ) ) که مسیر کامل را می‌سازد.

تست و پایش ریدایرکت‌ها

پس از پیاده‌سازی، سه لایه تست الزامی است: لایه اول، تست دستی: چند URL قدیم را در مرورگر باز کنید و مطمئن شوید که به مقصد درست می‌روند. لایه دوم، تست خودکار: با curl -I می‌توانید کد وضعیت و مقصد ریدایرکت را ببینید:

curl -I https://site.com/old-url/
# انتظار: HTTP/1.1 301 Moved Permanently
# Location: https://site.com/new-url/

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

امنیت در ریدایرکت‌ها

ریدایرکت، یک نقطه ورود بالقوه امنیتی است. سه حمله رایج: یک — Open Redirect: مهاجم با دست‌کاری پارامتر URL، کاربر را به سایت مخرب می‌فرستد. دفاع: wp_safe_redirect. دو — Header Injection: اگر مقصد ریدایرکت از ورودی کاربر بیاید و پاک‌سازی نشود، مهاجم می‌تواند هدرهای اضافی تزریق کند. دفاع: esc_url_raw + حذف کاراکترهای \r\n. سه — CSRF در لینک ریدایرکت: اگر ریدایرکت به‌عنوان عمل حساس قابل انجام باشد، باید nonce داشته باشد. راهنمای کامل در PHP امن در وردپرس، پاک‌سازی داده‌ها، اعتبارسنجی داده‌ها، و امنیت وردپرس برای مبتدیان. یک قاعده در پروژه‌های خودم: هر پارامتر redirect_to یا return_url که از URL خوانده شود، حتماً با allowlist مقایسه می‌شود، حتی اگر در سایت داخلی باشد.

هدرهای HTTP مرتبط با ریدایرکت

سه هدر مرتبط که در پروژه‌های حرفه‌ای ارزش بررسی دارند: یک — Location: هدر استاندارد ریدایرکت. دو — Refresh: روش قدیمی ریدایرکت با HTML meta. وردپرس از آن استفاده نمی‌کند ولی گاهی در محتوا دیده می‌شود. توصیه: جایگزینش کنید با ریدایرکت واقعی. سه — Strict-Transport-Security: با فعال‌سازی HSTS، مرورگر تمام درخواست‌های HTTP به همان دامنه را به HTTPS ریدایرکت می‌کند بدون تماس با سرور. راهنمای کامل هدرهای امنیتی در هدرهای امنیتی HTTP.

جمع‌بندی

توابع ریدایرکت وردپرس، در چهار گروه خلاصه می‌شوند: توابع پایه (wp_redirect، wp_safe_redirect)، توابع URL کمکی (add_query_arg، home_url، get_permalink)، ریدایرکت در سطح سرور (.htaccess، Nginx)، و ریدایرکت در سطح افزونه. سه اصل را در پایان تاکید می‌کنم: اول، همیشه از wp_safe_redirect استفاده کنید، مگر با دلیل روشن. دوم، در تغییر ساختار URL، نقشه کامل را پیش از اعمال آماده کنید. سوم، ریدایرکت‌ها را دوره‌ای پایش کنید، نه فقط در روز پیاده‌سازی.

اگر امروز یک کار در این مسیر انجام می‌دهید: در Search Console، گزارش ۴۰۴ را باز کنید و ببینید آیا لینک‌های شکسته‌ای وجود دارد که باید ریدایرکت شوند. همان یک عدد، نقشه بهبود شماست. اگر تجربه‌ای از یک حادثه ریدایرکت یا مهاجرت موفق دارید، در دیدگاه‌ها بنویسید — همان گزارش‌های واقعی، این راهنما را برای توسعه‌دهنده بعدی دقیق‌تر می‌کند. 🔗