Skip to main content

Widgets

Widgets are dynamic content blocks that can be added to pages through the O2VEND editor or API. They provide flexible content management without code changes.

Widget Overview

Widgets are stored per page and section, allowing different content on different pages. They're managed through:

  • O2VEND Theme Editor (visual interface)
  • Back Office API (programmatic access)
  • Theme templates (rendering)

Widget Lifecycle

flowchart TD
Create[Create Widget] --> Configure[Configure Settings]
Configure --> Position[Set Position]
Position --> Save[Save Widget]
Save --> Render[Render in Template]
Render --> Display[Display on Page]
Display --> Update{Update?}
Update -->|Yes| Configure
Update -->|No| Delete{Delete?}
Delete -->|Yes| Remove[Remove Widget]
Delete -->|No| Display

Widget Creation Flow

flowchart LR
Start[Start] --> Select[Select Widget Type]
Select --> Configure[Configure Settings]
Configure --> Validate{Valid?}
Validate -->|No| Configure
Validate -->|Yes| Assign[Assign to Section]
Assign --> Position[Set Position]
Position --> Save[Save Widget]
Save --> Test[Test Rendering]
Test --> Complete[Complete]

Widget Structure

Each widget has:

  • Type: The widget type (e.g., ProductWidget, CarouselWidget)
  • Section: Where the widget appears (e.g., hero, content, footer)
  • Position: Order within the section
  • Settings: Widget-specific configuration
  • Content: Widget data

Available Widget Types

Product Widgets

ProductWidget / Product

Display a single product or product grid.

Template: widgets/product.liquid

Settings:

  • Product selection
  • Display style (grid, list, carousel)
  • Number of products
  • Show price, title, description

ProductCarouselWidget / ProductCarousel

Display products in a carousel/slider.

Template: widgets/product-carousel.liquid

SimpleProductWidget / SimpleProduct

Simplified product display.

Template: widgets/simple-product.liquid

SingleProductWidget / SingleProduct

Single product showcase.

Template: widgets/single-product.liquid

ProductCanvasWidget / ProductCanvas

Product canvas/featured product display.

Template: widgets/product-canvas.liquid

Category Widgets

CategoryWidget / Category

Display a single category.

Template: widgets/category.liquid

CategoryListWidget / CategoryList

Display a list of categories.

Template: widgets/category-list.liquid

CategoryListCarouselWidget / CategoryListCarousel

Category list in carousel format.

Template: widgets/category-list-carousel.liquid

Brand Widgets

BrandWidget / Brand

Display brand information.

Template: widgets/brand.liquid

BrandCarouselWidget / BrandCarousel

Brand logos in carousel.

Template: widgets/brand-carousel.liquid

Content Widgets

Image or content carousel.

Template: widgets/carousel.liquid

Image gallery.

Template: widgets/gallery.liquid

HtmlWidget / Html

Custom HTML content.

Template: widgets/html.liquid

NewsWidget / News

News/blog posts display.

Template: widgets/news.liquid

SplashWidget / Splash

Splash screen/banner.

Template: widgets/splash.liquid

SpaceBarWidget / SpaceBar

Spacing/divider widget.

Template: widgets/spacebar.liquid

SpaceBarCarouselWidget / SpaceBarCarousel

Spacing carousel.

Template: widgets/spacebar-carousel.liquid

HeaderWidget

Header layout and branding.

Template: widgets/header.liquid

HeaderMenu

Header navigation menu.

Template: widgets/header-menu.liquid

FooterWidget

Footer layout.

Template: widgets/footer.liquid

FooterMenu

Footer navigation menu.

Template: widgets/footer-menu.liquid

Special Widgets

DiscountTimeWidget / DiscountTime

Countdown timer for discounts.

Template: widgets/discount-time.liquid

RecentlyViewedWidget / RecentlyViewed

Recently viewed products.

Template: widgets/recently-viewed.liquid

TestimonialCarousel

Customer testimonials carousel.

Template: widgets/testimonial-carousel.liquid

Widget Sections

Widgets are organized into sections:

  • hero - Hero/banner section
  • content - Main content area
  • footer - Footer area
  • sidebar - Sidebar content
  • header - Header area

Using Widgets in Templates

Accessing Widgets

Widgets are available through the widgets object:

{% for widget in widgets.hero %}
{% render 'widget', widget: widget %}
{% endfor %}

