# Page Widget Tools Documentation

## Overview

Page widget tools manage the layout and content of **Widget Pages** (Layout Pages) in Modyo Channels.

**⚠️ IMPORTANT: These tools ONLY work with Widget Pages (Layout Pages).**

Modyo has three page types:
1. **Widget Pages** - Accept custom widgets (what these tools manage)
2. **Content Pages** - Use Liquid templates only, connected to Content API
3. **Origination Pages** - Form workflows, no custom widgets

See [MODYO_PAGE_TYPES.md](../MODYO_PAGE_TYPES.md) for complete page type documentation.

## Key Concepts

**Page Grid Layouts:**
Different grid types support different column configurations:
- `full_grid` - Single column (column 0 only)
- `full_two_cols_grid` - Two columns (0, 1)
- `full_three_cols_grid` - Three columns (0, 1, 2)
- `side_left_grid` - Left sidebar + main (0, 1)
- `side_right_grid` - Main + right sidebar (0, 1)
- `side_left_three_cols_grid` - Left + 2 columns (0, 1, 2)
- `side_right_three_cols_grid` - 2 columns + right (0, 1, 2)

**Widget Types:**
- `custom_widget` - Published widget from widget definitions
- `html` - Raw HTML code block
- `rich_text` - Rich text content editor

**Widget Positioning:**
- `column` - Which column (0, 1, or 2 depending on grid)
- `position` - Vertical position within column (0 = top)
- Multiple widgets in same column stack vertically by position

## Tools

### page-add-widgets

Adds or replaces widgets on a layout page. **Important: This replaces ALL widgets on the page** - include existing widgets you want to keep.

> For surgical operations on a single widget without touching the rest of the page, use `channels-pages-widget-instance` (list/get/create/update/delete one widget by id/uuid) and `channels-pages-widget-variables` (set/unset a variable per slug). These hit the atomic per-widget endpoints and avoid the read-modify-write race condition of the full replace-all.

**Use Cases:**
- Add published custom widgets to pages
- Create dashboard layouts with multiple widgets
- Add HTML/rich text content blocks
- Rearrange existing widgets
- Configure widget variables and options

**Parameters:**

**Required:**
- `platformSlug`: Platform identifier from platforms.json
- `siteId`: Numeric ID of the site
- `pageId`: Numeric ID of the page to modify
- `widgets`: Array of widget objects to add

**Widget Object Properties:**

**Required for all widgets:**
- `type`: Widget type - `"custom_widget"`, `"html"`, or `"rich_text"`
- `position`: Number (0+) - vertical position in column
- `column`: Number (0, 1, or 2) - which column (must match page's grid_type)

**Required for custom_widget:**
- `widget_definition_uuid`: String (OID format) - from `widget-get-custom-widgets`

**Optional (all types):**
- `id`: Number - existing widget ID (for updates)
- `uuid`: String - existing widget UUID (for updates)
- `title`: String (max 255 chars) - widget title
- `label`: String (max 255 chars) - widget label/name
- `enabled`: Boolean (default: true) - whether widget is active
- `blocked`: Boolean - whether widget is locked for editing
- `sync`: Boolean - **Widget loading mode**:
  - `true`: Synchronous - widget HTML/CSS/JS injected during page render (blocks rendering)
  - `false`: Asynchronous - widget loaded after page load (non-blocking, better performance)
- `use_default_title`: Boolean - use widget's default title
- `layout_page_id`: Number - parent page ID
- `grid_id`: Number - grid section ID
- `can_edit`: Boolean - editing permission

**Optional (custom widgets):**
- `variables`: Array of `{slug: string, value: string, selected?: boolean}`
- `options`: Object with properties:
  - `space_id`: Number - Content space ID
  - `content_type_uid`: String - Content type identifier
  - `locale`: String - Content locale
  - `space_uuid`: String - Content space UUID
  - `order`: String - Content ordering field
  - `order_type`: `"asc"` or `"desc"` - Ordering direction
  - `category_slug`: String - Category filter
  - `tags`: String - Comma-separated tags filter
  - `limit`: Number (1-100) - Max items to display

**Optional (html type):**
- `options.code`: String - HTML/JS code content

**Returns:**
Complete page object with updated widgets array, including:
- All widget details with new IDs and UUIDs
- Page metadata (grid_type, path, name, etc.)
- Workflow status
- Publish dates

**Important Notes:**
- **Replaces all widgets** - Include existing widgets you want to keep
- Validate column numbers against page's `grid_type`
- Use `page-get` first to see current widgets and grid type
- Widget `definition_uuid` uses OID format (40-char hex), not standard UUID
- After adding widgets, page may need republishing to be visible to end users
- Widget IDs are assigned by Modyo upon creation

**Examples:**

**Add 4 custom widgets to single-column page:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "custom_widget",
      widget_definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      position: 0,
      column: 0,
      enabled: true,
      label: "Account Balance"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "78d06422474244b364007bfc17f45f63be11c530",
      position: 1,
      column: 0,
      enabled: true,
      label: "Quick Transfer"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "5b6925958f0c82370aef9fdf4b606dafcda674c3",
      position: 2,
      column: 0,
      enabled: true,
      label: "Transaction List"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "78986a7ae2c1264e5448bb3522ee5eee87312b98",
      position: 3,
      column: 0,
      enabled: true,
      label: "Product Cards"
    }
  ]
}
```

**Add widgets to two-column layout:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    // Left column
    {
      type: "custom_widget",
      widget_definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      position: 0,
      column: 0,
      label: "Account Balance"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "78d06422474244b364007bfc17f45f63be11c530",
      position: 1,
      column: 0,
      label: "Quick Transfer"
    },
    // Right column
    {
      type: "custom_widget",
      widget_definition_uuid: "5b6925958f0c82370aef9fdf4b606dafcda674c3",
      position: 0,
      column: 1,
      label: "Transaction List"
    }
  ]
}
```

