إنتقل إلى المحتوى الرئيسي

أقسام الصفحة الرئيسية

تخطيط الصفحة الرئيسية هو القائمة المرتّبة للأقسام التي يعرضها المتجر في صفحته الرئيسية. لكل قسم نوع وإعدادات. يمكن إضافة عشرة أنواع في كل قالب: category-products وfeatured وcategories وbanner وimage-with-text وrich-text وtrust-badges وtestimonials وfaq وvideo. ويقدّم قالب مبني على الأقسام مثل atlas أيضاً hero وproduct-grid. يعطي types في استجابة GET إعدادات كل نوع. كل كتابة في هذه الصفحة تظهر في المتجر بمجرد أن تُرجع استجابتها.

هذه النقاط ليست GET /v1/store/home-sections التي تقرأ مفاتيح الصفحة الرئيسية في قوالب Digital وAriana وPrestige.

قبل أن تبدأ​

  • تحتاج GET إلى store:read، وتحتاج الكتابات إلى store:write. مفاتيح التاجر تحمل الاثنتين.
  • تحتاج POST وPATCH وDELETE إلى Idempotency-Key. وهو اختياري مع PUT. انظر Idempotency.
  • رقم الفئة يأتي من GET /v1/categories التي تحتاج إلى products:read.

كائن القسم​

الحقلالنوعملاحظات
idintثابت ما دام القسم موجوداً. القسم الذي يعود بالتراجع يأخذ رقماً جديداً.
typestringإحدى قيم type المذكورة في types ضمن GET /v1/store/home-layout.
settingsobjectكل إعدادات النوع، والقيم الافتراضية مملوءة.
is_activeboolfalse تُخفي القسم عن الزبائن وتُبقيه في القائمة.
availableboolfalse عندما لا يعود قالب المتجر يملك هذا النوع. يبقى القسم كما خُزّن، ويمكن لأي كتابة أن تُبقيه.

إعدادات category-products​

الإعدادالنوعالافتراضيالقواعد
categoryرقم فئة0فئة من هذا المتجر. 0 تعني بلا فئة، وعندها لا يعرض القسم شيئاً للزبائن. رقم فئة من متجر آخر يُرجع 422 invalid_settings.
titletext""حتى 80 حرفاً، ويُزال منه HTML. الفارغ يُظهر اسم الفئة.
countrange8من 4 إلى 12. الرقم خارج هذا المجال يُنقل إلى أقرب حدّ.
layoutselectgridgrid أو slider.
show_view_allcheckboxtrueرابط إلى صفحة الفئة.

الفئة التي لا منتجات فيها لا تعرض شيئاً للزبائن كذلك. اقرأ قواعد أي نوع من settings_schema الخاص به بدل كتابتها في برنامجك: قائمة الأنواع تتبع قالب المتجر.

صيغ الإعدادات​

نوع الإعدادالقيمة المقبولة
categoryرقم من GET /v1/categories، أو 0 لعدم الاختيار.
link#anchor، أو مسار /path داخل المتجر، أو عنوان http:// أو https://، أو رابط tel: أو mailto:، حتى 500 حرف، أو "". العنوان المرسل بلا بادئته، مثل wa.me/213...، يُحفظ مع https:// في أوله.
youtubeرابط فيديو YouTube أو معرّفه ذو 11 حرفاً. يُحفظ المعرّف.
imageمسار صورة رُفعت من لوحة التحكم لهذا المتجر، /uploads/banners/{store_id}/...، أو "". لا يمكن رفع الصور عبر الواجهة البرمجية حالياً: يرفع التاجر الصورة أولاً من إعدادات القسم في لوحة التحكم، ثم تُرجع GET مسارها.

متى يرى الزبائن القسم​

القسم الذي لم يُملأ محتواه بعد يُخزَّن وتُرجع الكتابة 2xx، لكن الزبائن لا يرونه حتى يُملأ:

النوعيراه الزبائن عندما
category-productsتكون category فئة من المتجر فيها منتجات.
featuredتكون في source المختار منتجات.
categoriesتكون في المتجر فئة فيها منتجات، أو أي فئة عندما تكون show_empty بقيمة true.
bannerتُملأ image.
image-with-textتُملأ image مع title أو text.
rich-textيُملأ title أو text.
trust-badgesدائماً. الشارتان 1 و2 الفارغتان تُظهران سطري التوصيل والدفع عند الاستلام الافتراضيين.
testimonialsيُملأ tN_text واحد على الأقل.
faqيُملأ qN واحد على الأقل مع aN الخاص به.
videoتحمل video معرّف فيديو YouTube.

