حقل مخصص في صفحة الدفع ووكومرس بنظام البلوكات

نموذج دفع زجاجي تنضم إليه خانة جديدة مضيئة، يرمز لإضافة حقل مخصص في صفحة الدفع ووكومرس

ضفت كود لحقل جديد في صفحة الدفع، عملت تحديث للصفحة… ومفيش حاجة ظهرت. لا خطأ PHP، ولا تحذير، والكود شغال نظريًا. المشكلة غالبًا مش في الكود نفسه، المشكلة إن متجرك بقى يستخدم صفحة دفع تانية خالص.

الكلام هنا ينفع أي متجر ووكومرس، في مصر أو الخليج أو غيرهما، لأنه كود وليس بوابة دفع أو شحن. والنتيجة حقل يعمل من غير أي إضافة مدفوعة.

لماذا لا يظهر الحقل أصلًا؟

ووكومرس يقدّم اليوم صفحتين للدفع (Checkout) مختلفتين تمامًا في طريقة البناء. الصفحة الكلاسيكية تعتمد على الكود المختصر [woocommerce_checkout] وتقرأ الفلتر woocommerce_checkout_fields. أما بلوك صفحة الدفع (Checkout Block) فيبني الواجهة بالبلوكات ويرسل البيانات عبر واجهة المتجر البرمجية (Store API).

النتيجة أن أي كود مكتوب للصفحة الكلاسيكية، مثل هذا المثال الشائع، لا يسجّل شيئًا في صفحة البلوكات:

add_filter( 'woocommerce_checkout_fields', function ( $fields ) {
    $fields['billing']['purchase_order_reference'] = array(
        'type'     => 'text',
        'label'    => 'Purchase order reference',
        'required' => false,
    );

    return $fields;
} );

لن ينفعك تغيير الأولوية (priority) ولا إضافة CSS. هذا لا يعني أن كل خطّاف (Hook) في ووكومرس توقف عن العمل مع البلوكات، بل أن لكل جزء من الصفحة نقطة ربط خاصة به.

الخطوة الأولى: اعرف أي صفحة دفع يستخدم متجرك

قبل أي كود، افتح صفحة الدفع المعيّنة في المتجر من محرر ووردبريس:

  • إذا وجدت الكود المختصر [woocommerce_checkout] فأنت على الصفحة الكلاسيكية، وكود الفلتر القديم مناسب لك.
  • إذا وجدت بلوك Checkout وبداخله بلوكات فرعية للأقسام، فأنت على صفحة البلوكات، وتحتاج الطريقة التالية.
  • إذا كانت الصفحة مبنية بإضافة أخرى أو بباني صفحات يستبدل صفحة الدفع، فراجع متطلبات تلك الإضافة أولًا.

ملاحظة: قد يحتوي الموقع على أكثر من صفحة اسمها «Checkout». تأكد من الصفحة المعيّنة فعلًا من إعدادات ووكومرس قبل أن تختبر عليها.

الحل: واجهة الحقول الإضافية لصفحة الدفع

الطريقة المدعومة رسميًا هي واجهة الحقول الإضافية (Additional Checkout Fields API) عبر الدالة woocommerce_register_additional_checkout_field. بحسب المصدر، يحدد دليل ووكومرس الإصدار 8.9.0 حدًّا أدنى لهذه الواجهة، لكن هذا حد أدنى وليس توصية: استخدم إصدارًا مدعومًا حديثًا يتوافق مع موقعك.

المثال العملي هنا حقل اختياري لـ«رقم أمر الشراء» (Purchase Order) يستخدمه عملاء الشركات، بالمواصفات التالية:

الخاصيةالقيمة في المثال
مكان الظهورقسم Order Information (معلومات الطلب)
إلزامي؟لا، اختياري
قيمة صحيحةمثل PO-104
قاعدة التنسيقحتى 40 حرفًا لاتينيًا أو رقمًا أو شرطة
يُحفظ معالطلب نفسه، لا مع عنوان العميل

