# Modyo Page Types Documentation

## Overview

Modyo Channels supports three distinct page types, each with different capabilities and use cases:

1. **Widget Pages** (Layout Pages) - Pages with grid layouts that accept custom widgets
2. **Content Pages** - Pages connected to Content API with automatic Liquid drops
3. **Origination Pages** - Pages for form workflows and multi-step processes

## Page Type Comparison

| Feature | Widget Page | Content Page | Origination Page |
|---------|-------------|--------------|------------------|
| Custom Widgets | ✅ Yes | ❌ No | ❌ No |
| Liquid Templates | ✅ Yes | ✅ Yes | ✅ Yes |
| Grid Layout | ✅ Yes | ❌ No | ❌ No |
| Content API Connection | ❌ No | ✅ Yes (required) | ❌ No |
| Automatic Liquid Drops | ❌ No | ✅ Yes | ❌ No |
| Index/Show Views | ❌ No | ✅ Yes | ❌ No |
| Form Workflows | ❌ No | ❌ No | ✅ Yes |
| **`has_router` Purpose** | **Client-side JS routing** | **Server-side content routing** | N/A |

## 1. Widget Pages (Layout Pages)

### Description
Traditional pages with grid layouts where you can position custom widgets. These are what we've been working with for the NeoBank homepage.

### Characteristics
- Accept custom widgets via `page-add-widgets` tool
- Grid-based layout system (full_grid, two_cols, three_cols, etc.)
- Widgets positioned by column and position
- No automatic Content API connection
- Liquid available in templates, but no automatic drops
- **`has_router: true`** - Enables client-side JS routing where widgets handle all sub-routes within page path

### Use Cases
- Landing pages
- Dashboards
- Marketing pages
- Multi-widget layouts
- Custom page designs
- **Single Page Applications (SPAs)** - Use `has_router: true` for client-side routing

### Client-Side Routing (`has_router`)

When `has_router: true` is set on a widget page:
- The same widgets are rendered for **all sub-routes** under the page path
- Widgets handle routing with JavaScript (React Router, Vue Router, etc.)
- Example: Page at `/app` with `has_router: true` will render same widgets for `/app/dashboard`, `/app/profile`, `/app/settings`
- Use case: Single Page Applications where widgets manage navigation

**Example SPA Widget Page:**
```typescript
page-create({
  platformSlug: "fed-team",
  siteId: 4605,
  name: "Banking App",
  path: "/app",
  page_type: "default",
  grid_type: "full_grid",
  has_router: true,  // Enable client-side routing
  private: false
})

// Add React/Vue SPA widget that handles:
// /app/dashboard
// /app/accounts
// /app/transfers
// All routes use the same widget with JS routing
```

### Creating Widget Pages
```typescript
page-create({
  platformSlug: "fed-team",
  siteId: 4605,
  name: "Dashboard",
  path: "/dashboard",
  page_type: "default",  // or "home" for homepage
  grid_type: "full_three_cols_grid",
  private: false,
  has_router: false  // Optional: true for SPA routing
})
```

### Adding Widgets
```typescript
page-add-widgets({
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "custom_widget",
      widget_definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      position: 0,
      column: 0,
      enabled: true
    }
  ]
})
```

## 2. Content Pages

### Description
Pages automatically connected to Modyo Content API with two view types: **Index** (list) and **Show** (detail). These pages receive automatic Liquid drops for rendering content.

### Characteristics
- **Cannot accept custom widgets** - Liquid templates only
- Connected to specific Space and Content Type
- Two view types:
  - **Index Page**: Lists multiple entries (e.g., blog index, product catalog)
  - **Show Page**: Displays single entry detail (e.g., blog post, product detail)
- Automatic Liquid drops injected based on view type
- **`has_router: true`** - Required for Show pages to enable dynamic routing for content entry slugs

### Index Page Liquid Drops

Automatically available in Index page template:

