فيه نوع من الأعطال بيضيّع يوم كامل من عمرك: النموذج بيتبعت، والـ API بيرد بنجاح، والسجل بيتعمل في نظام إدارة العملاء — وبعدين تفتح السجل تلاقي اسم الشركة متحطّ في خانة المسمى الوظيفي. مفيش رسالة خطأ واحدة تقولك إن فيه حاجة غلط. المشكلة دي مالهاش علاقة بالاتصال، دي مشكلة ربط حقول.
رمز 200 لا يعني أن البيانات صحيحة
عند تشخيص أي تكامل، يبدأ أغلب المطورين من رد الـ API:
POST /api/contacts
200 OK
يبدو كل شيء سليماً. لكن رمز الحالة 200 يخبرك بأمر واحد فقط: أن واجهة برمجة التطبيقات (API) قبِلت الطلب. لا يخبرك إطلاقاً بأن القيم ذهبت إلى الحقول التي قصدتها.
خذ نموذجاً بسيطاً في Contact Form 7، وهي أشهر إضافة نماذج في ووردبريس:
[text* customer-name]
[email* customer-email]
[tel customer-phone]
[text company]
[select inquiry-type "Sales" "Support" "Partnership"]
البيانات المرسلة ستبدو هكذا:
{
"customer-name": "John Smith",
"customer-email": "john@example.com",
"customer-phone": "+1 555 123 4567",
"company": "Example Inc",
"inquiry-type": "Sales"
}
بينما الـ API قد يتوقع شيئاً مختلفاً تماماً:
{
"name": "John Smith",
"email": "john@example.com",
"phone": "+1 555 123 4567",
"organization": "Example Inc",
"lead_source": "website"
}
أسماء حقول النموذج وأسماء حقول الـ API ليست الشيء نفسه، ولا يوجد ما يجعلها كذلك تلقائياً. المسافة بينهما هي ما نسميه طبقة ربط الحقول (Field Mapping).
ربط الحقول طبقة ترجمة، لا خطوة إعداد
أفضل طريقة لتشخيص هذه الأعطال هي التفكير في المسار كطبقات منفصلة، كل واحدة منها يمكن أن تفسد وحدها:
- Contact Form 7 يجمع المدخلات.
- بيانات النموذج المُرسَلة تخرج بأسماء حقول النموذج.
- طبقة الربط والتحويل تترجم الأسماء والأنواع.
- حمولة الـ API (Payload) تُبنى بالشكل المتوقع.
- نظام إدارة العملاء (CRM) يستقبل ويخزّن.
عطل في أي نقطة ينتج بيانات فاسدة في النهاية. والخطأ الشائع أن يبدأ المطور بتشخيص الطبقة الرابعة بينما العطل في الثالثة.
المثال الأوضح: حقل اسمه company في النموذج، اسمه organization في الـ API، واسمه الظاهر في واجهة الـ CRM هو «Company Name». القيمة واحدة والمعرّفات ثلاثة. بدون ترجمة صريحة من company إلى organization، قد يتجاهل الـ API القيمة، أو يضعها في مكان غير متوقع، أو يرفض الطلب كله.
ابدأ بجدول ربط قبل أن تكتب سطراً واحداً
قبل تعديل الكود، وقبل الشك في المصادقة، اصنع جدولاً بسيطاً:
| حقل Contact Form 7 | حقل الـ API | الحقل في الـ CRM |
|---|---|---|
customer-name | name | Name |
customer-email | email | |
customer-phone | phone | Phone |
company | organization | Company |
inquiry-type | lead_source | Lead Source |
هذا الجدول يكشف التعارضات فوراً، ويمنع الخطأ الأكثر تكراراً: افتراض أن الاسم الظاهر في واجهة الـ CRM هو نفسه اسم الخاصية في الـ API. الاسم الظاهر مصمم لموظف المبيعات، والمعرّف البرمجي مصمم للآلة، والتكامل يحتاج الثاني.
ملاحظة: احتفظ بهذا الجدول في ملف داخل المشروع أو في توثيق العميل. بعد ستة أشهر، عندما يطلب العميل إضافة حقل، سيوفّر عليك ساعتين من إعادة الاكتشاف.
الأنواع تكسر التكامل بصمت
ربط الحقول ليس مسألة أسماء فقط. نوع القيمة لا يقل خطورة.
نموذجك يرسل النص Yes بينما الـ API يتوقع القيمة المنطقية true. أو يرسل Sales بينما الـ CRM يتوقع معرّفاً رقمياً مثل 123. القيمة تبدو صحيحة لعين الإنسان وهي غير صالحة للنظام.
أكثر الحالات تكراراً:
- نص مقابل معرّف رقمي.
"true"مقابلtrueو"false"مقابلfalse.- نص تاريخ مقابل طابع زمني (Timestamp).
- الاسم الظاهر للخيار مقابل معرّفه الداخلي.
- قيمة مفردة مقابل مصفوفة.
- نص فارغ مقابل
null.
القوائم المنسدلة هي المصدر الأول لهذه الأعطال. قائمة مثل:
[select* department "Sales" "Support" "Billing"]
قد لا يقبلها الـ CRM بهذه الصيغة إطلاقاً، بل يطلب { "department_id": 42 }. فالربط هنا ليس department → department، بل جدول قيم كامل.
تنبيه للمواقع العربية: عندما تكون خيارات القائمة بالعربية («مبيعات»، «دعم فني»)، لا ترسلها كما هي أبداً. اربطها بمعرّفات رقمية، وإلا فأنت تبني تكاملاً يعتمد على تطابق نصي عربي حرفاً بحرف — وأول مرة يعدّل فيها أحدهم مسافة في خيار القائمة، ينكسر كل شيء بصمت.
كود عملي: الربط والتسجيل في مكان واحد
هذا مثال متكامل يربط Contact Form 7 بأي API، ويطبّق النقاط السابقة كلها:
add_action( 'wpcf7_mail_sent', function ( $contact_form ) {
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return;
}
$data = $submission->get_posted_data();
$payload = array(
'name' => $data['customer-name'] ?? '',
'email' => $data['customer-email'] ?? '',
'phone' => acms_normalize_phone( $data['customer-phone'] ?? '' ),
'organization' => $data['company'] ?? '',
'lead_source' => 'website',
'department_id' => acms_map_department( $data['department'] ?? '' ),
);
// Log the exact payload before sending, then compare it with the CRM record.
error_log( 'CRM payload: ' . wp_json_encode( $payload, JSON_UNESCAPED_UNICODE ) );
wp_remote_post( 'https://crm.example.com/api/contacts', array(
'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
'body' => wp_json_encode( $payload, JSON_UNESCAPED_UNICODE ),
'timeout' => 15,
) );
} );
ودالة ترجمة القيم، وهي الجزء الذي يُنسى غالباً:
/**
* Translate a visible dropdown label into the CRM option ID.
* Returning null is safer than sending an unrecognised string.
*/
function acms_map_department( $label ) {
$map = array(
'Sales' => 42,
'Support' => 43,
'Billing' => 44,
);
return $map[ $label ] ?? null;
}
ودالة توحيد أرقام الهواتف، وهي ضرورة في السوق المصري والخليجي لأن الزائر يكتب رقمه بخمس صيغ مختلفة:
/**
* Normalise a phone number to E.164. Local numbers starting with 0
* are treated as Egyptian (+20). Adjust the prefix per market.
*/
function acms_normalize_phone( $raw ) {
$digits = preg_replace( '/D+/', '', $raw );
if ( '' === $digits ) {
return '';
}
if ( 0 === strpos( $digits, '0' ) ) {
$digits = '20' . substr( $digits, 1 );
}
return '+' . $digits;
}
الخيار JSON_UNESCAPED_UNICODE في السطرين أعلاه ليس تفصيلاً جمالياً. بدونه يتحول الاسم العربي إلى تسلسلات مثل أحمد، وبعض أنظمة إدارة العملاء تخزّنها كما هي فيرى فريق المبيعات رموزاً بدل الأسماء.
تسلسل التشخيص الصحيح
أكبر مضيعة للوقت في تكاملات الـ API هي تشخيص الاتصال بينما الاتصال ليس هو المشكلة. اتبع هذا الترتيب ولا تقفز خطوة:
- هل أُرسل النموذج فعلاً؟
- هل استُدعي الـ API أو الويب هوك (Webhook)؟
- ما الحمولة التي أُرسلت بالضبط؟
- هل قَبِل الـ API الطلب؟
- ما الحقول التي عالجها الـ API فعلياً؟
- ما القيم التي ظهرت في الـ CRM؟
الفارق بين الخطوة الثالثة والخطوة السادسة هو موضع العطل دائماً. إن كانت الحمولة خاطئة أصلاً، فالمشكلة بين النموذج وبناء الطلب. وإن كانت الحمولة صحيحة والسجل خاطئاً، فالمشكلة في تعريفات الحقول أو التحويلات داخل الـ CRM نفسه.
في JetEngine: إن كنت تستخدم JetFormBuilder بدل Contact Form 7، فالمنطق نفسه ينطبق على إجراء Webhook أو Call Hook. الفرق أن الربط يُضبط من الواجهة، وهذا يخفي طبقة الترجمة بدل أن يلغيها — لذا سجّل الحمولة قبل الإرسال بنفس الطريقة، ولا تفترض أن الواجهة تعرف ما يتوقعه الـ API.
الخلاصة
للتكامل الناجح تعريفان مختلفان: تعريف تقني يعني أن الطلب أُرسل وقُبِل، وتعريف تشغيلي يعني أن فريق المبيعات فتح السجل ووجد بيانات يستطيع استخدامها. الثاني وحده هو المهم.
عامل طبقة ربط الحقول على إنها ترجمة مقصودة بتكتبها بإيدك، مش حاجة بتحصل لوحدها. اعمل جدول الربط الأول، سجّل الحمولة قبل ما تبعتها، وبعدين قارن. هتلاقي العطل في دقايق بدل يوم كامل.
المصدر الأصلي: Why Your Contact Form Submissions Are Ruining Your CRM Data (And How to Fix Field Mapping) — https://dev.to/rahul_sharma_15bd129bc69e/why-your-contact-form-submissions-are-ruining-your-crm-data-and-how-to-fix-field-mapping-3n3o
اقرأ أيضًا
الأسئلة الشائعة
النموذج يرسل ورد الـ API ناجح، فلماذا البيانات خاطئة في الـ CRM؟
لأن رمز 200 يعني أن الطلب قُبل شكلاً، لا أن القيم وُضعت في الحقول التي قصدتها. أسماء حقول النموذج لا تطابق تلقائياً أسماء حقول الـ API، والفجوة بينهما هي طبقة ربط الحقول.
ما الفرق بين اسم الحقل الظاهر في الـ CRM واسمه في الـ API؟
الاسم الظاهر مصمم للبشر مثل «Company Name»، بينما الـ API يتوقع معرّفاً برمجياً مثل organization. الاعتماد على الاسم الظاهر من أكثر أسباب فشل التكاملات شيوعاً.
كيف أتحقق مما أرسله موقعي فعلاً؟
سجّل الحمولة المرسلة قبل الإرسال مباشرة باستخدام error_log() أو إضافة سجلات، ثم قارنها بسجل الـ CRM. إن كانت الحمولة خاطئة فالمشكلة قبل الـ API، وإن كانت صحيحة فالمشكلة في تعريفات الحقول داخل الـ CRM.
لماذا تظهر الأسماء العربية كرموز غريبة في نظام إدارة العملاء؟
غالباً لأن الحمولة رُمِّزت بـ json_encode دون الخيار JSON_UNESCAPED_UNICODE، فتتحول الحروف العربية إلى تسلسلات أ. بعض الأنظمة تفك هذا الترميز وبعضها يخزنه كما هو.
هل تنطبق نفس القواعد على JetFormBuilder و WPForms؟
نعم تماماً. آلية الاستدعاء تختلف لكن المشكلة واحدة: ترجمة أسماء الحقول وأنواع القيم بين النموذج والـ API. جدول الربط والتسجيل قبل الإرسال يعملان مع أي أداة نماذج.



