Skip to main content
iVentureTeam

website_publish_button

The Published smart button that turns into red Unpublish when you hover it is two parts: a server method and this widget. website_publish_button renders the label; it toggles nothing itself.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 25, 2026Updated August 25, 20265 min read
Technical namewebsite_publish_button
Field typesboolean
Viewsform (inside stat buttons)
Modulewebsite
Used in core2 occurrences across 2 modules: website_sale, website_profile
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupNo. Added in view XML inside a stat button
Alternativeswebsite_redirect_button, boolean_toggle, boolean

What the publish button field does

Publish state in Odoo's backend is shown on a form's button box, and this widget is the oldest way core renders it. website_publish_button is a component with a template and nothing else: no options, no supported types declared, no click handler.

The template renders two stacked spans over the boolean value. The not hovered span states the fact: Published in green when the field is true, Unpublished in red when false. The hovered span states the action you are about to take: Unpublish in red when currently published, Publish in green otherwise. The flip between them is pure CSS through the o_stat_info hover classes, which is why the widget only makes visual sense inside a stat button.

The toggling is the wrapping button's job. Both core usages are <button name="website_publish_button" type="object"> around <field name="is_published" widget="website_publish_button"/>: the button calls the method, the widget repaints the label from the updated field.

What this means for your team

For anything sold or shown on your website, the publish flag is the last gate before the public sees it. Surfacing it as a large stateful button on the backend form means a product manager can check a shipping method's visibility while editing it, without opening the website. The hover flip is a small piece of UX honesty: at rest the button reports, under the cursor it warns you what clicking will do.

The pattern is worth copying on custom published models, a course catalog, a dealer directory, a careers page, because it reuses the exact mental model your team already has from products and shipping methods: green means live, hover to see the action, click to flip.

Working examples

The complete core pattern

<button name="website_publish_button" type="object"
        class="oe_stat_button" icon="fa-globe">
    <field name="is_published" widget="website_publish_button"/>
</button>

Verbatim from the shipping method and forum badge forms. The outer button carries the method name and the globe icon; the inner field is only the two-state label.

On a custom published model

<!-- model inherits website.published.mixin -->
<button name="website_publish_button" type="object" class="oe_stat_button" icon="fa-globe">
    <field name="is_published" widget="website_publish_button"/>
</button>

Inheriting the mixin gives you the method, the fields and the rights checks; the view snippet gives you the standard button.

One name, two things: widget vs mixin method

The naming collision deserves one careful paragraph, because it trips developers constantly: website_publish_button is simultaneously a widget in the fields registry and a method on website.published.mixin. In the XML above, the name on the button refers to the method; the widget on the field refers to the component. They are wired together only by convention, and either works without the other: swap the inner widget for a plain boolean and clicking still toggles; remove the outer button and the label still renders, inert.

The mixin method itself is three lines: ensure one record, write website_published to its inverse, return the new value. The interesting behavior is in the mixin's write, which raises for users lacking publishing rights, so the button is safe to expose broadly. Note also what the widget does not check: can_publish is never read client side, so users without rights see a clickable button and get the access error only after clicking.

Finally, scope: newer core code renders most publish toggles with standalone components on list and kanban views. This widget remains the form-view, stat-button variant, which is why its core usage count looks so modest next to how often you see publish toggles in Odoo.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. Development branch shows template cosmetics only; see below.
Odoo 19.0VerifiedVerified against the shipped source.
Odoo 18.0VerifiedSame behavior and markup.
Odoo 17.0VerifiedSame behavior; labels moved from inline translation calls to template variables.
Odoo 16.0VerifiedSame behavior on the legacy props API.

Upgrade note. Views carry over unchanged from 16 through 19. In 16 the labels were translated inline in the template; since 17 they are template variables, invisible to XML but relevant if you had patched the template for wording.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. We read the widget's files on the public development branch at the time of writing; the branch is unstable and can change before release.

No functional changes: the JavaScript is byte-identical to 19, and the template only swaps t-esc for t-out plus the new explicit this. prefixes, part of the framework-wide template migration. Views and patches keep working. We re-verify once Odoo 20 ships.

Common problems and fixes

SymptomCause and fix
Clicking the button does nothingThe field was placed without a wrapping type="object" button; the widget itself has no click handler. Wrap it in <button name="website_publish_button" type="object"> as core does.
AccessError when some users clickThe mixin's write checks publishing rights server side; the widget never disables itself client side. Grant the publishing right, or hide the button with groups= for viewer roles.
Label renders as plain text without colors or hover flipThe widget sits outside a stat button, so the o_stat_info hover CSS never applies. Place it inside a button with class oe_stat_button in the form's button box.
Widget shows Unpublished but the page is liveThe field bound is not the one the website checks; is_published vs website_published mismatches on custom models. Bind the widget to the same field the mixin computes, is_published.
Missing widget warning in the consoleThe website module is not installed in this database; the registration lives there. Install website, or drop the widget on non-website databases.

Publish button field vs the alternatives

WidgetBest forKey difference
website_publish_buttonThe Published / Unpublish stat button on forms of website-published recordsPure two-state label with a CSS hover flip; the wrapping button's method does the toggle
website_redirect_buttonJumping from the form to the record's live website pageIts click opens the website URL and never changes the publish state
boolean_toggleFlipping a boolean inline, especially in list viewsAn editable switch that writes the field directly, no server method involved
booleanA plain checkbox rendering of the published flagNo state wording, no hover action, no button-box styling

Choose by interaction: a stat-button label that reports and warns is this widget; an inline switch users flip in lists is boolean_toggle; a button that jumps to the website page instead of toggling is website_redirect_button.

Frequently asked questions

Why does the button say Published normally but Unpublish when I hover?+
By design. The idle span reports the current state; the hover span previews the action a click will take. The swap is pure CSS via the stat button's o_hover classes, so it reads as report at rest and warning under the cursor.
Where is the actual publish logic?+
In website_publish_button, a method on website.published.mixin that writes website_published to its inverse. The widget only displays the boolean; the button element calls the method.
How do I add this to my own model?+
Inherit website.published.mixin on the model, then copy the core snippet: a type="object" stat button named website_publish_button containing the is_published field with this widget.
Why do products use a different publish toggle?+
Newer core screens render publish state through standalone components and list-view toggles. This widget is the older form-view variant, still used on shipping methods and forum badges, and still the simplest one to reuse in custom forms.
Can unpublished users see the button?+
Yes, visibility is not gated client side. Users without publishing rights get a server access error after clicking, so hide the button with groups= if that is confusing for viewer roles.

Publishing to your store still feels riskier than it should?

Clean publish workflows, staged product launches and page visibility rules are bread and butter of our Odoo eCommerce work. We build storefronts where what is live is always one glance, and one deliberate click, away.

Book a free consultation

How this page was produced

Verified by reading publish_button.js and its template in the Odoo 19.0 website module, the mixin method in website/models/mixins.py, and both core usages in website_sale and website_profile. Branch history was diffed across 16.0 through the development branch. Spotted an error? Tell us and we will correct the page.