**Add HTML widget:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "html",
      position: 0,
      column: 0,
      label: "Hero Banner",
      options: {
        code: "<div class='hero'><h1>Welcome to NeoBank</h1></div>"
      }
    }
  ]
}
```

**Add widget with Content API configuration:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "custom_widget",
      widget_definition_uuid: "78986a7ae2c1264e5448bb3522ee5eee87312b98",
      position: 0,
      column: 0,
      label: "Product Cards",
      options: {
        space_id: 2514,
        content_type_uid: "credit-card-product",
        locale: "en",
        order: "created_at",
        order_type: "desc",
        category_slug: "premium-cards",
        limit: 6
      }
    }
  ]
}
```

**Add widget with variables:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "custom_widget",
      widget_definition_uuid: "78d06422474244b364007bfc17f45f63be11c530",
      position: 0,
      column: 0,
      label: "Quick Transfer",
      variables: [
        { slug: "api_endpoint", value: "https://api.example.com/transfer", selected: true },
        { slug: "max_amount", value: "10000", selected: true },
        { slug: "enable_international", value: "true", selected: true }
      ]
    }
  ]
}
```

**Add widget with sync/async control:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "custom_widget",
      widget_definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      position: 0,
      column: 0,
      label: "Account Balance",
      sync: true,  // Load synchronously - critical content
      enabled: true
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "5b6925958f0c82370aef9fdf4b606dafcda674c3",
      position: 1,
      column: 0,
      label: "Transaction List",
      sync: false,  // Load asynchronously - better performance
      enabled: true
    }
  ]
}
```

**Update existing widgets (keep IDs):**
```typescript
// First, get current page to retrieve widget IDs
page-get({ platformSlug: "fed-team", siteId: 4605, pageId: 175255 })

// Then update with existing IDs to preserve them
{
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      id: 675224,  // Existing widget ID
      type: "custom_widget",
      widget_definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      position: 1,  // Changed position (was 0)
      column: 0,
      enabled: true,
      label: "Account Balance"
    },
    // Include other widgets...
  ]
}
```

## Complete Workflow Example

### Building a Dashboard Page

**Scenario:** Create a banking dashboard with 4 widgets in a single-column layout.

**Step 1: Check page grid type**
```typescript
page-get({
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255
})
// Response shows: "grid_type": "full_grid" (column 0 only)
```