```liquid
{% comment %}
  Automatic drops for Index (list) view:
  - entries: Array of content entries from the connected content type
  - meta: Pagination metadata
  - space: Current space information
  - content_type: Current content type information
{% endcomment %}

{% for entry in entries %}
  <article>
    <h2>{{ entry.meta.name }}</h2>
    <p>{{ entry.fields['Description'] }}</p>
    <a href="{{ site.url }}/blog/{{ entry.meta.slug }}">Read more</a>
  </article>
{% endfor %}

{% comment %} Pagination {% endcomment %}
{% if meta.total_pages > 1 %}
  <div class="pagination">
    {% for page in (1..meta.total_pages) %}
      <a href="?page={{ page }}">{{ page }}</a>
    {% endfor %}
  </div>
{% endif %}
```

### Show Page Liquid Drops

Automatically available in Show (detail) view:

```liquid
{% comment %}
  Automatic drops for Show (detail) view:
  - entry: Single content entry object with all fields
  - space: Current space information
  - content_type: Current content type information
{% endcomment %}

<article>
  <h1>{{ entry.meta.name }}</h1>
  <time>{{ entry.meta.created_at | date: "%B %d, %Y" }}</time>

  {% if entry.fields['Featured Image'] %}
    <img src="{{ entry.fields['Featured Image'].url }}" alt="{{ entry.meta.name }}">
  {% endif %}

  <div class="content">
    {{ entry.fields['Content'] }}
  </div>

  {% if entry.fields['Tags'] %}
    <div class="tags">
      {% for tag in entry.fields['Tags'] %}
        <span>{{ tag }}</span>
      {% endfor %}
    </div>
  {% endif %}
</article>
```

### Use Cases
- Blog system (index = posts list, show = single post)
- Product catalog (index = products grid, show = product detail)
- News section (index = articles list, show = article)
- Portfolio (index = projects grid, show = project detail)
- Documentation (index = docs list, show = single doc)

### Creating Content Pages

**Important Parameters:**
- `page_type`: Must be `"content"` or `"entry"` (check API docs)
- `content_type_id`: Numeric ID of the content type from the space
- Must specify which space and content type to connect

```typescript
// Create content page for blog posts
page-create({
  platformSlug: "fed-team",
  siteId: 4605,
  name: "Blog",
  path: "/blog",
  page_type: "content",  // or "entry" - verify in API docs
  content_type_id: 5756,  // ID of content type in space
  private: false
})
```

### Routing for Content Pages

**Index Page:**
- URL: `/blog` (the path you defined)
- Shows: List of all entries from content type

**Show Pages (automatic):**
- URL: `/blog/{entry-slug}` (automatically generated)
- Shows: Single entry detail
- Entry slug comes from `entry.meta.slug`

### Example: Blog System

**Step 1: Create content type in Content module**
```typescript
// In Content module, create "Blog Post" type with fields:
// - Title (string)
// - Content (rich_text)
// - Featured Image (asset)
// - Author (string)
// - Tags (checkbox)
```

**Step 2: Create content entries**
```typescript
// Create several blog post entries
// Each gets automatic slug based on title
```

**Step 3: Create content page in site**
```typescript
page-create({
  platformSlug: "fed-team",
  siteId: 4605,
  name: "Blog",
  path: "/blog",
  page_type: "content",
  content_type_id: 1234,  // Blog Post content type ID
})
```