لا تتغيّر rendered لهذا السبب: فهي تقول إن كان القالب يعرض الأقسام المخزّنة، لا إن كان قسم بعينه ظاهراً. في قالب مبني على الأقسام (atlas) لا تحلّ الأقسام المحفوظة محل الصفحة الرئيسية للقالب إلا ما دامت تتضمن قسم product-grid ظاهراً، وتبقى rendered بقيمة false حتى ذلك الحين؛ وقبل ذلك يرى الزبائن الصفحة الأصلية للقالب، ولا تعرض GET إلا الأقسام المحفوظة، لا أقسام القالب نفسه.

GET /v1/store/home-layout​

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

المصادقة: مفتاح منصة بصلاحية store:read.

الطلب​

curl 'https://api.dzbuild.app/v1/store/home-layout' \
-H "Authorization: Bearer $DZ_KEY"

الاستجابة 200​

{
"data": {
"theme": "starter",
"rendered": true,
"max_sections": 25,
"cap": 25,
"version": "9c1e04b7a2d35f68",
"sections": [
{
"id": 412,
"type": "category-products",
"settings": {
"category": 57,
"title": "",
"count": 8,
"layout": "grid",
"show_view_all": true
},
"is_active": true,
"available": true
},
{
"id": 415,
"type": "category-products",
"settings": {
"category": 61,
"title": "Nos parfums",
"count": 10,
"layout": "slider",
"show_view_all": false
},
"is_active": false,
"available": true
}
],
"types": [
{
"type": "category-products",
"name": {"ar": "منتجات فئة", "fr": "Produits d'une catégorie"},
"description": {"ar": "اعرض منتجات فئة واحدة في شبكة أو شريط تمرير.", "fr": "Affichez les produits d'une catégorie en grille ou en carrousel."},
"icon": "bi-grid-3x3-gap",
"limit": 12,
"settings_schema": [
{"id": "category", "type": "category", "default": 0, "label": {"ar": "الفئة", "fr": "Catégorie"}},
{"id": "title", "type": "text", "max": 80, "default": "", "label": {"ar": "العنوان (إذا تركته فارغاً يظهر اسم الفئة)", "fr": "Titre (si vide, le nom de la catégorie s'affiche)"}},
{"id": "count", "type": "range", "min": 4, "max": 12, "default": 8, "label": {"ar": "عدد المنتجات", "fr": "Nombre de produits"}},
{"id": "layout", "type": "select", "options": ["grid", "slider"], "default": "grid", "label": {"ar": "طريقة العرض", "fr": "Affichage"}, "option_labels": {"ar": ["شبكة", "شريط تمرير"], "fr": ["Grille", "Carrousel"]}},
{"id": "show_view_all", "type": "checkbox", "default": true, "label": {"ar": "زر عرض الكل", "fr": "Lien « Voir tout »"}}
]
}
]
},
"meta": {"request_id": "8f2c1a9d4b7e6035", "api_version": "v1"}
}
الحقلالمعنى
themeمفتاح قالب المتجر.
renderedfalse عندما لا يعرض قالب المتجر الحالي أقسام الصفحة الرئيسية. تبقى الأقسام محفوظة وتظهر من جديد مع قالب يعرضها. وفي قالب مبني على الأقسام لا تكون true إلا ما دام قسم product-grid ظاهر محفوظاً.
max_sections25، أقصى عدد من الأقسام تحمله صفحة رئيسية واحدة.
capعدد الأقسام الذي تسمح به خطة المتجر: 3 في الخطة المجانية أو خطة منتهية، و25 ابتداءً من Pro.
versionبصمة التخطيط المخزَّن. أرسلها في version مع PUT لرفض تخطيط تغيّر منذ هذه القراءة.
sectionsالأقسام بترتيب عرضها، ومعها الأقسام المخفية.
typesالأنواع التي يمكن إضافتها في هذا القالب، مع name وdescription وicon وlimit (أقصى عدد من أقسام هذا النوع في الصفحة) وsettings_schema. يعرض المثال أعلاه نوعاً واحداً منها.

القراءة بعد الكتابة​

