6-1 モジュールとは何か
HubSpot モジュールの役割と、テンプレートとの違いを理解する。
🧩 モジュールの定義
モジュールはドラッグ&ドロップエディタで配置できる再利用可能なコンポーネントです。開発者がコードと編集フィールドを定義し、マーケターはノーコードで内容を変更できます。ヒーローバナー・CTA セクション・カード一覧・テスティモニアルなど、あらゆる UI パーツをモジュール化できます。
📄 テンプレートとの違い
テンプレートはページ全体の骨格(1ページに1つ)。モジュールはテンプレート内に複数配置できる部品。テンプレートが「間取り図」ならモジュールは「家具」のイメージ。
🔁 再利用性
1つのモジュールを作れば、複数テンプレートで共有できます。モジュールを更新すると、配置されている全ページに反映されます(グローバルモジュールの場合)。
6-2 モジュールのディレクトリ構造
モジュールは .module 拡張子のディレクトリで構成される。
hero-banner.module/
fields.json← 編集可能フィールドの定義(必須)
module.html← HubL テンプレート(必須)
module.css← モジュール固有のスタイル(任意)
module.js← モジュール固有の JS(任意)
meta.json← モジュールのメタ情報(必須)
ファイル命名規則:
ディレクトリ名の
.module が識別子です。例えば hero-banner.module/ の場合、HubSpot は自動的にこれをモジュールとして認識します。中のファイル名は固定です(fields.json・module.html・meta.json は変更不可)。
6-3 fields.json — フィールド定義の完全ガイド
マーケターが編集できるフィールドをすべて fields.json で定義する。
| type | 用途 | 戻り値 |
|---|---|---|
text | 1行テキスト | 文字列 |
richtext | リッチテキストエディタ | HTML 文字列 |
image | 画像選択 | オブジェクト(src, alt, width, height) |
url | URL・リンク先 | オブジェクト(url, type, open_in_new_tab) |
choice | ドロップダウン選択 | 選択値(文字列) |
boolean | オン/オフ トグル | true / false |
number | 数値入力 | 数値 |
color | カラーピッカー | オブジェクト(color, opacity) |
font | フォント設定 | オブジェクト(font, size, bold, italic…) |
group | フィールドのグルーピング(リスト化可能) | オブジェクト配列 |
hubdbrow | HubDB 行の選択 | 行 ID |
cta | HubSpot CTA の選択 | CTA ID |
form | HubSpot フォームの選択 | フォーム情報 |
blog | ブログの選択 | ブログ ID |
fields.json — ヒーローバナーモジュールの例
[
{
"id": "heading",
"name": "heading",
"label": "見出し",
"type": "text",
"default": "あなたのビジネスを加速させる",
"required": true
},
{
"id": "subheading",
"name": "subheading",
"label": "サブ見出し",
"type": "text",
"default": "HubSpot で顧客管理を一元化しましょう"
},
{
"id": "background_image",
"name": "background_image",
"label": "背景画像",
"type": "image",
"default": { "src": "", "alt": "" }
},
{
"id": "cta_button",
"name": "cta_button",
"label": "CTAボタン",
"type": "group",
"children": [
{ "id": "text", "name": "text", "label": "ボタンテキスト", "type": "text", "default": "無料で始める" },
{ "id": "url", "name": "url", "label": "リンク先", "type": "url", "default": { "url": "", "open_in_new_tab": false } },
{ "id": "style", "name": "style", "label": "スタイル", "type": "choice",
"choices": [["primary","プライマリ"],["secondary","セカンダリ"],["outline","アウトライン"]],
"default": "primary" }
]
},
{
"id": "layout",
"name": "layout",
"label": "レイアウト",
"type": "choice",
"choices": [["center","中央揃え"],["left","左揃え"],["right","右揃え"]],
"default": "center"
},
{
"id": "overlay_opacity",
"name": "overlay_opacity",
"label": "オーバーレイの不透明度 (%)",
"type": "number",
"default": 50,
"min": 0,
"max": 100
}
]
6-4 module.html — HubL テンプレートの実装
fields.json で定義したフィールドを module.html で HubL として利用する。
module.html — ヒーローバナー
{# module_attribute でフィールド値を取得 #}
<section
class="hero-banner hero-layout-{{ module.layout }}"
style="
{% if module.background_image.src %}
background-image: url({{ module.background_image.src | resize_image_url(1440, 800) }});
{% endif %}
"
>
{# 背景オーバーレイ #}
<div
class="hero-overlay"
style="opacity: {{ module.overlay_opacity / 100 }}"
></div>
<div class="hero-content">
{% if module.heading %}
<h1 class="hero-heading">{{ module.heading }}</h1>
{% endif %}
{% if module.subheading %}
<p class="hero-subheading">{{ module.subheading }}</p>
{% endif %}
{% if module.cta_button.url.url %}
<a
href="{{ module.cta_button.url.url }}"
class="btn btn-{{ module.cta_button.style }}"
{% if module.cta_button.url.open_in_new_tab %}target="_blank" rel="noopener"{% endif %}
>
{{ module.cta_button.text }}
</a>
{% endif %}
</div>
</section>
module.html — group フィールドのリスト表示(カード一覧)
{# fields.json で type: group, occurrence: {min:1, max:6} を設定したリピートグループ #}
<div class="card-grid card-cols-{{ module.columns }}">
{% for card in module.cards %}
<div class="card">
{% if card.icon %}
<div class="card-icon">{{ card.icon }}</div>
{% endif %}
<h3 class="card-title">{{ card.title }}</h3>
<p class="card-body">{{ card.body }}</p>
{% if card.link.url %}
<a href="{{ card.link.url }}" class="card-link">{{ card.link_text | default('詳しく見る') }} →</a>
{% endif %}
</div>
{% endfor %}
</div>
6-5 meta.json — モジュールのメタ情報
モジュールの表示名・使用可能なコンテキスト・アイコンなどを設定する。
meta.json
{
"label": "ヒーローバナー",
"css_assets": [{ "path": "module.css" }],
"js_assets": [],
"other_assets": [],
"smart_type": "NOT_SMART",
"icon": "heroicons/solid/photograph",
"is_available_for_new_content": true,
// このモジュールが使えるコンテキストを制限
"content_types": ["SITE_PAGE", "LANDING_PAGE"],
// DnD テンプレートでのみ使用可能にする
"host_template_types": ["PAGE", "BLOG_POST"]
}
| content_types の値 | 説明 |
|---|---|
SITE_PAGE | サイトページ |
LANDING_PAGE | ランディングページ |
BLOG_POST | ブログ記事 |
BLOG_LISTING | ブログ一覧 |
EMAIL | マーケティングメール |
6-6 module.css / module.js のベストプラクティス
モジュール固有のスタイルと JS を適切にスコープする。
module.css — スコープ付きスタイル
/* モジュール固有のスタイルは .hero-banner クラスでスコープ */
.hero-banner {
position: relative;
min-height: 560px;
display: flex;
align-items: center;
justify-content: center;
background-size: cover;
background-position: center;
overflow: hidden;
}
.hero-overlay {
position: absolute; inset: 0;
background: #000;
}
.hero-content {
position: relative; z-index: 1;
text-align: center; max-width: 720px;
padding: 40px 24px;
color: #fff;
}
.hero-layout-left .hero-content { text-align: left; }
.hero-layout-right .hero-content { text-align: right; }
@media (max-width: 768px) {
.hero-banner { min-height: 320px; }
}
module.js — 初期化パターン
// DOMContentLoaded を待たずに即時実行(HubSpot の非同期ロードに対応)
(function() {
function initHeroBanner() {
const banners = document.querySelectorAll('.hero-banner');
banners.forEach(function(banner) {
// すでに初期化済みならスキップ
if (banner.dataset.initialized) return;
banner.dataset.initialized = 'true';
// 初期化処理...
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initHeroBanner);
} else {
initHeroBanner();
}
})();
⚠ グローバル変数の汚染に注意:
module.js は即時関数(IIFE)でラップし、グローバルスコープを汚染しないようにしてください。同じページに複数のモジュールが配置される場合、変数名が衝突する可能性があります。
6-7 この章のまとめ
✅ Chapter 6 チェックリスト
- モジュールの4ファイル構成(fields.json / module.html / module.css / meta.json)を理解した
- fields.json の主要フィールド型(text / image / url / choice / group)を使いこなせる
- group フィールドでリピート可能なコンポーネントを設計できる
- module.html で
module.フィールド名を HubL で参照できる - meta.json で使用可能なコンテキストを適切に制限できる
- IIFE パターンで JS をスコープし、グローバル汚染を防げる
次章(Chapter 7)について:ワークフロー拡張とカスタムコードアクションを学びます。Node.js による Custom Code Action・Serverless Functions・Run Agent ステップを解説します。