Skip to main content

Create Your First App

This tutorial guides you through creating your first O2VEND app to extend theme functionality.

Prerequisites

  • Understanding of Liquid templates
  • Basic knowledge of HTML/CSS/JavaScript
  • Access to app development environment

Step 1: Create App Structure

Create the app directory structure:

my-first-app/
app.json
snippets/
theme_head.liquid
assets/
app.css
app.js

Step 2: Create App Metadata

Create app.json:

{
"id": "my-first-app",
"name": "My First App",
"version": "1.0.0",
"description": "A simple app to demonstrate app development",
"author": "Your Name",
"hooks": ["theme_head", "theme_body_end"],
"assets": ["app.css", "app.js"],
"priority": 100,
"settings": {
"enabled": {
"type": "checkbox",
"label": "Enable App",
"default": true
},
"message": {
"type": "text",
"label": "Welcome Message",
"default": "Welcome to our store!"
}
}
}

Step 3: Create Hook Snippets

Theme Head Hook

Create snippets/theme_head.liquid:

{% comment %}
Hook: theme_head
App: my-first-app
{% endcomment %}

{% if settings.enabled %}
<link rel="stylesheet" href="/apps/{{ tenant.id }}/{{ app.id }}/assets/app.css">
<meta name="my-app" content="enabled">
{% endif %}

Theme Body End Hook

Create snippets/theme_body_end.liquid:

{% comment %}
Hook: theme_body_end
App: my-first-app
{% endcomment %}

{% if settings.enabled %}
<div id="my-app-message" class="app-message">
{{ settings.message }}
</div>
<script src="/apps/{{ tenant.id }}/{{ app.id }}/assets/app.js"></script>
{% endif %}

Step 4: Create App CSS

Create assets/app.css:

.app-message {
position: fixed;
bottom: 20px;
right: 20px;
background: #000;
color: #fff;
padding: 1rem 1.5rem;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
z-index: 1000;
animation: slideIn 0.3s ease-out;
}

@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}

.app-message.hidden {
display: none;
}

Step 5: Create App JavaScript

Create assets/app.js:

(function() {
'use strict';

const MyApp = {
init: function() {
this.bindEvents();
this.showMessage();
},

bindEvents: function() {
const messageEl = document.getElementById('my-app-message');
if (messageEl) {
// Auto-hide after 5 seconds
setTimeout(() => {
this.hideMessage();
}, 5000);

// Click to dismiss
messageEl.addEventListener('click', () => {
this.hideMessage();
});
}
},

showMessage: function() {
const messageEl = document.getElementById('my-app-message');
if (messageEl) {
messageEl.classList.remove('hidden');
}
},

hideMessage: function() {
const messageEl = document.getElementById('my-app-message');
if (messageEl) {
messageEl.classList.add('hidden');
}
}
};

// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => MyApp.init());
} else {
MyApp.init();
}
})();

Step 6: Install App

Local Installation

  1. Copy app to /apps/my-first-app/
  2. App automatically discovered
  3. Available in app system

Tenant Repository Installation

  1. Upload app to tenant repository:
    {tenant-repository}/apps/my-first-app/
  2. App discovered automatically
  3. Available for use

Step 7: Configure App

  1. Access app settings (via Back Office or API)
  2. Enable app
  3. Set welcome message
  4. Save settings

Step 8: Test App

  1. Visit your storefront
  2. Verify message appears
  3. Test message dismissal
  4. Check console for errors

Advanced: Product Price Hook

Add product price modification:

Create snippets/product_price_after.liquid:

{% comment %}
Hook: product_price_after
App: my-first-app
{% endcomment %}

{% if settings.show_discount_badge and product.compare_at_price > product.price %}
<span class="app-discount-badge">
Save {{ product.compare_at_price | minus: product.price | money }}!
</span>
{% endif %}

Update app.json to include hook:

{
"hooks": ["theme_head", "theme_body_end", "product_price_after"],
"settings": {
"show_discount_badge": {
"type": "checkbox",
"label": "Show Discount Badge",
"default": true
}
}
}

Best Practices

  1. Namespace Everything: Prefix CSS classes and IDs
  2. Error Handling: Handle missing data gracefully
  3. Performance: Keep apps lightweight
  4. Documentation: Document all settings
  5. Testing: Test with different themes

Next Steps