Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions website_blog_schema_org/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

===============================
Website Blog Schema.org JSON-LD
===============================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:8278fba613e989bd9de78cadfd1d5a61f4b079fa81a4db585d93c48dd6c6d2b8
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fwebsite-lightgray.png?logo=github
:target: https://github.com/OCA/website/tree/19.0/website_blog_schema_org
:alt: OCA/website
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/website-19-0/website-19-0-website_blog_schema_org
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/website&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds structured ``schema.org/BlogPosting`` JSON-LD metadata
to every published Odoo Website blog post.

Why it matters
--------------

Search engines understand HTML, but they understand structured data even
better. By embedding a JSON-LD block in each blog post, you help Google
and other crawlers surface rich results such as headline, author,
publication date, modification date, publisher and featured image.

The module does not change the visual design of your blog; it only
injects an invisible ``<script type="application/ld+json">`` block that
uses the content you already maintain in Odoo.

What is injected
----------------

The JSON-LD block is generated from the blog post record and includes:

- ``@type``: ``BlogPosting``
- ``headline``: post name
- ``url`` and ``mainEntityOfPage``: canonical post URL
- ``datePublished``: post date
- ``dateModified``: last modification date
- ``author``: name of the post author
- ``publisher``: website name and logo
- ``inLanguage``: current environment language
- ``image``: OpenGraph image when available

Technical notes
---------------

The module inherits ``blog.post`` and adds ``_get_article_jsonld()``.
This method builds a Python dictionary following the schema.org
``BlogPosting`` vocabulary, serialises it with
``json.dumps(..., ensure_ascii=False)`` and returns it wrapped in
``markupsafe.Markup`` so Odoo renders it as safe HTML.

The template inherits ``website_blog.blog_post_complete`` and injects
the script block right before ``<section id="o_wblog_post_top">`` using
``t-out``.

**Table of contents**

.. contents::
:local:

Installation
============

To install this module, you need to:

1. Add this repository to your addons path, or install the
``odoo-addon-website_blog_schema_org`` package.
2. Make sure ``website_blog`` is installed.
3. Update the apps list and install **Website Blog Schema.org JSON-LD**.

Usage
=====

1. Open a published blog post in the frontend.
2. Open the browser developer tools and search for
``application/ld+json`` in the page source.
3. You should see a JSON-LD script block right before the main post
section.
4. Validate it with Google's `Rich Results
Test <https://search.google.com/test/rich-results>`__ or the
`Schema.org Validator <https://validator.schema.org/>`__.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/website/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/website/issues/new?body=module:%20website_blog_schema_org%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Domatix

Contributors
------------

- `Domatix <https://www.domatix.com>`__:

- Nacho Serra

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/website <https://github.com/OCA/website/tree/19.0/website_blog_schema_org>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions website_blog_schema_org/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
13 changes: 13 additions & 0 deletions website_blog_schema_org/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "Website Blog Schema.org JSON-LD",
"summary": "Inject schema.org BlogPosting JSON-LD metadata into blog posts",
"version": "19.0.1.0.0",
"category": "Website",
"license": "LGPL-3",
"website": "https://github.com/OCA/website",
"author": "Domatix, Odoo Community Association (OCA)",
"application": False,
"installable": True,
"depends": ["website_blog"],
"data": ["views/blog_post_templates.xml"],
}
1 change: 1 addition & 0 deletions website_blog_schema_org/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import blog_post
57 changes: 57 additions & 0 deletions website_blog_schema_org/models/blog_post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2026 Domatix <info@domatix.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

import json

from markupsafe import Markup

from odoo import models


class BlogPost(models.Model):
_inherit = "blog.post"

def _get_article_jsonld(self):
"""Build a schema.org BlogPosting JSON-LD block."""
self.ensure_one()
website = self.website_id or self.env["website"].get_current_website()
base_url = website.get_base_url()
slug = self.env["ir.http"]._slug
url = f"{base_url}/blog/{slug(self.blog_id)}/{slug(self)}"
logo_url = f"{base_url}/web/image/website/{website.id}/logo"
og_img = self.website_meta_og_img
if og_img and og_img.startswith("http"):
image = og_img
elif og_img:
image = f"{base_url}/web/image/{og_img}"
else:
image = None
date_published = self.post_date.isoformat() if self.post_date else None
date_modified = self.write_date.isoformat() if self.write_date else None
data = {
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": self.name or "",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": url,
},
"url": url,
"datePublished": date_published,
"dateModified": date_modified,
"publisher": {
"@type": "Organization",
"name": website.name,
"logo": {
"@type": "ImageObject",
"url": logo_url,
},
},
"inLanguage": self.env.lang,
}
author_name = self.author_id.sudo().name
if author_name:
data["author"] = {"@type": "Person", "name": author_name}
if image:
data["image"] = image
return Markup(json.dumps(data, ensure_ascii=False))
3 changes: 3 additions & 0 deletions website_blog_schema_org/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
2 changes: 2 additions & 0 deletions website_blog_schema_org/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [Domatix](https://www.domatix.com):
- Nacho Serra
27 changes: 27 additions & 0 deletions website_blog_schema_org/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
This module adds structured `schema.org/BlogPosting` JSON-LD metadata to every published Odoo Website blog post.

## Why it matters

Search engines understand HTML, but they understand structured data even better. By embedding a JSON-LD block in each blog post, you help Google and other crawlers surface rich results such as headline, author, publication date, modification date, publisher and featured image.

The module does not change the visual design of your blog; it only injects an invisible `<script type="application/ld+json">` block that uses the content you already maintain in Odoo.

## What is injected

The JSON-LD block is generated from the blog post record and includes:

* `@type`: `BlogPosting`
* `headline`: post name
* `url` and `mainEntityOfPage`: canonical post URL
* `datePublished`: post date
* `dateModified`: last modification date
* `author`: name of the post author
* `publisher`: website name and logo
* `inLanguage`: current environment language
* `image`: OpenGraph image when available

## Technical notes

The module inherits `blog.post` and adds `_get_article_jsonld()`. This method builds a Python dictionary following the schema.org `BlogPosting` vocabulary, serialises it with `json.dumps(..., ensure_ascii=False)` and returns it wrapped in `markupsafe.Markup` so Odoo renders it as safe HTML.

The template inherits `website_blog.blog_post_complete` and injects the script block right before `<section id="o_wblog_post_top">` using `t-out`.
6 changes: 6 additions & 0 deletions website_blog_schema_org/readme/INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
To install this module, you need to:

1. Add this repository to your addons path, or install the
``odoo-addon-website_blog_schema_org`` package.
2. Make sure ``website_blog`` is installed.
3. Update the apps list and install **Website Blog Schema.org JSON-LD**.
4 changes: 4 additions & 0 deletions website_blog_schema_org/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1. Open a published blog post in the frontend.
2. Open the browser developer tools and search for `application/ld+json` in the page source.
3. You should see a JSON-LD script block right before the main post section.
4. Validate it with Google's [Rich Results Test](https://search.google.com/test/rich-results) or the [Schema.org Validator](https://validator.schema.org/).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading