آموزش نمایش تاریخ شمسی در وردپرس

یکی از چالش‌های رایج در وردپرس فارسی، نمایش پیش‌فرض تاریخ به‌صورت میلادی است؛ در حالی که برای مخاطب فارسی‌زبان، نمایش تاریخ به شکل شمسی طبیعی‌تر و قابل‌فهم‌تر است. در این نوشتار، روشی کامل، امن و آزمایش‌شده برای نمایش تاریخ شمسی در وردپرس ارائه می‌شود؛ روشی که به‌ویژه برای تم‌های مبتنی بر ویرایشگر کامل سایت (Full Site Editing) نظیر Twenty Twenty-Three مناسب است. این راهکار با استفاده از افزونۀ رایگان Code Snippets پیاده‌سازی می‌شود و نیازی به ویرایش مستقیم فایل‌های قالب ندارد.

مزایای این روش

پیش از پرداختن به کد، ذکر ویژگی‌هایی که این راهکار را از سایر روش‌های متداول متمایز می‌سازد، ضروری به نظر می‌رسد:

  • عدم نیاز به افزونۀ جانبی سنگین: پیاده‌سازی تنها با افزونۀ سبک Code Snippets انجام می‌شود.
  • سازگاری با تم‌های بلاکی: این روش مستقیماً بر بلاک «تاریخ نوشته» (Post Date) اعمال می‌شود.
  • حفظ کامل سئوی سایت: تنها متنی که برای بازدیدکننده نمایش داده می‌شود تغییر می‌کند؛ دادۀ ساختاریافته (Schema)، متاتگ‌های Open Graph، فید RSS و نقشۀ سایت بدون تغییر باقی می‌مانند و همچنان بر پایۀ تاریخ میلادی معتبر عمل می‌کنند.
  • نمایش با ارقام فارسی: خروجی به‌صورت «۱۰ مرداد ۱۴۰۵» ارائه می‌شود، نه با ارقام لاتین.
  • هماهنگی با فونت سایت: از آنجا که متن جدید درون همان تگ اصلی جایگزین می‌شود، فونت قالب به‌صورت خودکار اعمال خواهد شد.

پیش‌نیازها

  1. نصب و فعال‌سازی افزونۀ Code Snippets.
  2. دسترسی به پیشخوان وردپرس با سطح مدیر سایت.
  3. تهیۀ نسخۀ پشتیبان (Backup) از سایت، پیش از افزودن هرگونه قطعه‌کد جدید.

لازم به ذکر است که این کد اختصاصی به افزونۀ Code Snippets نبوده و با هر افزونۀ دیگری که امکان افزودن کد PHP سفارشی به سایت را فراهم می‌کند (نظیر WPCode یا My Custom Functions) نیز قابل‌استفاده است.

مراحل پیاده‌سازی

گام اول: ایجاد اسنیپت جدید

از منوی پیشخوان، مسیر Snippets > Add New را طی کرده و یک اسنیپت جدید از نوع PHP Snippet ایجاد کنید.

گام دوم: افزودن کد

کد زیر را به‌طور کامل در محل مربوط به کد اسنیپت جدید قرار دهید:

if (!function_exists('jk_gregorian_to_jalali')) {
function jk_gregorian_to_jalali($g_y, $g_m, $g_d) {
    $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
    $gy = $g_y - 1600;
    $gm = $g_m - 1;
    $gd = $g_d - 1;
    $g_day_no = 365 * $gy + intval(($gy + 3) / 4) - intval(($gy + 99) / 100) + intval(($gy + 399) / 400);
    for ($i = 0; $i < $gm; ++$i) $g_day_no += $g_days_in_month[$i];
    if ($gm > 1 && (($g_y % 4 == 0 && $g_y % 100 != 0) || ($g_y % 400 == 0))) $g_day_no++;
    $g_day_no += $gd;
    $j_day_no = $g_day_no - 79;
    $j_np = intval($j_day_no / 12053);
    $j_day_no = $j_day_no % 12053;
    $jy = 979 + 33 * $j_np + 4 * intval($j_day_no / 1461);
    $j_day_no %= 1461;
    if ($j_day_no >= 366) {
        $jy += intval(($j_day_no - 1) / 365);
        $j_day_no = ($j_day_no - 1) % 365;
    }
    for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i) $j_day_no -= $j_days_in_month[$i];
    $jm = $i + 1;
    $jd = $j_day_no + 1;
    return array($jy, $jm, $jd);
}
}

if (!function_exists('jk_persian_month_name')) {
function jk_persian_month_name($m) {
    $months = array(1=>'فروردین',2=>'اردیبهشت',3=>'خرداد',4=>'تیر',5=>'مرداد',6=>'شهریور',
                     7=>'مهر',8=>'آبان',9=>'آذر',10=>'دی',11=>'بهمن',12=>'اسفند');
    return isset($months[$m]) ? $months[$m] : '';
}
}

