theme-snippets について
Odoo のウェブサイトスニペットを開発するためのリファレンスです。静的・データ駆動型テンプレート、カスタマイズ項目、バージョン差を扱い、各バージョン向けにスニペットを作成・調整する開発者を対象としています。
主な機能
- 01静的スニペットテンプレート一覧
- 02動的スニペットのデータフロー
- 03スニペット設定要素と属性
- 04JavaScript ハンドラーとウィジェット
- 05Odoo 14~19 のバージョン差
活用シーン
- 01ランディングページや FAQ 用の選択
- 02Odoo モジュールへのカスタムスニペット登録
- 03編集可能なスニペットコントロールの設定
- 04データ駆動型の商品表示の構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ ahmed-lakosha/ odoo-plugins --skill theme-snippetsインストール後、Claude Code で/theme-snippetsを入力して読み込まれたか確認します。
詳細
Odoo Webサイトスニペットのリファレンス
スニペットのアーキテクチャ
STATIC SNIPPETS (81+ templates) DYNAMIC SNIPPETS (data-driven)
├── Pre-built HTML ├── ir.filters (data source)
├── Drag & drop ├── website.snippet.filter (fetcher)
└── 6 categories └── Display templates (renderer)
SNIPPET OPTIONS SYSTEM
we-select | we-button | we-colorpicker | we-input
data-selector | data-select-class | data-js
静的スニペットの一覧(81以上のテンプレート)
構造(14)
| ID | 名前 | 最適な用途 |
|---|---|---|
s_banner | バナー | ランディングページ |
s_cover | カバー | ヘッダー |
s_text_image | テキスト - 画像 | 特徴 |
s_image_text | 画像 - テキスト | 特徴 |
s_title | タイトル | セクションヘッダー |
s_text_block | テキストブロック | コンテンツ |
s_numbers | 数字 | 実績 |
s_three_columns | カラム | コンテンツグリッド |
s_features | 特徴 | メリット |
s_masonry_block | メイソンリー | ギャラリー |
s_image_gallery | 画像ギャラリー | ポートフォリオ |
機能(11)
| ID | 名前 | 最適な用途 |
|---|---|---|
s_comparisons | 比較 | 製品比較 |
s_company_team | チーム | 会社概要ページ |
s_call_to_action | CTA | コンバージョン |
s_references | 導入事例 | ソーシャルプルーフ |
s_accordion | アコーディオン | FAQ |
s_features_grid | 特徴グリッド | メリット |
s_pricelist | 価格表 | 製品 |
s_faq_collapse | FAQ | サポート |
s_tabs | タブ | 情報整理 |
動的コンテンツ(15)
| ID | 名前 | 最適な用途 |
|---|---|---|
s_google_map | Google マップ | お問い合わせページ |
s_website_form | フォーム | 見込み顧客の獲得 |
s_social_media | ソーシャルメディア | エンゲージメント |
s_dynamic_snippet | 動的 | データ表示 |
s_countdown | カウントダウン | イベント |
s_popup | ポップアップ | プロモーション |
s_newsletter_block | ニュースレター | マーケティング |
内部コンテンツ(16)
| ID | 名前 | 最適な用途 |
|---|---|---|
s_card | カード | アイテム |
s_three_cards / s_four_cards | カード | サービス/特徴 |
s_timeline | タイムライン | 沿革 |
s_process_steps | ステップ | チュートリアル |
s_quotes_carousel | お客様の声 | ソーシャルプルーフ |
s_blockquote | 引用ブロック | 強調 |
メガメニュー(9)
| ID | 名前 |
|---|---|
s_mega_menu_multi_menus | 複数のメニュー列 |
s_mega_menu_cards | カード形式のメニュー |
s_mega_menu_big_icons | 大きなアイコンのメニュー |
s_mega_menu_thumbnails | サムネイルギャラリー |
カスタムスニペットの作成
Odoo 14-17:シンプルな登録
<template id="s_my_snippet" name="My Snippet">
<section class="s_my_snippet pt48 pb48 o_cc o_cc1">
<div class="container">
<div class="row">
<div class="col-lg-12 text-center">
<h2>My Custom Snippet</h2>
<p>Content goes here...</p>
</div>
</div>
</div>
</section>
</template>
<template id="s_my_snippet_insert" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_structure']//t[@t-snippet][last()]" position="after">
<t t-snippet="my_module.s_my_snippet"
t-thumbnail="/my_module/static/src/img/snippets/s_my_snippet.svg">
<keywords>my, custom, snippet</keywords>
</t>
</xpath>
</template>
Odoo 18-19:スニペットグループを使用(必須)
<template id="snippet_group_custom" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_groups']" position="inside">
<t snippet-group="custom"
t-snippet="website.s_snippet_group"
string="Custom Snippets"/>
</xpath>
</template>
<template id="s_my_snippet_insert" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_structure']/*[1]" position="before">
<t t-snippet="my_module.s_my_snippet"
string="My Snippet"
group="custom"
t-thumbnail="/my_module/static/src/img/snippets/s_my_snippet.svg"/>
</xpath>
</template>
パネルのカテゴリー
| パネル ID | カテゴリー | XPath |
|---|---|---|
snippet_structure | 構造 | //div[@id='snippet_structure'] |
snippet_media | ギャラリー | //div[@id='snippet_media'] |
snippet_feature | 機能 | //div[@id='snippet_feature'] |
snippet_dynamic | 動的 | //div[@id='snippet_dynamic'] |
snippet_inner_content | 内部コンテンツ | //div[@id='snippet_inner_content'] |
スニペットオプションシステム
We-* 要素
| 要素 | 用途 | 主な属性 |
|---|---|---|
we-select | ドロップダウン | data-name, data-dependencies |
we-button | 切り替え | data-select-class, data-toggle-class |
we-colorpicker | カラーピッカー | data-css-property |
we-input | テキスト/数値 | data-attribute-name, data-unit |
we-range | スライダー | data-min, data-max, data-step |
we-checkbox | 切り替え | data-select-class |
データ属性
| 属性 | 用途 |
|---|---|
data-selector | 対象の CSS セレクター |
data-select-class | CSS クラスの切り替え |
data-css-property | 変更する CSS プロパティ |
data-js | JavaScript ハンドラークラス |
data-dependencies | 条件付き表示 |
data-no-preview | ライブプレビューを無効化 |
オプションの完全な例
<template id="s_my_snippet_options" inherit_id="website.snippet_options">
<xpath expr="." position="inside">
<div data-js="MySnippetHandler"
data-selector=".s_my_snippet"
data-drop-in=".oe_structure">
<we-select string="Layout" data-name="layout_opt">
<we-button data-select-class="layout-grid">Grid</we-button>
<we-button data-select-class="layout-list">List</we-button>
</we-select>
<we-colorpicker string="Background"
data-select-style="true"
data-css-property="background-color"/>
<we-range string="Spacing"
data-select-style="true"
data-css-property="gap"
data-min="0" data-max="100" data-step="5" data-unit="px"/>
</div>
</xpath>
</template>
組み込み JS ハンドラー
BackgroundImage、BackgroundPosition、BackgroundToggler、ColoredLevelBackground、BackgroundShape、ImageTools、Carousel、DynamicSnippet
動的スニペット
アーキテクチャ
Data Source (ir.filters) → Filter (website.snippet.filter) → Display Template
動的スニペットの作成
ステップ 1:フィルターを定義
<record id="dynamic_filter_my_items" model="website.snippet.filter">
<field name="name">My Items</field>
<field name="model_name">my.model</field>
<field name="limit">12</field>
<field name="filter_id" ref="ir_filter_my_items"/>
</record>
ステップ 2:表示テンプレート
<template id="dynamic_filter_template_my_model_card" name="Card">
<t t-foreach="records" t-as="record">
<div class="col-lg-4 mb-4">
<div class="card h-100 shadow-sm">
<img t-att-src="record.image_url" class="card-img-top"/>
<div class="card-body">
<h5 class="card-title" t-esc="record.name"/>
</div>
</div>
</div>
</t>
</template>
ステップ 3:動的スニペット
<template id="s_dynamic_my_items" name="Dynamic My Items">
<section class="s_dynamic_snippet s_dynamic_my_items pt48 pb48"
data-snippet="s_dynamic_my_items"
data-filter-id="my_module.dynamic_filter_my_items"
data-template-key="my_module.dynamic_filter_template_my_model_card"
data-number-of-elements="6">
<div class="container">
<div class="dynamic_snippet_template row"/>
</div>
</section>
</template>
Product Dynamic Snippets (website_sale)
Filters: dynamic_filter_newest_products, dynamic_filter_recently_sold_products, dynamic_filter_recently_viewed_products
Display templates: card_style, centered, horizontal_card, mini, minimalist_*, banner
Snippet JavaScript
publicWidget for Snippets
/** @odoo-module **/
import publicWidget from "@web/legacy/js/public/public_widget";
publicWidget.registry.MySnippet = publicWidget.Widget.extend({
selector: '.s_my_snippet',
disabledInEditableMode: false,
start: function () {
if (!this.editableMode) {
this._initializeAnimations();
}
return this._super(...arguments);
},
destroy: function () {
$(window).off('.mySnippet');
this._super(...arguments);
},
});
Snippet Options Handler
/** @odoo-module **/
import options from "@web_editor/js/editor/snippets.options";
options.registry.MySnippetOption = options.Class.extend({
selectDataAttribute: function(previewMode, widgetValue, params) {
this._super(...arguments);
if (params.attributeName === 'layout') {
this._applyLayout(widgetValue);
}
},
});
Version Differences
| Feature | Odoo 14-17 | Odoo 18-19 |
|---|---|---|
| Registration | Simple XPath | Groups required |
| JavaScript | @odoo-module | Plugin-based (19) |
| Bootstrap | 4.x (14-15) / 5.1.3 (16-17) | 5.1.3 |
| Dynamic Snippets | Basic | Full + Categories |
Odoo 19 Plugin Pattern
import { Plugin } from "@html_editor/plugin";
import { registry } from "@web/core/registry";
export class MySnippetPlugin extends Plugin {
static id = "mySnippet";
resources = {
builder_options: [{
template: "my_module.MySnippetOption",
selector: "section",
applyTo: ".s_my_snippet",
}],
};
}
registry.category("website-plugins").add("mySnippet", MySnippetPlugin);
コメント
Markdown 対応