Opened 9 years ago

Last modified 13 months ago

#3558 new enhancement

BlogList macro: Allow the base heading level to be specified

Reported by: James Teh Owned by: Odd Simon Simonsen
Priority: highest Component: FullBlogPlugin
Severity: normal Keywords:
Cc: Mitar Trac Release: 0.11


When using the BlogList macro with the full or float formats, blog posts are rendered with their heading inside an h1 tag. Structurally, this infers a top level heading and associated section. This breaks the structure of a document when the BlogList macro is used to render posts beneath the top level. For example, on the front page of, I use heading level 1 for the page title and heading level 2 for the main section headings. "News" is a main section heading (level 2), so the blog post titles should be at heading level 3.

Attachments (1)

tracfullblog_heading-level.patch (3.8 KB) - added by James Teh 6 years ago.
Patch updated for latest code

Download all attachments as: .zip

Change History (7)

comment:1 Changed 9 years ago by James Teh

This patch uses a stream filter to "rebase" the heading levels. I don't think there is a nice way to do this from within the templates. py:replace or py:match might be used to achieve this, but it would be a bit ugly at best. Nevertheless, a better implementation is welcome.

Note that the web site given as an example above ( has this patch applied. The blog posts appear at heading level 3 instead of heading level 1. Heading level 1 is of course still the default.

comment:2 Changed 8 years ago by Mitar

Cc: Mitar added; anonymous removed

Why was this patch not integrated? I would also like this feature. Even more, I would like to be able to specify base heading level of posts also when listed or displayed standalone (through some configuration option). I would like to do something like for lists:

<h1>Listing description</h1> ... <h2>Post title</h2> ... <h3>First heading level, for example = ... = in post content<h3>

and when displayed standalone:

<h1>Post title</h1> ... <h2>First heading level, for example = ... = in post content<h2>

This would make blog pages semantically valid XML/HTML.

I have tried to do this with site.html template (using #6023):

<py:match path="div[@class='blog-main-list']//h6"><h6>${select('*|text()')}</h6></py:match>
<py:match path="div[@class='blog-main-list']//h5"><h6>${select('*|text()')}</h6></py:match>
<py:match path="div[@class='blog-main-list']//h4"><h5>${select('*|text()')}</h5></py:match>
<py:match path="div[@class='blog-main-list']//h3"><h4>${select('*|text()')}</h4></py:match>
<py:match path="div[@class='blog-main-list']//h2"><h3>${select('*|text()')}</h3></py:match>
<py:match path="div[@class='blog-main-list']//h1"><h2>${select('*|text()')}</h2></py:match>
<py:match path="div[@class='blog-main-list']//div[@class='blog-body']//h6"><h6>${select('*|text()')}</h6></py:match>
<py:match path="div[@class='blog-main-list']//div[@class='blog-body']//h5"><h6>${select('*|text()')}</h6></py:match>
<py:match path="div[@class='blog-main-list']//div[@class='blog-body']//h4"><h6>${select('*|text()')}</h6></py:match>
<py:match path="div[@class='blog-main-list']//div[@class='blog-body']//h3"><h5>${select('*|text()')}</h5></py:match>
<py:match path="div[@class='blog-main-list']//div[@class='blog-body']//h2"><h4>${select('*|text()')}</h4></py:match>
<py:match path="div[@class='blog-main-list']//div[@class='blog-body']//h1"><h3>${select('*|text()')}</h3></py:match>

but it does not work because of the #8770. So the other way I see this to make work is to do it in plugins code. With for example two configuration options which would output from wiki_to_html in post render pipe through header rebaser.

comment:3 Changed 8 years ago by Odd Simon Simonsen

Priority: normalhighest

I've somehow overlooked this ticket and patch. It is useful, and a nice implementation. Thanks jteh!

I'll look to get it integrated as a macro-only thing, and don't think I want to redo the regular blog listings.

comment:4 Changed 8 years ago by Mitar

I doubt it has to be much reworked. Would not it be enough to change line to:

${wiki_to_html(context(post.resource), do_shorten and post.body[:blog_max_size] + ' ... ' or post.body) | HeadingRebaser(list_heading_level_from_config if list_mode else alone_heading_level_from_config)}

with HeadingRebaser from above patch?

comment:5 in reply to:  3 Changed 6 years ago by James Teh

Replying to osimons:

I'll look to get it integrated as a macro-only thing

Is there something that needs to be fixed/changed before this can be committed? I'm happy to try to do the required work if any.

Changed 6 years ago by James Teh

Patch updated for latest code

comment:6 Changed 13 months ago by anonymous

Has any changes with this problem?

Modify Ticket

Change Properties
Set your email in Preferences
as new The owner will remain Odd Simon Simonsen.

Add Comment

E-mail address and name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.