Blog template markup

Last updated:
  • Marketing Hub
    • Professional or Enterprise
  • CMS Hub
    • Professional or Enterprise

HubSpot blogs consist of blog listing pages and the individual blog posts. In addition to listing the individual blog posts, the blog listing template is also used for rendering the author and tag listing pages. You can either create a single template to render all listing and blog post pages, or you can create two separate templates. 

Below, learn about blog template markup, template components, and customization options.

Render listing pages and posts with one template

To create one template that renders the listing and post pages, add the templateType: blog annotation to the top of your template file. When using one template to render both, you'll use an if statement that evaluates whether the user is looking at a listing page or an individual post. If you are using the drag and drop design manager layouts, this if statement is built into the UI of blog content module buttons.

Within the if statement, you'll write both your post and listing code.

{% if is_listing_view %} Markup for blog listing template {% else %} Markup for blog post template {% endif %}

Alternatively, you can choose to have a separate template for blog post and listing pages. This allows your code to be cleaner and easier to read as a developer, and makes the templates easier to select for content creators. The CMS boilerplate has a separate listing template and post template. If you build separate post and listing templates, this is_listing_view check is not required, you only need to make sure to select the separate templates in Settings > Website > Blog > Templates

Blog settings template selection

Blog listing for loop

The listing of posts is generated by a for loop that iterates through your blog posts. Contents is a predefined sequence of content that contains all the posts contained in that blog.

{% for content in contents %} <div class="post-item"> Post item markup that renders with each iteration. </div> {% endfor %}

Listing template markup

The boilerplate blog listing page contents for loop is rendered with the following markup:

