How to Implement Custom Sorting Options in the Odoo 19 Website Portal
Enhancing user experience is one of the most important factors when building and customizing web portals in any Business Management Software, and Odoo 19 provides a highly flexible framework for creating personalized portal interactions. One key feature often required by businesses is the ability to sort portal records allowing users to view information in the order they find most helpful.
Whether you’re displaying recruitment applications, purchase orders, invoices, or service requests, adding a custom “Sort By” option in the Odoo portal significantly improves usability and navigation.
In this blog, we will take a deep dive into how to add sorting functionality to the Odoo 19 website portal. We will walk through creating a custom menu, displaying data in the portal, implementing sort options, understanding the controller logic, and ensuring smooth integration between XML templates and Python controllers.
Why Add Sorting Options in the Odoo 19 Portal?
The Odoo portal is designed to give customers a self-service experience, where they can log in and view information such as:
-
Sales orders
-
Purchase orders
-
Quotations
-
Invoices
-
Recruitment applications
-
Timesheets
-
Tickets
However, when the list grows large, users need a way to locate information efficiently. Sorting options such as “Sort by Date,” “Sort by Status,” or “Sort by Name” help organize records so that users can quickly find what matters most.
Odoo provides a powerful and extendable structure that allows developers to easily implement this feature without modifying core code.
Step 1: Add a Custom Menu to the Customer Portal
Before adding sorting features, we first create a dedicated portal menu—for example, Recruitment. This menu item will appear under the “My Account” section of the customer portal.
This is done using XML inheritance:
XML Snippet for Adding the Recruitment Menu
<template id="portal_recruitment" name="Recruitment" inherit_id="portal.portal_breadcrumbs" priority="30"> <xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside"> <li t-if="page_name == 'recruitment'" t-attf-class="breadcrumb-item #{'active ' if recruitment else ''}"> <a t-if="recruitment" t-attf-href="/recruitment?{{ keep_query() }}">Recruitment</a> <t t-else="">Recruitment</t> </li> </xpath> </template>
This extends the portal breadcrumbs and ensures the new section appears when users navigate to the recruitment page.
Next, the menu entry is added to the customer’s “My Account” dashboard:
<template id="portal_my_home_menu_recruitment" name="Recruitment" inherit_id="portal.portal_my_home" customize_show="True" priority="30"> <xpath expr="//div[hasclass('o_portal_docs')]" position="before"> <t t-set="portal_client_category_enable" t-value="True"/> </xpath> <div id="portal_client_category" position="inside"> <t t-call="portal.portal_docs_entry"> <t t-set="icon" t-value="'/portal_recruitment/static/src/img/recruitment.png'"/> <t t-set="title">Recruitment</t> <t t-set="url" t-value="'/recruitment'"/> <t t-set="text">View the Recruitments</t> <t t-set="placeholder_count" t-value="'portal_recruitment'"/> </t> </div> </template>
Now that the menu is ready, the next step is displaying the data and enabling sorting.
Step 2: Prepare the Controller for Data Display
The controller is responsible for:
-
Fetching recruitment records
-
Passing them to the template
-
Handling sorting logic
-
Rendering the correct view
Start by extending the default CustomerPortal controller:
class WebsiteEvents(CustomerPortal): def _prepare_home_portal_values(self, counters): values = super()._prepare_home_portal_values(counters) if 'portal_recruitment' in counters: values['portal_recruitment'] = request.env[ 'hr.applicant'].sudo().search_count([('user_id', '=', request.env.uid)]) return values
This ensures that the number of recruitment items appears on the “My Account” dashboard.
Step 3: Add Sorting Logic in the Controller
Sorting is enabled by preparing a sorting dictionary and applying it when retrieving data.
@http.route(['/recruitment', '/Recruitment/page/<int:page>'], type='http', auth="user", website=True) def portal_recruitment(self, sortby=None): searchbar_sortings = { 'date': {'label': _('Date'), 'order': 'create_date desc'}, 'stage': {'label': _('Status'), 'order': 'stage_id'}, }
How Sorting Works
-
Keys define the sorting option names
-
Labels define the display text
-
Order defines the SQL sorting logic
If no sorting option is selected:
if not sortby: sortby = 'date'
The selected sorting is applied:
order = searchbar_sortings[sortby]['order'] recruitment = request.env['hr.applicant'].sudo().search( [('user_id', '=', request.env.uid)], order=order)
Finally, the results are passed to the template:
return request.render('portal_recruitment.portal_my_home_recruitment_views', { 'recruitment': recruitment, 'searchbar_sortings': searchbar_sortings, 'sortby': sortby, 'page_name': 'recruitment', })
Step 4: Displaying Sorted Data in the Portal Template
The XML template loops through the sorted recruitment records:
<t t-foreach="recruitment" t-as="record"> <tr> <td class='text-left'> <span t-field="record.partner_name"/> </td> <td class='text-center'> <span t-field="record.create_date"/> </td> <td class='text-center'> <span t-field="record.job_id.name"/> </td> <td class='text-end'> <span t-field="record.stage_id.name"/> </td> </tr> </t>
The portal automatically updates the list when users switch between sorting options.
Step 5: Understanding the Sorting Dropdown
Once implemented, users will see a “Sort By” dropdown at the top of the page. Options may include:
-
Sort by Date
-
Sort by Status
This improves usability, helping customers and employees navigate records efficiently.
Step 6: Extending Sorting Options Further
You can add new sorting fields, for example:
-
Sorting by Job Position
-
Sorting by Applicant Name
-
Sorting by Deadline
-
Sorting by Priority
Simply add entries to the sorting dictionary:
'name': {'label': _('Name'), 'order': 'partner_name'},
And Odoo will support the new sorting option immediately.
Conclusion
Adding a sorting feature to the Odoo 19 website portal is a powerful way to enhance user experience and improve information accessibility. By combining XML inheritance, portal controller extensions, and flexible sorting logic, you can build highly interactive and user-friendly portal pages. Whether you are creating recruitment views, invoice listings, or project summaries, Odoo’s modular design makes it simple to adapt, extend, and customize your portal functionality.
This feature is especially useful for organizations managing large sets of application data or customer information—ensuring that your Odoo portal remains intuitive, responsive, and aligned with real-world workflow needs.