افزایش سرعت سایت وردپرس؛ ۲۰ راهکار عملی از سرور تا فونت فارسی

فهرست مطالب
- اول اندازه بگیرید: معیارهای سرعت وردپرس
- Core Web Vitals و TTFB به زبان ساده
- PageSpeed Insights را درست بخوانید
- TTFB را از نزدیک مخاطب با curl بسنجید
- داخل وردپرس را با Query Monitor و سلامت سایت ببینید
- یک خط مبنا ثبت کنید
- گلوگاه کجاست؛ هاست یا خود سایت؟
- لایهٔ سرور: راهکارهای ۱ تا ۵
- ۱. نسخهٔ PHP را بهروز کنید
- ۲. OPcache را فعال و درست تنظیم کنید
- ۳. کش آبجکت پایدار با Redis
- ۴. وبسرور، HTTP/2، HTTP/3 و فشردهسازی
- ۵. منابع کافی و محدودیتهای هاست
- کش صفحه، کش مرورگر و CDN: راهکارهای ۶ تا ۸
- ۶. کش صفحه متناسب با وبسرور
- ۷. کش مرورگر برای فایلهای ثابت
- ۸. CDN فقط وقتی مخاطب دور است
- تصاویر و LCP: راهکارهای ۹ تا ۱۱
- ۹. WebP و AVIF به جای JPEG و PNG
- ۱۰. ابعاد درست، srcset و جلوگیری از CLS
- ۱۱. lazy load درست و تصویر LCP
- CSS، جاوااسکریپت و فونت فارسی: راهکارهای ۱۲ تا ۱۵
- ۱۲. CSS و JS بلااستفاده را حذف کنید
- ۱۳. جاوااسکریپت را با تأخیر اجرا کنید
- ۱۴. فونت فارسی را روی هاست خودتان بگذارید
- ۱۵. پیشبارگذاری فونت اصلی و تصویر LCP
- افزونهها، قالب و درخواستهای خارجی: راهکارهای ۱۶ و ۱۷
- ۱۶. افزونهها و قالب را ممیزی کنید
- ۱۷. اسکریپتها و درخواستهای خارجی را مهار کنید
- دیتابیس و کارهای پسزمینه: راهکارهای ۱۸ تا ۲۰
- ۱۸. ویرایشها و ترنزینتها را پاک کنید
- ۱۹. گزینههای autoload را سبک کنید
- ۲۰. Heartbeat و WP-Cron را تنظیم کنید
- عیبیابی: نشانه، علت، راهحل
- کی سراغ هاست یا سرور قویتر بروید
- پرسشهای متداول
- سایت وردپرس باید در چند ثانیه بارگذاری شود؟
- آیا امتیاز ۱۰۰ در PageSpeed Insights لازم است؟
- کدام افزونهٔ کش برای وردپرس مناسب است؟
- آیا تعداد زیاد افزونه سایت را کند میکند؟
- چرا پیشخوان وردپرس کند است ولی سایت سریع باز میشود؟
- برای سایتی با مخاطب ایرانی CDN لازم است؟
- جمعبندی
برای افزایش سرعت سایت وردپرس، اول باید بفهمید زمان کجا هدر میرود: در سرور (TTFB بالا)، در خود صفحه (تصویر، فونت و جاوااسکریپت) یا در دیتابیس. این راهنما اول روش سنجش را نشان میدهد و بعد ۲۰ راهکار عملی را لایهبهلایه، با دستور و مسیر دقیق منو، توضیح میدهد.
افزونهٔ کش، سروری را که به سقف منابع رسیده سریع نمیکند و ارتقای هاست هم تصویر سنگین را سبک نمیکند؛ پس ترتیب مهم است: سنجش، یافتن گلوگاه، اصلاح و سنجش دوباره. دستورهای سرور برای Ubuntu 24.04 با PHP 8.3 است و تنظیمات وردپرس روی هاست اشتراکی cPanel و DirectAdmin هم اجراشدنی است.
بهطور خلاصه: ۱) LCP، INP، CLS و TTFB را با PageSpeed Insights و
curlثبت کنید. ۲) اگر TTFB بدون کش بالای حدود ۰٫۸ ثانیه است (و بالای ۱٫۸ ثانیه قطعاً)، سراغ PHP 8.3 به بالا، OPcache، کش آبجکت و افزونههای سنگین بروید. ۳) کش صفحه را متناسب با وبسرور فعال کنید. ۴) تصاویر را WebP یا AVIF کنید و تصویر بالای صفحه را lazy نکنید. ۵) فونت فارسی را روی هاست خودتان باfont-display: swapبگذارید. ۶) اسکریپتهای خارجی را حذف یا با تأخیر اجرا کنید. ۷) autoload، Heartbeat و WP-Cron را مرتب کنید.
اول اندازه بگیرید: معیارهای سرعت وردپرس
گوگل تجربهٔ کاربر را با سه معیار Core Web Vitals و بر اساس صدک ۷۵ام بازدیدهای واقعی میسنجد؛ موبایل و دسکتاپ جدا.
Core Web Vitals و TTFB به زبان ساده
| معیار | چه چیزی را میسنجد | خوب | ضعیف |
|---|---|---|---|
| LCP | نمایش بزرگترین تصویر یا متن صفحه | تا ۲٫۵ ثانیه | بیش از ۴ ثانیه |
| INP | تأخیر پاسخ به کلیک، لمس و تایپ | تا ۲۰۰ میلیثانیه | بیش از ۵۰۰ میلیثانیه |
| CLS | جابهجایی ناگهانی اجزای صفحه | تا ۰٫۱ | بیش از ۰٫۲۵ |
| TTFB | رسیدن اولین بایت پاسخ سرور | تا ۰٫۸ ثانیه | بیش از ۱٫۸ ثانیه |
INP (Interaction to Next Paint) از مارس ۲۰۲۴ جای FID را گرفته است. TTFB (Time to First Byte) جزو Core Web Vitals نیست، اما مستقیم به LCP اضافه میشود و روشنترین شاخص وضعیت سرور و PHP است.
PageSpeed Insights را درست بخوانید
در pagespeed.web.dev آدرس صفحه را تحلیل کنید و اول نتیجهٔ Mobile را ببینید. بخش بالا دادهٔ کاربران واقعی کروم (CrUX) در ۲۸ روز اخیر است و Core Web Vitals واقعی سایت همین است. بخش پایین آزمون آزمایشگاهی Lighthouse است: امتیاز ۹۰ تا ۱۰۰ سبز، ۵۰ تا ۸۹ نارنجی و زیر ۵۰ قرمز. در بخشهای تشخیص ببینید عنصر LCP کدام است و چه فایلهایی رندر را مسدود کردهاند.
برای سایتهای ایرانی: آزمون آزمایشگاهی از دیتاسنترهای گوگل در آمریکای شمالی، اروپا یا آسیا اجرا میشود، پس TTFB سرور داخل ایران مسیر بینالمللی را هم دارد. اگر ارتباط بینالملل سرور مختل باشد، PageSpeed شاید اصلاً صفحه را باز نکند؛ این لزوماً به معنای کندی برای کاربر داخلی نیست. سایت کمبازدید هم معمولاً دادهٔ کاربران واقعی ندارد.
TTFB را از نزدیک مخاطب با curl بسنجید
اگر مخاطبتان ایرانی است، این دستور را از رایانه یا سروری در ایران اجرا کنید (لینوکس، macOS یا WSL):
curl -o /dev/null -s -w 'dns: %{time_namelookup}s\nconnect: %{time_connect}s\ntls: %{time_appconnect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n' https://example.com/
dns: 0.004s
connect: 0.031s
tls: 0.072s
ttfb: 0.214s
total: 0.236s
یک بار آدرس عادی و یک بار با پارامتری تصادفی مثل ?nocache=8213 که کش را دور میزند بسنجید و هر بار عدد را عوض کنید. اختلاف ttfb و tls، منهای یک رفتوبرگشت شبکه (تقریباً connect منهای dns)، زمان ساختن صفحه در سرور است. اگر نسخهٔ بدون کش از حدود ۰٫۸ ثانیه بیشتر است، کش صفحه فقط مشکل را پنهان میکند و کاربران واردشده و سبد خرید همچنان کند میمانند.
داخل وردپرس را با Query Monitor و سلامت سایت ببینید
افزونهٔ رایگان Query Monitor در نوار مدیریت زمان تولید صفحه، حافظه و زمان و تعداد کوئریها را نشان میدهد. پنلهای Queries by Component (سهم هر افزونه از دیتابیس) و HTTP API Calls (درخواستهای بیرونی و زمانشان) بیشترین کمک را میکنند. پس از عیبیابی غیرفعالش کنید.
مسیر ابزارها ← سلامت سایت (Tools → Site Health) هم نبود کش صفحه یا زمان پاسخ بالای ۶۰۰ میلیثانیه، نبود کش آبجکت پایدار و autoload بیش از ۸۰۰ کیلوبایت را گزارش میکند.
یک خط مبنا ثبت کنید
برای صفحهٔ اصلی، یک نوشتهٔ پربازدید و یک صفحهٔ محصول یا دسته، LCP و INP و CLS موبایل، TTFB با کش و بدون کش و زمان تولید صفحه را یادداشت کنید. پیش از شروع بکاپ کامل بگیرید، ترجیحاً روی نسخهٔ آزمایشی (Staging) کار کنید و هر بار فقط یک تغییر بدهید و دوباره بسنجید.
گلوگاه کجاست؛ هاست یا خود سایت؟
| نشانه | گلوگاه محتمل | راهکارها |
|---|---|---|
| TTFB بدون کش بالا، زمان کوئری کم | PHP قدیمی، پردازندهٔ محدود، افزونهٔ سنگین | ۱، ۲، ۵ و ۱۶ |
| زمان کوئری بالا یا کوئری تکراری | دیتابیس و افزونهٔ ناکارآمد | ۳، ۱۸ و ۱۹ |
| TTFB خوب، LCP ضعیف | تصویر، فونت، CSS و JS | ۹ تا ۱۵ |
| INP ضعیف | جاوااسکریپت سنگین و اسکریپت خارجی | ۱۲، ۱۳ و ۱۷ |
| خطای 508 یا 503 در ساعات شلوغ | سقف منابع هاست | ۵، ۶ و ۲۰ |
| پیشخوان کند، سایت سریع | درخواست خارجی، Heartbeat، autoload | ۱۷، ۱۹ و ۲۰ |
منصفانه بگوییم: اگر TTFB با کش زیر ۰٫۸ ثانیه است و فقط LCP یا INP ضعیف است، هاست بزرگتر کمکی نمیکند و مشکل در خود صفحه است. اما اگر روی نسخهٔ آزمایشی با قالب پیشفرض و افزونههای حداقلی هم TTFB بدون کش بالاست، یا هاست مدام به سقف منابع میرسد، گلوگاه واقعاً هاست است.
لایهٔ سرور: راهکارهای ۱ تا ۵
۱. نسخهٔ PHP را بهروز کنید
وردپرس PHP 8.3 یا جدیدتر را توصیه میکند و نسخههای 6.9 به بعد با PHP 8.5 هم سازگارند. وضعیت شاخهها در آبان ۱۴۰۵:
| نسخه | وضعیت | پایان وصلهٔ امنیتی |
|---|---|---|
| PHP 8.2 | فقط امنیتی | ۳۱ دسامبر ۲۰۲۶ |
| PHP 8.3 | فقط امنیتی | ۳۱ دسامبر ۲۰۲۷ |
| PHP 8.4 | پشتیبانی فعال تا پایان ۲۰۲۶ | ۳۱ دسامبر ۲۰۲۸ |
| PHP 8.5 | پشتیبانی فعال | ۳۱ دسامبر ۲۰۲۹ |
در cPanel، از بخش Software ابزار MultiPHP Manager را باز کنید، تیک دامنه را بزنید، نسخه را از منوی PHP Version انتخاب و Apply را بزنید. در هاستهای CloudLinux ابزار Select PHP Version همین کار را میکند. نسخهای را که سایت واقعاً با آن اجرا میشود در ابزارها ← سلامت سایت ← اطلاعات ← سرور ببینید؛ php -v روی سرور فقط نسخهٔ خط فرمان را نشان میدهد. جزئیات بیشتر در مقالهٔ تأثیر آپدیت PHP بر سایتهای وردپرس آمده است.
هشدار: بعضی افزونهها و قالبهای تجاری، از جمله برخی محصولات فارسی، با ionCube رمزگذاری شدهاند؛ مثلاً فایلی که برای PHP 7 یا حتی PHP 8.1 رمزگذاری شده، روی PHP 8.3 اجرا نمیشود و فروشنده باید نسخهٔ سازگار بدهد. پیش از ارتقا از فروشنده بپرسید.
۲. OPcache را فعال و درست تنظیم کنید
OPcache کد کامپایلشدهٔ PHP را در حافظه نگه میدارد تا هر درخواست از صفر شروع نشود. حافظهٔ پیشفرض آن ۱۲۸ مگابایت است و سایتی با ووکامرس، صفحهساز و دهها افزونه ممکن است حافظه یا سقف تعداد فایلهای آن را پر کند. روی هاست اشتراکی تنظیمش با میزبان است؛ روی Ubuntu همراه php-fpm نصب و فعال میشود. بررسی:
sudo php-fpm8.3 -i | grep -E '^opcache\.(enable|memory_consumption|max_accelerated_files) '
opcache.enable => On => On
opcache.max_accelerated_files => 10000 => 10000
opcache.memory_consumption => 128 => 128
برای سایتهای بزرگتر، یک فایل تنظیم جداگانه بسازید و PHP-FPM را دوباره راهاندازی کنید:
sudo nano /etc/php/8.3/fpm/conf.d/99-opcache-tuning.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
sudo systemctl restart php8.3-fpm
با revalidate_freq=60، ویرایش فایل با FTP تا یک دقیقه بعد اثر میکند؛ بهروزرسانی از پیشخوان وردپرس کش فایلهای عوضشده را خودش باطل میکند. در Ubuntu 26.04 که PHP 8.5 دارد، در همهٔ دستورها و مسیرهای این مقاله 8.5 را به جای 8.3 بگذارید؛ از PHP 8.5، OPcache جزء همیشگی خود PHP است و بستهٔ جدا ندارد.
۳. کش آبجکت پایدار با Redis
کش آبجکت (Object Cache) وردپرس با پایان هر درخواست پاک میشود و Redis آن را پایدار میکند. سود اصلی برای صفحههای کشنشدنی است: ووکامرس، سایت عضویت و پیشخوان شلوغ؛ برای وبلاگ دارای کش صفحه تفاوت کم است. روی هاست اشتراکی فقط اگر میزبان ارائه کند قابل استفاده است. روی سرور مجازی Ubuntu 24.04 یا 26.04:
sudo apt update
sudo apt install redis-server php-redis
redis-cli ping
پاسخ باید PONG باشد. در /etc/redis/redis.conf سقف حافظه بگذارید تا Redis همهٔ RAM را نگیرد، سپس سرویسها را دوباره راهاندازی کنید:
maxmemory 256mb
maxmemory-policy allkeys-lru
sudo systemctl restart redis-server php8.3-fpm
این خطوط را در wp-config.php و بالاتر از خط require_once ABSPATH . 'wp-settings.php'; بگذارید. پیشوند هر سایت روی یک سرور باید متفاوت باشد:
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PREFIX', 'example-com' );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
افزونهٔ Redis Object Cache را نصب و از تنظیمات ← Redis کش را فعال کنید؛ یا با WP-CLI، ابزار خط فرمان وردپرس. اگر WP-CLI ندارید، یکبار به روش رسمی نصبش کنید:
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
دستورهای wp را با root اجرا نکنید (WP-CLI خطا میدهد)؛ آنها را از پوشهٔ وردپرس و با کاربر صاحب فایلهای سایت اجرا کنید که در این مقاله www-data است:
cd /var/www/example.com
sudo -u www-data wp plugin install redis-cache --activate
sudo -u www-data wp redis enable
sudo -u www-data wp redis status
روی هاست cPanel، اگر میزبان WP-CLI را فعال کرده باشد، دستورها را بدون sudo -u www-data در Terminal و داخل public_html اجرا کنید. خروجی wp redis status باید Status: Connected باشد. پورت 6379 را در فایروال باز نکنید و اگر از زبانهٔ Object در LiteSpeed Cache استفاده میکنید، این افزونه را کنارش نصب نکنید.
۴. وبسرور، HTTP/2، HTTP/3 و فشردهسازی
اول نوع وبسرور را ببینید، چون روش کش صفحه (راهکار ۶) هم به آن بستگی دارد:
curl -s -o /dev/null -D - https://example.com/ | grep -i '^server:'
برای دیدن پروتکل، در DevTools کروم (کلید F12) زبانهٔ Network را باز کنید و با راستکلیک روی سرستونها ستون Protocol را فعال کنید: h2 یعنی HTTP/2 و h3 یعنی HTTP/3. اگر http/1.1 است، روی هاست اشتراکی از پشتیبانی بخواهید. روی Nginx:
# Ubuntu 24.04 (nginx 1.24)
listen 443 ssl http2;
# Ubuntu 26.04 (nginx 1.28)
listen 443 ssl;
http2 on;
HTTP/3 در Nginx هنوز آزمایشی است. اگر nginx -V 2>&1 | grep -o with-http_v3_module خروجی داشت، این دو خط را به بلوک server اضافه و پورت UDP 443 را باز کنید (sudo ufw allow 443/udp). بدون هدر Alt-Svc مرورگر سراغ HTTP/3 نمیرود؛ reuseport را هم برای هر پورت فقط در یک بلوک server بنویسید:
listen 443 quic reuseport;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
در /etc/nginx/nginx.conf پیشفرض Debian و Ubuntu، gzip on; فعال است ولی خط gzip_types کامنت شده؛ یعنی CSS و JS فشرده نمیشوند. یا خطهای کامنتشدهٔ gzip را در همان فایل از حالت کامنت خارج کنید، یا فایل /etc/nginx/conf.d/gzip.conf را با محتوای زیر بسازید، نه هر دو. خط gzip on; را تکرار نکنید، چون nginx خطای duplicate میدهد:
# gzip on; is already set in nginx.conf
gzip_vary on;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript text/javascript text/xml application/xml image/svg+xml;
sudo nginx -t && sudo systemctl reload nginx
روی Apache با mod_deflate، در .htaccess:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/javascript application/json image/svg+xml
</IfModule>
در بررسی زیر باید content-encoding: gzip یا br ببینید:
curl -s -o /dev/null -D - -H 'Accept-Encoding: gzip, br' https://example.com/wp-includes/css/dist/block-library/style.min.css | grep -i content-encoding
۵. منابع کافی و محدودیتهای هاست
در هاست اشتراکی با CloudLinux، صفحهٔ Resource Usage در cPanel (معمولاً در بخش Metrics) نشان میدهد کی به سقف پردازنده، حافظه، IO یا درخواستهای همزمان (Entry Processes) رسیدهاید. پر شدن Entry Processes خطای 508 میدهد و کمبود حافظه معمولاً 500 یا 503. پیش از ارتقا علت را پیدا کنید؛ گاهی رباتها، حمله به wp-login.php یا WP-Cron شلوغ مقصرند.
روی سرور مجازی، گلوگاه پنهان رایج pm.max_children در /etc/php/8.3/fpm/pool.d/www.conf است که پیشفرضش ۵ است؛ یعنی فقط ۵ درخواست PHP همزمان. نشانهاش در لاگ:
sudo grep max_children /var/log/php8.3-fpm.log | tail -3
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
میانگین حافظهٔ هر پردازهٔ PHP را بگیرید:
ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1} END {printf "%.0f MB\n", s/NR/1024}'
اگر هر پردازه حدود ۸۰ مگابایت است و پس از سهم MySQL و سیستمعامل ۱٫۵ گیگابایت برای PHP میماند، عدد ۱۸ مناسب است؛ عدد بزرگتر کار را به Swap میکشاند. مقدار را در همان فایل www.conf بگذارید و PHP-FPM را دوباره راهاندازی کنید:
pm.max_children = 18
sudo systemctl restart php8.3-fpm
تنظیمات بیشتر در مقالهٔ بهینهسازی سرور مجازی برای وردپرس آمده است.
کش صفحه، کش مرورگر و CDN: راهکارهای ۶ تا ۸
۶. کش صفحه متناسب با وبسرور
کش صفحه (Page Cache) HTML آماده را به بازدیدکنندهٔ مهمان تحویل میدهد تا PHP و دیتابیس درگیر نشوند. ابزارش به وبسرور بستگی دارد:
| وبسرور | گزینهٔ مناسب |
|---|---|
| LiteSpeed یا OpenLiteSpeed | LiteSpeed Cache |
| Apache | WP Super Cache یا W3 Total Cache |
| Nginx روی سرور مجازی | FastCGI Cache همراه Nginx Helper |
LiteSpeed: افزونهٔ LiteSpeed Cache را نصب کنید؛ گزینهٔ Enable Cache در LiteSpeed Cache ← Cache پیشفرض روشن است. دستور زیر را دو بار اجرا کنید؛ بار دوم هدر باید x-litespeed-cache: hit باشد:
curl -s -o /dev/null -D - https://example.com/ | grep -i x-litespeed-cache
Apache: در تنظیمات ← WP Super Cache، زبانهٔ Easy، گزینهٔ Caching On را انتخاب و Update Status را بزنید و با Test Cache نتیجه را بسنجید.
Nginx: ناحیهٔ کش را در سطح http، مثلاً در /etc/nginx/conf.d/wp-fastcgi-cache.conf، تعریف کنید:
fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WORDPRESS:64m inactive=60m max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
سپس در بلوک server سایت، این شرطها را بیرون از هر location اضافه و بلوک PHP فعلی را با این نسخه جایگزین کنید (سوکت برای Ubuntu 24.04):
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php|wp-.*\.php|sitemap") { set $skip_cache 1; }
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in|woocommerce_items_in_cart|wp_woocommerce_session") { set $skip_cache 1; }
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 301 302 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
# an add_header here stops inheriting server-level add_header lines
add_header X-Cache $upstream_cache_status;
}
sudo mkdir -p /var/cache/nginx/wordpress
sudo nginx -t && sudo systemctl reload nginx
در درخواست دوم، X-Cache: HIT یعنی کش کار میکند. برای پاک شدن کش هنگام انتشار مطلب، افزونهٔ Nginx Helper را نصب کنید و در تنظیمات ← Nginx Helper گزینهٔ Enable Purge را روشن کنید، Caching Method را nginx Fastcgi cache و Purge Method را Delete local server cache files بگذارید و مسیر را در wp-config.php تعریف کنید:
define( 'RT_WP_NGINX_HELPER_CACHE_PATH', '/var/cache/nginx/wordpress/' );
نکته: در قانون Nginx، صفحههای سبد خرید و تسویهحساب ووکامرس را هم مستثنا کنید؛ اگر نشانیشان فارسی است، شرط را با
$uriبنویسید، چون$request_uriحروف فارسی را بهصورت کدشده (Percent-encoded) دارد.
۷. کش مرورگر برای فایلهای ثابت
وردپرس به نشانی CSS و JS پارامتر ?ver= میدهد، پس ماندگاری طولانی در مرورگر بیخطر است. در LiteSpeed Cache روشن کردن Browser Cache در زبانهٔ Cache ← Browser کافی است. روی Apache یا LiteSpeed بدون افزونه، در .htaccess:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 30 days"
ExpiresByType application/javascript "access plus 30 days"
ExpiresByType text/javascript "access plus 30 days"
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/webp "access plus 30 days"
ExpiresByType image/avif "access plus 30 days"
ExpiresByType image/svg+xml "access plus 30 days"
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
روی Nginx، در بلوک server:
location ~* \.(?:css|js|jpe?g|png|gif|webp|avif|svg|ico|woff2)$ {
expires 30d;
access_log off;
try_files $uri =404;
}
پس از آن، هدر پاسخ این فایلها باید Cache-Control: max-age=2592000 یعنی ۳۰ روز باشد.
۸. CDN فقط وقتی مخاطب دور است
CDN فایلها را از سروری نزدیکتر به بازدیدکننده تحویل میدهد. اگر سرور و مخاطب هر دو در ایراناند، CDN بدون نقطهٔ حضور در ایران چیزی را نزدیکتر نمیکند؛ برای مخاطب پراکنده یا خارجی کمک واقعی است. CDN کندی PHP را هم حل نمیکند. برای مقایسهٔ گزینهها، راهنمای جامع انتخاب CDN را ببینید.
محل سرور هم همین منطق را دارد: برای مخاطب داخلی، سروری در ایران مثل سرور مجازی ایران مسیر را کوتاه میکند، اما بهروزرسانیها و سرویسهای خارجیای که سایت صدا میزند به کیفیت ارتباط بینالملل وابسته میشوند (راهکار ۱۷).
تصاویر و LCP: راهکارهای ۹ تا ۱۱
۹. WebP و AVIF به جای JPEG و PNG
وردپرس از نسخهٔ 5.8 فرمت WebP و از 6.5 فرمت AVIF را پشتیبانی میکند، به شرطی که Imagick یا GD سرور آن را بشناسد؛ این را در ابزارها ← سلامت سایت ← اطلاعات ← Media Handling ببینید. افزونهٔ رسمی Modern Image Formats از تیم کارایی وردپرس، تصاویر جدید را هنگام بارگذاری تبدیل میکند؛ پیشفرضش AVIF است (اگر سرور نشناسد، WebP) و فرمت را در تنظیمات ← رسانه انتخاب میکنید. برای تصاویر قبلی، پس از بکاپ و در ساعت کمبازدید، از پوشهٔ سایت (مثل راهکار ۳):
sudo -u www-data wp media regenerate --yes
این کار روی کتابخانهٔ بزرگ پردازندهٔ زیادی میگیرد. بهینهسازی تصویر LiteSpeed Cache با سرویس QUIC.cloud انجام میشود و به ارتباط سرور با خارج وابسته است؛ روی سرور داخل ایران، پیش از تکیه بر آن امتحانش کنید.
۱۰. ابعاد درست، srcset و جلوگیری از CLS
- تصویر را پیش از بارگذاری کوچک کنید: برای محتوای ۸۰۰ پیکسلی، عرض حدود ۱۶۰۰ پیکسل کافی است. وردپرس تصاویر بزرگتر از ۲۵۶۰ پیکسل را کوچک میکند، ولی فایل اصلی را هم نگه میدارد.
- تصویر را با بلوک تصویر درج کنید تا وردپرس
srcsetبسازد و موبایل فایل کوچکتر بگیرد؛ تصویر پسزمینهٔ CSS این مزیت را ندارد. widthوheightتصاویر را نگه دارید و برای بنر، ابزار چت و هر جزء تزریقی باmin-heightجا رزرو کنید؛ اینها علت اصلی CLS هستند.
۱۱. lazy load درست و تصویر LCP
وردپرس از نسخهٔ 5.5 به تصاویر و از 5.7 به iframeها loading="lazy" میدهد. از 6.3 هم سه تصویر اول محتوا را lazy نمیکند و به تصویر احتمالی LCP، fetchpriority="high" میدهد؛ پس افزونهٔ lazy load معمولاً لازم نیست. اگر افزونه یا صفحهسازی تصویر بالای صفحه را هم lazy کند، LCP بالا میرود:
- عنصر LCP را در گزارش PageSpeed پیدا کنید و اگر
loading="lazy"دارد، مستثنایش کنید؛ در LiteSpeed Cache از Page Optimization ← Media Excludes. - اسلایدر بالای صفحه را با یک تصویر ثابت عوض کنید.
- تصویر اصلیای را که پسزمینهٔ CSS است، پیشبارگذاری کنید (راهکار ۱۵).
CSS، جاوااسکریپت و فونت فارسی: راهکارهای ۱۲ تا ۱۵
۱۲. CSS و JS بلااستفاده را حذف کنید
بسیاری از افزونهها فایلهایشان را در همهٔ صفحهها بارگذاری میکنند؛ مثلاً CSS فرم تماس در صفحهای که فرم ندارد. در DevTools با Ctrl+Shift+P فرمان Show Coverage را اجرا و صفحه را بازخوانی کنید تا سهم کد بلااستفاده را ببینید. افزونهٔ Asset CleanUp فایلها را برای هر صفحه غیرفعال (Unload) میکند و گزینهٔ Generate UCSS در LiteSpeed Cache، با سرویس QUIC.cloud، CSS هر صفحه را جدا میسازد. Minify سود کمی دارد و Combine روی HTTP/2 معمولاً لازم نیست.
۱۳. جاوااسکریپت را با تأخیر اجرا کنید
جاوااسکریپت سنگین رشتهٔ اصلی مرورگر (Main Thread) را اشغال و INP را بد میکند. Defer فایل را بعد از ساخته شدن صفحه اجرا میکند و Delay تا اولین تعامل کاربر اصلاً بارگذاریاش نمیکند؛ Delay برای چت، آمار و پیکسلها مناسب است. در LiteSpeed Cache از Page Optimization ← JS Settings گزینهٔ Load JS Deferred را روی Deferred یا Delayed بگذارید. روی سرورهای دیگر، افزونهٔ Autoptimize در تنظیمات ← Autoptimize با گزینههای Optimize JavaScript Code و Do not aggregate but defer، اسکریپتها را Defer میکند. توسعهدهندهها از وردپرس 6.3 روش بارگذاری را هنگام ثبت اسکریپت تعیین میکنند:
wp_enqueue_script(
'my-theme-main',
get_theme_file_uri( 'assets/main.js' ),
array(),
'1.0.0',
array( 'strategy' => 'defer', 'in_footer' => true )
);
بعد از هر تغییر، منو، فرم و سبد خرید را روی موبایل امتحان کنید. پنل Performance در DevTools مقدار LCP و CLS را فوراً و INP را پس از کلیک نشان میدهد؛ با تنظیم CPU، گوشی کند را شبیهسازی کنید.
۱۴. فونت فارسی را روی هاست خودتان بگذارید
بسیاری از قالبهای فارسی هفت یا هشت وزن فونت بارگذاری میکنند و صفحهساز هم فونت گوگل اضافه میکند. در زبانهٔ Network با فیلتر Font فایلها را بشمارید؛ دو یا سه فایل WOFF2 معمولاً کافی است. مثال با فونت آزاد وزیرمتن (Vazirmatn، مجوز SIL Open Font License):
- آخرین نسخه را از صفحهٔ انتشار وزیرمتن در GitHub بگیرید. هر وزن در پوشهٔ
fonts/webfontsحدود ۵۰ کیلوبایت است و فایل متغیرVazirmatn[wght].woff2که همهٔ وزنها را دارد، حدود ۱۱۰ کیلوبایت. - فقط وزنهای لازم، مثلاً Regular و Bold، را با File Manager یا FTP در
wp-content/fonts/vazirmatn/بگذارید؛ کتابخانهٔ رسانه بهطور پیشفرض فایل WOFF2 را نمیپذیرد. - این CSS را در نمایش ← سفارشیسازی ← CSS اضافی (در قالبهای بلوکی: نمایش ← ویرایشگر ← استایلها ← CSS اضافی) یا قالب فرزند بگذارید:
@font-face {
font-family: "Vazirmatn";
src: url("/wp-content/fonts/vazirmatn/Vazirmatn-Regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Vazirmatn";
src: url("/wp-content/fonts/vazirmatn/Vazirmatn-Bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: "Vazirmatn", Tahoma, sans-serif;
}
با font-display: swap متن فوراً با فونت جایگزین (Tahoma در ویندوز و فونت سیستم در موبایل) نمایش داده میشود و با رسیدن وزیرمتن عوض میشود. بارگذاری فونت خود قالب را از تنظیمات قالب خاموش کنید تا فونت دو بار دانلود نشود. در المنتور از نسخهٔ 3.32.1، گزینهٔ Load Google Fonts Locally در Elementor ← Editor ← Settings ← Performance است و پیشفرض خاموش است.
دلیل ایرانی این کار: CSS فونتهای گوگل مسدودکنندهٔ رندر است و در زمان اختلال ارتباط بینالملل، میتواند نمایش صفحه را برای کاربر داخل ایران تا پایان مهلت اتصال نگه دارد. برای فونت تجاری فارسی، مجوز نسخهٔ وب را هم بررسی کنید.
۱۵. پیشبارگذاری فونت اصلی و تصویر LCP
Preload به مرورگر میگوید فایلی را که دیر کشف میکند، زودتر بگیرد. فایل wp-content/mu-plugins/speed-tweaks.php را بسازید؛ افزونههای این پوشه بدون فعالسازی اجرا میشوند و برخلاف functions.php قالب، با تعویض یا بهروزرسانی قالب از بین نمیروند:
<?php
/**
* Plugin Name: Speed tweaks
*/
add_action( 'wp_head', function () {
// Main text font. crossorigin is required even on the same domain.
echo '<link rel="preload" href="/wp-content/fonts/vazirmatn/Vazirmatn-Regular.woff2" as="font" type="font/woff2" crossorigin>' . "\n";
// Hero image that is a CSS background, front page only.
if ( is_front_page() ) {
echo '<link rel="preload" as="image" href="/wp-content/uploads/2026/10/hero.webp" fetchpriority="high">' . "\n";
}
}, 1 );
ویژگی crossorigin برای فونت حتی روی همان دامنه لازم است، وگرنه شاید فایل دو بار دانلود شود. بیش از یکی دو فایل را Preload نکنید. وردپرس 6.8 به بعد هم با بارگذاری حدسی (Speculative Loading) صفحهٔ بعد را از لحظهٔ شروع کلیک پیشواکشی میکند و تنظیمی نمیخواهد؛ البته فقط برای کاربران واردنشده، در سایتهایی با پیوند یکتای غیرپیشفرض و در مرورگرهای مبتنی بر کروم.
افزونهها، قالب و درخواستهای خارجی: راهکارهای ۱۶ و ۱۷
۱۶. افزونهها و قالب را ممیزی کنید
تعداد افزونه بهتنهایی معیار نیست؛ یک افزونهٔ بدساخت از بیست افزونهٔ سبک بدتر است.
- در Query Monitor پنلهای Queries by Component و HTTP API Calls را ببینید و افزونههای پرهزینه را فهرست کنید.
- روی نسخهٔ آزمایشی افزونهها را یکییکی غیرفعال کنید و هر بار TTFB بدون کش را بسنجید.
- همپوشانیها را حذف کنید: دو افزونهٔ کش یا سئو، چند اسلایدر، افزودنی صفحهساز برای یک ویجت.
- یک قالب پیشفرض مثل Twenty Twenty-Five را روی نسخهٔ آزمایشی امتحان کنید؛ اگر اعداد خیلی بهتر شد، قالب فعلی بخش بزرگی از مشکل است.
افزونهٔ پولی را فقط از منبع رسمی بگیرید؛ نسخههای «نالشده» بارها همراه کد مخرب پخش شدهاند.
۱۷. اسکریپتها و درخواستهای خارجی را مهار کنید
هر ابزار خارجی (چت، آمار، پیکسل، ویدیو، نشان اعتماد، Gravatar) یعنی اتصال تازه و اغلب جاوااسکریپتی که INP را بدتر میکند. در زبانهٔ Network درخواستها را بر اساس دامنه مرتب کنید و هرکدام را حذف، Delay یا به هاست خودتان منتقل کنید. ویدیو را با تصویر پیشنمایش و پخش با کلیک بگذارید و برای مخاطب ایرانی یادتان باشد یوتیوب از داخل ایران در دسترس نیست. اگر آواتار لازم ندارید، در تنظیمات ← گفتگو نمایش آواتارها را خاموش کنید.
پیشخوان هم همین مشکل را دارد: وردپرس و افزونهها برای بهروزرسانی و مجوز با سرورهای خارجی تماس میگیرند و مهلت پیشفرض هر درخواست ۵ ثانیه است. روی سرور داخل ایران، در زمان اختلال ارتباط بینالملل، همین درخواستها هر صفحهٔ پیشخوان را چند ثانیه معطل میکنند (پنل HTTP API Calls نشانشان میدهد). راهحل موقت، بستن درخواستهای بیرونی و مجاز کردن فقط سرویسهای داخلی لازم در wp-config.php است (دامنهها نمونهاند):
define( 'WP_HTTP_BLOCK_EXTERNAL', true );
define( 'WP_ACCESSIBLE_HOSTS', 'your-payment-gateway.ir,*.your-payment-gateway.ir,your-sms-panel.ir,*.your-sms-panel.ir' );
هشدار: این تنظیم همهٔ درخواستهای HTTP API وردپرس را میبندد، نه فقط پیشخوان را؛ افزونهای که مستقیم با cURL یا SoapClient تماس میگیرد از آن اثر نمیپذیرد. اگر دامنهٔ درگاه پرداخت یا پنل پیامک در فهرست نباشد، تأیید پرداخت و ارسال پیامک ممکن است شکست بخورد. الگوی
*.domain.irخودdomain.irرا شامل نمیشود، پس هر دو را بنویسید. پس از رفع اختلال این دو خط را بردارید، وگرنه بهروزرسانیهای وردپرس هم متوقف میمانند.
دیتابیس و کارهای پسزمینه: راهکارهای ۱۸ تا ۲۰
۱۸. ویرایشها و ترنزینتها را پاک کنید
وردپرس همهٔ نسخههای ویرایش (Revisions) را نگه میدارد. برای محدود کردنشان، در wp-config.php:
define( 'WP_POST_REVISIONS', 5 );
این تنظیم نسخههای قبلی را فقط در ذخیرهٔ بعدی هر نوشته کم میکند. برای پاکسازی یکجا، پس از بکاپ و از پوشهٔ سایت:
# count revisions
sudo -u www-data wp post list --post_type=revision --format=count
# delete them permanently, 500 at a time
sudo -u www-data wp post list --post_type=revision --format=ids | xargs -r -n 500 sudo -u www-data wp post delete --force
# remove expired transients
sudo -u www-data wp transient delete --expired
بدون دسترسی به خط فرمان، افزونهٔ WP-Optimize همین کار را میکند. اثر این پاکسازی بر TTFB معمولاً از راهکار بعدی کمتر است.
۱۹. گزینههای autoload را سبک کنید
گزینههای autoload در جدول wp_options در هر درخواست یکجا خوانده میشوند و افزونههای حذفشده گاهی مگابایتها داده جا میگذارند. از وردپرس 6.6، مقادیر yes، on، auto-on و auto بارگذاری خودکار میشوند. در phpMyAdmin یا با wp db query اجرا کنید (پیشوند wp_ را در صورت نیاز عوض کنید):
SELECT ROUND(SUM(LENGTH(option_value)) / 1024) AS autoload_kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto');
SELECT option_name, ROUND(LENGTH(option_value) / 1024, 1) AS kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto')
ORDER BY LENGTH(option_value) DESC
LIMIT 20;
از پیشوند نام، افزونهٔ صاحب هر گزینه را پیدا کنید. اگر افزونه حذف شده، گزینه را پاک کنید و اگر فعال است، autoload آن را خاموش کنید (نامها نمونهاند):
sudo -u www-data wp option delete old_plugin_settings
sudo -u www-data wp option set-autoload big_plugin_cache off
۲۰. Heartbeat و WP-Cron را تنظیم کنید
Heartbeat در پیشخوان بهطور پیشفرض هر ۶۰ ثانیه و در صفحهٔ ویرایش کلاسیک نوشته هر ۱۰ ثانیه یک درخواست به admin-ajax.php میفرستد؛ چند کاربر یا زبانهٔ فعال در پیشخوان، روی هاست اشتراکی میتواند به پر شدن سقف Entry Processes کمک کند. این کد را به speed-tweaks.php اضافه کنید:
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 120; // default interval, seconds
$settings['minimalInterval'] = 60; // floor for every screen, max 600
return $settings;
} );
از ۱۲۰ ثانیه بالاتر نروید، چون قفل ویرایش نوشته پس از ۱۵۰ ثانیه منقضی میشود. LiteSpeed Cache همین تنظیم را در Toolbox ← Heartbeat دارد.
WP-Cron کارهای زمانبندیشده را همراه بازدیدها اجرا میکند؛ با کش صفحه ممکن است دیر اجرا شوند و در سایت شلوغ درخواست اضافه میسازند. آن را به Cron سیستم بسپارید؛ اول این خط را در wp-config.php بگذارید:
define( 'DISABLE_WP_CRON', true );
در cPanel، با ابزار Cron Jobs در بخش Advanced، این فرمان را هر ۵ دقیقه اجرا کنید:
wget -q -O /dev/null https://example.com/wp-cron.php
روی سرور مجازی، با sudo crontab -u www-data -e:
*/5 * * * * cd /var/www/example.com && /usr/local/bin/wp cron event run --due-now --quiet
دستور wp cron event list یا افزونهٔ WP Crontrol رویدادهای سنگین و تکراری را نشان میدهد.
عیبیابی: نشانه، علت، راهحل
| نشانه | علت محتمل | راهحل |
|---|---|---|
| پس از Defer، منو یا اسلایدر از کار افتاد | کد درونخطی به jQuery وابسته است | jQuery را از Defer مستثنا کنید |
| هدر کش همیشه miss یا BYPASS است | آزمون در حالت ورود، کوکی یا پارامتر آدرس | با پنجرهٔ ناشناس یا curl بدون پارامتر بسنجید |
| تغییر مطلب یا CSS دیده نمیشود | کش صفحه، CDN یا مرورگر | کش افزونه و CDN را پاک و با Ctrl+F5 بازخوانی کنید |
| خطای 508 Resource Limit Is Reached | پر شدن Entry Processes | کش صفحه، کاهش Heartbeat، مهار رباتها و در صورت تکرار، ارتقا |
| CLS بالا در سایت فارسی | تعویض فونت، تصویر بیابعاد، بنر تزریقی | Preload فونت، width و height، رزرو فضا |
| Redis Object Cache پیام Not connected میدهد | Redis خاموش است یا php-redis نصب نیست |
systemctl status redis-server، نصب افزونهٔ PHP و راهاندازی مجدد PHP-FPM |
| صفحهٔ سفید پس از تغییر نسخهٔ PHP | افزونهٔ ناسازگار یا فایل ionCube | برگشت به نسخهٔ قبل و بررسی error_log |
کی سراغ هاست یا سرور قویتر بروید
اگر پس از این راهکارها TTFB بدون کش روی نسخهٔ آزمایشی سبک هنوز بالاست یا Resource Usage مدام Fault ثبت میکند، منابع واقعاً کم است. برای بیشتر وبلاگها و سایتهای شرکتی، یک هاست وردپرس با کش صفحه کافی است. سرور مجازی وقتی منطقی است که فروشگاه پرترافیک دارید، به Redis و تنظیم PHP-FPM نیاز دارید یا چند سایت را کنار هم میزبانی میکنید.
هاکان سرور هم هاست وردپرس دارد و هم سرور مجازی. در سرور مجازی، ارتقای منابع سرویس با ثبت تیکت انجام میشود؛ پس میتوانید با پلن کوچک شروع کنید و وقتی اعداد نشان دادند، بزرگتر شوید. اگر ترجیح میدهید این کارها را به متخصص بسپارید، صفحهٔ پشتیبانی وردپرس را ببینید. پشتیبانی فنی ۲۴ ساعته از طریق تیکت در دسترس است.
پرسشهای متداول
سایت وردپرس باید در چند ثانیه بارگذاری شود؟
معیار گوگل LCP تا ۲٫۵ ثانیه برای دستکم ۷۵ درصد بازدیدهای واقعی است، جدا برای موبایل و دسکتاپ. TTFB زیر ۰٫۸ ثانیه هم نقطهٔ شروع خوبی است.
آیا امتیاز ۱۰۰ در PageSpeed Insights لازم است؟
نه. امتیاز نتیجهٔ آزمون آزمایشگاهی است و Core Web Vitals کاربران واقعی اهمیت بیشتری دارد. امتیاز بالای ۹۰ کافی است.
کدام افزونهٔ کش برای وردپرس مناسب است؟
به وبسرور بستگی دارد: روی LiteSpeed افزونهٔ LiteSpeed Cache، روی Apache افزونهٔ WP Super Cache و روی Nginx کش FastCGI همراه Nginx Helper. فقط یک افزونهٔ کش صفحه فعال کنید.
آیا تعداد زیاد افزونه سایت را کند میکند؟
نه بهخودیخود؛ کیفیت افزونه مهمتر از تعداد است. با Query Monitor افزونهٔ پرهزینه را پیدا و جایگزین یا حذف کنید.
چرا پیشخوان وردپرس کند است ولی سایت سریع باز میشود؟
صفحههای سایت از کش میآیند، اما پیشخوان کش نمیشود. علت معمولاً درخواست خارجی بیپاسخ، Heartbeat، autoload سنگین یا افزونهای سنگین است که Query Monitor نشانش میدهد.
برای سایتی با مخاطب ایرانی CDN لازم است؟
اگر سرور و مخاطب هر دو در ایراناند، معمولاً نه، مگر CDN در ایران نقطهٔ حضور داشته باشد. برای سرور خارج از ایران یا مخاطب پراکنده مفید است.
جمعبندی
افزایش سرعت سایت وردپرس کار یک افزونه نیست؛ حاصل سنجش و اصلاح لایهبهلایه است: سرور (PHP، OPcache، کش و Redis)، صفحه (تصویر، فونت و جاوااسکریپت) و پسزمینه (autoload، Heartbeat و WP-Cron).
قدم بعدی: همین امروز خط مبنای سه صفحه را ثبت کنید و از جدول تشخیص گلوگاه، اولین راهکار مرتبط را اجرا کنید. فقط وقتی اعداد نشان دادند منابع کم است، سراغ ارتقای هاست بروید.