قاعدة الأربعين حرفًا قاعدة عمل خاصة بالمثال. عدّلها إذا كان عملاؤك يكتبون مسافات أو شرطات مائلة في أرقامهم.

ضع الكود في إضافة صغيرة

لا تضع كود صفحة الدفع في functions.php الخاص بالقالب الأب، لأن أول تحديث للقالب يمسحه. أنشئ مجلدًا باسم checkout-blocks-order-reference داخل wp-content/plugins/، وبداخله ملف checkout-blocks-order-reference.php يحتوي على:

<?php
/**
 * Plugin Name: Checkout Blocks Order Reference Example
 * Description: Add an optional purchase-order reference to Checkout Blocks.
 * Version: 1.0.0
 * Requires Plugins: woocommerce
 * Text Domain: swift-commerce-checkout-example
 */

defined( 'ABSPATH' ) || exit;

add_action(
    'woocommerce_init',
    'swift_commerce_example_register_order_reference'
);

function swift_commerce_example_register_order_reference() {
    if (
        ! function_exists(
            'woocommerce_register_additional_checkout_field'
        )
    ) {
        return;
    }

    woocommerce_register_additional_checkout_field(
        array(
            'id'       => 'swift-commerce-tutorial/order-reference',
            'label'    => __(
                'Purchase order reference',
                'swift-commerce-checkout-example'
            ),
            'location' => 'order',
            'type'     => 'text',
            'required' => false,
            'sanitize_callback' =>
                'swift_commerce_example_sanitize_order_reference',
            'validate_callback' =>
                'swift_commerce_example_validate_order_reference',
        )
    );
}

function swift_commerce_example_sanitize_order_reference( $value ) {
    return is_string( $value )
        ? trim( sanitize_text_field( $value ) )
        : '';
}

function swift_commerce_example_validate_order_reference( $value ) {
    if ( '' === $value ) {
        return true;
    }

    if ( ! preg_match( '/\A[A-Za-z0-9-]{1,40}\z/', $value ) ) {
        return new WP_Error(
            'swift_commerce_example_invalid_order_reference',
            __(
                'Use up to 40 letters, numbers or hyphens for the purchase order reference.',
                'swift-commerce-checkout-example'
            )
        );
    }

    return true;
}

بدّل البادئة swift_commerce_example ومعرّف الحقل باسم مشروعك قبل الإطلاق، فهي من مثال كاتب المقال الأصلي. ثم فعّل الإضافة من «الإضافات ← الإضافات المنصّبة»، وأضف منتجًا إلى السلة وافتح صفحة الدفع. ابحث عن الحقل في قسم معلومات الطلب، وليس داخل عنوان الفوترة.

بصراحة: هذا الشرح قراءة للكود والتوثيق كما ورد في المصدر، ولم نختبره على متجر حي. شغّله على نسخة تجريبية (Staging) مع وضع الاختبار في بوابة الدفع قبل نقله للمتجر الفعلي.

ثلاثة قرارات داخل الكود تستحق الفهم

لماذا التسجيل على woocommerce_init؟

يجب أن يتم التسجيل بعد تهيئة ووكومرس، وأن يكون متاحًا خارج صفحة الدفع المرئية أيضًا. صفحة البلوكات ترسل البيانات عبر Store API، فلو وضعت التسجيل داخل شرط if ( is_checkout() ) فلن يعمل أثناء الطلب الذي يعالج قيمة الحقل.

القاعدة ببساطة: سجّل تعريف الحقل دائمًا، واترك لووكومرس قرار مكان عرضه.

اختيار المكان ليس مسألة شكل

قيمة location تحدد أين يُحفظ الحقل وليس مكان ظهوره فقط. رقم أمر الشراء يخص طلبًا واحدًا، لذلك استخدم المثال:

'location' => 'order',

الواجهة توفر أيضًا contact للمعلومات المرتبطة بالعميل، وaddress للعناوين. انتبه هنا: address يطبّق الحقل على عنوان الفوترة والشحن معًا، وليس على الفوترة وحدها. والمكان order يضمن ألا يُنسخ رقم أمر شراء قديم تلقائيًا إلى طلب جديد.