عبر api.dzbuild.app تُخزَّن استجابة GET الناجحة 30 ثانية لكل مفتاح وسلسلة استعلام (ترويسة X-Cache: HIT|MISS تخبرك بالحالة). لذلك قد تُرجع GET المرسلة مباشرة بعد كتابة التخطيطَ السابق لها. استعمل التخطيط الموجود في استجابة الكتابة: كل كتابة تُرجع القائمة كاملة بترتيب العرض مع version الجديدة. وإن احتجت إلى قراءة جديدة، أضف سلسلة استعلام من عندك، مثل ?fresh=1727520000.

POST /v1/store/home-layout/sections​

يضيف قسماً واحداً.

المصادقة: مفتاح منصة بصلاحية store:write. يتطلب Idempotency-Key.

الجسم​

الحقلالنوعإلزاميملاحظات
typestringنعمقيمة type من types.
settingsobjectلاالإعدادات التي لا ترسلها تأخذ القيم الافتراضية للنوع.
positionintلا0 يضع القسم في الأعلى، و24 آخر مكان. بدونه يُضاف القسم في النهاية.

الطلب​

curl -X POST 'https://api.dzbuild.app/v1/store/home-layout/sections' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-add-sacs-1" \
-d '{"type": "category-products", "settings": {"category": 64, "layout": "slider"}, "position": 0}'

الاستجابة 201​

{
"data": {
"section": {
"id": 418,
"type": "category-products",
"settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true},
"is_active": true,
"available": true
},
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},
{"id": 412, "type": "category-products", "settings": {"category": 57, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 10, "layout": "slider", "show_view_all": false}, "is_active": false, "available": true}
],
"version": "e27a90c4b1f36d05",
"change_id": 90231,
"rendered": true
},
"meta": {"request_id": "3b7d0e5a9c14f862", "api_version": "v1"}
}

PATCH /v1/store/home-layout/sections/{id}​

يغيّر قسماً واحداً. الإعدادات التي ترسلها تُدمج فوق الإعدادات المخزّنة. أرسل settings أو is_active أو كليهما.

المصادقة: مفتاح منصة بصلاحية store:write. يتطلب Idempotency-Key.

الجسم​

الحقلالنوعإلزاميملاحظات
settingsobjectلاتُدمج فوق الإعدادات المخزّنة.
is_activeboolلاfalse تُخفي القسم، وtrue تُظهره.
replaceboolلامع settings، القيمة true تُرجع كل إعداد لا ترسله إلى قيمته الافتراضية.

الطلب​

curl -X PATCH 'https://api.dzbuild.app/v1/store/home-layout/sections/415' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-415-show-1" \
-d '{"settings": {"count": 6}, "is_active": true}'

الاستجابة 200​

للاستجابة الحقول نفسها التي لاستجابة POST: section (القسم بعد التغيير)، وsections، وversion، وchange_id، وrendered.

{
"data": {
"section": {
"id": 415,
"type": "category-products",
"settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false},
"is_active": true,
"available": true
},
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},
{"id": 412, "type": "category-products", "settings": {"category": 57, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}, "is_active": true, "available": true}
],
"version": "51d8c3e06fa2b974",
"change_id": 90232,
"rendered": true
},
"meta": {"request_id": "c90a6e1f2d7b4538", "api_version": "v1"}
}

DELETE /v1/store/home-layout/sections/{id}​

يحذف قسماً واحداً.

المصادقة: مفتاح منصة بصلاحية store:write. يتطلب Idempotency-Key.

الطلب​

curl -X DELETE 'https://api.dzbuild.app/v1/store/home-layout/sections/412' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: hs-del-412-1"

الاستجابة 200​

{
"data": {
"deleted": true,
"id": 412,
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}, "is_active": true, "available": true}
],
"version": "0f6b2d9e84a1c357",
"change_id": 90233,
"rendered": true
},
"meta": {"request_id": "71e4b08c3a5d9f26", "api_version": "v1"}
}

POST /v1/store/home-layout/reorder​

يحدّد ترتيب العرض. تذكر ids كل أقسام الصفحة مرة واحدة بالضبط، ومعها الأقسام المخفية.

المصادقة: مفتاح منصة بصلاحية store:write. يتطلب Idempotency-Key.

الطلب​

curl -X POST 'https://api.dzbuild.app/v1/store/home-layout/reorder' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-order-2" \
-d '{"ids": [415, 418]}'

الاستجابة 200​