**Step 4: Customize Index template**
```liquid
<div class="blog-index">
  <h1>Latest Posts</h1>

  <div class="posts-grid">
    {% for entry in entries %}
      <article class="post-card">
        {% if entry.fields['Featured Image'] %}
          <img src="{{ entry.fields['Featured Image'].url }}" alt="{{ entry.meta.name }}">
        {% endif %}

        <h2>{{ entry.meta.name }}</h2>
        <p class="meta">
          By {{ entry.fields['Author'] }} on {{ entry.meta.published_at | date: "%B %d, %Y" }}
        </p>
        <p>{{ entry.fields['Content'] | strip_html | truncate: 150 }}</p>
        <a href="{{ site.url }}/blog/{{ entry.meta.slug }}" class="read-more">Read More →</a>
      </article>
    {% endfor %}
  </div>

  {% if meta.total_pages > 1 %}
    <nav class="pagination">
      {% if meta.current_page > 1 %}
        <a href="?page={{ meta.current_page | minus: 1 }}">← Previous</a>
      {% endif %}

      Page {{ meta.current_page }} of {{ meta.total_pages }}

      {% if meta.current_page < meta.total_pages %}
        <a href="?page={{ meta.current_page | plus: 1 }}">Next →</a>
      {% endif %}
    </nav>
  {% endif %}
</div>
```

**Step 5: Customize Show template**
```liquid
<article class="blog-post">
  {% if entry.fields['Featured Image'] %}
    <div class="featured-image">
      <img src="{{ entry.fields['Featured Image'].url }}" alt="{{ entry.meta.name }}">
    </div>
  {% endif %}

  <header>
    <h1>{{ entry.meta.name }}</h1>
    <p class="meta">
      By {{ entry.fields['Author'] }} | {{ entry.meta.published_at | date: "%B %d, %Y" }}
    </p>
  </header>

  <div class="post-content">
    {{ entry.fields['Content'] }}
  </div>

  {% if entry.fields['Tags'] %}
    <footer>
      <div class="tags">
        {% for tag in entry.fields['Tags'] %}
          <span class="tag">{{ tag }}</span>
        {% endfor %}
      </div>
    </footer>
  {% endif %}

  <nav class="post-nav">
    <a href="{{ site.url }}/blog">← Back to Blog</a>
  </nav>
</article>
```

## 3. Origination Pages

### Description
Specialized pages for multi-step form workflows and data collection processes (e.g., loan applications, account openings, surveys).

### Characteristics
- Cannot accept custom widgets
- Designed for form submissions and workflows
- Support for multi-step processes
- Task-based navigation
- Integration with Customers module
- Stepper/progress indicators
- Sidebar configurations

### Use Cases
- Loan applications
- Account opening flows
- Insurance quote processes
- Registration wizards
- Survey forms
- Onboarding workflows

### Creating Origination Pages

```typescript
page-create({
  platformSlug: "fed-team",
  siteId: 4605,
  name: "Loan Application",
  path: "/apply/loan",
  page_type: "origination",
  origination_uuid: "uuid-of-origination-config",
  options: {
    show_stepper: true,
    stepper_position: "top",
    show_task_details: true,
    show_sidebar: true,
    sidebar_position: "right",
    sidebar_sticky: true
  }
})
```

### Configuration Options

Available in `options` object when creating/updating origination pages:

```typescript
{
  show_origination_title: boolean,
  origination_title_position: "top" | "bottom",
  show_stepper: boolean,
  stepper_position: "top" | "bottom",
  show_task_details: boolean,
  task_details_position: "top" | "bottom",
  show_task_title: boolean,
  show_task_description: boolean,
  show_task_stepper: boolean,
  show_sidebar: boolean,
  sidebar_position: "left" | "right",
  sidebar_sticky: boolean,
  sidebar_sticky_top_margin: number,  // 0-200
  show_submission_id: boolean
}
```

## Choosing the Right Page Type

### Widget Pages — General-purpose pages

Widget pages are the default page type for general site content. They support **grid layouts** where you position **widgets** (micro frontends) — self-contained components built with any framework (React, Vue, Angular, plain HTML/JS). Each widget is an independent unit with its own HTML, CSS, and JS.

**Use when:**
- Building any general-purpose page (landing pages, about, contact, etc.)
- Embedding micro frontends or SPAs (single page applications)
- Creating dashboards with multiple independent components
- Need grid-based layout with columns (1, 2, or 3 column grids)
- Building pages where content is managed via widgets, not Modyo Content