التنظيف شيء والتحقق شيء آخر

دالة التنظيف تحوّل القيمة إلى نص سطر واحد بلا مسافات زائدة باستخدام trim( sanitize_text_field( $value ) ). ثم تأتي دالة التحقق لتفحص النتيجة بالتعبير /\A[A-Za-z0-9-]{1,40}\z/: القيمة الفارغة تمر لأن الحقل اختياري، وPO-104 يمر، وأي قيمة فيها مسافة أو تتجاوز 40 حرفًا تُرفض برسالة واضحة.

لا تعتمد على خصائص المتصفح أو JavaScript وحدها في هذا الفحص، فالتحقق من جهة الخادم ضروري. ولا تنسخ معالج نماذج قديمًا يقرأ $_POST مباشرة، لأن الدالة تستقبل القيمة من واجهة ووكومرس وليس من الطلب الخام.

الحفظ تلقائي، فلا تكتب معالجًا ثانيًا

لن تحتاج دالة تقرأ $_POST['purchase_order_reference'] وتحدّث بيانات الطلب يدويًا، فالواجهة تتولى الحفظ بنفسها. لاحظ أن معرّف الحقل هنا هو swift-commerce-tutorial/order-reference، وهو مختلف عن المفتاح القديم في كود الصفحة الكلاسيكية.

تحذير: ثبّت هذا المعرّف بعد الإطلاق. تغييره لاحقًا يُنشئ حقلًا جديدًا تمامًا، ولا ينقل القيم المحفوظة في الطلبات السابقة.

قراءة القيمة من الطلب

داخل مسار معالجة طلبات موجود ومصرّح به، تقرأ القيمة هكذا:

use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;

// $order_id comes from your existing, authorized order workflow.
$order = wc_get_order( $order_id );

if ( $order instanceof WC_Order ) {
    $checkout_fields = Package::container()->get(
        CheckoutFields::class
    );

    $reference = $checkout_fields->get_field_from_object(
        'swift-commerce-tutorial/order-reference',
        $order,
        'other'
    );

    if ( is_string( $reference ) && '' !== $reference ) {
        echo esc_html( $reference );
    }
}

ضع سطري use في أعلى ملف PHP خارج أي دالة، وشغّل الكود بعد تهيئة ووكومرس. المجموعة other هي المستخدمة مع الحقول التي مكانها order.

استخدام wc_get_order() بدل استعلام مباشر على جدول المقالات مهم للمتاجر التي فعّلت تخزين الطلبات عالي الأداء (HPOS). وهذا الكود لا يمنح صلاحية عرض الطلب: لو بنيت عليه صفحة للعميل أو نقطة API عامة، فتحقق من الصلاحية وملكية الطلب أولًا.

الحقل ما زال لا يظهر؟ راجع هذه القائمة

قبل تعديل الكود، تأكد من التالي:

  1. أنك تختبر صفحة الدفع المعيّنة في إعدادات ووكومرس وليس صفحة أخرى بالاسم نفسه.
  2. أن الصفحة تستخدم بلوك Checkout فعلًا، فهذا الكود لا يضيف الحقل للصفحة الكلاسيكية ولا لبانيات صفحات الدفع الخارجية.
  3. أن البلوك الفرعي Order Information موجود داخل بلوك الدفع ولم يُحذف من المحرر.
  4. أن الإضافة مفعّلة، وأن الدالة woocommerce_register_additional_checkout_field متاحة، وإلا فالشرط في الكود يخرج بصمت.
  5. أنه لا يوجد كود آخر يسجّل المعرّف نفسه. اترك تنفيذًا واحدًا فقط أثناء التصحيح.
  6. أنك لا تبحث عن الحقل في مكانه القديم داخل عنوان الفوترة.

اختبر ما بعد الظهور