تحمل الاستجابة sections بالترتيب الجديد، وversion، وchange_id، وrendered. الرقم الذي ليس في الصفحة يُرجع 404 section_not_found. والرقم الناقص أو المكرر يُرجع 422 invalid_order.

PUT /v1/store/home-layout​

يستبدل التخطيط كله بالقائمة التي ترسلها، بترتيبها.

المصادقة: مفتاح منصة بصلاحية store:write. Idempotency-Key اختياري.

الجسم​

الحقلالنوعإلزاميملاحظات
sectionsarrayنعم25 عنصراً على الأكثر، كل عنصر {id?, type, settings?, is_active?}. القائمة الفارغة تحذف كل الأقسام.
versionstringلاقيمة version من آخر قراءة لك. إذا تغيّر التخطيط منذها، يُرجع النداء 409 write_conflict مع sections وversion الحاليتين ولا يكتب شيئاً.

كيف يُقرأ كل عنصر:

  • العنصر الذي يحمل id يُبقي ذلك القسم. ويجب أن يكون type هو النوع الحالي للقسم.
  • العنصر الذي بلا id ينشئ قسماً.
  • كل قسم في الصفحة غير موجود في القائمة يُحذف.
  • settings هو الكائن كاملاً: الإعداد الذي تتركه يعود إلى قيمته الافتراضية. أرسل الإعدادات كاملة لكل قسم تُبقيه.
  • قيمة is_active الافتراضية true.

الطلب​

curl -X PUT 'https://api.dzbuild.app/v1/store/home-layout' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-replace-7" \
-d '{
"version": "0f6b2d9e84a1c357",
"sections": [
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}},
{"type": "category-products", "settings": {"category": 57}}
]
}'

الاستجابة 200​

تحمل الاستجابة sections وversion وchange_id وrendered. القسم 418 لم يُرسل، لذلك يُحذف. وإعادة إرسال التخطيط الذي قرأته كما هو تُرجع change_id: null.

مع Idempotency-Key، إعادة المحاولة بالمفتاح نفسه والجسم نفسه تُرجع الاستجابة المخزّنة لمدة 24 ساعة مع Idempotency-Replay: 1، والمفتاح نفسه مع جسم آخر يُرجع 422 idempotency_key_reuse. وبدون مفتاح يُنفَّذ النداء في كل مرة، وهذا آمن: إرسال القائمة نفسها مرتين يترك التخطيط نفسه.

التراجع​

كل كتابة تُرجع change_id، أو null عندما لا تغيّر شيئاً. يُرجع POST /v1/changes/{change_id}/undo الصفحة الرئيسية كلها كما كانت قبل ذلك التغيير.

  • يمكن التراجع عن إضافة قسم أيضاً: التراجع يزيله. في الموارد الأخرى يرفض التراجع أي تغيير أنشأ شيئاً.
  • إذا تغيّرت الصفحة الرئيسية بعد ذلك التغيير، عبر الواجهة البرمجية أو من لوحة التحكم، يُرجع التراجع 409 layout_changed ولا يكتب شيئاً. اقرأ التخطيط واكتب ما تريده مباشرة.
  • القسم الذي يعود بعد حذفه يأخذ رقماً جديداً.
  • التراجع نفسه يُسجَّل تغييراً مستقلاً، undo_change_id، ويمكنك التراجع عنه بدوره. التراجع عن تراجعٍ عن حذف يُرجع 409 layout_changed، لأن القسم عاد برقم جديد.
  • التغييرات التي يحفظها التاجر من لوحة التحكم لا تُسجَّل، فلا يمكن التراجع عنها عبر الواجهة البرمجية.
  • يعرض GET /v1/changes?entity=store.home_layout تغييرات تخطيط الصفحة الرئيسية، الأحدث أولاً، بصلاحية store:read.
  • لا تحمل استجابة التراجع التخطيط. اقرأه مع سلسلة استعلام من عندك، مثل ?fresh=<unix time>، حتى لا يُرجع التخزين المؤقت لمدة 30 ثانية التخطيطَ السابق للتراجع.

يحتاج التراجع إلى store:write وإلى Idempotency-Key.

curl -X POST 'https://api.dzbuild.app/v1/changes/90231/undo' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: undo-90231"
{
"data": {
"undone": true,
"change_id": 90231,
"entity": "store.home_layout",
"undo_change_id": 90240
},
"meta": {"request_id": "5ad2f7c01e9b8634", "api_version": "v1"}
}

التغيير الذي تتراجع عنه مرة ثانية يُرجع 409 already_undone.