if (!function_exists('jk_to_persian_digits')) {
function jk_to_persian_digits($string) {
    $latin  = array('0','1','2','3','4','5','6','7','8','9');
    $persian = array('۰','۱','۲','۳','۴','۵','۶','۷','۸','۹');
    return str_replace($latin, $persian, $string);
}
}

if (!function_exists('jk_jalali_string')) {
function jk_jalali_string($post_id = null) {
    $post_id = $post_id ? $post_id : get_the_ID();
    if (!$post_id) return '';
    $post_date = get_post_field('post_date', $post_id);
    if (empty($post_date) || $post_date === '0000-00-00 00:00:00') return '';
    $parts = explode(' ', $post_date);
    $date_parts = explode('-', $parts[0]);
    if (count($date_parts) !== 3) return '';
    $g_y = (int) $date_parts[0];
    $g_m = (int) $date_parts[1];
    $g_d = (int) $date_parts[2];
    list($jy, $jm, $jd) = jk_gregorian_to_jalali($g_y, $g_m, $g_d);
    $jd = (int) $jd;
    if ($jd < 1 || $jd > 31) return '';
    $result = $jd . ' ' . jk_persian_month_name($jm) . ' ' . $jy;
    return jk_to_persian_digits($result);
}
}

// حالت اول: پوسته‌های بلاکی (FSE) که از بلاک گوتنبرگ core/post-date استفاده می‌کنند
// تنها نقطه‌ی تغییر: فقط متن نمایشی داخل <time> عوض می‌شه، ویژگی datetime دست‌نخورده می‌مونه (امن برای سئو)
add_filter('render_block_core/post-date', function($block_content, $block) {
    $jalali = jk_jalali_string();
    if (empty($jalali)) return $block_content;
    $new_content = preg_replace_callback(
        '/(<time[^>]*>)(.*?)(<\/time>)/su',
        function($matches) use ($jalali) {
            return $matches[1] . $jalali . $matches[3];
        },
        $block_content,
        1
    );
    return $new_content ? $new_content : $block_content;
}, 10, 2);

// حالت دوم: پوسته‌های کلاسیک PHP که مستقیماً از get_the_date() / get_the_modified_date() استفاده می‌کنند
// (مثل همین پوسته drjk-theme که در content.php و single.php این تابع را صدا می‌زند)
// فرمت‌های 'c' و 'U' دست‌نخورده می‌مانند چون معمولاً برای ویژگی datetime (ماشین‌خوان/سئو) استفاده می‌شوند
add_filter('get_the_date', function($the_date, $format, $post) {
    if ($format === 'c' || $format === 'U') {
        return $the_date;
    }
    $post_id = $post ? $post->ID : get_the_ID();
    $jalali = jk_jalali_string($post_id);
    return !empty($jalali) ? $jalali : $the_date;
}, 10, 3);

add_filter('get_the_modified_date', function($the_date, $format, $post) {
    if ($format === 'c' || $format === 'U') {
        return $the_date;
    }
    $post_id = $post ? $post->ID : get_the_ID();
    $jalali = jk_jalali_string($post_id);
    return !empty($jalali) ? $jalali : $the_date;
}, 10, 3);

// شورت‌کد مستقل و بی‌خطر برای استفاده در هر جای دلخواه: [jalali_date]
add_shortcode('jalali_date', function() {
    $timestamp = current_time('timestamp');
    list($jy, $jm, $jd) = jk_gregorian_to_jalali((int)date('Y',$timestamp), (int)date('n',$timestamp), (int)date('j',$timestamp));
    $result = $jd . ' ' . jk_persian_month_name($jm) . ' ' . $jy;
    return jk_to_persian_digits($result);
});

گام سوم: تنظیم محل اجرا

در بخش «Run snippet» (محل اجرا)، گزینۀ Run snippet everywhere را انتخاب کنید تا اسنیپت هم در فرانت‌اند و هم در پیشخوان فعال باشد.

گام چهارم: فعال‌سازی اسنیپت

بر روی گزینۀ Save Changes and Activate کلیک کنید.

گام پنجم: پاک‌سازی کش

در صورت استفاده از افزونه‌های کش (نظیر LiteSpeed Cache ،WP Rocket یا W3 Total Cache)، لازم است کش کل سایت به‌طور کامل پاک‌سازی شود تا تغییرات اعمال گردد.

نتیجه‌ی نهایی

پس از فعال‌سازی، در هر بخشی از سایت که بلاک «تاریخ نوشته» به کار رفته باشد (نظیر صفحۀ تک‌پست یا آرشیو مطالب)، به‌جای تاریخ میلادی، تاریخ شمسی با ارقام فارسی نمایش داده خواهد شد:

۱۰ مرداد ۱۴۰۵

