feat: Add premade card templates and click analytics
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
WordPress Plugin v2.0.0: - Add Promo Banner widget (dark banner with deal text) - Add Horizontal Product Row widget (wide list format) - Add Category Card widget (image-based categories) - Add Compact Card widget (dense grid layout) - Add CannaiQAnalytics click tracking (tracks add_to_cart, product_view, promo_click, category_click events) - Register cannaiq-templates Elementor category - Fix branding: CannaiQAnalytics (not CannaIQAnalytics) Backend: - Add POST /api/analytics/click endpoint for WordPress plugin - Accepts API token auth, records to product_click_events table - Stores metadata: product_name, price, category, url, referrer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,118 @@
|
||||
/**
|
||||
* CannaIQ Menus - WordPress Plugin JavaScript
|
||||
* v1.5.3
|
||||
* v2.0.0
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Click Analytics Tracker
|
||||
*/
|
||||
var CannaiQAnalytics = {
|
||||
/**
|
||||
* Track a click event
|
||||
* @param {string} eventType - Type of event (add_to_cart, product_view, promo_click, etc)
|
||||
* @param {object} data - Event data (product_id, store_id, product_name, etc)
|
||||
*/
|
||||
track: function(eventType, data) {
|
||||
if (!window.cannaiqAnalytics || !window.cannaiqAnalytics.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var payload = {
|
||||
event_type: eventType,
|
||||
store_id: data.store_id || window.cannaiqAnalytics.store_id,
|
||||
product_id: data.product_id || null,
|
||||
product_name: data.product_name || null,
|
||||
product_price: data.product_price || null,
|
||||
category: data.category || null,
|
||||
url: data.url || window.location.href,
|
||||
referrer: document.referrer || null,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Send to analytics endpoint
|
||||
$.ajax({
|
||||
url: window.cannaiqAnalytics.api_url + '/analytics/click',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + window.cannaiqAnalytics.api_token
|
||||
},
|
||||
// Fire and forget - don't block user interaction
|
||||
async: true
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize click tracking on all CannaiQ elements
|
||||
*/
|
||||
init: function() {
|
||||
var self = this;
|
||||
|
||||
// Track Add to Cart clicks
|
||||
$(document).on('click', '.cannaiq-cart-button, .cannaiq-add-to-cart, .cannaiq-hr-add-btn, .cannaiq-cc-button, [class*="cannaiq"][href*="dutchie"], [class*="cannaiq"][href*="iheartjane"]', function(e) {
|
||||
var $el = $(this);
|
||||
var $card = $el.closest('[data-product-id], .cannaiq-product-card, .cannaiq-premium-card, .cannaiq-horizontal-row, .cannaiq-compact-card');
|
||||
|
||||
self.track('add_to_cart', {
|
||||
product_id: $card.data('product-id') || $el.data('product-id'),
|
||||
product_name: $card.data('product-name') || $el.data('product-name') || $card.find('.cannaiq-product-name, .cannaiq-premium-name, .cannaiq-hr-name, .cannaiq-cc-name').first().text().trim(),
|
||||
product_price: $card.data('product-price') || $el.data('product-price'),
|
||||
store_id: $card.data('store-id') || $el.data('store-id'),
|
||||
category: $card.data('category') || $el.data('category'),
|
||||
url: $el.attr('href')
|
||||
});
|
||||
});
|
||||
|
||||
// Track product card clicks (view intent)
|
||||
$(document).on('click', '.cannaiq-product-card, .cannaiq-premium-card, .cannaiq-special-card', function(e) {
|
||||
// Don't double-track if clicking the cart button
|
||||
if ($(e.target).closest('.cannaiq-cart-button, .cannaiq-add-to-cart').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $card = $(this);
|
||||
self.track('product_view', {
|
||||
product_id: $card.data('product-id'),
|
||||
product_name: $card.data('product-name') || $card.find('.cannaiq-product-name, .cannaiq-premium-name').first().text().trim(),
|
||||
product_price: $card.data('product-price'),
|
||||
store_id: $card.data('store-id'),
|
||||
category: $card.data('category')
|
||||
});
|
||||
});
|
||||
|
||||
// Track promo banner clicks
|
||||
$(document).on('click', '.cannaiq-promo-banner .cannaiq-promo-button, .cannaiq-promo-banner', function(e) {
|
||||
var $banner = $(this).closest('.cannaiq-promo-banner');
|
||||
self.track('promo_click', {
|
||||
store_id: $banner.data('store-id'),
|
||||
promo_headline: $banner.find('.cannaiq-promo-headline').text().trim(),
|
||||
url: $(this).attr('href') || $banner.find('a').first().attr('href')
|
||||
});
|
||||
});
|
||||
|
||||
// Track category clicks
|
||||
$(document).on('click', '.cannaiq-category-card, .cannaiq-category-item', function(e) {
|
||||
var $cat = $(this);
|
||||
self.track('category_click', {
|
||||
store_id: $cat.data('store-id'),
|
||||
category: $cat.data('category') || $cat.find('.cannaiq-cat-name, .cannaiq-category-name').first().text().trim(),
|
||||
url: $cat.attr('href')
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize plugin
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
// Initialize analytics tracking
|
||||
CannaiQAnalytics.init();
|
||||
|
||||
// Lazy load images
|
||||
if ('IntersectionObserver' in window) {
|
||||
const imageObserver = new IntersectionObserver((entries, observer) => {
|
||||
@@ -49,10 +152,13 @@
|
||||
threshold: 0.1
|
||||
});
|
||||
|
||||
document.querySelectorAll('.cannaiq-product-card').forEach(card => {
|
||||
document.querySelectorAll('.cannaiq-product-card, .cannaiq-premium-card, .cannaiq-compact-card').forEach(card => {
|
||||
cardObserver.observe(card);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Expose for external use
|
||||
window.CannaiQAnalytics = CannaiQAnalytics;
|
||||
|
||||
})(jQuery);
|
||||
|
||||
Reference in New Issue
Block a user