دليل تطوير سمات Odoo: إنشاء سمات مخصصة لـ Odoo 17/18
يحقق نظام سمات Odoo البيئي ما يزيد عن 12 مليون دولار سنويًا على متجر تطبيقات Odoo، ومع ذلك فإن أقل من 8% من السمات تحصل على تصنيف 5 نجوم. يكمن الاختلاف بين القالب الذي يمكن نسيانه والموضوع الأكثر مبيعًا في فهم مسار العرض الخاص بـ Odoo، ووراثة قالب QWeb، وبنية السحب والإفلات الخاصة بمنشئ موقع الويب.
يغطي هذا الدليل كل طبقة من طبقات تطوير سمة Odoo - بدءًا من هيكلة المشروع وحتى بنية SCSS المتقدمة، ومن إنشاء مقتطفات مخصصة إلى جعل السمة الخاصة بك تعمل بسلاسة مع أداة إنشاء مواقع الويب الخاصة بـ Odoo.
الوجبات السريعة الرئيسية
- موضوعات Odoo هي وحدات قياسية ذات بنية دليل محددة — فهي توسع وحدة
websiteوتسجل القوالب، وSCSS، وJavaScript عبر نظام تجميع الأصول. - QWeb هو محرك القوالب من جانب خادم Odoo — يستخدم توجيهات XML (t-if، t-foreach، t-call، t-inherit) التي يتم تحويلها إلى HTML. يعد فهم توريث القالب باستخدام XPath أمرًا ضروريًا لتخصيص أي جزء من موقع الويب.
- **يتم تجميع خط SCSS من خلال مدير أصول Odoo — تتجاوز المتغيرات المخصصة الإعدادات الافتراضية لـ Bootstrap 5، ويجب تحميل
_variables.scssقبل إطار العمل. - يتطلب تكامل أداة إنشاء مواقع الويب تحديد خيارات المقتطفات وكتل البناء المخصصة وكتل المحتوى الديناميكي التي يمكن للمستخدمين غير التقنيين تهيئتها من خلال محرر السحب والإفلات.
- التصميم سريع الاستجابة في Odoo يعمل على تعزيز نظام الشبكة الخاص بـ Bootstrap 5 مع الأدوات المساعدة الخاصة بـ Odoo - قم بالاختبار عبر جميع نقاط التوقف وفكر في لغات RTL لعمليات النشر الدولية.
1. هيكل وحدة الموضوع
تتبع سمة Odoo بنية الوحدة القياسية مع الإضافات الخاصة بموقع الويب:
theme_ecosire/
├── __init__.py
├── __manifest__.py
├── data/
│ ├── theme_data.xml # Default pages, menus
│ └── images.xml # Pre-loaded image library
├── static/
│ ├── description/
│ │ ├── icon.png # Module icon (128x128)
│ │ └── icon.svg # SVG version
│ ├── src/
│ │ ├── img/ # Theme images
│ │ ├── fonts/ # Custom fonts
│ │ ├── scss/
│ │ │ ├── _variables.scss # Bootstrap variable overrides
│ │ │ ├── _mixins.scss # Custom SCSS mixins
│ │ │ ├── _typography.scss # Font stacks, sizes
│ │ │ ├── _header.scss # Header styles
│ │ │ ├── _footer.scss # Footer styles
│ │ │ ├── _snippets.scss # Snippet-specific styles
│ │ │ └── primary.scss # Main entry point
│ │ ├── js/
│ │ │ ├── snippets/ # Snippet JS (animations, interactions)
│ │ │ └── theme.js # Theme-wide JS
│ │ └── xml/
│ │ └── snippets.xml # OWL snippet templates
│ └── img/ # Public images (backgrounds, icons)
├── views/
│ ├── assets.xml # Asset bundle registration
│ ├── layout.xml # Header/footer templates
│ ├── pages.xml # Pre-built page templates
│ └── snippets/
│ ├── options.xml # Snippet options (color pickers, etc.)
│ └── s_custom_block.xml # Custom snippet definitions
└── tests/
└── test_theme.py # Theme installation tests
بيان الموضوع
# __manifest__.py
{
'name': 'Theme Ecosire',
'description': 'Modern, performance-optimized theme for Odoo Website',
'category': 'Theme',
'version': '18.0.1.0.0',
'author': 'ECOSIRE Private Limited',
'website': 'https://ecosire.com',
'license': 'LGPL-3',
'depends': ['website'],
'data': [
'views/assets.xml',
'views/layout.xml',
'views/pages.xml',
'views/snippets/options.xml',
'views/snippets/s_custom_block.xml',
],
'assets': {
'web.assets_frontend': [
# Variables MUST come before Bootstrap
('prepend', 'theme_ecosire/static/src/scss/_variables.scss'),
'theme_ecosire/static/src/scss/primary.scss',
'theme_ecosire/static/src/js/theme.js',
],
'website.assets_wysiwyg': [
'theme_ecosire/static/src/js/snippets/*.js',
],
},
'images': [
'static/description/banner.png',
'static/description/theme_screenshot.jpg',
],
'snippet_lists': {
'website.snippets': [
('replace', 'theme_ecosire.s_custom_hero'),
],
},
'installable': True,
'application': False,
'auto_install': False,
}
ملاحظة هامة حول المفتاح assets: في Odoo 17+، يعتبر قاموس assets في __manifest__.py الطريقة المفضلة لتسجيل الملفات الثابتة. لا يزال أسلوب views/assets.xml الأقدم باستخدام <template inherit_id="web.assets_frontend"> يعمل ولكن يتم التخلص منه تدريجيًا. استخدم كلاهما لتحقيق أقصى قدر من التوافق.
2. الغوص العميق في قوالب QWeb
QWeb هو محرك قوالب قائم على XML من Odoo. يقوم بمعالجة التوجيهات المسبوقة بـ t- وإخراج HTML. إن فهم QWeb أمر غير قابل للتفاوض لتطوير السمات.
###التوجيهات الأساسية
<!-- Conditional rendering -->
<div t-if="website.is_publisher()">
<span>Edit mode controls here</span>
</div>
<div t-elif="request.env.user._is_internal()">
<span>Internal user view</span>
</div>
<div t-else="">
<span>Public visitor view</span>
</div>
<!-- Loops -->
<ul>
<t t-foreach="website.menu_id.child_id" t-as="menu_item">
<li t-attf-class="nav-item #{('active' if menu_item.is_active else '')}">
<a t-att-href="menu_item.url" t-out="menu_item.name"/>
</li>
</t>
</ul>
<!-- Variable setting -->
<t t-set="company" t-value="res_company"/>
<t t-set="primary_color" t-value="'#FF6B00'"/>
<!-- Output (auto-escaped) -->
<span t-out="partner.name"/>
<!-- Raw HTML output (use with caution) -->
<div t-raw="sanitized_html_content"/>
<!-- Dynamic attributes -->
<div t-att-id="'section-' + str(section.id)"
t-attf-class="container #{extra_class}"
t-att-data-section="section.sequence"/>
<!-- Template calling -->
<t t-call="theme_ecosire.hero_section">
<t t-set="title">Welcome to Our Store</t>
<t t-set="subtitle">Premium Odoo Themes</t>
</t>
وراثة القالب باستخدام XPath
هذا هو المكان الذي يصبح فيه تطوير الموضوع قويًا. يمكنك تعديل أي قالب موجود دون استبداله:
<!-- views/layout.xml -->
<template id="custom_header" inherit_id="website.layout" name="Custom Header">
<!-- Replace the entire header -->
<xpath expr="//header" position="replace">
<header id="top" class="ecosire-header">
<nav class="navbar navbar-expand-lg">
<div class="container">
<a class="navbar-brand" t-att-href="'/'">
<img t-if="website.logo"
t-att-src="website.image_url(website, 'logo')"
alt="Logo" class="img-fluid" style="max-height: 50px;"/>
</a>
<!-- Custom mega menu -->
<t t-call="theme_ecosire.mega_menu"/>
<!-- CTA button -->
<a href="/contactus" class="btn btn-primary ms-3">
Get Started
</a>
</div>
</nav>
</header>
</xpath>
<!-- Add a top bar before the header -->
<xpath expr="//header[@id='top']" position="before">
<div class="ecosire-topbar bg-dark text-white py-1">
<div class="container d-flex justify-content-between">
<span t-out="res_company.phone"/>
<span t-out="res_company.email"/>
</div>
</div>
</xpath>
<!-- Modify footer: add a newsletter section -->
<xpath expr="//footer" position="inside">
<div class="ecosire-newsletter bg-primary text-white py-5">
<div class="container text-center">
<h3>Stay Updated</h3>
<t t-call="website.s_newsletter_block"/>
</div>
</div>
</xpath>
</template>
مرجع موضع XPath
| الموقف | تأثير |
|---|---|
replace | استبدل العنصر المطابق بالكامل |
inside | إلحاق داخل العنصر المطابق |
before | أدخل قبل العنصر المطابق |
after | أدخل بعد العنصر المطابق |
attributes | تعديل سمات العنصر المطابق |
<!-- Modify attributes example -->
<xpath expr="//div[@id='wrapwrap']" position="attributes">
<attribute name="class" add="ecosire-theme" separator=" "/>
</xpath>
<!-- Remove an element -->
<xpath expr="//div[hasclass('o_not_editable')]" position="replace"/>
3. هندسة SCSS
يتم تجميع مسار SCSS الخاص بـ Odoo من خلال مدير الأصول الخاص به، مما يعني أنه يجب تحميل تجاوزات المتغيرات قبل إعدادات Bootstrap الافتراضية. استخدم توجيه "الإرفاق المسبق" في قاموس أصول البيان الخاص بك للتأكد من أن ملف _variables.scss الخاص بك يحظى بالأولوية. يتحكم هذا الملف الفردي في الألوان والخطوط والمسافات ونصف قطر الحدود وكل رمز مميز آخر لتصميم Bootstrap في قالبك.
تجاوزات المتغيرات (_variables.scss)
// _variables.scss — loaded BEFORE Bootstrap
// Override Bootstrap 5 defaults
// Brand Colors
$o-brand-primary: #FF6B00;
$o-brand-secondary: #1A1F36;
// Bootstrap color overrides
$primary: $o-brand-primary;
$secondary: $o-brand-secondary;
$success: #00C853;
$info: #2196F3;
$warning: #FFB300;
$danger: #FF1744;
// Typography
$font-family-sans-serif: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
$font-family-monospace: 'JetBrains Mono', 'Fira Code', monospace;
$font-size-base: 1rem;
$headings-font-weight: 700;
$headings-line-height: 1.2;
// Spacing
$spacer: 1rem;
// Border radius
$border-radius: 0.5rem;
$border-radius-lg: 1rem;
$border-radius-pill: 50rem;
// Shadows
$box-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.05);
$box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
$box-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12);
// Navbar
$navbar-padding-y: 1rem;
$navbar-brand-font-size: 1.5rem;
// Cards
$card-border-radius: $border-radius-lg;
$card-border-color: transparent;
$card-box-shadow: $box-shadow;
ورقة الأنماط الرئيسية (primary.scss)
// primary.scss — Main entry point
@import 'variables'; // Already prepended, but import for IDE support
@import 'mixins';
@import 'typography';
@import 'header';
@import 'footer';
@import 'snippets';
// ============================================
// Global Overrides
// ============================================
#wrapwrap.ecosire-theme {
// Smooth scrolling
scroll-behavior: smooth;
// Better text rendering
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// ============================================
// Section Spacing
// ============================================
.s_section {
padding: 5rem 0;
@media (max-width: 768px) {
padding: 3rem 0;
}
}
// ============================================
// Button Styles
// ============================================
.btn-primary {
background: linear-gradient(135deg, $primary, darken($primary, 10%));
border: none;
padding: 0.75rem 2rem;
font-weight: 600;
letter-spacing: 0.02em;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba($primary, 0.4);
}
}
// ============================================
// Card Component
// ============================================
.ecosire-card {
background: white;
border-radius: $border-radius-lg;
overflow: hidden;
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow: $box-shadow-lg;
}
&__image {
aspect-ratio: 16 / 9;
object-fit: cover;
width: 100%;
}
&__body {
padding: 1.5rem;
}
}
تحميل الخط المخصص
// _typography.scss
@font-face {
font-family: 'Inter';
src: url('/theme_ecosire/static/src/fonts/Inter-Variable.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
font-style: normal;
}
@font-face {
font-family: 'Inter';
src: url('/theme_ecosire/static/src/fonts/Inter-Variable-Italic.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
font-style: italic;
}
// Heading hierarchy
h1, .h1 { font-size: 2.5rem; font-weight: 800; }
h2, .h2 { font-size: 2rem; font-weight: 700; }
h3, .h3 { font-size: 1.5rem; font-weight: 600; }
h4, .h4 { font-size: 1.25rem; font-weight: 600; }
4. المقتطفات المخصصة (الكتل الأساسية)
المقتطفات هي وحدات بناء السحب والإفلات في أداة إنشاء مواقع الويب الخاصة بـ Odoo. إن إنشاء مقتطفات مخصصة هو ما يجعل الموضوع ذا قيمة حقيقية.
تعريف قالب المقتطف
<!-- views/snippets/s_custom_block.xml -->
<odoo>
<!-- The snippet template -->
<template id="s_ecosire_hero" name="Ecosire Hero Section">
<section class="s_ecosire_hero pt-5 pb-5 o_cc o_cc1">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-6">
<h1 class="display-4 fw-bold">
Transform Your Business
</h1>
<p class="lead text-muted mt-3">
Enterprise solutions that scale with your ambitions.
</p>
<div class="mt-4">
<a href="/contactus" class="btn btn-primary btn-lg me-3">
Get Started
</a>
<a href="/about" class="btn btn-outline-secondary btn-lg">
Learn More
</a>
</div>
</div>
<div class="col-lg-6">
<img src="/theme_ecosire/static/src/img/hero-illustration.svg"
alt="Hero" class="img-fluid" loading="lazy"/>
</div>
</div>
</div>
</section>
</template>
<!-- Register snippet in the builder panel -->
<template id="snippets" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_structure']//t[@t-snippet]/.."
position="inside">
<t t-snippet="theme_ecosire.s_ecosire_hero"
t-thumbnail="/theme_ecosire/static/src/img/snippets/hero_thumb.png"/>
</xpath>
</template>
</odoo>
خيارات المقتطف (تخصيص المستخدم)
<!-- views/snippets/options.xml -->
<odoo>
<template id="s_ecosire_hero_options" inherit_id="website.snippet_options">
<xpath expr="." position="inside">
<div data-js="EcosireHeroOptions"
data-selector=".s_ecosire_hero">
<!-- Layout selector -->
<we-select string="Layout">
<we-button data-select-class="s_hero_left">Text Left</we-button>
<we-button data-select-class="s_hero_center">Centered</we-button>
<we-button data-select-class="s_hero_right">Text Right</we-button>
</we-select>
<!-- Background style -->
<we-select string="Background">
<we-button data-select-class="bg-white">White</we-button>
<we-button data-select-class="bg-dark text-white">Dark</we-button>
<we-button data-select-class="bg-gradient">Gradient</we-button>
</we-select>
<!-- Animation toggle -->
<we-checkbox string="Enable Animation"
data-toggle-class="s_hero_animated"/>
</div>
</xpath>
</template>
</odoo>
مقتطف جافا سكريبت (الرسوم المتحركة)
// static/src/js/snippets/s_ecosire_hero.js
/** @odoo-module */
import publicWidget from '@web/legacy/js/public/public_widget';
const EcosireHero = publicWidget.Widget.extend({
selector: '.s_ecosire_hero.s_hero_animated',
disabledInEditableMode: true,
start() {
this._super(...arguments);
this._initAnimation();
return Promise.resolve();
},
_initAnimation() {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.2 }
);
this.el.querySelectorAll('.animate-target').forEach(el => {
observer.observe(el);
});
},
destroy() {
this._super(...arguments);
},
});
publicWidget.registry.EcosireHero = EcosireHero;
export default EcosireHero;
5. أفضل ممارسات التصميم سريع الاستجابة
موبايل-أولاً SCSS
// _responsive.scss
// Mobile-first breakpoints (Bootstrap 5)
// xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px
.ecosire-header {
// Mobile default
padding: 0.5rem 0;
.navbar-brand img {
max-height: 35px;
}
.nav-link {
padding: 0.75rem 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
// Tablet and up
@include media-breakpoint-up(md) {
padding: 0.75rem 0;
.nav-link {
padding: 0.5rem 1rem;
border-bottom: none;
}
}
// Desktop
@include media-breakpoint-up(lg) {
padding: 1rem 0;
.navbar-brand img {
max-height: 50px;
}
}
}
// Touch-friendly elements
@media (hover: none) {
.btn {
min-height: 44px;
min-width: 44px;
}
.nav-link {
min-height: 44px;
display: flex;
align-items: center;
}
}
دعم RTL
// _rtl.scss — Critical for Arabic, Hebrew, Urdu markets
html[dir="rtl"] {
.ecosire-header {
.navbar-brand {
margin-left: 1rem;
margin-right: 0;
}
.btn + .btn {
margin-right: 0.75rem;
margin-left: 0;
}
}
.ecosire-card__body {
text-align: right;
}
// Use logical properties where possible
.ms-3 { margin-inline-start: 1rem; }
.me-3 { margin-inline-end: 1rem; }
}
6. تحسين الأداء
تحسين الصورة
<!-- Use responsive images with srcset -->
<img t-att-src="'/web/image/ir.attachment/%s/datas/800x400' % image.id"
t-att-srcset="'/web/image/ir.attachment/%s/datas/400x200 400w, /web/image/ir.attachment/%s/datas/800x400 800w, /web/image/ir.attachment/%s/datas/1200x600 1200w' % (image.id, image.id, image.id)"
sizes="(max-width: 576px) 400px, (max-width: 992px) 800px, 1200px"
loading="lazy"
decoding="async"
alt="Descriptive alt text"/>
التضمين الحرج لـ CSS
<!-- views/layout.xml -->
<template id="critical_css" inherit_id="website.layout">
<xpath expr="//head" position="inside">
<style type="text/css">
/* Inline critical above-the-fold CSS */
.ecosire-header { min-height: 72px; }
.s_ecosire_hero { min-height: 60vh; }
.navbar-brand img { max-height: 50px; }
</style>
</xpath>
</template>
استراتيجية تحميل الأصول
# __manifest__.py
'assets': {
# Critical CSS — loaded in head
'web.assets_frontend': [
('prepend', 'theme_ecosire/static/src/scss/_variables.scss'),
'theme_ecosire/static/src/scss/primary.scss',
],
# Non-critical JS — deferred
'web.assets_frontend_lazy': [
'theme_ecosire/static/src/js/animations.js',
'theme_ecosire/static/src/js/parallax.js',
],
# Editor-only assets
'website.assets_wysiwyg': [
'theme_ecosire/static/src/js/snippets/*.js',
'theme_ecosire/static/src/scss/_editor.scss',
],
},
7. تكامل أداة إنشاء المواقع
كتل المحتوى الديناميكي
<!-- A snippet that fetches products dynamically -->
<template id="s_featured_products" name="Featured Products Grid">
<section class="s_featured_products pt-5 pb-5">
<div class="container">
<h2 class="text-center mb-5">Featured Products</h2>
<div class="row" t-if="products">
<t t-foreach="products[:8]" t-as="product">
<div class="col-md-3 mb-4">
<div class="ecosire-card h-100">
<img t-att-src="product.image_url"
t-att-alt="product.name"
class="ecosire-card__image" loading="lazy"/>
<div class="ecosire-card__body">
<h5 t-out="product.name"/>
<p class="text-primary fw-bold"
t-out="product.list_price"
t-options='{"widget": "monetary"}'/>
<a t-att-href="product.website_url"
class="btn btn-outline-primary btn-sm">
View Details
</a>
</div>
</div>
</div>
</t>
</div>
</div>
</section>
</template>
قوالب الصفحة
<!-- Pre-built page templates that users can select -->
<template id="landing_page_template" name="Landing Page">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<t t-call="theme_ecosire.s_ecosire_hero"/>
<t t-call="theme_ecosire.s_features_grid"/>
<t t-call="theme_ecosire.s_testimonials"/>
<t t-call="theme_ecosire.s_cta_banner"/>
</div>
</t>
</template>
8. اختبار المظهر الخاص بك
# tests/test_theme.py
from odoo.tests.common import HttpCase, tagged
@tagged('post_install', '-at_install')
class TestThemeEcosire(HttpCase):
def test_01_theme_installation(self):
"""Theme installs without errors."""
module = self.env['ir.module.module'].search([
('name', '=', 'theme_ecosire')
])
self.assertEqual(module.state, 'installed')
def test_02_homepage_loads(self):
"""Homepage renders with theme applied."""
response = self.url_open('/')
self.assertEqual(response.status_code, 200)
self.assertIn('ecosire-theme', response.text)
def test_03_snippets_available(self):
"""Custom snippets appear in the builder."""
self.start_tour('/web#action=website.action_website',
'theme_ecosire_snippet_tour', login='admin')
def test_04_responsive_meta(self):
"""Viewport meta tag is present."""
response = self.url_open('/')
self.assertIn('viewport', response.text)
9. النشر على متجر تطبيقات Odoo
| المتطلبات | التفاصيل |
|---|---|
| لقطات الشاشة | 3-5 لقطات شاشة عالية الجودة (1920x1080) |
| أيقونة | 128 × 128 PNG في static/description/ |
| الوصف | وصف HTML في static/description/index.html |
| الترخيص | LGPL-3 للموضوعات (الممارسة القياسية) |
| النسخة | سلسلة ماتش اودو (18.0.x.y.z) |
| اختبار | اجتياز اختبارات الفحص الآلية لـ Odoo |
| بيانات تجريبية | قم بتضمين بيانات تجريبية للتجربة قبل الشراء |
الأسئلة المتداولة
هل يمكنني استخدام Tailwind CSS في قالب Odoo؟
على الرغم من أنه ممكن من الناحية الفنية، فإن استخدام Tailwind CSS جنبًا إلى جنب مع Bootstrap 5 المدمج في Odoo يؤدي إلى حدوث تعارضات ويزيد من حجم الحزمة بشكل كبير. يتمثل الأسلوب الموصى به في استخدام أدوات Bootstrap 5 المساعدة وخصائص SCSS المخصصة، والتي تتكامل أصلاً مع مسار أصول Odoo ومنشئ مواقع الويب. إذا كنت بحاجة إلى فئات أدوات مساعدة لا يوفرها Bootstrap، فقم بإنشاء أدوات مساعدة SCSS مخصصة بدلاً من ذلك.
كيف أجعل المظهر الخاص بي متوافقًا مع الإصدارين 17 و18 من Odoo؟
إنشاء فروع منفصلة لكل إصدار من إصدارات Odoo. يستخدم Odoo 17 الإصدار Bootstrap 5.1 بينما يستخدم Odoo 18 الإصدار Bootstrap 5.3 مع دعم متغير CSS. تم أيضًا تغيير تسجيل الأصول - يفضل Odoo 18 مفتاح أصول البيان بينما يستخدم Odoo 17 وراثة قالب XML. حافظ على أجزاء SCSS المشتركة وملفات التكامل الخاصة بالإصدار.
لماذا لا تعمل تجاوزات متغيرات SCSS الخاصة بي؟
السبب الأكثر شيوعًا هو ترتيب التحميل. يجب تحميل _variables.scss الخاص بك قبل تجميع Bootstrap. استخدم توجيه "prepend" في البيان الخاص بك: ("prepend"، "theme_name/static/src/scss/_variables.scss"). تأكد أيضًا من تجاوز أسماء المتغيرات الصحيحة - يقوم Odoo بتغليف بعض متغيرات Bootstrap بإصدارات مسبوقة بـ o مثل $o-brand-primary.
كيف تعمل المقتطفات المخصصة مع أداة إنشاء مواقع الويب؟
المقتطفات المخصصة هي قوالب QWeb المسجلة في لوحة المقتطفات من خلال توريث قالب website.snippets. يحتاج كل مقتطف إلى قالب لبنية HTML الخاصة به، وخيارات اختيارية محددة في website.snippet_options للوحة التخصيص، وJavaScript اختياري يوسع publicWidget.Widget للتفاعل. تتعامل أداة إنشاء مواقع الويب تلقائيًا مع السحب والإفلات والتحرير المضمن والتراجع/الإعادة للمقتطفات المسجلة.
ما هي أفضل طريقة لإضافة خطوط مخصصة إلى سمة Odoo؟
ضع ملفات خطوط WOFF2 في static/src/fonts/ وحدد قواعد @font-face في SCSS. استخدم عرض الخط: مبادلة الأداء. ثم قم بتجاوز متغير Bootstrap $font-family-sans-serif في _variables.scss. تجنب تحميل الخطوط من شبكات CDN الخارجية لأنها تضيف بحث DNS وقد تفشل في الشبكات المقيدة. مجموعة الخطوط الفرعية تتضمن نطاقات الأحرف المطلوبة فقط.
كيف أدعم الوضع المظلم في سمة Odoo الخاصة بي؟
قدم Odoo 18 دعمًا أصليًا للوضع المظلم من خلال خصائص CSS المخصصة. قم بتجاوز متغيرات الوضع المظلم في القالب الخاص بك باستخدام محدد [data-bs-theme = "dark"] . حدد المتغيرات الفاتحة والداكنة للألوان والخلفيات والظلال المخصصة. يتولى تبديل أداة إنشاء موقع الويب عملية التبديل — يحتاج المظهر الخاص بك فقط إلى توفير قيم متغيرات CSS الصحيحة لكلا الوضعين.
الخطوات التالية
تطوير الموضوع هو حيث يلتقي التصميم بالهندسة. يمكن لموضوع Odoo المصمم جيدًا أن يخدم مئات العملاء ويحقق إيرادات متكررة كبيرة على متجر تطبيقات Odoo.
للأدلة ذات الصلة:
- دليل تطوير Odoo Python — أساسيات تطوير الواجهة الخلفية
- تطوير وحدة Odoo المخصصة — نظرة عامة على بنية الوحدة
- البرنامج التعليمي لـ Odoo REST API — أنماط تكامل واجهة برمجة التطبيقات
هل تحتاج إلى سمة Odoo مخصصة أو إعادة تصميم موقع الويب؟ يقوم [فريق تخصيص Odoo التابع لـ ECOSIRE] (/services/odoo/customization) بتصميم وإنشاء سمات على مستوى المؤسسة من خلال التكامل الكامل لمنشئ موقع الويب، والتصميم سريع الاستجابة عبر جميع نقاط التوقف، ودعم RTL لعمليات النشر الدولية. لقد قدمنا سمات مخصصة للعملاء في أكثر من 40 دولة. اتصل بنا للحصول على استشارة مجانية حول التصميم.
بقلم
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
مقالات ذات صلة
تجزئة العملاء المدعومة بالذكاء الاصطناعي: من RFM إلى التجميع التنبؤي
تعرف على كيفية قيام الذكاء الاصطناعي بتحويل تجزئة العملاء من تحليل RFM الثابت إلى التجميع التنبؤي الديناميكي. دليل التنفيذ باستخدام Python وOdoo وبيانات عائد الاستثمار الحقيقي.
الذكاء الاصطناعي لتحسين سلسلة التوريد: الرؤية والتنبؤ والأتمتة
تحويل عمليات سلسلة التوريد باستخدام الذكاء الاصطناعي: استشعار الطلب، وتسجيل مخاطر الموردين، وتحسين المسار، وأتمتة المستودعات، والتنبؤ بالاضطرابات. دليل 2026.
استراتيجية التجارة الإلكترونية B2B: بناء الأعمال التجارية عبر الإنترنت بالجملة في عام 2026
إتقان التجارة الإلكترونية بين الشركات (B2B) مع إستراتيجيات لتسعير الجملة، وإدارة الحسابات، وشروط الائتمان، والكتالوجات النهائية، وتكوين بوابة Odoo B2B.