{% for content in contents %} {# On the blog homepage the first post will be featured above older posts #} {% if (loop.first && current_page_num == 1 && !topic) %} <div class="blog-index__post blog-index__post--large"> <a class="blog-index__post-image blog-index__post-image--large" {% if content.featured_image %} style="background-image: url('{{ content.featured_image }}')"; {% endif %} href="{{ content.absolute_url }}"></a> <div class="blog-index__post-content blog-index__post-content--large"> <h2><a href="{{ content.absolute_url }}">{{ }}</a></h2> {{ content.post_list_content }} </div> </div> {% else %} <div class="blog-index__post blog-index__post--small"> <a class="blog-index__post-image blog-index__post-image--small" {% if content.featured_image %} style="background-image: url('{{ content.featured_image }}')"; {% endif %} href="{{ content.absolute_url }}"></a> <div class="blog-index__post-content blog-index__post-content--small"> <h2><a href="{{ content.absolute_url }}">{{ }}</a></h2> {{ content.post_list_content|truncatehtml(100) }} </div> </div> {% endif %} {% endfor %}

If blog_author statement

Within the standard HubSpot blog listing markup, there is an if blog_author statement. This statement evaluates to true when you are looking at an author listing page. An author listing page is a page of posts by a single author. The boilerplate template includes the author's name, bio, and social media accounts.

{% if blog_author %} <div class="blog-header"> <div class="blog-header__inner"> {% if blog_author.avatar %} <div class="blog-header__author-avatar" style="background-image: url('{{ blog_author.avatar }}');"></div> {% endif %} <h1 class="blog-header__title">{{ blog_author.display_name }}</h1> <h4 class="blog-header__subtitle">{{ }}</h4> {% if blog_author.has_social_profiles %} <div class="blog-header__author-social-links"> {% if %} <a href="{{ }}" target="_blank"> {% icon name="link" style="SOLID" width="10" %} </a> {% endif %} {% if blog_author.facebook %} <a href="{{ blog_author.facebook }}" target="_blank"> {% icon name="facebook-f" style="SOLID" width="10" %} </a> {% endif %} {% if blog_author.linkedin %} <a href="{{ blog_author.linkedin }}" target="_blank"> {% icon name="linkedin-in" style="SOLID" width="10" %} </a> {% endif %} {% if blog_author.twitter %} <a href="{{ blog_author.twitter }}" target="_blank"> {% icon name="twitter" style="SOLID" width="10" %} </a> {% endif %} </div> {% endif %} </div> </div> {% else %}

If tag statement

In addition to the if blog_author statement that defines markup that should only render on author listing pages, there is a tag variable that can be used to only render code on a blog topic listing page. The example below is a snippet that uses the page title variable to automatically print the tag name at the top of a tag listing page. This snippet could be added to your blog listing code.

{% if tag %} <h3>Posts about {{ page_meta.html_title|split(" | ")|last }}</h3> {% endif %}

If not simple_list_page statement

Within the for loop, there is an if statement that determines what to render in a simple versus regular listing.

  • A simple listing is a listing of all your posts and does not support pagination. The simple listing is not affected by the post limit blog setting and generally just contains links to the most recent 200 blog posts.
  • The regular listing iterates through the number of posts specified by the post listing blog setting and paginates accordingly.

The address of your simple listing page is the URL for your blog with /all added to the end of the path.

The following code is a simplified version of this if statement that defines what should be iterated in a simple listing page. Notice the if statement uses reverse logic; therefore, the else defines the simple listing view. Optionally you could use an unless statement instead.

{% if not simple_list_page %} Iterated post markup for regular listing {% else %} <h2 class="post-listing-simple"><a href="{{content.absolute_url}}">{{ }}</a></h2> {% endif %}

Listing pagination

Blog listing pages have auto-generated pagination. Your listing template can include logic to allow visitors to easily pages through your blog posts. The boilerplate blog accomplishes simple, number pagination through the following markup:

{% if contents.total_page_count > 1 %} <div class="blog-pagination"> {% set page_list = [-2, -1, 0, 1, 2] %} {% if contents.total_page_count - current_page_num == 1 %}{% set offset = -1 %} {% elif contents.total_page_count - current_page_num == 0 %}{% set offset = -2 %} {% elif current_page_num == 2 %}{% set offset = 1 %} {% elif current_page_num == 1 %}{% set offset = 2 %} {% else %}{% set offset = 0 %}{% endif %} <a class="blog-pagination__link blog-pagination__prev-link {{ "blog-pagination__prev-link--disabled" if !last_page_num }}" href="{{ blog_page_link(last_page_num) }}"> {% icon name="chevron-left" style="SOLID", width="13", no_wrapper=True %} Prev </a> {% for page in page_list %} {% set this_page = current_page_num + page + offset %} {% if this_page > 0 and this_page <= contents.total_page_count %} <a class="blog-pagination__link blog-pagination__number-link {{ "blog-pagination__link--active" if this_page == current_page_num }}" href="{{ blog_page_link(this_page) }}">{{ this_page }}</a> {% endif %} {% endfor %} <a class="blog-pagination__link blog-pagination__next-link {{ "blog-pagination__next-link--disabled" if !next_page_num }}" href="{{ blog_page_link(current_page_num + 1) }}"> Next {% icon name="chevron-right" style="SOLID", width="13", no_wrapper=True %} </a> </div> {% endif %}

Blog post markup

All blog posts in a blog are generated by a single blog template. Content is a predefined object of data that contains information about the requested blog post. Boilerplate posts are rendered with the following markup:

<div class="content-wrapper"> <div class="blog-post"> <h1>{{ }}</h1> <div class="blog-post__meta"> <a href="{{ blog_author_url(, content.blog_post_author.slug) }}"> {{ content.blog_post_author.display_name }} </a> <div class="blog-post__timestamp"> {{ content.publish_date_localized }} </div> </div> <div class="blog-post__body"> {{ content.post_body }} </div> {% if content.tag_list %} <div class="blog-post__tags"> {% icon name="tag" style="SOLID" %} {% for tag in content.tag_list %} <a class="blog-post__tag-link" href="{{ blog_tag_url(, tag.slug) }}">{{ }}</a>{% if not loop.last %},{% endif %} {% endfor %} </div> {% endif %} </div> <div class="blog-comments"> {% module "blog_comments" path="@hubspot/blog_comments", label="Blog Comments" %} </div> </div>

Blog post author information is also available within the content data.

<img alt="{{ content.blog_post_author.display_name }}" src="{{ content.blog_post_author.avatar }}"> <h3>Written by <a class="author-link" href="{{ blog_author_url(, content.blog_post_author.slug) }}">{{ content.blog_post_author.display_name }}</a></h3> <p>{{ }}</p> {% if content.blog_post_author.has_social_profiles %} <div class="hs-author-social-section"> <div class="hs-author-social-links"> {% if content.blog_post_author.facebook %} <a href="{{ content.blog_post_author.facebook }}" target="_blank" class="hs-author-social-link hs-social-facebook">Facebook</a> {% endif %} {% if content.blog_post_author.linkedin %} <a href="{{ content.blog_post_author.linkedin }}" target="_blank" class="hs-author-social-link hs-social-linkedin">LinkedIn</a> {% endif %} {% if content.blog_post_author.twitter %} <a href="{{ content.blog_post_author.twitter }}" target="_blank" class="hs-author-social-link hs-social-twitter">Twitter</a> {% endif %} {% if content.blog_post_author.google_plus %} <a href="{{ content.blog_post_author.google_plus }}?rel=author" target="_blank" class="hs-author-social-link hs-social-google-plus">Google+</a> {% endif %} </div> </div> {% endif %}

Was this article helpful? *
This form is used for documentation feedback only. Learn how to get help with HubSpot...