How to build multilevel dynamic pages with HubDB

A dynamic website page is a CMS page whose content changes based on the path of the URL requested by an end user. HubDB already allows you to store, filter, and display data in your HubSpot website pages. Multilevel dynamic pages take this concept further, allowing you to create up to five levels of pages within one dynamic template.

Each dynamic page includes its own unique, SEO-friendly URL, and offers page-specific analytics. You can reference more detailed HubDB documentation here.

  • A HubSpot account with the $300 Website Add-On
    • Portals with Website Starter or without the Website Add-On do not support HubDB
    • You can check if your portal has the $300 Website Add-On by signing in here.
  • Some prior knowledge of HubSpot's CMS, HTML, and HubL

Please note that this tutorial assumes you already have multiple HubDB tables created. Please see the HubDB documentation if you are unfamiliar with HubDB or want to create your first HubDB tables.

1. Enable child tables in your table's settings.

Navigate to HubDB in your HubSpot portal, and edit the table you would like to be a parent of other tables. In the table settings, ensure "Allow child tables" and "Enable pages for child tables" are both selected.

Screen Shot 2018-10-10 at 10.39.16 AM

This will add a new "Child Table" column to select other published HubDB tables in your portal.

2. Select child tables for each row

Each row in your parent table can now be linked to a child table.

A HubDB table can be selected as a child table only if the table setting "Enable creation of dynamic pages using row data" has been enabled.

Screen Shot 2018-10-10 at 10.46.44 AM

The child tables can have their own unique properties.

Screen Shot 2018-10-10 at 10.49.37 AM

When setting multilevel dynamic pages, the page paths for each row in the child table will be "parent_path/child_path". For example, the page path for the "apple" row will be "page_path/food/apple". Setting "Enable pages for child tables" to true means the intermediate paths ("page_path/food" and "page_path/beverage") also resolve to the dynamic template, and you can build separate listing pages for those subtypes. If you would rather have those intermediate routes not resolve and return a 404 page, then you can uncheck "Enable pages for child tables".

3. Create the multilevel template

Previously dynamic pages only supported two levels, the top-level listing page and the dynamic page generated from the row. Child tables allows you to create up to a max of five levels of pages within one dynamic template. To separate out the different template levels, you can use the dynamic_page_route_level HubL variable which starts at 0, for the top-level template and increments for each table layer:

{% if dynamic_page_route_level == 0 %}
	Top Level Template
{% elif dynamic_page_route_level == 1 %}
	Parent table template (/food /beverage)
{% elif dynamic_page_route_level == 2 %}
	Child table template (/food/banana etc., /beverage/soda etc.)
{% endif %}

4. Populate the top-level template

Each template level may be doing something unique. In the top level template, we would like to list the child rows and group them by parent category. First we get the category rows using dynamic_page_hubdb_table_id. Then we can utilize the hs_child_table_id property of each category row to get the table IDs of the child tables. Finally we use those table IDs to list the child rows under each parent category:

Note: It is important to try to keep your child table columns and their internal names the same. If they are not the same, you will need to use conditional logic to render unique content for a given table.

{% if dynamic_page_route_level == 0 %}
    {% set rows = hubdb_table_rows(dynamic_page_hubdb_table_id) %}
    {% for row in rows %}
     	<h2><a href="{{ request.path }}/{{ row.hs_path }}">{{ row.hs_name }}</a></h2>
      	{% set childRows = hubdb_table_rows(row.hs_child_table_id) %}
      	{% for childRow in childRows %}
        	<li><a href="{{ request.path }}/{{ row.hs_path }}/{{childRow.hs_path}}">{{ childRow.hs_name }}</a></li>   
      	{% endfor %}             
     {% endfor %}
{% endif %}

5. Populate the dynamic-level templates

For each template level we wish to show, we need to define a template. It is sometimes useful in child templates to access data in the parent row. For example, when we resolve to "food/banana" the dynamic_page_hubdb_row variable will be set the "banana" row, however we would still like to access data from the "food" row. We can use hs_parent_row value on the dynamic_page_hubdb_row to retrieve the parent row:

{% if dynamic_page_route_level == 1 %}
    {% set rows = hubdb_table_rows(dynamic_page_hubdb_row.hs_child_table_id) %}
    {% for row in rows %}
    	<li><a href="{{ request.path }}/{{ row.hs_path }}">{{ row.hs_name }}</a></li>                
    {% endfor %}
{% elif dynamic_page_route_level == 2 %}
{% endif %}

6. Link parent table to page

The final step is to create a page from the multilevel template and link the top-level parent table to the page under the "Advanced Options" section of the page editor. Here is an example nested dynamic page generated from the template created in this tutorial.

Screen Shot 2018-10-10 at 11.44.33 AM