Bạn dựng một trang tùy biến bằng controller — trang ưu đãi, trang tra cứu. Nó chạy tốt. Nhưng vài tuần sau nhận ra Google chưa hề index nó: trang không có trong sitemap.xml, <title> trơ trọi, không thẻ meta mô tả. Lý do đơn giản: route tự viết không tự động vào sitemap hay có SEO — Odoo cần bạn khai. Bài này chỉ cách làm đúng: sitemap=True để route vào sitemap.xml, callback cho URL động, và đặt title/meta/OG qua website.layout — tất cả kiểm chứng bằng sitemap.xml và thẻ <head> thật trên Odoo 19.

sitemap=True: đưa route vào sitemap.xml

Odoo tự sinh /sitemap.xml từ hai nguồn: các website.page đã đăng, và các route controller có khai sitemap. Route của bạn phải nói rõ nó có muốn vào sitemap không — bằng tham số sitemap trong @http.route.

Ảnh chụp mã Python nền tối. Route http quan_ca_phe uu-dai type http auth public website True sitemap True, chú thích sitemap True nghĩa route này vào sitemap xml. Hàm uu_dai trả về request render uu_dai_page với các biến website.layout đọc để dựng title và meta: additional_title Ưu đãi thành viên, website_meta_description Chương trình ưu đãi cho thẻ thành viên giảm giá tích điểm quà tặng, website_meta_keywords ưu đãi thẻ thành viên cà phê. Phần dưới hai route khác: route quan_ca_phe noi_bo với sitemap False nghĩa không vào sitemap dùng cho trang riêng hoặc API; và một hàm sitemap_the nhận env rule qs lặp các thẻ yield dict loc gạch chéo the id, gắn vào route the int the_id với sitemap bằng sitemap_the cho URL động có tham số

Hình 1: Ba kiểu khai sitemap. sitemap=True — URL tĩnh vào sitemap. sitemap=False — route không vào (trang nội bộ, API). sitemap=<hàm callback> — cho URL động có tham số (như /the/<id>): Odoo gọi hàm để tự liệt kê từng URL cụ thể. Lưu ý Odoo 19 cảnh báo nếu route website bỏ trống hẳn tham số sitemap — nên luôn khai rõ.

Curl thật /sitemap.xml sau khi thêm route, nó xuất hiện ngay:

Ảnh chụp terminal nền tối sitemap xml thật trên Odoo 19 sau khi thêm route sitemap True. Lệnh curl robots txt trả về User-agent sao và dòng Sitemap trỏ tới sitemap xml. Lệnh curl sitemap xml trả về urlset chứa nhiều url loc: trang chủ gạch chéo, gạch chéo shop, gạch chéo blog, và dòng được tô sáng loc http gạch chéo quan_ca_phe gạch chéo uu-dai với chú thích route của ta. Ghi chú tổng 20 lên 21 URL, xoá route thì tự về 20, cache regen sau 12 giờ

Hình 2: robots.txt trỏ crawler tới sitemap.xml; sitemap.xml liệt kê mọi trang công khai. Sau khi thêm route sitemap=True, /quan_ca_phe/uu-dai xuất hiện — tổng từ 20 lên 21 URL. Lưu ý: sitemap được cache 12 giờ (lưu trong một ir.attachment), nên thay đổi không hiện ngay — xoá cache để thấy liền khi test.

Đặt title, meta description và Open Graph

Vào được sitemap là để Google tìm thấy; còn để Google hiểu và hiển thị đẹp thì cần thẻ meta. website.layout đọc vài biến từ giá trị controller truyền vào để dựng <head>:

  • additional_title → <title> (thành "<additional_title> | <tên website>").
  • website_meta_description → <meta name="description"> (đoạn mô tả Google hiện dưới tiêu đề).
  • website_meta_keywords → <meta name="keywords">.

Và từ những cái đó, website.layout tự sinh luôn thẻ Open Graph (og:title, og:url, og:image...) để chia sẻ lên Facebook/Zalo hiện thumbnail đẹp. Curl trang và xem <head> thật:

Ảnh chụp terminal nền tối thẻ SEO trong head của trang dựng từ giá trị controller truyền. Lệnh curl quan_ca_phe uu-dai grep meta title. Kết quả: title Ưu đãi thành viên gạch đứng My Website chú thích additional_title; meta name description content Chương trình ưu đãi cho thẻ thành viên; meta name keywords content ưu đãi thẻ thành viên cà phê; meta property og type content website; meta property og title content Ưu đãi thành viên gạch đứng My Website; meta property og url content http quan_ca_phe uu-dai; meta property og image content http web image website 1 logo. Ghi chú description và keywords do ta truyền còn og sao website layout tự sinh

Hình 3: Thẻ <head> thật. <title> và <meta name="description"> đúng những gì controller truyền; og:type, og:title, og:url, og:image do website.layout tự sinh. Chỉ cần truyền additional_title + website_meta_description, phần còn lại Odoo lo.

Chi tiết đáng nhớ

  • Cache sitemap 12 giờ. sitemap.xml được sinh rồi cache trong một ir.attachment (12h). Trang mới sẽ vào sitemap nhưng có độ trễ — bình thường không sao (Google cũng không crawl liên tục), chỉ khi test mới cần xoá cache để thấy ngay.
  • Chỉ trang công khai mới nên vào sitemap. sitemap=True cho trang auth='public' thật sự công khai; trang cần đăng nhập (auth='user') đặt sitemap=False — đưa vào sitemap chỉ khiến Google gặp trang chuyển hướng đăng nhập.
  • URL động cần callback. Route có tham số (/the/<id>) không thể chỉ sitemap=True (Odoo không biết những id nào tồn tại) — phải viết hàm callback yield từng {'loc': ...}.
  • website.page thì tự động. Trang khai bằng XML (như phần 170) tự vào sitemap nếu website_published=True và website_indexed=True — không cần code.
  • Dữ liệu có cấu trúc (JSON-LD). Muốn rich snippet (sao đánh giá, giá...), thêm <script type="application/ld+json"> trong template với schema.org phù hợp — Odoo không tự sinh cái này cho trang tùy biến.

Ba ý mang về

  1. Route tùy biến không tự vào sitemap — khai sitemap=True (URL tĩnh), sitemap=<callback> (URL động, yield từng loc), hoặc sitemap=False (không index); Odoo 19 cảnh báo nếu bỏ trống hẳn.
  2. SEO meta đặt qua giá trị controller mà website.layout đọc: additional_title (title), website_meta_description, website_meta_keywords — và OG tags được tự sinh từ đó.
  3. sitemap.xml cache 12 giờ (trong ir.attachment); robots.txt trỏ tới nó; website.page công khai + indexed tự vào sitemap; URL động và JSON-LD thì phải tự lo.

Ta đã lo phần máy tìm kiếm. Phần sau quay lại phía người dùng thật: cách gắn trang tùy biến vào điều hướng của website. Phần sau nói về website menu và page quản lý — thêm mục vào thanh menu, tổ chức các trang, và cho người quản trị bật/tắt, sắp xếp chúng ngay trên giao diện.