استفاده از شورت‌کد در سایر بخش‌های سایت

برای نمایش تاریخ روز جاری (به شمسی) در یک صفحه، ویجت متنی یا هر بخش دیگری از سایت، کافی است شورت‌کد زیر در محتوای مورد نظر درج شود:

[jalali_date]

ملاحظات مهم پیش از پیاده‌سازی

سازگاری اختصاصی با تم‌های بلاکی (FSE)

این کد مبتنی بر فیلتر render_block_core/post-date طراحی شده که مختص بلاک «تاریخ نوشته» در تم‌های مبتنی بر ویرایشگر کامل سایت است (نظیر Twenty Twenty-Three ،Twenty Twenty-Four و تم‌های مشابه). در صورت استفاده از یک تم کلاسیک (غیربلاکی)، احتمالاً لازم است کد برای فیلترهای the_date یا get_the_date نیز تنظیم شود؛ با این حال، توصیه می‌شود این کار با احتیاط صورت گیرد، چرا که در بخش بعدی دلایل آن تشریح خواهد شد.

پرهیز از فیلتر کردن get_the_date و the_date

ممکن است این تصور پیش آید که با فیلتر کردن توابع هسته‌ای get_the_date() یا the_date()، بتوان تاریخ را در سراسر سایت به شمسی تبدیل کرد. این رویکرد اکیداً توصیه نمی‌شود، زیرا این توابع در موقعیت‌های حساسی نظیر تولید دادۀ ساختاریافتۀ Schema.org (که مبنای Rich Snippets در نتایج گوگل است) با فرمت‌های ماشین‌خوان نظیر ISO 8601 فراخوانی می‌شوند. فیلتر کردن این توابع می‌تواند به جایگزینی یک تاریخ میلادی معتبر با یک رشتۀ شمسی نامعتبر در خروجی Schema منجر شود و اعتبار دادۀ ساختاریافتۀ سایت را نزد گوگل مخدوش کند.

رویکرد ایمن، همان روشی است که در این کد به کار رفته است: صرفاً متن نمایشی نهایی درون تگ <time> تغییر می‌کند، در حالی که ویژگی datetime (که ماشین‌خوان است) بدون تغییر و بر مبنای تقویم میلادی باقی می‌ماند.

سازگاری با افزونه‌های سئو

این روش با افزونه‌های سئوی متداول در وردپرس فارسی، از جمله Rank Math و Yoast SEO، کاملاً سازگار است؛ چرا که این افزونه‌ها معمولاً داده‌های تاریخ مربوط به Schema را مستقیماً از دیتابیس (فیلد post_date) استخراج می‌کنند و نه از خروجی فیلترشده‌ی get_the_date(). برای اطمینان کامل، پیشنهاد می‌شود پس از پیاده‌سازی، آدرس یک نمونه پست در ابزار Google Rich Results Test بررسی شود تا از معتبر و میلادی بودن مقدار datePublished اطمینان حاصل گردد.

ضرورت تهیۀ نسخه‌ی پشتیبان

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

رفع اشکال

در صورتی که پس از فعال‌سازی، تاریخ نمایش داده نشد یا به‌صورت ناقص ظاهر شد، بررسی موارد زیر توصیه می‌شود:

  • عدم پاک‌سازی کش سایت: بخش عمده‌ای از مشکلات نمایشی ناشی از همین مورد است. کش صفحه و کش سرور (نظیر LiteSpeed) باید به‌طور کامل خالی شود.
  • انتخاب نوع نادرست اسنیپت: لازم است اطمینان حاصل شود که هنگام ایجاد اسنیپت، گزینۀ PHP Snippet انتخاب شده باشد، نه CSS یا JS.
  • محدودیت در محل اجرا: تنظیم مربوطه باید بر روی گزینۀ «Run snippet everywhere» قرار داشته باشد.
  • عدم استفاده‌ی قالب از بلاک استاندارد Post Date: در صورتی که قالب سایت از یک افزونۀ صفحه‌ساز (نظیر المنتور) برای نمایش تاریخ استفاده می‌کند، این کد نیازمند تنظیمات تکمیلی خواهد بود.

جمع‌بندی

با اتکا به این روش، بدون نیاز به ویرایش فایل‌های هسته یا قالب و بدون هیچ‌گونه ریسکی برای سئوی سایت، امکان نمایش تاریخ شمسی با ارقام فارسی و هماهنگ با فونت سایت فراهم می‌شود. کافی است کد فوق در افزونۀ Code Snippets درج شده و کش سایت پاک‌سازی گردد.

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

گفتگو با ما
آفلاین - پاسخ را پیامک یا ایمیل می‌کنیم

لطفاً برای شروع، نام خود را وارد کنید:

سلام! چطور می‌توانیم کمکتان کنیم؟
پشتیبانی در حال تایپ است...