CMS Development

rossatgrowth
Contributor | Platinum Partner
Contributor | Platinum Partner

Building Editable Modules Efficiently

SOLVE

Hello all,

 

Lately, we've been taking on increased HubSpot CMS projects. We want clients to have the ability to edit copy, images etc. but the drag and drop editor lacks the flexibility to match high fidelity mockups and so we're effectively building these websites out with HTML templates. However, this leaves the need to replace all text/images/assets with editable modules, which we've been saving as the last step to launch.

 

The issue we are facing is that some of these sites can require hundreds of modules if built how we're currently using them and its' very time-consuming. Say a single section has 3 images, a heading, body text and a CTA—this translates to 6 for a single section and so we build these out separately in the Design Manager and replace the default content with the HTML code that's been written, copy that module snippet and paste it back into the code.

 

It really seems there has to be a better way to achieve this other than one-by-one via design manager and back and forth copy/paste to build out editable modules. Does anyone have experience with a similar process and can shed light on more efficient means of achieving editable HTML themes?

 

Thanks a ton!

1 Accepted solution
Teun
Solution
Key Advisor | Diamond Partner
Key Advisor | Diamond Partner

Building Editable Modules Efficiently

SOLVE

@rossatgrowth 

I'll describe the way you can achieve this step by step. Lets say you have a project folder in VSCode where you want to store all your modules in a '/modules' folder and are running the hs watch command to sync every change you make to HubSpot.

 

1. Create the module by using CLI command:

hs create module rich-text.module src/modules

This should give you a new folder called `rich-text.module` with the following files: module.html, module.css, module.js, fields.json and meta.json.

2. Create the necessary fields in the fields.json. By using the above command, the module comes with a prefilled `richtext` field, but for the sake of explaining, lets assume it is empty. 
You first define an array, cause all fields should be stored in an array. The next step is to add the JSON for the fields you need. Assuming you have the VSCode extension installed, you can type field.richtext and press enter to create the right JSON. The next step is to update the name and label and decide if this field is required for this module. The output should be something like this:

[
  {
    "name": "hero_text",
    "label": "Hero text",
    "required": false,
    "locked": false,
    "type": "richtext",
    "inline_help_text": "",
    "help_text": "",
    "default": null
  }
]

If needed, you could add simple HTML to the fields.json to add some dummy content:

[
  {
    "name": "hero_text",
    "label": "Hero text",
    "required": false,
    "locked": false,
    "type": "richtext",
    "inline_help_text": "",
    "help_text": "",
    "default": "<h1>This is the content for the hero</h1><p>Please replace this with the right content</p>"
  }
]

 

 

3. The next step is to add the necessary HTML to the `module.html`. You can write whatever you want, so i'll just add the content with a wrapper:

<section class="c-hero-text">
  <div class="c-hero-text__content">
    {{module.hero_text}}
  </div>
</section>

You can retrieve the values from the fields simply by adding the `module.fieldname` and calling it within the HTML.

 

5. Add some styling to the module.css of your module (if needed) and preview your module from the design manager. Because you are running `hs watch` every time you save a file, the contents will be synced to HubSpot. You can lookup your module in the design manager and click on the 'preview without display options' to see what it looks like.

 

6. Lets assume you have a template coded that is called 'homepage.html' in a templates folder (as it is setup in the CMS Boilerplate). You can now simply call your module from that module like this:

<!--
  templateType: page
  isAvailableForNewContent: true
  label: Home
  screenshotPath: ../images/template-previews/home.png
-->
{% extends "./layouts/base.html" %}

{% block body %}