Rendering Widgets

Use the widget render snippet:

{% render 'widget', widget: widget %}

Or render specific widget types:

{% case widget.type %}
{% when 'ProductWidget' %}
{% render 'widgets/product', widget: widget %}
{% when 'CarouselWidget' %}
{% render 'widgets/carousel', widget: widget %}
{% else %}
{% render 'widgets/generic', widget: widget %}
{% endcase %}

Widget Fallback

Provide fallback content when no widgets are available:

{% if widgets.hero.size > 0 %}
{% for widget in widgets.hero %}
{% render 'widget', widget: widget %}
{% endfor %}
{% else %}
<div class="hero-fallback">
<h1>Welcome to {{ shop.name }}</h1>
</div>
{% endif %}

Widget Data Structure

Widgets have the following structure:

{
"id": "widget-123",
"type": "ProductWidget",
"section": "hero",
"position": 1,
"settings": {
"title": "Featured Products",
"product_ids": ["prod-1", "prod-2"],
"display_style": "grid",
"columns": 3
},
"content": {
"title": "Featured Products",
"products": [...]
}
}

Widget Template Location

Widget templates are in widgets/ directory:

themes/theme-name/widgets/
product.liquid
carousel.liquid
banner.liquid

Widget Template Example

{% comment %}
Widget: ProductWidget
Displays a grid of products
{% endcomment %}

<div class="product-widget" data-widget-id="{{ widget.id }}">
{% if widget.settings.title %}
<h2 class="widget-title">{{ widget.settings.title }}</h2>
{% endif %}

<div class="product-grid" style="grid-template-columns: repeat({{ widget.settings.columns | default: 3 }}, 1fr);">
{% for product in widget.content.products %}
{% render 'product-card', product: product %}
{% endfor %}
</div>
</div>

Widget Settings Schema

Widgets can define settings schemas in config/settings_schema.json:

{
"name": "Product Widget",
"settings": [
{
"type": "text",
"id": "title",
"label": "Widget Title",
"default": "Featured Products"
},
{
"type": "product_list",
"id": "products",
"label": "Products"
},
{
"type": "range",
"id": "columns",
"label": "Columns",
"min": 1,
"max": 6,
"default": 3
}
]
}

Widget API

Widgets can be managed via the Back Office API:

  • GET /api/widgets/{pageId}/{section} - Get widgets for a section
  • POST /api/widgets/{pageId}/{section} - Create widget
  • PUT /api/widgets/{pageId}/{section}/{widgetId} - Update widget
  • DELETE /api/widgets/{pageId}/{section}/{widgetId} - Delete widget
  • PUT /api/widgets/{pageId}/{section}/{widgetId}/position - Update position

Widget Configuration Examples

Product Widget Configuration

{
"type": "ProductWidget",
"section": "content",
"position": 1,
"settings": {
"productIds": ["prod-123", "prod-456"],
"displayStyle": "grid",
"columns": 3,
"showPrice": true,
"showTitle": true,
"showDescription": false,
"limit": 6
}
}
{
"type": "BannerWidget",
"section": "hero",
"position": 1,
"settings": {
"title": "Summer Sale",
"subtitle": "Up to 50% off",
"image": "banner-summer.jpg",
"link": "/collections/sale",
"buttonText": "Shop Now",
"alignment": "center",
"overlay": true
}
}

Category List Widget Configuration

{
"type": "CategoryListWidget",
"section": "content",
"position": 2,
"settings": {
"categoryIds": [1, 2, 3],
"displayStyle": "grid",
"columns": 4,
"showImages": true,
"showDescription": true,
"limit": 8
}
}

Widget Customization

Widgets can be customized through their settings in the theme editor. Each widget type has specific settings that can be configured to customize its appearance and behavior.

Widget Settings Schema

{
"name": "Product Grid Widget",
"settings": [
{
"type": "text",
"id": "title",
"label": "Widget Title",
"default": "Featured Products"
},
{
"type": "product_list",
"id": "products",
"label": "Select Products"
},
{
"type": "select",
"id": "layout",
"label": "Layout",
"options": [
{ "value": "grid", "label": "Grid" },
{ "value": "list", "label": "List" },
{ "value": "carousel", "label": "Carousel" }
],
"default": "grid"
},
{
"type": "range",
"id": "columns",
"label": "Columns",
"min": 1,
"max": 6,
"default": 3
},
{
"type": "checkbox",
"id": "showPrice",
"label": "Show Price",
"default": true
}
]
}

