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
CarouselWidget / Carousel
Image or content carousel.
Template: widgets/carousel.liquid
GalleryWidget / Gallery
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
Navigation Widgets
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 sectioncontent- Main content areafooter- Footer areasidebar- Sidebar contentheader- 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 sectionPOST /api/widgets/{pageId}/{section}- Create widgetPUT /api/widgets/{pageId}/{section}/{widgetId}- Update widgetDELETE /api/widgets/{pageId}/{section}/{widgetId}- Delete widgetPUT /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
}
}
Banner Widget Configuration
{
"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:
- 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 %}
- Verify widget template exists:
{% if widget.template_path %}
{% render widget.template_path, widget: widget %}
{% else %}
<p>Widget template not found: {{ widget.type }}</p>
{% endif %}
- Check widget settings:
<pre>{{ widget | json }}</pre>
Widget Settings Not Working
Problem: Widget settings don't apply
Solutions:
- Use default filter:
{{ widget.settings.title | default: 'Default Title' }}
- Validate settings exist:
{% if widget.settings.title %}
<h2>{{ widget.settings.title }}</h2>
{% endif %}
- Check settings schema matches:
{
"settings": {
"title": "My Title" // Must match schema id
}
}
Widget Position Issues
Problem: Widgets appear in wrong order
Solutions:
- Sort widgets by position:
{% assign sorted_widgets = widgets.content | sort: 'position' %}
{% for widget in sorted_widgets %}
{{ widget | render_widget }}
{% endfor %}
- Check position values:
{% for widget in widgets.content %}
Position: {{ widget.position }}<br>
{% endfor %}
Widget Styling Conflicts
Problem: Widget styles conflict with theme
Solutions:
- Use widget-specific classes:
<div class="widget widget-{{ widget.type }} widget-{{ widget.id }}">
<!-- Widget content -->
</div>
- Scope CSS:
.widget-product-grid {
/* Scoped styles */
}
- Use CSS variables:
<div class="widget" style="--widget-color: {{ widget.settings.color }}">
Best Practices
- Widget Templates: Create dedicated templates for each widget type
- Fallback Content: Always provide fallback when widgets are empty
- Performance: Limit number of widgets per section
- Responsive Design: Ensure widgets work on all screen sizes
- Settings Validation: Validate widget settings in templates
- Error Handling: Handle missing or invalid widget data gracefully
- Widget IDs: Use widget IDs for styling and JavaScript targeting
- Lazy Loading: Implement lazy loading for image-heavy widgets
- Caching: Cache widget data when possible
- Documentation: Document widget settings and usage
Next Steps
- Snippets - Create reusable components
- Sections - Build page sections
- Editor Guide - Learn to edit widgets visually
- Widget Best Practices - Widget development best practices