مقاله ووکامرس

خاموش شدن sync on read در ووکامرس ۱۰.۷؛ کد قدیمی شما کجا می‌شکند؟

از ووکامرس ۱۰.۷، همگام‌سازی هنگام خواندن در HPOS به‌طور پیش‌فرض خاموش است. اگر جایی از کدتان هنوز سفارش را با update_post_meta یا SQL مستقیم عوض می‌کند، این تغییر بی‌صدا ولی جدی است. این‌جا نشان می‌دهم چطور پیدایش کنید و درستش کنید.

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

حمید اعراب ۲۷ مهر ۱۴۰۵ ۵ دقیقه مطالعه

جلد پیکسلی: دو جدول دیتابیس و پیکانی که قطع شده
فهرست مطالب (8)

اگر چند سال است با ووکامرس کار می‌کنید، HPOS را می‌شناسید: ذخیره‌سازی سفارش‌ها در جدول‌های اختصاصی به‌جای جدول‌های wp_posts و wp_postmeta. ولی تغییری که ووکامرس ۱۰.۷ آورد، کمتر دیده شد. این نسخه ۱۴ آوریل ۲۰۲۶ منتشر شد و از آن به بعد، سازوکار «sync on read» به‌طور پیش‌فرض خاموش است.

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

sync on read دقیقاً چه کاری می‌کرد؟

وقتی HPOS و «حالت سازگاری» (compatibility mode) با هم روشن باشند، ووکامرس داده را در هر دو جا نگه می‌دارد: جدول‌های تازهٔ HPOS و جدول‌های قدیمی پست‌ها. همگام‌سازی عادی از HPOS به سمت پست‌هاست.

sync on read یک راه برگشت بود. موقع خواندن سفارش، ووکامرس زمان آخرین تغییر را در دو طرف مقایسه می‌کرد. اگر دادهٔ جدول پست‌ها تازه‌تر بود، یعنی کسی بیرون از ووکامرس مستقیم آن‌جا نوشته بود، همان را به HPOS برمی‌گرداند.

این مکانیزم کد قدیمی را سرپا نگه می‌داشت. ولی به گفتهٔ خود تیم ووکامرس، همین رفتار باعث «برگشتن وضعیت سفارش یا جایگزین شدن رکوردهای HPOS با داده‌های کهنه» هم می‌شد. یعنی گاهی دادهٔ قدیمی، دادهٔ درست را پاک می‌کرد.

چه کسی آسیب می‌بیند؟

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

  • update_post_meta( $order_id, ... )
  • wp_update_post( array( 'ID' => $order_id, 'post_status' => ... ) )
  • SQL مستقیم روی wp_posts یا wp_postmeta برای سفارش‌ها

این نوشتن‌ها از ۱۰.۷ به بعد دیگر خودکار به HPOS نمی‌رسند.

فروشگاهی که همهٔ افزونه‌هایش با HPOS سازگارند، یا هنوز روی ذخیره‌سازی قدیمی پست‌هاست، تغییری حس نمی‌کند.

اول: پیدا کردن کدهای مشکوک

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

grep -rnE "update_post_meta|get_post_meta|wp_update_post|delete_post_meta" \
  wp-content/plugins/my-custom-* wp-content/themes/my-theme \
  | grep -iE "order|_billing|_shipping|_payment|shop_order"

نتیجه دقیق نیست و ممکن است مورد اشتباه هم پیدا کند. ولی فهرستی می‌دهد که باید یکی‌یکی نگاهش کنید. هر جا شناسهٔ سفارش به یکی از این توابع داده شده، باید به لایهٔ CRUD ووکامرس منتقل شود. یک جست‌وجوی دوم هم برای $wpdb در همان پوشه‌ها بزنید.

دوم: جایگزین درست

الگوی جایگزینی تقریباً همیشه همین است: سفارش را با wc_get_order بگیرید، با متدهای خودش تغییر دهید و در آخر save() را صدا بزنید.