{# 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">
  {% dnd_area 'dnd_area' label='Main section', class='body-container body-container--home' %}
    {% dnd_section %}
      {% dnd_module path='../modules/rich-text' width="12" offset="0" %}
        {% module_attribute 'hero_text' %}
          <h1>Hero title</h1>
          <p>Add some hero content here</p>
        {% end_module_attribute %}
      {% end_dnd_module %}
      {% dnd_module path='../modules/rich-text', width="12", offset="0", hero_text="<h1>Hero title</h1><p>Add some hero content here</p>" %}
      {% end_dnd_module %}
    {% end_dnd_section %}
  {% end_dnd_area %}
</main>
{% endblock body %}

Important is to understand that the path is relative to where your template file is located. There are two ways of adding some default content, the first is the {% module_attribute 'field_name' %} and the second one is passing it as a param in the {% dnd_module %}. I've included both examples.
Please take a look at this page: https://developers.hubspot.com/docs/cms/building-blocks/templates/drag-and-drop-areas to understand the structure of a template with dnd_area.

Finally, preview your template to see if everything is the way you want it. You can add padding and margin through the styling of your module, but you can also add it as a param to the dnd_section or dnd_module.



Did my answer solve your issue? Help the community by marking it as the solution.

View solution in original post

11 Replies 11
webdew
Guide | Diamond Partner
Guide | Diamond Partner

Building Editable Modules Efficiently

SOLVE

Hi @rossatgrowth ,

If you update module defult like , image, css, CTA its effect all the page and make if its not work you need to update every page:

Follow this link also: https://developers.hubspot.com/docs/cms/building-blocks/modules


Hope this helps!


If we were able to answer your query, kindly help the community by marking it as a solution.

Thanks and Regards. 

0 Upvotes
Teun
Solution
Key Advisor | Diamond Partner
Key Advisor | Diamond Partner

Building Editable Modules Efficiently

SOLVE

@rossatgrowth 

I'll describe the way you can achieve this step by step. Lets say you have a project folder in VSCode where you want to store all your modules in a '/modules' folder and are running the hs watch command to sync every change you make to HubSpot.

 

1. Create the module by using CLI command:

hs create module rich-text.module src/modules

This should give you a new folder called `rich-text.module` with the following files: module.html, module.css, module.js, fields.json and meta.json.

2. Create the necessary fields in the fields.json. By using the above command, the module comes with a prefilled `richtext` field, but for the sake of explaining, lets assume it is empty. 
You first define an array, cause all fields should be stored in an array. The next step is to add the JSON for the fields you need. Assuming you have the VSCode extension installed, you can type field.richtext and press enter to create the right JSON. The next step is to update the name and label and decide if this field is required for this module. The output should be something like this:

[
  {
    "name": "hero_text",
    "label": "Hero text",
    "required": false,
    "locked": false,
    "type": "richtext",
    "inline_help_text": "",
    "help_text": "",
    "default": null
  }
]

If needed, you could add simple HTML to the fields.json to add some dummy content:

[
  {
    "name": "hero_text",
    "label": "Hero text",
    "required": false,
    "locked": false,
    "type": "richtext",
    "inline_help_text": "",
    "help_text": "",
    "default": "<h1>This is the content for the hero</h1><p>Please replace this with the right content</p>"
  }
]

 

 

3. The next step is to add the necessary HTML to the `module.html`. You can write whatever you want, so i'll just add the content with a wrapper:

<section class="c-hero-text">
  <div class="c-hero-text__content">
    {{module.hero_text}}
  </div>
</section>

You can retrieve the values from the fields simply by adding the `module.fieldname` and calling it within the HTML.

 

5. Add some styling to the module.css of your module (if needed) and preview your module from the design manager. Because you are running `hs watch` every time you save a file, the contents will be synced to HubSpot. You can lookup your module in the design manager and click on the 'preview without display options' to see what it looks like.

 

6. Lets assume you have a template coded that is called 'homepage.html' in a templates folder (as it is setup in the CMS Boilerplate). You can now simply call your module from that module like this:

<!--
  templateType: page
  isAvailableForNewContent: true
  label: Home
  screenshotPath: ../images/template-previews/home.png
-->
{% extends "./layouts/base.html" %}

{% block body %}

{# 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">
  {% dnd_area 'dnd_area' label='Main section', class='body-container body-container--home' %}
    {% dnd_section %}
      {% dnd_module path='../modules/rich-text' width="12" offset="0" %}
        {% module_attribute 'hero_text' %}
          <h1>Hero title</h1>
          <p>Add some hero content here</p>
        {% end_module_attribute %}
      {% end_dnd_module %}
      {% dnd_module path='../modules/rich-text', width="12", offset="0", hero_text="<h1>Hero title</h1><p>Add some hero content here</p>" %}
      {% end_dnd_module %}
    {% end_dnd_section %}
  {% end_dnd_area %}
</main>
{% endblock body %}

Important is to understand that the path is relative to where your template file is located. There are two ways of adding some default content, the first is the {% module_attribute 'field_name' %} and the second one is passing it as a param in the {% dnd_module %}. I've included both examples.
Please take a look at this page: https://developers.hubspot.com/docs/cms/building-blocks/templates/drag-and-drop-areas to understand the structure of a template with dnd_area.

Finally, preview your template to see if everything is the way you want it. You can add padding and margin through the styling of your module, but you can also add it as a param to the dnd_section or dnd_module.



Did my answer solve your issue? Help the community by marking it as the solution.
rossatgrowth
Contributor | Platinum Partner
Contributor | Platinum Partner

Building Editable Modules Efficiently

SOLVE

This example is excellent @Teun, I'm sure it will help a lot of others seeking similar information—marked as a solution.

 

Best,

Ross

Teun
Key Advisor | Diamond Partner
Key Advisor | Diamond Partner

Building Editable Modules Efficiently

SOLVE
You could use the command line to create the module with 'hs create module rich-text.module src' where the last argument is the location where you want to store the folder. In the modules fields.json you van set defaults, but you could also set the default value through the template (check the CMS Boilerplate file I linked earlier).

I am not sure about preventing the extra divs. I think it can be set as an argument, but ill have to check where tomorrow.

I can give you some example code tomorrow for all the steps you described. Currently typing from my mobile phone 😅


Did my answer solve your issue? Help the community by marking it as the solution.
rossatgrowth
Contributor | Platinum Partner
Contributor | Platinum Partner

Building Editable Modules Efficiently

SOLVE

@Teun that would be amazing if you could provide the code for the requested example (when you're not on your phone of course) as well as any VSCode shorthand/protips along the way.

 

Looking at the modules I've created in design manager via VSCode, it appears the default content on the module level is defined in fields.json on a single line, although using this method requires escaping quotations and other special characters as well as new lines for formatting if it were to be viewed in the Design Manager. I'm wondering if there's a better way to get the prebuilt content we have in the HTML to the editable modules without manually escaping w/ regex or the likes? Either way, this is 100% preferred over how we were previously creating in the Design Manager.

0 Upvotes
Teun
Key Advisor | Diamond Partner
Key Advisor | Diamond Partner

Building Editable Modules Efficiently

SOLVE

Hi @rossatgrowth 

This is probably the best place to start: https://developers.hubspot.com/docs/cms/building-blocks/modules

So the HubSpot docs kinda describe what you are doing currently. But instead of creating the module through the design manager, you could just simply create it in VSCode. You can simply create a folder called 'module_name.module' which should always contain a module.html, module.css, module.js, meta.json and fiels.json file. Now the fields.json is where you can write all your fields. Lets say you need a module with an image on the left, and content on the right and an option to swap those around, your fields.json would look something like this:

 

[
{
  "name": "content",
  "label": "Content",
  "required": false,
  "locked": false,
  "type": "richtext",
  "inline_help_text": "",
  "help_text": "",
  "default": null 
},
{
"name": "image",
"label": "Image",
"required": false,
"locked": false,
"inline_help_text": "",
"help_text": "",
"responsive": true,
"resizable": true,
"show_loading" : false,
"type": "image",
"default": {
  "size_type" : "auto",
  "src": "",
  "alt": null,
  "loading": "disabled"
}
},
{
  "name": "position",
  "label": "Position of content",
  "required": false,
  "locked": false,
  "display": "select",
  "inline_help_text": "",
  "help_text": "",
  "choices": [
  [
    "left",
    "Left"
  ],
  [
    "right",
    "Right"
  ]
  ],
  "type": "choice",
  "placeholder": "",
  "default": null 
}
]

 

If you use the VSCode extension, you could simply type: field.image and press enter, and the extension will paste the correct JSON for an image field. You would only have to update the name and label if needed.

Schermafbeelding 2021-08-12 om 15.57.35.png



Did my answer solve your issue? Help the community by marking it as the solution.
rossatgrowth
Contributor | Platinum Partner
Contributor | Platinum Partner

Building Editable Modules Efficiently

SOLVE

@Teun this is fantastic information, thank you so much.

 

Say, for example, I wanted to create a rich text module with some default content that has an H1 and some paragraph text.

  • First I create the module folder, say "rich-text.module" and populate with module.css, module.html, module.js (is there a quick way of doing this in VSCode or is copy & paste folder the best bet?)
  • In fields.json I use VSCode extension and type field.richtext and change the name and label to "hero_text" and "Hero Text" respectively.

What would be the remaining steps to set that default header and paragraph text for this module, and then call that module (let's say it's located in "modules/rich-text.module") from the template code? Also, is there a way to call the module content so that HS doesn't wrap it in extra <div>s? Any VSCode protips would be incredibly helpful as well!

 

I think we may have just about found that frustratingly missing piece to more streamlined CMS development thanks to your answers. Much kudos your way!

0 Upvotes
Teun
Key Advisor | Diamond Partner
Key Advisor | Diamond Partner

Building Editable Modules Efficiently

SOLVE

@rossatgrowth Try going for the HubSpot CMS for Developers certification. This academy course will learn you a lot about local development and themes.



Did my answer solve your issue? Help the community by marking it as the solution.
Teun
Key Advisor | Diamond Partner
Key Advisor | Diamond Partner

Building Editable Modules Efficiently

SOLVE

Hi @rossatgrowth , do you use the HubSpot CLI to develop your websites locally? You should definitely take a look at the CMS Theme Boilerplate.
It sounds like you are still developing through the design manager, which is very time consuming.


Combine the power of the HubSpot CLI and use the CMS Theme Boilerplate to setup some standard for your development team and creating websites should be a piece of cake.
What we do is, we first develop each module that we need for the website (we only use custom modules, never HubSpot native modules). You can register all the fields you need for a module with json in the `fields.json` file of a module. 
After the modules are finished (and all fields are registered), we start building the templates locally. If you take a look at one of the templates available in the CMS Boilerplate, you can see that it consists of some partials and a dnd_area. In the dnd_area, you can prefill the modules you need for a specific type of page and add default content to those modules. You can then preview the templates through the design tools to evaluate your template and modules once more.
Once all templates are done, you could use content staging to create all the pages, simply by clicking on the template. Because you have modules setup in the template allready (through code), you do not need to edit any more content. 
Using coded templates gives you full control on how the Drag and Drop sections of a template work, so you should have no issues to recreate the high fidelity designs.

Pro tip: Use VSCode combined with the HubSpot VSCode extension, and developing modules gets even easier.



Did my answer solve your issue? Help the community by marking it as the solution.
miljkovicmisa
Top Contributor | Gold Partner
Top Contributor | Gold Partner

Building Editable Modules Efficiently

SOLVE

Hello @Teun and @rossatgrowth !
@Teun Very nice explanation through your process, thank you for sharing that, one thing I would like to point out is the creation of a custom module, I personally find it easier to create the module right inside the design manager (as manually entering the json data can get pretty messy) and then hs fetch the module folder to my local development through the CLI.

0 Upvotes
rossatgrowth
Contributor | Platinum Partner
Contributor | Platinum Partner

Building Editable Modules Efficiently

SOLVE

Hi @Teun, thanks so much for your quick and in-depth response. We do use HubSpot CLI to develop the templates locally, and also within VSCode. However, have been crafting modules in Design Manager, which, as you mentioned is very time-consuming.

 

Could you elaborate on the first step you described on developing each module for the website (which it seems you do prior to the actual template) with JSON? This sounds like it's the gap we're missing. We've been using partials to build out our header, footer and body but haven't made use of the dnd_area.

 

It appears that they've updated the certification you referenced so thanks a ton for pointing this out—I took the course about a year ago but didn't recall any extensive discussion around theme building and local dev. Are there any other resources (especially pertaining to modules) outside of HubSpot's Knowledgebase you would recommend?

 

Thanks again, you've been very helpful!

-Ross