Widget Performance Tips

1. Limit Widget Count Per Section

Avoid too many widgets:

{% for widget in widgets.content %}
{{ widget | render_widget }}
{% endfor %}
<!-- If widgets.content has 50+ widgets, this is slow -->

Limit widgets per section:

{% assign limited_widgets = widgets.content | limit: 10 %}
{% for widget in limited_widgets %}
{{ widget | render_widget }}
{% endfor %}

2. Lazy Load Widget Content

Use lazy loading for image-heavy widgets:

<div class="widget-gallery" data-widget-id="{{ widget.id }}">
{% for image in widget.images %}
<img src="{{ image | img_url: 'small' }}"
data-src="{{ image | img_url: 'large' }}"
loading="lazy"
alt="{{ widget.title }}">
{% endfor %}
</div>

3. Cache Widget Data

Cache expensive widget operations:

{% assign widget_products = widget.settings.products %}
{% assign product_count = widget_products.size %}

4. Optimize Widget Templates

Keep widget templates lightweight:

<!-- ✅ Good: Simple, focused widget -->
<div class="widget-banner">
<h2>{{ widget.settings.title }}</h2>
<img src="{{ widget.settings.image | img_url: 'large' }}" alt="">
</div>

<!-- ❌ Bad: Complex logic in widget template -->
<div class="widget-complex">
{% for i in (1..100) %}
{% for product in all_products %}
<!-- Too much processing -->
{% endfor %}
{% endfor %}
</div>

5. Use Widget-Specific CSS

Scope CSS to widgets to avoid conflicts:

<style>
.widget-{{ widget.id }} {
/* Widget-specific styles */
}
</style>

Troubleshooting Common Widget Issues

Widget Not Rendering

Problem: Widget doesn't appear on page

Solutions:

  1. Check widget exists in section:
{% if widgets.hero.size > 0 %}
{% for widget in widgets.hero %}
{{ widget | render_widget }}
{% endfor %}
{% else %}
<p>No widgets in hero section</p>
{% endif %}
  1. Verify widget template exists:
{% if widget.template_path %}
{% render widget.template_path, widget: widget %}
{% else %}
<p>Widget template not found: {{ widget.type }}</p>
{% endif %}
  1. Check widget settings:
<pre>{{ widget | json }}</pre>

Widget Settings Not Working

Problem: Widget settings don't apply

Solutions:

  1. Use default filter:
{{ widget.settings.title | default: 'Default Title' }}
  1. Validate settings exist:
{% if widget.settings.title %}
<h2>{{ widget.settings.title }}</h2>
{% endif %}
  1. Check settings schema matches:
{
"settings": {
"title": "My Title" // Must match schema id
}
}

Widget Position Issues

Problem: Widgets appear in wrong order

Solutions:

  1. Sort widgets by position:
{% assign sorted_widgets = widgets.content | sort: 'position' %}
{% for widget in sorted_widgets %}
{{ widget | render_widget }}
{% endfor %}
  1. Check position values:
{% for widget in widgets.content %}
Position: {{ widget.position }}<br>
{% endfor %}

Widget Styling Conflicts

Problem: Widget styles conflict with theme

Solutions:

  1. Use widget-specific classes:
<div class="widget widget-{{ widget.type }} widget-{{ widget.id }}">
<!-- Widget content -->
</div>
  1. Scope CSS:
.widget-product-grid {
/* Scoped styles */
}
  1. Use CSS variables:
<div class="widget" style="--widget-color: {{ widget.settings.color }}">

Best Practices

  1. Widget Templates: Create dedicated templates for each widget type
  2. Fallback Content: Always provide fallback when widgets are empty
  3. Performance: Limit number of widgets per section
  4. Responsive Design: Ensure widgets work on all screen sizes
  5. Settings Validation: Validate widget settings in templates
  6. Error Handling: Handle missing or invalid widget data gracefully
  7. Widget IDs: Use widget IDs for styling and JavaScript targeting
  8. Lazy Loading: Implement lazy loading for image-heavy widgets
  9. Caching: Cache widget data when possible
  10. Documentation: Document widget settings and usage

Next Steps