الأخطاء​

HTTPالرمزالسبب
400bad_requestالجسم ليس كائن JSON، أو حقل من نوع خاطئ (type غائب، أو settings ليس كائناً، أو is_active ليس قيمة منطقية، أو position خارج 0 إلى 24، أو ids ليس مصفوفة من أرقام الأقسام، أو version ليس نصاً)، أو رقم القسم في المسار ليس رقماً موجباً، أو Idempotency-Key غائب أو غير صالح مع POST أو PATCH أو DELETE.
401unauthorizedمفتاح خاطئ أو غائب.
402quota_exceededانتهت حصة الطلبات الشهرية للمتجر. انظر حدود المعدل.
403forbiddenMissing scope: store:read أو Missing scope: store:write.
403plan_requiredالكتابة تترك أقساماً أكثر مما تسمح به الخطة. يحمل الخطأ plan وcap.
404section_not_foundلا يوجد قسم بهذا الرقم في الصفحة.
409write_conflictوصلت كتابة أخرى قبلك، أو version المرسلة مع PUT ليست الحالية. عندما يحمل الخطأ sections وversion فهما التخطيط الحالي: أعد المحاولة انطلاقاً منهما. وإلا فاقرأ التخطيط وأعد المحاولة.
409layout_changedللتراجع فقط: تغيّرت الصفحة الرئيسية بعد هذا التغيير.
409already_undoneللتراجع فقط: سبق التراجع عن هذا التغيير.
413payload_too_largeالجسم أكبر من 1 ميغابايت.
422invalid_settingsرُفضت قيمة. تذكر fields كل إعداد مرفوض في القسم، مثل settings.category. ومع PUT تذكر إعدادات أول قسم مرفوض فقط، مثل sections.2.settings.layout، وتشمل أيضاً id ليس في الصفحة (sections.N.id) وقسماً مُبقى أُرسل بنوع آخر (sections.N.type). وتذكر message المسارات أيضاً.
422invalid_section_typeالنوع غير موجود أو لا يمكن إضافته في هذا القالب. تعطي fields المسار.
422limit_reachedأكثر من 25 قسماً، أو أكثر من limit لنوع واحد. يحمل الخطأ limit، إلا عندما ترسل PUT أكثر من 25 عنصراً.
422invalid_orderids في إعادة الترتيب ينقصها قسم أو تكرر قسماً.
422no_changesPATCH بلا settings ولا is_active.
422idempotency_key_reuseاستُعمل Idempotency-Key نفسه مع جسم آخر.
429rate_limitedطلبات كثيرة، ومنها أكثر من 30 كتابة على تخطيط الصفحة الرئيسية في الدقيقة للمتجر. انتظر المدة في Retry-After.
429too_many_concurrentأكثر من 5 كتابات على تخطيط الصفحة الرئيسية تعمل في الوقت نفسه للمتجر. أعد المحاولة بعد ثوانٍ.
500server_errorفشل الطلب. أعد المحاولة بالـ Idempotency-Key نفسه.

هكذا تبدو استجابة invalid_settings.

{
"error": {
"code": "invalid_settings",
"message": "Invalid value at settings.category: category not found in this store; accepted values are in settings_schema of GET /v1/store/home-layout",
"fields": [{"path": "settings.category", "code": "invalid"}]
},
"meta": {"request_id": "e4c19a0b7d2f5836", "api_version": "v1"}
}

الحدود​

  • 25 قسماً في الصفحة الرئيسية (max_sections).
  • حدّ الخطة (cap): 3 أقسام في الخطة المجانية أو خطة منتهية، و25 ابتداءً من Pro. الأقسام المخفية تُحسب. المتجر الذي تجاوز حدّه بعد نزول خطته يُبقي أقسامه ويستطيع تعديلها وإخفاءها وترتيبها وحذفها. الكتابة التي تترك أقساماً أكثر من الحدّ وأكثر مما كانت تُرجع 403 plan_required.
  • لكل نوع: لكل نوع limit في types، وهو 12 لـ category-products.
  • الإعدادات: 8 كيلوبايت لكل قسم بعد الترميز. النص الأطول يُقصّ عند max الخاص بالإعداد.
  • الجسم: 1 ميغابايت.
  • الكتابات: 30 في الدقيقة و5 في الوقت نفسه لكل متجر، فوق حدّ المتجر في الدقيقة. انظر حدود المعدل.