[IMP] howtos/website_theming: Adapts "Layout" chapter

closes odoo/documentation#16589

Signed-off-by: Brandon Mercier (bram) <bram@odoo.com>
This commit is contained in:
Brandon Mercier
2026-02-23 15:44:20 +01:00
parent 32a8a76278
commit 7541b7e20b

View File

@@ -207,7 +207,7 @@ below:
.. code-block:: xml
<xpath expr="//header" position="attributes">
<attribute name="class" add="x_airproof_header" separator=" "/>
<attribute name="class" add="x_airproof_header" separator=" " />
</xpath>
This XPath moves the element with `.o_footer_scrolltop_wrapper` class before the element with the
@@ -255,6 +255,42 @@ QWeb
QWeb is the primary templating engine used by Odoo. It is an XML templating engine mainly used to
generate HTML fragments and pages.
`t-call` directives can receive parameters:
.. code-block:: xml
<!-- Old way -->
<t t-call="portal.user_dropdown">
<t t-set="_icon" t-value="True" />
<t t-set="_item_class" t-valuef="dropdown" />
</t>
<t t-call="website.layout">
<t t-set="additional_title">My page title</t>
</t>
<!-- New way (Parametric) -->
<t t-call="portal.user_dropdown"
_icon="true"
_item_class.f="dropdown" />
<t t-call="website.layout"
additional_title.translate="My page title" />
.. list-table::
:header-rows: 1
:stub-columns: 1
:widths: 20 80
* - Attribute (examples)
- Description
* - `_icon="true"`
- Pass the raw value (here a boolean set to `true`)
* - `_item_class.f="dropdown"`
- Pass value as a string
* - `additional_title.translate="My page title"`
- Pass value as a string
.. seealso::
:doc:`QWeb templates documentation <../../reference/frontend/qweb>`.
@@ -281,7 +317,7 @@ First, create a record to declare the field. This field has to be linked to an e
<field name="ttype">html</field>
<field name="state">manual</field>
<field name="index">0</field>
<field name="model_id" ref="website_blog.model_blog_post"/>
<field name="model_id" ref="website_blog.model_blog_post" />
</record>
.. note:: Fields creation is also possible (and recommended) through `a model using Python </developer/tutorials/backend>`_.
@@ -300,10 +336,10 @@ interface and fill it afterwards.
<record id="view_blog_post_form_category" model="ir.ui.view">
<field name="name">view_blog_post_form_category</field>
<field name="model">blog.post</field>
<field name="inherit_id" ref="website_blog.view_blog_post_form"/>
<field name="inherit_id" ref="website_blog.view_blog_post_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='blog_id']" position="before">
<field name="x_post_category" string="..." placeholder="..."/>
<field name="x_post_category" string="..." placeholder="..." />
</xpath>
</field>
</record>
@@ -318,7 +354,7 @@ The field value can be shown somewhere in a page by calling `model_name.field_na
.. code-block:: xml
:caption: ``/website_airproof/views/website_blog_templates.xml``
<h1 t-field="blog_post.x_post_category"/>
<h1 t-field="blog_post.x_post_category" />
.. _website_themes/layout/background :
@@ -393,7 +429,7 @@ Enable one of the header default templates.
:caption: ``/website_aiproof/data/presets.xml``
<record id="website.template_header_default" model="ir.ui.view">
<field name="active" eval="False"/>
<field name="active" eval="False" />
</record>
Explicitly set the desired template in the `primary_variables.scss` file.
@@ -403,15 +439,15 @@ Explicitly set the desired template in the `primary_variables.scss` file.
$o-website-values-palettes: (
(
'header-template': 'Contact',
'header-template': 'stretch',
),
);
.. code-block:: xml
:caption: ``/website_airproof/data/presets.xml``
<record id="website.template_header_contact" model="ir.ui.view">
<field name="active" eval="True"/>
<record id="website.template_header_stretch" model="ir.ui.view">
<field name="active" eval="True" />
</record>
.. _website_themes/layout/header/standard/mobile :
@@ -423,7 +459,7 @@ Each header template comes with the `template_header_mobile` template ensuring a
experience accross every devices.
.. seealso::
`Mobile header template on Odoo's Git repository <https://github.com/odoo/odoo/blob/43b20e6e52526c415e28c21810cd7023f6feef1e/addons/website/views/website_templates.xml#L354>`_
`Mobile header template on Odoo's Git repository <https://github.com/odoo/odoo/blob/e9c9f0ca0a54b9ca966451d12b7eecc6b9a7d6e0/addons/website/views/website_templates.xml#L383>`_
.. _website_themes/layout/header/custom :
@@ -442,9 +478,9 @@ Create your own template and add it to the list.
Use the following code to add an option for your new custom header on the Website Builder.
.. code-block:: xml
:caption: ``/website_airproof/static/src/website_builder/header_option.xml``
:caption: ``/website_airproof/static/src/website_builder/header_template_option.xml``
<t t-inherit="website.HeaderTemplateOption" t-inherit-mode="extension">
<t t-name="website_airproof.HeaderTemplateOption" t-inherit="website.HeaderTemplateOption" t-inherit-mode="extension">
<xpath expr="//BuilderRow[@label.translate='Template']//BuilderSelect" position="inside">
<BuilderSelectItem
id="'header_airproof_opt'"
@@ -453,16 +489,16 @@ Use the following code to add an option for your new custom header on the Websit
{
action: 'websiteConfig',
actionParam: {
views: ['website_airproof.header'],
vars: { 'header-template': 'airproof' },
checkVars: false,
}
}
views: ['website_airproof.header'],
vars: { 'header-template': 'airproof' },
checkVars: false,
},
},
]">
<Img attrs="{ style: 'width: calc(100% - 0.5rem);' }" src="'/website_airproof/static/src/img/wbuilder/template_header_opt.svg'"/>
<Img src="'/website_airproof/static/src/img/wbuilder/template-header-opt.svg'" attrs="{ style: 'width: calc(100% - 0.5rem);' }" />
</BuilderSelectItem>
</xpath>
</t>
</t>
.. list-table::
:header-rows: 1
@@ -472,10 +508,12 @@ Use the following code to add an option for your new custom header on the Websit
* - Attribute
- Description
* - views
- The template to enable
- The template(s) to enable
* - vars
- The name given to the variable
* - <Img> src
- The name given to the variable (same as used into `primary_variables.scss`)
* - checkVars
- Determine if `vars` are compared to set the option status.
* - src (in `Img`)
- The thumbnail of the custom template shown in the templates selection on the Website Builder
Now you have to explicitly define that you want to use your custom template in the Odoo SASS
@@ -527,9 +565,8 @@ Logo
.. code-block:: xml
<t t-call="website.placeholder_header_brand">
<t t-set="_link_class" t-valuef="..."/>
</t>
<t t-call="website.placeholder_header_brand"
_link_class.f="..." />
.. important::
@@ -544,10 +581,9 @@ Menu
.. code-block:: xml
<t t-foreach="website.menu_id.child_id" t-as="submenu">
<t t-call="website.submenu">
<t t-set="item_class" t-valuef="nav-item"/>
<t t-set="link_class" t-valuef="nav-link"/>
</t>
<t t-call="website.submenu"
item_class.f="nav-item"
link_class.f="nav-link" />
</t>
.. _website_themes/layout/header/components/signin :
@@ -557,10 +593,9 @@ Sign in
.. code-block:: xml
<t t-call="portal.placeholder_user_sign_in">
<t t-set="_item_class" t-valuef="nav-item"/>
<t t-set="_link_class" t-valuef="nav-link"/>
</t>
<t t-call="portal.placeholder_user_sign_in"
_item_class.f="nav-item"
_link_class.f="nav-link" />
.. _website_themes/layout/header/components/user_dropdown :
@@ -569,14 +604,13 @@ User dropdown
.. code-block:: xml
<t t-call="portal.user_dropdown">
<t t-set="_user_name" t-value="true"/>
<t t-set="_icon" t-value="false"/>
<t t-set="_avatar" t-value="false"/>
<t t-set="_item_class" t-valuef="nav-item dropdown"/>
<t t-set="_link_class" t-valuef="nav-link"/>
<t t-set="_dropdown_menu_class" t-valuef="..."/>
</t>
<t t-call="portal.user_dropdown"
_user_name="true"
_icon="false"
_avatar="false"
_item_class.f="nav-item dropdown"
_link_class.f="nav-link"
_dropdown_menu_class.f="..." />
.. _website_themes/layout/header/components/language_selector :
@@ -585,9 +619,8 @@ Language selector
.. code-block:: xml
<t t-call="website.placeholder_header_language_selector">
<t t-set="_div_classes" t-valuef="..."/>
</t>
<t t-call="website.placeholder_header_language_selector"
_div_classes.f="..." />
.. _website_themes/layout/header/components/cta :
@@ -596,9 +629,8 @@ Call to action
.. code-block:: xml
<t t-call="website.placeholder_header_call_to_action">
<t t-set="_div_classes" t-valuef="..."/>
</t>
<t t-call="website.placeholder_header_call_to_action"
_div_classes.f="..." />
.. _website_themes/layout/header/components/navbar_toggler :
@@ -607,13 +639,12 @@ Navbar toggler
.. code-block:: xml
<t t-call="website.navbar_toggler">
<t t-set="_toggler_class" t-valuef="..."/>
</t>
<t t-call="website.navbar_toggler"
_toggler_class.f="..." />
.. seealso::
You can add a :ref:`header overlay <website_themes/pages/theme_pages/header_overlay>` to position your header over the content of
your page. It has to be done on each page individually.
You can add a :ref:`header overlay <website_themes/pages/theme_pages/header_overlay>` to position
your header over the content of your page. It has to be done on each page individually.
.. _website_themes/layout/footer :
@@ -640,7 +671,7 @@ footer template first.
:caption: ``/website_aiproof/data/presets.xml``
<record id="website.footer_custom" model="ir.ui.view">
<field name="active" eval="False"/>
<field name="active" eval="False" />
</record>
.. code-block:: scss
@@ -656,7 +687,7 @@ footer template first.
:caption: ``/website_airproof/data/presets.xml``
<record id="website.template_footer_links" model="ir.ui.view">
<field name="active" eval="True"/>
<field name="active" eval="True" />
</record>
.. _website_themes/layout/footer/custom :
@@ -670,15 +701,15 @@ active footer template first.
**Option**
.. code-block:: js
:caption: ``/website_airproof/static/src/website_builder/airproof_footer_plugin.js``
:caption: ``/website_airproof/static/src/website_builder/footer_option_plugin.js``
import { Plugin } from "@html_editor/plugin";
import { registry } from "@web/core/registry";
import { _t } from "@web/core/l10n/translation";
import { FooterTemplateChoice } from "@website/builder/plugins/options/footer_template_option";
export class AirproofFooterPlugin extends Plugin {
static id = "airproofFooter";
export class AirproofFooterOptionPlugin extends Plugin {
static id = "airproofFooterOption";
resources = {
footer_templates_providers: () => [
{
@@ -688,15 +719,30 @@ active footer template first.
title: _t("Airproof"),
view: "website_airproof.footer",
varName: "airproof",
imgSrc: "/website_airproof/static/src/img/wbuilder/template_footer_opt.svg",
imgSrc: "/website_airproof/static/src/img/wbuilder/template-footer-opt.svg",
},
},
],
};
}
registry.category("website-plugins").add(AirproofFooterPlugin.id, AirproofFooterPlugin);
registry.category("website-plugins").add(AirproofFooterOptionPlugin.id, AirproofFooterOptionPlugin);
.. list-table::
:header-rows: 1
:stub-columns: 1
:widths: 20 80
* - Property
- Description
* - title
- Display title of the template
* - view
- Template that is enabled.
* - varName
- Value used in `primary_variables.scss` under `footer-template`.
* - imgSrc
- The thumbnail of the custom template shown in the templates selection on the Website Builder
**Declaration**
@@ -712,7 +758,7 @@ active footer template first.
**Template**
.. code-block:: xml
:caption: ``/website_airproof/views/website_templates.xml``
:caption: ``/website_airproof/views/website_templates.xml``
<template id="footer" inherit_id="website.layout" name="Airproof - Footer" active="True">
<xpath expr="//div[@id='footer']" position="replace">
@@ -732,15 +778,15 @@ There is only one template available at the moment for the copyright bar.
To replace the content or modify its structure, you can add your own code to the following XPath.
.. code-block:: xml
:caption: ``/website_airproof/views/website_templates.xml``
:caption: ``/website_airproof/views/website_templates.xml``
<template id="copyright" inherit_id="website.layout">
<xpath expr="//div[hasclass('o_footer_copyright')]" position="replace">
<div class="o_footer_copyright" data-name="Copyright">
<!-- Content -->
</div>
</xpath>
</template>
<template id="copyright" inherit_id="website.layout">
<xpath expr="//div[hasclass('o_footer_copyright')]" position="replace">
<div class="o_footer_copyright" data-name="Copyright">
<!-- Content -->
</div>
</xpath>
</template>
.. _website_themes/layout/dropzone :
@@ -755,7 +801,7 @@ You can define an empty area that the user can fill with snippets.
.. code-block:: xml
<div id="oe_structure_layout_01" class="oe_structure"/>
<div id="oe_structure_layout_01" class="oe_structure" />
.. list-table::
:header-rows: 1
@@ -776,13 +822,13 @@ You can also populate an existing drop zone with your content.
.. code-block:: xml
<template id="oe_structure_layout_01" inherit_id="..." name="...">
<xpath expr="//*[@id='oe_structure_layout_01']" position="replace">
<div id="oe_structure_layout_01" class="oe_structure oe_structure_solo">
<!-- Content -->
</div>
</xpath>
</template>
<template id="oe_structure_layout_01" inherit_id="..." name="...">
<xpath expr="//*[@id='oe_structure_layout_01']" position="replace">
<div id="oe_structure_layout_01" class="oe_structure oe_structure_solo">
<!-- Content -->
</div>
</xpath>
</template>
.. _website_themes/layout/responsive :
@@ -844,15 +890,21 @@ Hide a section on desktop:
.. code-block:: xml
<section class="s_text_block o_cc o_cc1 o_colored_level pt16 pb16 d-lg-none o_snippet_desktop_invisible" data-snippet="s_text_block" name="Text">
<!-- Content -->
<section
class="s_text_block o_cc o_cc1 o_colored_level pt16 pb16 d-lg-none o_snippet_desktop_invisible"
data-snippet="s_text_block"
data-name="Text">
<!-- Content -->
</section>
Hide a column on mobile:
.. code-block:: xml
<section class="s_text_block o_cc o_cc1 o_colored_level pt16 pb16" data-snippet="s_text_block" name="Text">
<section
class="s_text_block o_cc o_cc1 o_colored_level pt16 pb16"
data-snippet="s_text_block"
data-name="Text">
<div class="container s_allow_columns">
<div class="row">
<div class="col-12 col-lg-6 d-none d-lg-block o_snippet_mobile_invisible">