**Key detail:** Widget pages do NOT connect to Modyo Content spaces. If you need content from a space, use Content Pages instead, or fetch it via JavaScript within a widget.

### Content Pages — Display entries from Modyo Content spaces

Content pages connect directly to a **Modyo Content space and content type**. They provide two Liquid templates:
- **Index template**: Lists all entries of the content type (e.g., blog post list, product catalog)
- **Show template**: Displays a single entry by slug (e.g., blog post detail, product detail)

Modyo automatically injects Liquid drops (`entries`, `entry`, `meta`, `space`, `content_type`) so you can render content without JavaScript.

**Use when:**
- Displaying entries from a Modyo Content space (blog, news, catalog, portfolio, docs)
- Need automatic index (list) and show (detail) views
- Want server-side rendering with Liquid templates
- Content is managed by editors in Modyo Content, not by developers

**Key detail:** Content pages require a `content_type_id` at creation. They do NOT accept widgets — all rendering is done via Liquid templates.

### Origination Pages — Multi-step form workflows

Origination pages render a **published origination flow** (multi-step forms for data collection). They only work when the site has a **realm assigned** (Modyo Customers module) because originations are tied to user authentication and submission tracking.

**Use when:**
- The site has a realm assigned (Modyo Customers)
- You want to embed a multi-step form workflow (loan applications, account opening, insurance quotes, onboarding)
- Need stepper/progress indicators, task navigation, and submission tracking
- The origination has already been created and published in the Customers module

**Key detail:** Origination pages require `origination_uuid` (the UUID of a published origination). Without a realm on the site, origination pages will not function. Create the origination in Customers first, publish it, then create the page.

## Important Differences

### Widget Management
- **Widget Pages**: Accept custom widgets via API
- **Content Pages**: No custom widgets, Liquid only
- **Origination Pages**: No custom widgets, form-focused

### Content Connection
- **Widget Pages**: Manual Content API calls in widget JavaScript
- **Content Pages**: Automatic connection with Liquid drops
- **Origination Pages**: No direct content connection

### Template System
- **Widget Pages**: Templates in grid sections, widgets have own templates
- **Content Pages**: Two templates (index.html, show.html) with automatic drops
- **Origination Pages**: Task-based templates with form layouts

### Routing
- **Widget Pages**: Static path only (e.g., `/dashboard`)
- **Content Pages**: Index + dynamic show routes (e.g., `/blog`, `/blog/{slug}`)
- **Origination Pages**: Static path with task routes (e.g., `/apply/loan/step-1`)

## Common Mistakes to Avoid

1. ❌ **Trying to add custom widgets to content pages**
   - Content pages don't support custom widgets
   - Use Liquid templates to render content instead

2. ❌ **Not specifying content_type_id for content pages**
   - Content pages require connection to specific content type
   - Must provide both space and content type

3. ❌ **Expecting automatic drops in widget pages**
   - Widget pages don't get automatic `entries` or `entry` drops
   - Must fetch content via JavaScript or use content widgets

4. ❌ **Using wrong page_type value**
   - Check API documentation for correct string values
   - May be "content", "entry", "default", "home", "origination"

5. ❌ **Forgetting to customize show template**
   - Content pages need both index AND show templates
   - Show template displays single entry detail

## API References

- Page Types: https://docs.modyo.com/en/platform/channels/pages.html
- Content Pages: https://docs.modyo.com/en/platform/channels/pages.html#content-pages
- Liquid Drops: https://docs.modyo.com/en/platform/channels/liquid-markup.html#drops
- Content API: https://docs.modyo.com/en/platform/content/public-api-reference.html

## Next Steps

Based on this information, we need to:

1. ✅ Update page creation tools to support all three page types
2. ✅ Add `content_type_id` parameter for content pages
3. ✅ Document automatic Liquid drops for content pages
4. ✅ Create examples for each page type
5. ⚠️ Update `page-add-widgets` documentation to clarify it only works with widget pages
6. ⚠️ Create separate tools/docs for content page template management
