Convert a WordPress theme to a HubSpot CMS theme

If you're familiar with developing on WordPress and want to create websites on the HubSpot CMS, review the below guide for recreating WordPress themes as HubSpot CMS themes.

For a video walkthrough on developing on both WordPress and HubSpot, check out the YouTube series Getting Started With HubSpot CMS Hub for WordPress Devs:

For support while developing on HubSpot, check out the CMS developer community or join the HubSpot developer Slack. And if you need further assistance in recreating your website or migrating your content to HubSpot, you can request help from a HubSpot partner.

Please note: this guide does not discuss recreating WordPress themes that rely on complex plugins. Depending on the plugins you're using, HubSpot may provide those functionalities by default. You may also be able to find apps and assets already developed on HubSpot's marketplace to provide a similar functionality. Alternatively, you may need to develop custom modules or apps

Converting a theme

To get started, you'll need to build a theme in HubSpot, then rebuild your WordPress functionality with HubSpot elements:

  • Install the HubSpot CLI so that you can develop your theme locally.
  • Download the HubSpot CMS theme boilerplate by following the steps in the CMS theme boilerplate walkthrough. This walkthrough will teach you the basics of accessing your theme locally, making changes, and sending those changes to HubSpot. You can learn more about HubSpot themes by viewing the

    themes overview.

  • Rebuild your WordPress theme in HubSpot using the reference sections below to learn about the differences between developing on WordPress and HubSpot.
  • Once you've created your HubSpot theme, import your content into HubSpot.

Below, learn more about the various differences between WordPress and HubSpot, including example code.

Building blocks

Both WordPress and HubSpot use a similar framework for architecting themes, templates, and template partials. Below, learn about the differences between each platform's building blocks, along with example code. You can learn more about HubSpot's building blocks in the CMS developer documentation.

Languages

While HubSpot and WordPress use many of the same coding languages, the main difference is that WordPress sites are built primarily with PHP, while HubSpot themes rely heavily on HubSpot's templating language HubL. In addition, in Wordpress you might use PHP tags and hooks, while in HubSpot you'll use HubL filters, functions, and tags.

Below, learn more about some of the difference between WordPress and HubSpot languages.

 
WordPress HubSpot

Stylesheets and JavaScript files can be included in a theme by using wp_enqueue_style() and wp_enqueue_script().

Stylesheets and JavaScript files can be included in a theme by using require_css() and require_js().

In addition, you can include CSS and JavaScript in individual modules to keep the code exclusive to that module.

Theme styling can be coded using CSS, SCSS, SASS, LESS, and other supersets of CSS.

CSS + HubL can be used to enable variables and macros in your HubSpot theme CSS. 

Returns relative file paths for a theme folder in WordPress with get_template_directory_uri()

Return the public URL of a specific template or coded file with get_asset_url().

Create custom functionality with a functions.php file.

The HubSpot CMS doesn't have an equivalent file, as there is no concept of hooks. However, you can extend functionality with HubL macros, serverless functions, and custom apps.

Themes

In WordPress, themes often control how the content management system works. For example, a theme can define the custom post types available or which content fields are editable in page templates. In HubSpot, a theme is a collection of developer assets. One HubSpot website might use multiple themes, and updating a theme will only affect the pages that use that theme's templates. The templates and modules within a HubSpot theme are portable, meaning they can be used in multiple themes, moved between themes, or cloned to create a variation of the asset.

Both WordPress and HubSpot share the concept of a single file being used as the starting point for a theme when calling in global partials. In WordPress, index.php is generally the main file that's used to call in partials such as header.php and footer.php. In HubSpot, the main file is called base.html.

Below, compare the standard Wordpress index.php file to HubSpot's base.html file.

WordPress index.php

