اگر تا به حال پستی را منتشر کردهاید و دیدهاید که در سایت عمومی با برچسب «۵۷ سال پیش» نمایش داده میشود، در حالی که داشبورد شما با آرامش تأکید میکند که پست ده دقیقه پیش منتشر شده است، شما درد و سوز این باگ را درک میکنید. این باگ چیدمان سایت را خراب نمیکند. خطای بحرانی (fatal error) ایجاد نمیکند. فقط محتوای شما را نیم قرن پیر میکند، و خیره شدن به فایلهای قالب شما هم باعث نمیشود این عدد تغییر کند.
این مشکل معمولاً از بررسیهای همیشگی جان سالم به در میبرد. شما در فایلهای single.php ،archive.php و functions.php به دنبال یک فراخوانی اشتباه از get_the_date() میگردید. همه چیز استاندارد به نظر میرسد. صفحه زنده را رفرش میکنید. اما روح سال ۱۹۶۸ هنوز در زیر عنوان (byline) شما پرسه میزند. در این مرحله، مشکل تقریباً هیچ ارتباطی با قالبهای شما ندارد و تماماً به نحوه عبور زمان از میان پشته (stack) وردپرس مربوط میشود.
چرا این عدد خاص مدام ظاهر میشود
عدد «۵۷ سال پیش» تصادفی نیست. قالبهای وردپرس اغلب زمان نسبی را از طریق تابع human_time_diff() نمایش میدهند که برچسب زمانی (timestamp) یک پست را با لحظه فعلی مقایسه کرده و عبارتی دوستانه مانند «۲ ساعت پیش» چاپ میکند. برای اینکه این محاسبات درست کار کند، PHP به یک تایماستمپ یونیکس (Unix timestamp) معتبر نیاز دارد؛ یعنی شمارشی از ثانیهها از اول ژانویه ۱۹۷۰، که همان عصر یونیکس (Unix epoch) است.
وقتی چیزی تایماستمپ را قبل از رسیدن به آن مرحله از محاسبات، حذف یا خراب میکند، این تابع اغلب با مقایسه عدد صفر (یا یک نقطه شروع نامعتبر مشابه) با زمان حال روبرو میشود. نتیجه، بازهای است که تقریباً پنج و نیم دهه به عقب برمیگردد و سال به سال به جلو میآید. این یک نشانه از مقدار زمانی مفقود یا اشتباه خوانده شده است، نه دیتابیسی پر از پستهای وبلاگی قدیمی.
فریب داشبورد
یکی از ناامیدکنندهترین جنبههای این باگ، شخصیت دوگانه پنل مدیریت شماست. در داخل wp-admin، لیست نوشتهها (Posts) تاریخ انتشار صحیح را نشان میدهد، زیرا وردپرس اغلب آن را مستقیماً از جدول wp_posts در MySQL میگیرد و بدون عبور دادن از فیلتر زمان نسبی، آن را در سمت سرور قالببندی میکند. با این حال، بخش فرانتاند (frontend) ممکن است به قالب یا افزونهای وابسته باشد که human_time_diff() را فراخوانی میکند، یا ممکن است مقدار خام دیتابیس را از طریق زنجیرهای از تبدیلهای منطقه زمانی PHP عبور دهد که بخش بکاند (backend) کاملاً از آن چشمپوشی میکند.
بنابراین دادهها معمولاً سالم هستند. مشکل در واقع در خط لوله (pipeline) بین دیتابیس و HTML رندر شده است که دچار گره شده است.
نسخه PHP و تنظیمات منطقه زمانی (Timezone)
با PHP شروع کنید. پنلهای هاستینگ تغییر نسخه را بیخطر جلوه میدهند، اما PHP در نسخههای اصلی مختلف، اشیاء زمانی (time objects) را متفاوت مدیریت میکند. سایتی که کدهای قدیمی PHP 7.4 را در یک محیط ناگهانی PHP 8.1 اجرا میکند، ممکن است با تغییرات ظریفی در نحوه مقداردهی اولیه رشتههای خالی یا بدشکل در اشیاء DateTime مواجه شود. اگر فایل php.ini شما date.timezone را تعریف نکرده باشد، PHP به صورت پیشفرض روی UTC تنظیم میشود و فرض میکند سرور بهتر میداند. وردپرس ممکن است با این موضوع مخالف باشد.
بررسی کنید که آیا کسی اعلامیه منطقه زمانی را به صورت سختافزاری (hardcoded) در wp-config.php قرار داده است یا خیر. خطی مانند date_default_timezone_set( 'Asia/Kolkata' ); ممکن است مفید به نظر برسد، اما وردپرس انتظار دارد ساعت خود را از طریق مقداری که در بخش Settings > General تنظیم شده، مدیریت کند. اجبار کردن یک آفست (offset) در سطح PHP میتواند باعث ایجاد یک Race Condition شود که در آن هسته وردپرس معتقد است زمان محلی است و PHP معتقد است زمان جهانی است. وقتی این آفستها در طول تبدیل تایماستمپ با هم برخورد میکنند، نتیجهای که به قالب شما بازگردانده میشود میتواند به صفر سقوط کند.
پیکربندیهای منطقه زمانی سرور
سرور MySQL شما تصور خاص خود را از زمان محلی دارد. وردپرس برای هر پست دو تاریخ مینویسد: post_date به زمان محلی سایت، و post_date_gmt به زمان جهانی (Universal Time). اگر time_zone جهانی دیتابیس تغییر کند - مثلاً پس از مهاجرت از SYSTEM به +00:00 - تابع strtotime() در PHP ممکن است نتواند رشته ذخیره شده را با آنچه انتظار دارد تطبیق دهد. دیتابیس همچنان 2024-03-15 14:30:00 را ذخیره میکند، اما بافت (context) اطراف آن تغییر میکند و خروجی تجزیهشده در PHP به مقدار false یا null تبدیل میشود.
مثال واقعی: یک هاست مدیریتشده، دیتابیس شما را از یک نود (node) که MySQL 5.7 با زمان SYSTEM را اجرا میکند به کلاستری که MariaDB 10.11 با تنظیمات دقیق UTC را اجرا میکند، منتقل میکند. قالب شما هرگز تغییر نمیکند. تنظیمات وردپرس شما هرگز تغییر نمیکند. با این حال، get_the_time( 'U' ) - که فرمت تایماستمپ یونیکس است - ناگهان برای برخی از پستها مقدار خالی برمیگرداند و تابع زمان نسبی به همان محاسبه عصر صفر (epoch-zero) بازمیگردد. راه حل، همسو کردن منطقه زمانی اپلیکیشن، منطقه زمانی دیتابیس و ساعت سیستمعامل است تا وردپرس مجبور نباشد حدس بزند از کدام مرجع زمانی استفاده کند.
فرمتهای تایماستمپ دیتابیس
WordPress core stores post dates in MySQL DATETIME columns, not TIMESTAMP fields. That distinction matters because DATETIME holds a calendar value without_zone awareness in older MySQL versions, whereas TIMESTAMP converts everything to UTC behind the scenes. If a plugin or migration tool has altered your wp_posts schema, or if an old backup restored invalid zero dates into the table, WordPress may read a value like 0000-00-00 00:00:00 and quietly hand it off to your theme.
Modern MySQL modes, particularly NO_ZERO_DATE and STRICT_TRANS_TABLES, reject those zero placeholders. If a backup script inserted them during a migration, the database might have truncated or nulled them on import. You can verify this quickly with a direct SQL query:
SELECT ID, post_title, post_date, post_date_gmt
FROM wp_posts
WHERE post_status = 'publish'
ORDER BY post_date DESC
LIMIT 10;
If the raw columns look correct but the site still displays ancient history, the corruption is happening after the query. If the columns themselves contain zeroes, you have found the leak in the plumbing.
Plugin Conflicts with Date Functions
Plugins that filter date output are common culprits. Multilingual tools such as WPML or Polylang hook into get_the_date to translate month names. Caching plugins intercept the final HTML. Either layer can accidentally pass an unformatted string into a function expecting a Unix integer.
A translation plugin might replace “March 15, 2024” with its localized equivalent, but if a theme then pipes that localized string into strtotime() inside a custom function, the parser fails on non-English characters and returns false. That false value hits human_time_diff(), which compares zero against now, producing the infamous half-century gap.
Object cache layers complicate this further. Redis or Memcached can store a serialized WP_Post object from a request that briefly failed to parse the date. Every subsequent visitor receives that corrupted object straight from RAM, bypassing the database entirely. The issue persists on the live site because your production stack has cache infrastructure that your local install lacks.
A Practical Debugging Checklist
Because the symptom hides deep in the stack, you need to peel layers systematically until the dates snap back into place.
- Query the database directly. Open phpMyAdmin or run WP-CLI and inspect the raw
post_datevalues. If they are correct, the database is not the problem. - Switch to a default theme. Activate Twenty Twenty-Four or Twenty Twenty-Three. If the bug disappears, audit your active theme and child theme for custom functions wrapping time output.
- Silence the plugins. Rename the
/wp-content/pluginsfolder temporarily, or disable all plugins from the dashboard. Re-enable them one by one, checking the frontend after each activation. - Read the error log. Look for timezone warnings,
DateTimeerrors, orstrtotime()complaints. They often point to the exact
