
Jinja في ثيمات زد: القوالب والـ Objects والفلاتر والأنماط التي ستستخدمها يوميًا
كيف تستخدم ثيمات Vitrin لغة Jinja: بنية الملفات، والوراثة والتضمين، والـ Objects والدوال الموثّقة، وحلقات المنتجات، والترجمة، والعلامات التجارية، وإعداد حقل الكوبون.
أين تعيش Jinja داخل الثيم؟
ثيمات زد مبنية على محرك القوالب Jinja، وله صيغتان: {{ ... }} لعرض قيمة، و{% ... %} للمنطق والحلقات وبنية القالب. تدعم زد فلاتر Jinja الأساسية، وتضيف فوقها مجموعة صغيرة من الوسوم والفلاتر والماكروهات الخاصة بالمنصة. وهذه بنية المجلدات المطلوبة:
├── locale/ar/LC_MESSAGES/messages.po
├── assets/
├── sections/
│ ├── slider.jinja
│ └── slider.schema.json
├── components/
│ └── pagination.jinja
├── templates/
│ ├── home.jinja
│ ├── cart.jinja
│ └── product.jinja
├── layout.jinja
├── layout.schema.json
├── footer.jinja
├── footer.schema.json
├── header.jinja
└── header.schema.json- أسماء القوالب والـLayout ومساراتها يجب أن تكون بالأسماء التي يعرفها النظام (مثل
home.jinjaوproduct.jinjaوcart.jinja)، أما الأقسام والمكوّنات فتسميها كما تشاء. - كل قسم
.jinjaيحتاج ملف.schema.jsonمقابلًا له في المجلد نفسه، والـLayout والرأس والتذييل تحتاجlayout.schema.jsonوheader.schema.jsonوfooter.schema.jsonفي جذر الثيم. - الأصول في
assets/، وتُعطى بصمة وتُقدَّم عبر CDN زد.
الوراثة والكتل والتضمين
كل قالب يمتد من layout.jinja ويملأ كتلة المحتوى؛ أمثلة مكتبة القوالب تستخدم الكتلة main_content. هذا مقتطف من مثال product.jinja في التوثيق:
{% extends "layout.jinja" %}
{% block main_content %}
<h1>{{ product.name }}</h1>
<div class="price">
{% if product.selected_product.formatted_sale_price %}
<span>{{ product.selected_product.formatted_sale_price }}</span>
<del>{{ product.selected_product.formatted_price }}</del>
{% else %}
{{ product.selected_product.formatted_price }}
{% endif %}
</div>
{{ product.description | safe }}
{% include 'vitrin:products/variants_list.jinja' %}
{% include 'vitrin:shared/bank_discounts.jinja' %}
{% endblock %}includeيُدرج قالبًا آخر وقت العرض، مثلcomponents/pagination.jinja. ولتمرير سياق محلي صغير:{% with a=1 %}{% include 'x' %}{% endwith %}.- القوالب التي تديرها المنصة تُضمَّن بالبادئة
vitrin:، مثلvitrin:products/variants_list.jinjaوvitrin:cart/products_list.jinja. - في الصفحة الرئيسية، الوسم
{% template_components %}يعرض الأقسام التي يرتّبها التاجر في محرر الثيم.
الـ Objects المتاحة في القوالب
كل صفحة في مكتبة القوالب تسرد متغيراتها. store وsession متاحان في القوالب الموثّقة، ومعهما Object خاص بالصفحة:
productفيproduct.jinja:nameوslugوdescription(HTML) وselected_productوهو المتغيّر الحالي بخصائصهformatted_priceوformatted_sale_priceوin_stockوskuوmedia، إضافة إلىvariantsوoptionsوratingوrelated_productsوbrand.brandوproductsفيbrand.jinja(المسار/brands/{slug_brand}): للعلامةidوnameوslugوdescriptionوlogo، وقائمة المنتجات فيهاresultsوcountوpageوpages_countوfilters. وقائمة كل العلامات فيbrands.jinjaعلى المسار/brands.settings: نسخة مسطّحة من ملف المخطط؛ فالإعدادlogoداخل المجموعةheaderيصبحsettings.header_logo. والإعدادات داخل قائمة تصبح قائمة Objects تمر عليها بـsafeget(settings, "images", []).session:session.query_params.get('q')لURL Parameters، وsession.url.pathللمسار الحالي، وsession.url.include_query_params(page=2)لبناء رابط بـ Parameters إضافية.store.settings: إعدادات المتجر، مثلstore.settings.checkout.is_coupon_form_enabled.
results وcount وpage وpage_size وpages_count، بدل مفاتيح Twig القديمة مثل data وtotal وlast_page.الدوال والفلاتر الخاصة بالمنصة
asset_url(فلتر): يعيد رابط CDN بإصدار محدد لملف منassets/.url_for: يبني رابط المسار من اسم العملية (Operation) ويحترم اللغة وقواعد التوجيه، مثلproduct_detailsوlist_productsوcart_pageوfaqs، ويقبلquery_paramsلإضافة Parameters. مسارات العلامات التجارية غير مدعومة فيه حاليًا، فاستخدم/brandsو/brands/{{ brand.slug }}.image_url(ماكرو):image_url(path, w=None, h=None, q=None, f=None)؛wوhللأبعاد بالبكسل، وqللجودة من 0 إلى 100، وf='auto'ليختار المتصفح أفضل صيغة (AVIF أو WebP).- التاريخ والوقت:
today()وnow()وformat_datetimeوformat_time، والمنطقة الزمنية واللغة مضبوطتان مسبقًا. - فلاتر Jinja الأساسية تعمل كالمعتاد، مثل
upperوlengthوsafe(لعرض HTML خام) وdefault(أوd) وreplaceوtojsonوurlencode.
<link rel="stylesheet" href="{{ 'theme.css' | asset_url }}">
<a href="{{ url_for('product_details', slug=product.slug) }}">{{ product.name }}</a>
<a href="{{ url_for('faqs') }}">Help & FAQs</a>
<img src="{{ image_url(my_image, w=400, q=85, f='auto') }}" alt="">
{{ format_datetime(order.created_at, fmt="long") }}أنماط شائعة: الحلقات والشروط والحماية من القيم الفارغة
أكثر نمط ستكتبه هو المرور على قائمة منتجات مع الفلاتر والتقسيم إلى صفحات. هذا مقتطف من مثال brand.jinja في التوثيق، وهو النمط نفسه في صفحات قوائم المنتجات:
{% extends "layout.jinja" %}
{% block main_content %}
<h1>{{ brand.name }}</h1>
{% if products.filters | length > 0 %}
{% include 'vitrin:products/filters.jinja' %}
{% endif %}
<div class="products">
{% for product in products.results %}
{% include 'components/product-card.jinja' %}
{% endfor %}
</div>
{% include 'components/pagination.jinja' %}
{% endblock %}- Jinja تتعامل بأمان مع الوصول المتسلسل إلى قيم فارغة، لكن المرور على قيمة فارغة أو القسمة على صفر يكسر العرض. احمِ الحلقات بـ
{% if var is defined and var is iterable %}. - للقيم الافتراضية:
{{ title or 'Untitled' }}أو{{ title | default('Untitled') }}، وdefault('x', true)يعامل القيم الفارغة مثل''و0كأنها غير موجودة. - لعرض العلامة التجارية في صفحة المنتج، تحقق أولًا بـ
{% if product.brand %}ثم اعرضproduct.brand.logoوproduct.brand.name. - لمعرفة توفر المتغيّر الحالي استخدم
product.selected_product.in_stock، وللمخزونproduct.selected_product.quantity.
الترجمة عبر gettext
القوالب تحتوي نصوصًا إنجليزية حرفية، وملف locale/ar/LC_MESSAGES/messages.po يربط كل نص (msgid) بترجمته (msgstr). الصيغ الأساسية:
{{ _("Add to cart") }}
{{ _("Hello %(name)s", name=user.name) }}
{% trans count=n %}{{ count }} item{% pluralize %}{{ count }} items{% endtrans %}
{{ pgettext("button", "Open") }}
{{ pgettext("verb", "Open") }}- أبقِ النصوص حرفية ولا تبنها بالدمج، حتى تجدها أدوات الاستخراج.
- استخدم العناصر النائبة
%(name)sبدل.format(). {% trans %}مع{% pluralize %}يترك صيغ الجمع لقواعد اللغة، وهذا مهم للعربية التي لها ست صيغ (msgstr[0]إلىmsgstr[5]).pgettextيفرّق بين نصين متطابقين بمعنيين مختلفين، واحرص أن يكون كلmsgidفريدًا في الملف، وأبقِ وسوم HTML خارج النص المترجَم.
إعدادات المتجر التي تغيّر ما تعرضه: حقل الكوبون
بعض إعدادات التاجر يجب أن يحترمها القالب. يتحكم التاجر في حقل الكوبون من Settings ثم Checkout Options عبر الخيار Show coupon code field (مفعّل افتراضيًا)، ويقرأ الثيم القيمة store.settings.checkout.is_coupon_form_enabled:
{% set coupon_form_enabled = store.settings.checkout.is_coupon_form_enabled != false %}
{% if coupon_form_enabled %}
<section class="cart-coupon" data-coupon-section>
{# Coupon input, apply button, applied coupon details, and remove button #}
</section>
{% endif %}- استخدم
!= falseلا شرط القيمة الصحيحة المباشر، حتى يبقى القسم ظاهرًا عندما تكون القيمةnullأو غير موجودة. - أخفِ القسم كاملًا: الحقل وزر التطبيق والكوبون المطبّق وزر الإزالة ورسائل التحقق والخطأ.
- لا تخفِه بـ CSS؛ الشرط في Jinja يمنع توليد HTML من الأساس.
- أضف فحصًا للقيمة الفارغة في JavaScript قبل الوصول إلى عناصر الكوبون، وطبّق الشرط في كل مواضع السلة.
- إعدادات المتجر قد تُخزَّن مؤقتًا حتى 10 دقائق، فانتظر قبل أن تحكم على نتيجة الاختبار.
الخلاصة
- كل قالب يمتد من
layout.jinja، والقوالب التي تديرها المنصة تُضمَّن بالبادئةvitrin:. - اعتمد على الـ Objects الموثّقة فقط:
storeوsessionوsettingsو Object الصفحة مثلproductأوproducts. - استخدم
asset_urlوimage_urlوurl_forبدل الروابط الثابتة، مع استثناء مسارات العلامات التجارية. - النصوص عبر
_()و{% trans %}معmsgidفريد لكل نص. - احمِ القالب من القيم الفارغة، وأخفِ قسم الكوبون فقط عندما تكون القيمة
falseصراحةً.
المصادر
ابدأ البناء على زد
سجّل بنفسك في بوابة الشركاء، وطوّر واختبر على متجر تجريبي.