**Step 2: Get published widget UUIDs**
```typescript
widget-get-custom-widgets({
  platformSlug: "fed-team",
  siteId: 4605
})
// Extract definition_uuid from each widget
```

**Step 3: Add widgets to page**
```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,
      label: "Account Balance"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "78d06422474244b364007bfc17f45f63be11c530",
      position: 1,
      column: 0,
      enabled: true,
      label: "Quick Transfer"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "5b6925958f0c82370aef9fdf4b606dafcda674c3",
      position: 2,
      column: 0,
      enabled: true,
      label: "Transaction List"
    },
    {
      type: "custom_widget",
      widget_definition_uuid: "78986a7ae2c1264e5448bb3522ee5eee87312b98",
      position: 3,
      column: 0,
      enabled: true,
      label: "Product Cards"
    }
  ]
})
```

**Step 4: Verify and publish (if needed)**
```typescript
// Check workflow status
page-get({ platformSlug: "fed-team", siteId: 4605, pageId: 175255 })

// If workflow.current_state is "draft", publish via release
release-create({
  platformSlug: "fed-team",
  siteId: 4605,
  data: {
    page: [{ id: 175255, selected: true }]
  }
})
```

## Best Practices

1. **Always check grid_type first** - Use `page-get` to see valid columns
2. **Include all widgets** - Tool replaces entire widgets array
3. **Get UUIDs from custom_widgets** - Don't guess or reuse from other sites
4. **Order matters** - Position 0 appears at top, incrementing downward
5. **Use meaningful labels** - Helps identify widgets in Modyo admin UI
6. **Test column layouts** - Verify responsive behavior with different grid types
7. **Keep widgets enabled** - Set `enabled: false` only for A/B testing
8. **Configure content options** - Use `options` to connect widgets to Content API
9. **Validate before republishing** - Preview changes before creating release
10. **Document variable mappings** - Keep track of widget variable configurations
11. **Choose sync mode carefully**:
    - Use `sync: true` for critical above-the-fold content that must render immediately
    - Use `sync: false` (async) for better performance - widgets load after page renders
    - Default to async unless widget content is essential for initial page render

## Grid Type Column Reference

| Grid Type | Columns Available | Common Use |
|-----------|------------------|------------|
| `full_grid` | 0 | Full-width content |
| `full_two_cols_grid` | 0, 1 | Split content |
| `full_three_cols_grid` | 0, 1, 2 | Three-column layout |
| `side_left_grid` | 0, 1 | Sidebar + main |
| `side_right_grid` | 0, 1 | Main + sidebar |
| `side_left_one_col_grid` | 0, 1 | Narrow sidebar |
| `side_right_one_col_grid` | 0, 1 | Narrow sidebar |
| `side_left_three_cols_grid` | 0, 1, 2 | Sidebar + 2 cols |
| `side_right_three_cols_grid` | 0, 1, 2 | 2 cols + sidebar |

## Common Errors

**"Column must be included in [0]"**
- Used invalid column for page's grid type
- Solution: Check page's `grid_type` and use valid columns only

**"Widget definition uuid can't be blank"**
- Missing or invalid `widget_definition_uuid` for custom_widget
- Solution: Get UUID from `widget-get-custom-widgets` first

**"Invalid uuid"** (during validation)
- Validation expects standard UUID format but OIDs are used
- Solution: This was fixed by updating schema to accept strings

**Widgets disappear after update**
- Didn't include existing widgets in update
- Solution: Get current widgets first and include them in the array

**Empty page after update**
- Passed empty widgets array
- Solution: Always pass at least one widget or keep existing ones

## Related Tools

- `page-get` - Retrieve current page details and widgets
- `page-list` - Find pages by name or path
- `page-create` - Create new pages
- `page-update` - Update page metadata (name, path, etc.)
- `widget-get-custom-widgets` - Get widget UUIDs for adding to pages
- `release-create` - Publish page changes to make them live

## API References

- Admin API: `/sites/{site_id}/layout_pages/{id}` (PUT)
- Request body: `{ layout_page: { widgets: [...] } }`
- Documentation: https://docs.modyo.com/en/platform/channels/pages.html
- Grid layouts: https://docs.modyo.com/en/platform/channels/pages.html#page-layouts
