fix: implement correct base_url routing for shop frontend
Fix shop frontend links to work correctly across all three access methods:
- Custom domain (wizamart.shop)
- Subdomain (wizamart.localhost)
- Path-based (/vendor/wizamart/)
Changes:
- Update get_shop_context() to calculate base_url based on access method
- Update all shop templates to use {{ base_url }} for links
- Add base_url to shop-layout.js Alpine.js component
- Document multi-access routing in shop architecture docs
This ensures links work correctly regardless of how the shop is accessed,
solving broken navigation issues with path-based access.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -37,20 +37,13 @@
|
||||
{% endif %}
|
||||
</style>
|
||||
|
||||
{# Tailwind CSS - uses CSS variables #}
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
{# Tailwind CSS with local fallback #}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/tailwind.min.css') }}';">
|
||||
|
||||
{# Base Shop Styles #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='shop/css/shop.css') }}">
|
||||
|
||||
{# Optional: Theme-specific stylesheet #}
|
||||
{% if theme.theme_name != 'default' %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='shop/themes/' + theme.theme_name + '.css') }}">
|
||||
{% endif %}
|
||||
|
||||
{# Alpine.js for interactivity #}
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
@@ -64,7 +57,7 @@
|
||||
|
||||
{# Vendor Logo #}
|
||||
<div class="flex items-center">
|
||||
<a href="/" class="flex items-center space-x-3">
|
||||
<a href="{{ base_url }}" class="flex items-center space-x-3">
|
||||
{% if theme.branding.logo %}
|
||||
{# Show light logo in light mode, dark logo in dark mode #}
|
||||
<img x-show="!dark"
|
||||
@@ -87,16 +80,16 @@
|
||||
|
||||
{# Navigation #}
|
||||
<nav class="hidden md:flex space-x-8">
|
||||
<a href="/" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
<a href="{{ base_url }}" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
Home
|
||||
</a>
|
||||
<a href="/products" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
<a href="{{ base_url }}products" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
Products
|
||||
</a>
|
||||
<a href="/about" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
<a href="{{ base_url }}about" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
About
|
||||
</a>
|
||||
<a href="/contact" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
<a href="{{ base_url }}contact" class="text-gray-700 dark:text-gray-300 hover:text-primary">
|
||||
Contact
|
||||
</a>
|
||||
</nav>
|
||||
@@ -113,7 +106,7 @@
|
||||
</button>
|
||||
|
||||
{# Cart #}
|
||||
<a href="/cart" class="relative p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<a href="{{ base_url }}cart" class="relative p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
@@ -139,7 +132,7 @@
|
||||
</button>
|
||||
|
||||
{# Account #}
|
||||
<a href="/account" class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<a href="{{ base_url }}account" class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
@@ -203,40 +196,101 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Quick Links #}
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4">Quick Links</h4>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="/products" class="text-gray-600 hover:text-primary dark:text-gray-400">Products</a></li>
|
||||
<li><a href="/about" class="text-gray-600 hover:text-primary dark:text-gray-400">About Us</a></li>
|
||||
<li><a href="/contact" class="text-gray-600 hover:text-primary dark:text-gray-400">Contact</a></li>
|
||||
<li><a href="/terms" class="text-gray-600 hover:text-primary dark:text-gray-400">Terms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{# Dynamic CMS Pages - Footer Navigation #}
|
||||
{% if footer_pages %}
|
||||
{# Split footer pages into two columns if there are many #}
|
||||
{% set half = (footer_pages | length / 2) | round(0, 'ceil') | int %}
|
||||
{% set col1_pages = footer_pages[:half] %}
|
||||
{% set col2_pages = footer_pages[half:] %}
|
||||
|
||||
{# Customer Service #}
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4">Customer Service</h4>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="/help" class="text-gray-600 hover:text-primary dark:text-gray-400">Help Center</a></li>
|
||||
<li><a href="/shipping" class="text-gray-600 hover:text-primary dark:text-gray-400">Shipping Info</a></li>
|
||||
<li><a href="/returns" class="text-gray-600 hover:text-primary dark:text-gray-400">Returns</a></li>
|
||||
<li><a href="/faq" class="text-gray-600 hover:text-primary dark:text-gray-400">FAQ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{# Column 1 #}
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4">Quick Links</h4>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="{{ base_url }}products" class="text-gray-600 hover:text-primary dark:text-gray-400">Products</a></li>
|
||||
{% for page in col1_pages %}
|
||||
<li><a href="{{ base_url }}{{ page.slug }}" class="text-gray-600 hover:text-primary dark:text-gray-400">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Column 2 #}
|
||||
{% if col2_pages %}
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4">Information</h4>
|
||||
<ul class="space-y-2">
|
||||
{% for page in col2_pages %}
|
||||
<li><a href="{{ base_url }}{{ page.slug }}" class="text-gray-600 hover:text-primary dark:text-gray-400">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# Fallback: Static links if no CMS pages configured #}
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4">Quick Links</h4>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="{{ base_url }}products" class="text-gray-600 hover:text-primary dark:text-gray-400">Products</a></li>
|
||||
<li><a href="{{ base_url }}about" class="text-gray-600 hover:text-primary dark:text-gray-400">About Us</a></li>
|
||||
<li><a href="{{ base_url }}contact" class="text-gray-600 hover:text-primary dark:text-gray-400">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4">Information</h4>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="{{ base_url }}faq" class="text-gray-600 hover:text-primary dark:text-gray-400">FAQ</a></li>
|
||||
<li><a href="{{ base_url }}shipping" class="text-gray-600 hover:text-primary dark:text-gray-400">Shipping</a></li>
|
||||
<li><a href="{{ base_url }}returns" class="text-gray-600 hover:text-primary dark:text-gray-400">Returns</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Copyright #}
|
||||
<div class="mt-8 pt-8 border-t border-gray-200 dark:border-gray-700 text-center text-gray-600 dark:text-gray-400">
|
||||
<p>© {{ now().year }} {{ vendor.name }}. All rights reserved.</p>
|
||||
<p>© <span x-text="new Date().getFullYear()"></span> {{ vendor.name }}. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{# Base Shop JavaScript #}
|
||||
{# JavaScript Loading Order (CRITICAL - must be in this order) #}
|
||||
|
||||
{# 1. Log Configuration (must load first) #}
|
||||
<script src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
{# 2. Icon System #}
|
||||
<script src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
{# 3. Base Shop Layout (Alpine.js component - must load before Alpine) #}
|
||||
<script src="{{ url_for('static', path='shop/js/shop-layout.js') }}"></script>
|
||||
|
||||
{# Page-specific JavaScript #}
|
||||
{# 4. Utilities #}
|
||||
<script src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
{# 5. API Client #}
|
||||
<script src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
{# 6. Alpine.js with CDN fallback (deferred - loads last) #}
|
||||
<script>
|
||||
(function() {
|
||||
var script = document.createElement('script');
|
||||
script.defer = true;
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js';
|
||||
|
||||
script.onerror = function() {
|
||||
console.warn('Alpine.js CDN failed, loading local copy...');
|
||||
var fallbackScript = document.createElement('script');
|
||||
fallbackScript.defer = true;
|
||||
fallbackScript.src = '{{ url_for("static", path="shared/js/vendor/alpine.min.js") }}';
|
||||
document.head.appendChild(fallbackScript);
|
||||
};
|
||||
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
|
||||
{# 7. Page-specific JavaScript #}
|
||||
{% block extra_scripts %}{% endblock %}
|
||||
|
||||
{# Toast notification container #}
|
||||
|
||||
Reference in New Issue
Block a user