Shell script
<!DOCTYPE html>
<html>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<title><?php wp_title( '|', true, 'right' ); ?></title>
<link rel="stylesheet" href="<?php echo esc_url( get_stylesheet_uri() ); ?>" type="text/css" />
<?php wp_head(); ?>
</head>
<body>
<h1><?php bloginfo( 'name' ); ?></h1>
<h2><?php bloginfo( 'description' ); ?></h2>
 
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
 
<h3><?php the_title(); ?></h3>
 
<?php the_content(); ?>
<?php wp_link_pages(); ?>
<?php edit_post_link(); ?>
 
<?php endwhile; ?>
 
<?php
if ( get_next_posts_link() ) {
next_posts_link();
}
?>
<?php
if ( get_previous_posts_link() ) {
previous_posts_link();
}
?>
 
<?php else: ?>
 
<p>No posts found. :(</p>
 
<?php endif; ?>
<?php wp_footer(); ?>
</body>
</html>

HubSpot base.html

HubL
<!--
  templateType: none
-->
<!doctype html>
<html lang="{{ html_lang }}" {{ html_lang_dir }}>
  <head>
    <meta charset="utf-8">
    {% if page_meta.html_title || pageTitle %}<title>{{ page_meta.html_title || pageTitle }}</title>{% endif %}
    {% if site_settings.favicon_src %}<link rel="shortcut icon" href="{{ site_settings.favicon_src }}" />{% endif %}
    <meta name="description" content="{{ page_meta.meta_description }}">
    {{ require_css(get_asset_url("../../css/main.css")) }}
    {# This is intended to be used if a template requires template specific style sheets #}
    {% if template_css %}
      {{ require_css(get_asset_url(template_css)) }}
    {% endif %}
    {{ require_css(get_asset_url("../../css/theme-overrides.css")) }}
    {# To see a full list of what is included via standard_header_includes please reference this article: https://developers.hubspot.com/docs/cms/hubl/variables#required-page-template-variables #}
    {{ standard_header_includes }}
  </head>
  <body>
    <div class="body-wrapper {{ builtin_body_classes }}">
      {% block header %}
        {% global_partial path='../partials/header.html' %}
      {% endblock header %}

      {# The main-content ID is used for the navigation skipper in the header.html file. More information on the navigation skipper can be found here: https://github.com/HubSpot/cms-theme-boilerplate/wiki/Accessibility #}

      <main id="main-content" class="body-container-wrapper">
        {% block body %}
        {% endblock body %}
      </main>

      {% block footer %}
        {% global_partial path='../partials/footer.html' %}
      {% endblock footer %}
    </div>
    {{ require_js(get_asset_url('../../js/main.js')) }}
    {# To see a full list of what is included via standard_footer_includes please reference this article: https://developers.hubspot.com/docs/cms/hubl/variables#required-page-template-variables #}
    {{ standard_footer_includes }}
  </body>
</html>

Note that HubSpot's base.html file includes the following variables:

  • {{ standard_header_includes }} 
  • {{ standard_footer_includes }}

These variables are required for a standalone template, and are used to pull in information such as HubSpot's tracking code and any code included in your website settings header and footer HTML. Learn more about these variables.

Templates

In both WordPress and HubSpot, a template is a subset of a theme which determines the page's layout.

In WordPress, the template that's used to display a page's content is programmatically determined by the template hierarchy where template file names are named based on their usage. For example, a general post template would be named single.php. You could then create a new post type with a name that's relative to that template, such as single-products.php, where products is the post type.

In HubSpot, the template selection process depends on the type of content you're creating:

  • All posts on a blog will use a single blog template, which you can select in your blog settings. You can use the same template to host your blog listing page, which provides a listing of your blog posts, or you can create a separate template for your blog listing page. Learn more about HubSpot's blog template markup.
  • When building website pages, content creators select which theme template they want to use before creating content. Templates can be swapped out at any time within the page editor.

Similar to WordPress, when creating a HubSpot template you need to include an annotation to set which type of content the template will be available for.

Template partials

In both WordPress and HubSpot, template partials are individual templates that can be used as components in a theme. In HubSpot, you can create two types of partials:

  •  Standard partials: partials that can be edited at the page-level without affecting other instances of the partial. For example, you might build a standard partial when adding a form if you want the form to be different across landing pages. 
  • Global partials: partials that update across all pages and templates when their content is updated. For example, you might build a header or footer global partial so that they're consistent across all pages.

Both types of partials can include modules, custom HTML, and drag and drop areas.

HubSpot doesn't have specially recognized partials for headers and footers. Instead, you can create global partials. When recreating your WordPress header.php and footer.php in HubSpot, it's recommended to view your header and footer in two ways:

  • Locate your header.php and footer.php files in WordPress. You can usually find these by navigating to SiteWordPress-includesheader.php and footer.php. This may depend on your install, however.
  • View the rendered header and footer by viewing the page's source code on a live page, then locating everything between <head> and </head> as well as <footer> and </footer>.

For recreating your header or footer navigation, learn more about how to manage menus on the HubSpot CMS. You can also view the HubSpot CMS boilerplate's menu module for reference.

Please note:

  • To include third-party tracking codes, it's recommended to re-export them from the vendor, rather than copying directly from WordPress.
  • WordPress-specific code is not necessary to copy to HubSpot, including any script from /WordPress-includes/ or /WordPress-content/

WordPress header.php

HTML
<?php
/**
 * The template for displaying the header
 */
?><!DOCTYPE html>
<html>
<head>
	<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
  <header class="header">
    <div class="container">
      <a id="site-logo" href="<?php echo site_url(); ?>">
        <img src="<?php bloginfo('stylesheet_directory'); ?>/images/logo.svg" alt="<?php bloginfo('name'); ?>" />
      </a>
      <nav id="site-navigation">
        <?php wp_nav_menu( array('menu_class' => 'nav-menu', 'theme_location' => 'primary' ) ); ?>
      </nav>
    </div>
  </header>
  <div class="site-content">

HubSpot header

HubL
<!--
  templateType: global_partial
  label: Website header
-->
<header class="header">
  <div class="container">
    {% logo "site_logo" %}
    <nav id="site-navigation">
      {% menu "site_menu" label="Site Navigation" %}
    </nav>
  </div>
</header>

WordPress footer.php

HubL
<?php
/**
 * The template for displaying the footer
 */
?>

  </div><!-- .site-content -->

  <footer class="site-footer">
    <div class="container">

      &copy; <?php echo date("Y") ?> <?php bloginfo('name'); ?>

    </div>
  </footer><!-- .site-footer -->

<?php wp_footer(); ?>

</body>
</html>

HubSpot footer

HubL
<!--
  templateType: global_partial
  label: Footer
-->
<footer class="footer">
  <div class="container">

    &copy; {{ year }} {{ site_settings.company_name }}

  </div>
</footer>

Content types

WordPress and HubSpot have different ways of referring to content types. The WordPress content model centers around the post, with different types of content, such as pages and blog posts, categorized as post types. WordPress also allows for custom post types.

HubSpot's content model has a similar hierarchy, but content types are self-described rather than categorized as post types. The main content types that you can build on HubSpot are website pages, landing pages, and blog posts. Outside of website development, you might also build email templates using the CMS. While HubSpot doesn't have custom content types, you can create custom objects to store data that doesn't fit into one of the standard content or object categories. Custom objects can be used both within the CRM and for CMS website data

Below, learn about how content types compare across each platform, along with code examples.

Pages

In HubSpot, there are two types of pages:

  • Website pages: the standard page type used for general pages across a HubSpot website.
  • Landing pages: the page type best suited for marketing-driven pages, often containing forms. These pages focus on the customer conversion path as a part of the inbound marketing methodology.

The differences between the two are more conceptual than practical, and when building a page template, you'll refer to them both with the template type of page. Below, view how WordPress's standard page markup compares with HubSpot's.

WordPress page markup

HubL
<?php
/*
 * The main template file
 */
get_header(); ?>

  <main>
  <?php
  if ( have_posts() ) :

	while ( have_posts() ) : the_post();
      the_content();
	endwhile;
    
  else :
    echo '<p>No content was found :(</p>'
  endif;
  ?>
  </main>

<?php get_footer(); ?>

HubSpot page markup

HubL
<!--
  templateType: page
  isAvailableForNewContent: true
  label: Page
-->
{% extends "./path-to/base.html" %}

{% block body %}
<main>
  {% widget_container "page_content" %}
  {% end_widget_container %}
</main>
{% endblock body %}

Note how HubSpot's page markup includes {% extends "./path-to/base.html"%}. This allows the page's {% block body %} block to populate the base.html file with its contents. It also means that you don't need to add the standard includes to the page, as base.html includes them. Learn more about blocks and extends.

Posts

In WordPress, the posts post type refers to content typically used by blogs, and can be used to create RSS feeds. 

In HubSpot, a post is an individual blog post created with the blog tool. Similar to WordPress, HubSpot blog posts are created using one template, which you can select in your blog settings. Blog posts are displayed on a blog listing page, and can also be accessed through an RSS feed. Learn more about HubSpot's blog template markup.

In both WordPress and HubSpot, you can call in blog post content using loops. In WordPress, you call in blog content using The Loop. For example:

HTML
<?php
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        // Display post content
    endwhile;
endif;
?>

In HubSpot, you call in blog content using a for loop. For example:

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

You can either create one template for your posts and blog listing page, or create a separate listing page template. Learn more about blog templates.

Content management

WordPress and HubSpot offer various features for managing website content, media, settings, and users. Below, learn about some of the content management differences between WordPress and HubSpot.

Editors

In WordPress, content creators generally use the default Gutenberg editor or use drag and drop editor plugins such as Elementor and Themify.

In HubSpot, content creators use HubSpot's default drag and drop editor for creating many types of content, including pages and emails. Developers can build drag and drop areas into a template to allow drag and drop editing, along with sections to contain those drag and drop areas.

In HubSpot, content creators use HubSpot's drag and drop editor for creating different types of content, including pages and emails. You can add drag and drop areas to a template to allow content creators to add modules to a page.

Databases and HubDB

While WordPress database management is often accomplished through plugins, HubSpot offers HubDB. HubDB is a relational data store that represents data in a table, and can be managed both within HubSpot and through the HubDB API.

In WordPress, you can register custom post types to extend your content taxonomy. In HubSpot, the equivalent would be creating custom objects, which allow you to store data as CRM records alongside other CRM objects, such as contacts and companies. Custom object data can be used not just by the CMS for website data, but by other parts of the business too. You can access custom objects from within HubSpot and through the API.

AJAX and serverless functions

In WordPress, you can create AJAX functions to extend functionality with APIs and custom code. In HubSpot, you can use serverless functions to write server-side code that interacts with APIs while keeping your credentials secret. 

Media and file storage

WordPress offers a media library for storing images, videos, and other types of files, which also allows for image editing.

Similarly, HubSpot offers the files tool, which can be used to upload and organize files into folders. You can access the files tool directly or from within content editors. In both locations, you can edit files as needed. The files tool also provides access to royalty-free stock images through Shutterstock.

Settings

In Wordpress, settings are often modified by plugins, and can have site-wide impact. In HubSpot, you can manage website settings within your HubSpot account, and can be applied globally or to individual domains and blogs. This includes settings for website pages, blogs, navigation, domains and URLs, and themes.

User management

In both WordPress and HubSpot, you can set permissions per user to control which users can view, edit, and publish website content and more.

In WordPress, permissions can also be used to set content access for end-users. In HubSpot, you can use the memberships feature to provide content access to specific contacts, and you can also password protect pages.


Was this page helpful? *
This form is for feedback on our developer docs. If you have feedback on the HubSpot product, please share it in our Idea Forum instead.