Hubspot is a marketing automation suite of tool that allows marketers to create landing pages, blog posts, hosted lead forms, and also comes with a pretty neat (and free) CRM module.
When a company/client is already using Hubspot to power their content marketing, but are looking to refresh their website and get moved on to Craft CMS, they might want to integrate the existing content from their HubSpot portal into their new website.
We at Guilty encountered this with one of our latest projects, and thought we might as well build a plugin for this that can be used by our self and others in the future to make this task a bit easier.
So we built the Craft CMS plugin called Hubspot Connector
composer require guilty/hubspot-connector
Then go to the Control Panel, click on to Settings → Plugins and click the “Install” button for HubSpot Connector.
It is now installed!
Now that we've got the plugin installed and configured with our Hubspot API key, we might want to pull down blog posts from the client's hubspot blog and show it within the new website design.
{#
Only return blog posts whos state is "PUBLISHED",
valid states are: DRAFT, PUBLISHED, or SCHEDULED.
A Hubspot "portal" can include several blogs,
pass the Blog ID as the first parameter to
only fetch content from that specific blog.
#}
{% set publishedBlogPosts = craft.hubspot.blogPosts("123123123", {
state: "PUBLISHED",
}) %}
{% for post in publishedBlogPosts %}
<article>
<h5>
<a href="{{ post.published_url }}">
{{ post.html_title }}
</a>
</h5>
{{ post.post_summary | striptags }}
</article>
{% endfor %}
And just like that, we've now pulled content from a Hubspot blog into our Craft CMS website template, now you can integrate that into the new website design.
Just listing out the existing blog posts are not enough for some projects though, sometimes you need to integrate the Hubspot content as if it was a native Craft Section, this can be done by the help of a custom route and some Twig code:
<?php
return [
// Easy: Use the blog post ID
'blog/<blogPostId>' => ['template' => 'blog/_entry'],
// OR
// Intermediate: Use the hubspot blog post slug
'blog/<slug>' => ['template' => 'blog/_entry'],
];
Now that we got our custom route set up, here is two examples of implementing a blog entry page with content pulled from a Hubspot Blog.
{# Note: I am assuming that you're extending a layout with a block called "content" #}
{% extends "_layout" %}
{# See: https://github.com/guilty-as/hubspot-connector/blob/master/src/variables/HubspotConnectorVariable.php#L33 #}
{# the variable blogPostId is injected into the template because it is a named route parameter #}
{% set post = craft.hubspot.blogPost(blogPostId) %}
{% set siteUrl = craft.app.request.absoluteUrl %}
{% block content %}
{# (optional) Integration with SEOMatic #}
{% do seomatic.meta.setAttributes({
seoTitle: post.html_title,
seoDescription: post.post_summary | striptags | default('') | raw,
seoKeywords: post.keywords,
seoImage: post.featured_image,
canonicalUrl: siteUrl,
twitter: {
card: "summary_large_image",
site: siteUrl,
creator: post.blog_post_author,
title: post.html_title,
description: post.post_summary | striptags | default('') | raw,
image: post.featured_image,
},
og: {
type: "article",
locale: "en_GB",
url: siteUrl,
title: post.html_title,
description: post.post_summary | striptags | default('') | raw,
image: post.featured_image,
}
}) %}
<h1>{{ post.html_title }}</h1>
<img src="{{ post.featured_image }}" class="post-featured-image">
<div class="post-body">
{#
Hot tip:
You can use the plugin "Retcon" to manipulate the HTML
retrieved from Hubspot, adding or removing classes, cleaning the HTML etc
#}
{{ post.post_body | default('') | raw }}
</div>
{% endblock %}
The second example is a little messy due to the fact that Hubspot does not allow us to search or fetch a blog post from the API by querying for the slug by itself, so we have to loop through all the posts until we find a matching one, it's not optimal, but it is a solution.
ProTip: use the cache tag to only have to do this once.
{% extends "_layout" %}
{% set slug = craft.app.request.segments | last %}
{#
Here we have to include the blogId, as we are now fetching a
list of blog posts from a specific blog in the hubspot portal
#}
{% set blogId = "123123123" %}
{% set siteUrl = craft.app.request.absoluteUrl %}
{% set posts = craft.hubspot.blogPosts(blogId, {
state: "PUBLISHED"
}) %}
{% block content %}
{# Loop thought all posts until we find the matching one. #}
{% for post in posts if post.slug == 'blog/' ~ slug %}
{# (optional) Integration with SEOMatic #}
{% do seomatic.meta.setAttributes({
seoTitle: post.html_title,
seoDescription: post.post_summary | striptags | default('') | raw,
seoKeywords: post.keywords,
seoImage: post.featured_image,
canonicalUrl: siteUrl,
twitter: {
card: "summary_large_image",
site: siteUrl,
creator: post.blog_post_author,
title: post.html_title,
description: post.post_summary | striptags | default('') | raw,
image: post.featured_image,
},
og: {
type: "article",
locale: "en_GB",
url: siteUrl,
title: post.html_title,
description: post.post_summary | striptags | default('') | raw,
image: post.featured_image,
}
}) %}
<h1>{{ post.html_title }}</h1>
<img src="{{ post.featured_image }}" class="post-featured-image">
<div class="post-body">
{#
Hot tip:
You can use the plugin "Retcon" to manipulate the HTML
retrieved from Hubspot, adding or removing classes, cleaning the HTML etc
#}
{{ post.post_body | default('') | raw }}
</div>
{% endfor %}
{% endblock %}
SEOMatic is a plugin we use for almost all of our Craft projects, it's the defacto standard SEO plugin, that allows clients to change meta titles, descriptions, that are shown when sharing your website on social media platforms like Facebook, Twitter etc.
To integrate our new external Hubspot content into SEOMatic, we can use a cool feature included by the SEOMatic plugin that lets us swap out the meta information from anywhere in your template (even within partials) by calling the setAttributes method, here is a simple example:
{% do seomatic.meta.setAttributes({
seoTitle: post.html_title,
seoDescription: post.post_summary | default('') | raw,
seoKeywords: post.keywords,
seoImage: post.featured_image,
canonicalUrl: craft.app.request.absoluteUrl,
twitter: {
card: "summary_large_image",
site: craft.app.request.absoluteUrl,
title: post.html_title,
description: post.post_summary | default('') | raw,
image: post.featured_image
},
og: {
type: "article",
locale: "en_GB",
url: craft.app.request.absoluteUrl,
title: post.html_title,
description: post.post_summary | default('') | raw,
image: post.featured_image,
}
}) %}
Note
You might have to clear the craft cache to see changes, as SEOMatic caches its meta tags.https://github.com/nystudio107/craft-seomatic/issues/298
You can find a full reference of available fields on the blog post api documentation.
For more templating examples including how to do pagination, check out the templating wiki on GitHub
If you encounter a bug or an issue with the plugin hit me up on the CraftCMS slack channel, send a private message to "helgesverre" and I'll try to help the best I can.
Host your CraftCMS websites with a secure, affordable and easy to manage VPS provider.
Get $10 free credits on signup