ظهور الخانة أول اختبار وليس آخره. نفّذ هذه الحالات بطلبات تجريبية:

  • اترك الحقل فارغًا وتأكد أن الطلب يكتمل.
  • أدخل PO-104 وتحقق من القيمة المحفوظة في الطلب.
  • أدخل قيمة غير صالحة، ثم قيمة أطول من 40 حرفًا، وتأكد أن الطلب يتوقف برسالة مفهومة.
  • كرر التجربة بحساب عميل مسجّل، ثم كزائر إن كان متجرك يسمح بذلك.
  • تأكد أن طلبًا جديدًا لا يرث رقم أمر شراء من طلب سابق.

إذا كان فريقك يحتاج الرقم في الفاتورة أو ملف التصدير أو نظام الشحن، فاختبر هذا المخرج أيضًا. حفظ الحقل لا يربطه تلقائيًا بكل إضافة خارجية، ومنها إضافات الفواتير وشركات الشحن المحلية.

كود أم إضافة لإدارة الحقول؟

الكود أعلاه مجاني ولا يحتاج أي ترخيص، ويناسبك إذا كنت المطوّر الذي يدير المتجر ويريد حقلًا أو اثنين ثابتين. أما إذا كان صاحب المتجر سيضيف الحقول ويعدّلها بنفسه، فإضافة لتحرير حقول صفحة الدفع بواجهة إعدادات أنسب له، حتى لو كلّفت ترخيصًا سنويًا.

كاتب المقال الأصلي يطوّر إضافة من هذا النوع، ويذكر أنها لا تنقل كل إمكانات الصفحة الكلاسيكية إلى البلوكات. القاعدة نفسها تنطبق على أي إضافة تختارها: راجع أنواع الحقول المدعومة مع صفحة البلوكات قبل الشراء.

الأسئلة الشائعة

س: لماذا لا يعمل فلتر woocommerce_checkout_fields في صفحة الدفع الجديدة؟
ج: لأنه مخصص لصفحة الدفع الكلاسيكية. صفحة البلوكات تُبنى وتُرسل بياناتها بطريقة مختلفة، وتحتاج تسجيل الحقل عبر woocommerce_register_additional_checkout_field.

س: هل أرجع لصفحة الدفع الكلاسيكية بدل تعديل الكود؟
ج: ممكن إذا كانت إضافاتك الحالية كلها مبنية عليها، لكن صفحة البلوكات هي الاتجاه الذي يطوّره ووكومرس. الأفضل نقل الحقول بالطريقة المدعومة.

س: أين يظهر الحقل الجديد في صفحة الدفع؟
ج: حسب قيمة location: في قسم معلومات الطلب مع order، أو مع بيانات التواصل مع contact، أو في عنواني الفوترة والشحن معًا مع address.

س: هل أحتاج كودًا لحفظ قيمة الحقل في الطلب؟
ج: لا، الواجهة تحفظها تلقائيًا. تحتاج كودًا فقط لقراءتها وعرضها حيث تريد.

س: ما أقل إصدار من ووكومرس يدعم هذه الطريقة؟
ج: يذكر المصدر أن دليل ووكومرس يحدد 8.9.0 حدًّا أدنى، والأفضل العمل على إصدار حديث مدعوم.

الخلاصة

لو حقلك اختفى من صفحة الدفع، اسأل الأول: الصفحة كلاسيكية ولا بلوكات؟ في البلوكات، سجّل الحقل بالواجهة الإضافية، اختار مكانه صح، وسيب ووكومرس يحفظه. جرّب الكود على نسخة تجريبية النهارده قبل ما تنقله للمتجر.

مراجع إضافية: Additional Checkout Fields (WooCommerce Docs)

مرجع المقال (بالإنجليزية): Why Your Custom Checkout Fields Don’t Appear in WooCommerce Checkout Blocks
المقال ده مش ترجمة حرفية: متكيّف للقارئ العربي ومضاف عليه سياق ووردبريس وElementor وJetEngine.

اترك تعليقاً