// Before: writes straight to postmeta and skips HPOS.
update_post_meta( $order_id, '_tracking_code', $code );
wp_update_post( array( 'ID' => $order_id, 'post_status' => 'wc-completed' ) );

// After: goes through WooCommerce's CRUD layer.
$order = wc_get_order( $order_id );
if ( $order ) {
	$order->update_meta_data( '_tracking_code', $code );
	$order->set_status( 'completed', __( 'Shipped with tracking code.', 'my-plugin' ) );
	$order->save();
}

برای خواندن هم به‌جای get_post_meta( $order_id, '_tracking_code', true ) از $order->get_meta( '_tracking_code' ) استفاده کنید. برای جست‌وجوی سفارش‌ها هم به‌جای WP_Query روی shop_order، از wc_get_orders() استفاده کنید.

در فایل اصلی افزونه هم سازگاری را اعلام کنید تا ووکامرس بداند این افزونه HPOS را می‌فهمد:

add_action( 'before_woocommerce_init', function () {
	if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
		\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
	}
} );

اگر متاباکس سفارشی روی صفحهٔ سفارش دارید، شناسهٔ صفحه را هم با wc_get_page_screen_id( 'shop-order' ) بگیرید، نه رشتهٔ ثابت shop_order. صفحهٔ ویرایش سفارش در HPOS دیگر صفحهٔ پست نیست.

سوم: تست قبل از اینکه مشتری تست کند

ووکامرس خودش راه تست را گذاشته است. روی نسخهٔ staging، sync on read را صراحتاً خاموش کنید و همهٔ مسیرهایی را که کد سفارشی‌تان به سفارش دست می‌زند، از اول تا آخر اجرا کنید:

// Staging only: behave like WooCommerce 10.7+ and make sure nothing depends on sync on read.
add_filter( 'woocommerce_hpos_enable_sync_on_read', '__return_false' );

اگر فعلاً فرصت اصلاح ندارید، همین فیلتر با __return_true رفتار قدیمی را برمی‌گرداند. ولی این فقط مُسکن است. تیم ووکامرس صراحتاً گفته sync on read ممکن است در نسخه‌های بعد کاملاً حذف شود.

چهارم: خاموش کردن حالت سازگاری

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

نتیجه‌اش یک نوشتن کمتر در هر تغییر سفارش است. در فروشگاه‌های پرسفارش این تفاوت محسوس است، به‌خصوص در کنار بهینه‌سازی‌های خود ۱۰.۷. مثلاً تعداد کوئری‌های مسیر سفارش‌ها در REST API در این نسخه از ۲۷۱ به ۱۳۲ رسیده است.

چک‌لیست کوتاه

  1. همهٔ نوشتن‌های مستقیم روی سفارش (*_post_meta، wp_update_post و $wpdb) را پیدا کنید.
  2. آن‌ها را به wc_get_order و setterها و save() منتقل کنید.
  3. سازگاری با custom_order_tables را در افزونه اعلام کنید.
  4. روی staging با __return_false تست کنید: پرداخت، تغییر وضعیت، استرداد، و هر cron یا webhookی که سفارش را عوض می‌کند.
  5. بعد از چند هفته بدون مشکل، حالت سازگاری را خاموش کنید.

HPOS از اول قرار بود سفارش‌ها را از جدول پست‌ها جدا کند. sync on read فقط یک دوران گذار بود و آن دوران دارد تمام می‌شود. هرچه زودتر کدتان را به CRUD منتقل کنید، ارتقای بعدی ووکامرس آرام‌تر می‌گذرد.

منابع

$ ./request_review

همین مشکل را در فروشگاه خودتان دارید؟

توسعه‌دهنده ارشد WordPress و WooCommerce برای معماری، اتصال سیستم‌ها و حل مسائل پیچیده production.

درخواست بررسی فنی

دیدگاه‌ها

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *