Odoo Tema Geliştirme Kılavuzu: Odoo için Özel Temalar Oluşturun 17/18
Odoo tema ekosistemi, Odoo App Store'da yılda 12 milyon dolardan fazla gelir sağlıyor, ancak temaların %8'inden azı 5 yıldız derecelendirmesi alıyor. Unutulabilir bir tema ile en çok satan bir tema arasındaki fark, Odoo'nun oluşturma hattını, QWeb şablonu mirasını ve web sitesi oluşturucunun sürükle ve bırak mimarisini anlamaktan gelir.
Bu kılavuz, proje iskelesinden gelişmiş SCSS mimarisine, özel parçacıklar oluşturmaktan temanızın Odoo'nun web sitesi oluşturucusuyla sorunsuz bir şekilde çalışmasını sağlamaya kadar Odoo teması geliştirmenin her katmanını kapsar.
Temel Çıkarımlar
- Odoo temaları, belirli bir dizin yapısına sahip standart modüllerdir —
websitemodülünü genişletirler ve varlık paketleme sistemi aracılığıyla şablonları, SCSS'yi ve JavaScript'i kaydederler. - QWeb, Odoo'nun sunucu tarafı şablon motorudur — HTML'ye derlenen XML direktiflerini (t-if, t-foreach, t-call, t-inherit) kullanır. XPath ile şablon devralmayı anlamak, web sitesinin herhangi bir bölümünü özelleştirmek için çok önemlidir.
- SCSS hattı Odoo'nun varlık yöneticisi aracılığıyla derlenir; özel değişkenler Bootstrap 5 varsayılanlarını geçersiz kılar ve çerçeveden önce
_variables.scssyüklenmelidir. - Web sitesi oluşturucu entegrasyonu, teknik bilgisi olmayan kullanıcıların sürükle ve bırak düzenleyici aracılığıyla yapılandırabileceği snippet seçeneklerinin, özel yapı taşlarının ve dinamik içerik bloklarının tanımlanmasını gerektirir.
- Odoo'daki duyarlı tasarım, Odoo'ya özgü yardımcı programlarla Bootstrap 5'in ızgara sisteminden yararlanır; tüm kesme noktalarında test edin ve uluslararası dağıtımlar için RTL dillerini göz önünde bulundurun.
1. Tema Modül Yapısı
Odoo teması, web sitesine özel eklemelerle standart modül yapısını takip eder:
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
Tema Bildirimi
# __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 anahtarı hakkında kritik not: Odoo 17+ sürümünde, __manifest__.py içindeki assets sözlüğü statik dosyaları kaydetmenin tercih edilen yoludur. <template inherit_id="web.assets_frontend"> kullanan eski views/assets.xml yaklaşımı hala çalışıyor ancak kullanımdan kaldırılıyor. Maksimum uyumluluk için her ikisini de kullanın.
2. QWeb Şablon Oluşturma Derinlemesine İnceleme
QWeb, Odoo'nun XML tabanlı şablon motorudur. t- önekine sahip yönergeleri işler ve HTML çıktısını alır. QWeb'i anlamak, tema geliştirme açısından tartışılamaz.
Temel Direktifler
<!-- 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 ile Şablon Mirası
Tema geliştirmenin güçlendiği yer burasıdır. Mevcut herhangi bir şablonu değiştirmeden değiştirebilirsiniz:
<!-- 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 Konum Referansı
| Pozisyon | Efekt |
|---|---|
| KOD0 | Eşleşen öğeyi tamamen değiştir |
| KOD0 | Eşleşen öğenin içine ekle |
| KOD0 | Eşleşen öğenin önüne ekle |
| KOD0 | Eşleşen öğenin arkasına ekle |
| KOD0 | Eşleşen öğenin niteliklerini değiştirin |
<!-- 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 Mimarisi
Odoo'nun SCSS işlem hattı, varlık yöneticisi aracılığıyla derlenir; bu, değişken geçersiz kılmalarınızın Bootstrap'in varsayılanlarından önce yüklenmesi gerektiği anlamına gelir. _variables.scss dosyanızın öncelikli olmasını sağlamak için bildiriminizin varlıklar sözlüğündeki 'prepend' yönergesini kullanın. Bu tek dosya, temanızdaki renkleri, yazı tiplerini, aralığı, kenarlık yarıçapını ve diğer tüm Bootstrap tasarım jetonlarını kontrol eder.
Değişken Geçersiz Kılmalar (_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;
Ana Stil Sayfası (birincil.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;
}
}
Özel Yazı Tipi Yükleme
// _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. Özel Parçacıklar (Yapı Taşları)
Parçacıklar, Odoo'nun web sitesi oluşturucusundaki sürükle ve bırak yapı taşlarıdır. Özel snippet'ler oluşturmak, bir temayı gerçekten değerli kılan şeydir.
Parçacık Şablonu Tanımlama
<!-- 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>
Parçacık Seçenekleri (Kullanıcı Özelleştirmesi)
<!-- 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>
JavaScript Parçacığı (Animasyonlar)
// 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. Duyarlı Tasarım için En İyi Uygulamalar
Mobil İlk 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 Desteği
// _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. Performans Optimizasyonu
Görüntü Optimizasyonu
<!-- 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"/>
Kritik CSS Satır İçi
<!-- 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>
Varlık Yükleme Stratejisi
# __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. Web Sitesi Oluşturucu Entegrasyonu
Dinamik İçerik Blokları
<!-- 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>
Sayfa Şablonları
<!-- 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. Temanızı Test Etme
# 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 App Store'da Yayınlama
| Gereksinim | Ayrıntılar |
|---|---|
| Ekran görüntüleri | 3-5 yüksek kaliteli ekran görüntüsü (1920x1080) |
| Simge | static/description/ içinde 128x128 PNG |
| Açıklama | static/description/index.html içindeki HTML açıklaması |
| Lisans | Temalar için LGPL-3 (standart uygulama) |
| Sürüm | Maç Odoo serisi (18.0.x.y.z) |
| Test | Odoo'nun otomatik astar kontrollerini geçin |
| Demo verileri | Satın almadan önce dene için demo verilerini ekleyin |
Sıkça Sorulan Sorular
Tailwind CSS'yi Odoo temasında kullanabilir miyim?
Teknik olarak mümkün olsa da, Tailwind CSS'yi Odoo'nun yerleşik Bootstrap 5'iyle birlikte kullanmak çakışmalara neden olur ve paket boyutunu önemli ölçüde artırır. Önerilen yaklaşım, Odoo'nun varlık hattı ve web sitesi oluşturucusuyla yerel olarak entegre olan Bootstrap 5 yardımcı programlarını ve SCSS özel özelliklerini kullanmaktır. Bootstrap'in sağlamadığı yardımcı program sınıflarına ihtiyacınız varsa bunun yerine özel SCSS yardımcı programları oluşturun.
Temamı hem Odoo 17 hem de 18 ile uyumlu hale nasıl getirebilirim?
Her Odoo sürümü için ayrı dallar oluşturun. Odoo 17, Bootstrap 5.1'i kullanırken Odoo 18, CSS değişken desteğiyle Bootstrap 5.3'ü kullanıyor. Varlık kaydı da değişti; Odoo 18, manifest varlık anahtarını tercih ederken, Odoo 17, XML şablon mirasını kullanıyor. Paylaşılan SCSS kısmilerini ve sürüme özel entegrasyon dosyalarını koruyun.
SCSS değişken geçersiz kılmalarım neden çalışmıyor?
En yaygın neden yükleme sırasıdır. Bootstrap derlenmeden önce _variables.scss dosyanız yüklenmelidir. Bildiriminizde 'prepend' yönergesini kullanın: ('prepend', 'theme_name/static/src/scss/_variables.scss'). Ayrıca doğru değişken adlarını geçersiz kıldığınızdan emin olun. Odoo, bazı Bootstrap değişkenlerini $o-brand-primary gibi o-önekli sürümlerle sarar.
Özel snippet'ler web sitesi oluşturucuyla nasıl çalışır?
Özel snippet'ler, website.snippets'in şablon mirası yoluyla snippet paneline kaydedilen QWeb şablonlarıdır. Her pasajın HTML yapısı için bir şablona, özelleştirme paneli için website.snippet_options'da tanımlanan isteğe bağlı seçeneklere ve etkileşim için publicWidget.Widget'ı genişleten isteğe bağlı JavaScript'e ihtiyacı vardır. Web sitesi oluşturucu, kayıtlı snippet'ler için sürükle ve bırak, satır içi düzenleme ve geri alma/yineleme işlemlerini otomatik olarak gerçekleştirir.
Odoo temasına özel yazı tipleri eklemenin en iyi yolu nedir?
WOFF2 yazı tipi dosyalarını static/src/fonts/ dizinine yerleştirin ve SCSS'nizde @font-face kurallarını tanımlayın. Font-display'i kullanın: performans için değiştirin. Ardından _variables.scss dosyasındaki $font-family-sans-serif Bootstrap değişkenini geçersiz kılın. Yazı tiplerini harici CDN'lerden yüklemekten kaçının çünkü bu, bir DNS araması ekler ve kısıtlı ağlarda başarısız olabilir. Yalnızca gerekli karakter aralıklarını içerecek şekilde yazı tiplerini alt kümeleyin.
Odoo temamda karanlık modu nasıl destekleyebilirim?
Odoo 18, CSS özel özellikleri aracılığıyla yerel karanlık mod desteğini sundu. [data-bs-theme = "dark"] seçiciyi kullanarak temanızdaki karanlık mod değişkenlerini geçersiz kılın. Özel renklerinizin, arka planlarınızın ve gölgelerinizin hem açık hem de koyu çeşitlerini tanımlayın. Web sitesi tasarım düğmesi geçiş işlemini gerçekleştirir; temanızın her iki mod için de doğru CSS değişkeni değerlerini sağlaması yeterlidir.
Sonraki Adımlar
Tema geliştirme, tasarımın mühendislikle buluştuğu yerdir. İyi oluşturulmuş bir Odoo teması yüzlerce müşteriye hizmet verebilir ve Odoo App Store'da önemli miktarda sürekli gelir elde edebilir.
İlgili kılavuzlar için:
- Odoo Python Geliştirme Kılavuzu — Arka uç geliştirmenin temelleri
- Odoo Özel Modül Geliştirme — Modül mimarisine genel bakış
- Odoo REST API Eğitimi — API entegrasyon modelleri
Özel bir Odoo temasına veya web sitesinin yeniden tasarımına mı ihtiyacınız var? ECOSIRE'ın Odoo özelleştirme ekibi tam web sitesi oluşturucu entegrasyonu, tüm kesme noktalarında duyarlı tasarım ve uluslararası dağıtımlar için RTL desteği ile kurumsal düzeyde temalar tasarlar ve oluşturur. 40'tan fazla ülkedeki müşterilerimize özel temalar sunduk. Ücretsiz tasarım danışmanlığı için bizimle iletişime geçin.
Yazan
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.
İlgili Makaleler
Yapay Zeka Destekli Müşteri Segmentasyonu: RFM'den Tahmine Dayalı Kümelemeye
Yapay zekanın müşteri segmentasyonunu statik RFM analizinden dinamik tahmine dayalı kümelemeye nasıl dönüştürdüğünü öğrenin. Python, Odoo ve gerçek yatırım getirisi verilerini içeren uygulama kılavuzu.
Tedarik Zinciri Optimizasyonu için Yapay Zeka: Görünürlük, Tahmin ve Otomasyon
Yapay zeka ile tedarik zinciri operasyonlarını dönüştürün: talep algılama, tedarikçi risk puanlaması, rota optimizasyonu, depo otomasyonu ve kesinti tahmini. 2026 kılavuzu.
B2B E-ticaret Stratejisi: 2026'da Toptan Satış Çevrimiçi İş Kurun
Toptan satış fiyatlandırması, hesap yönetimi, kredi koşulları, delme katalogları ve Odoo B2B portal yapılandırması stratejileriyle B2B e-ticarette uzmanlaşın.