(function () {
'use strict';
const WPDATA = typeof vertuCatalogAjax !== 'undefined' ? vertuCatalogAjax : {};
const config = { ajaxUrl: WPDATA.ajax_url, nonce: WPDATA.nonce, pageSize: 12 };
const state = {
allCategories: [],
currentMainCategory: null,
currentSubCategory: null,
currentSelectedCategoryId: null,
currentSortBy: 'default',
currentPage: 1,
};
const DOM = {};
//【恢复】这个 map 作为 "Learn More" 链接的首选来源
const landingPageMap = {
"Quantum Flip": "https://vertu.com/quantum/",
"Metavertu Curve": "https://vertu.com/metavertu-curve/",
"Metavertu 2 Max": "https://vertu.com/metamax/",
"Grand Watch": "https://vertu.com/grandwatch/",
"Aura Ring": "https://vertu.com/aura-ring/",
"Signature S": "https://vertu.com/signature-s/",
"Ironflip": "https://vertu.com/page-ironflip/",
"OWS Earbuds": "https://vertu.com/ows-earbuds/",
"AI Diamond Ring": "https://vertu.com/smartring/"
};
//【恢复】这个函数用于从 map 中查找链接
function getLandingPageUrlByName(productName) {
const name = productName.toLowerCase();
let bestMatch = null;
let longestKey = 0;
for (const key in landingPageMap) {
const lowerKey = key.toLowerCase();
if (name.includes(lowerKey)) {
if (lowerKey.length > longestKey) {
bestMatch = landingPageMap[key];
longestKey = lowerKey.length;
}
}
}
return bestMatch;
}
function initDOMCache() {
DOM.catalogWrapper = document.querySelector('.vertu-catalog-wrapper');
if (!DOM.catalogWrapper) { return false; }
const requiredIds = ['initial-loading', 'error-state', 'product-list', 'banner-categories', 'category-dropdown', 'dropdown-menu', 'sort-dropdown-btn', 'sort-dropdown-menu', 'discover-prev-btn', 'discover-next-btn'];
for (const id of requiredIds) {
DOM[id.replace(/-/g, '_')] = document.getElementById(id);
if (!DOM[id.replace(/-/g, '_')]) {
console.warn(`#${id} not found.`);
return false;
}
}
DOM.banner_title = DOM.catalogWrapper.querySelector('.banner-title');
DOM.banner_desc = DOM.catalogWrapper.querySelector('.banner-desc');
return true;
}
async function fetchData(action, data = {}) {
try {
const formData = new FormData();
formData.append('action', action);
formData.append('nonce', config.nonce);
for (const key in data) { formData.append(key, data[key]); }
const response = await fetch(config.ajaxUrl, { method: 'POST', body: formData });
if (!response.ok) throw new Error(`Network error: ${response.status}`);
const result = await response.json();
if (!result.success) throw new Error(result.data || 'AJAX request failed.');
return result.data;
} catch (error) {
console.error(`Failed to fetch ${action}:`, error);
loadingManager.showError(error.message);
return null;
}
}
//【修改】实现混合式 "Learn More" 链接逻辑
function renderProductCard(product) {
let learnMoreUrl = null;
// 1. 优先从 JS map 中查找
const urlFromMap = getLandingPageUrlByName(product.name);
if (urlFromMap) {
learnMoreUrl = urlFromMap;
}
// 2. 如果 map 中没有,则使用从 WP 后端传来的链接作为后备
else if (product.learn_more_url) {
learnMoreUrl = product.learn_more_url;
}
let learnMoreButtonHtml = '';
if (learnMoreUrl) {
learnMoreButtonHtml = `Learn more `;
}
const imageHtml = product.image_html || `
`;
return `
${product.on_sale ? '
On Sale
' : ''}
${imageHtml}
${product.name}
${product.price_html}
${product.stock_status !== 'outofstock' ? `
Buy now ` : ''}
${learnMoreButtonHtml}
`;
}
function renderProductsPaged(newProducts, reset = false) {
if (reset) {
DOM.product_list.innerHTML = newProducts.map(renderProductCard).join('');
} else {
DOM.product_list.insertAdjacentHTML('beforeend', newProducts.map(renderProductCard).join(''));
}
let loadMoreBtn = DOM.catalogWrapper.querySelector('.load-more-btn');
if (loadMoreBtn) loadMoreBtn.remove();
if (newProducts.length === config.pageSize) {
loadMoreBtn = document.createElement('button');
loadMoreBtn.className = 'load-more-btn';
loadMoreBtn.textContent = 'Load more';
loadMoreBtn.onclick = async (e) => {
const btn = e.target;
btn.textContent = 'Loading...';
btn.disabled = true;
state.currentPage++;
await updateProductsDisplay(false);
};
DOM.product_list.parentNode.appendChild(loadMoreBtn);
}
}
async function updateProductsDisplay(reset = true) {
if (reset) {
state.currentPage = 1;
loadingManager.showLoading();
}
const products = await fetchData('vertu_get_products', {
category_id: state.currentSelectedCategoryId,
sort_by: state.currentSortBy,
page: state.currentPage,
posts_per_page: config.pageSize
});
if (products) {
renderProductsPaged(products, reset);
}
if (reset) {
loadingManager.hideLoading();
}
}
function renderSubCategories() {
const parentId = state.currentMainCategory ? state.currentMainCategory.id : 0;
let subCats = state.allCategories.filter(cat => cat.parent === parentId);
// 添加调试信息
console.log('Current main category:', state.currentMainCategory?.name, 'ID:', parentId);
console.log('Sub categories found:', subCats.length);
subCats.forEach(cat => console.log('-', cat.name, 'term_order:', cat.term_order));
// 使用WordPress的term_order排序,如果都为0则按名称排序
subCats.sort((a, b) => {
const orderA = parseInt(a.term_order) || 0;
const orderB = parseInt(b.term_order) || 0;
// 如果term_order都为0,按名称排序
if (orderA == 0 && orderB == 0) {
return a.name.localeCompare(b.name);
}
// 否则按term_order排序
return orderA - orderB;
});
// 添加排序后的调试信息
console.log('Sorted sub categories:');
subCats.forEach((cat, index) => console.log(`${index + 1}. ${cat.name} (term_order: ${cat.term_order})`));
if (DOM.banner_categories) {
const imagePlaceholder = `
`;
DOM.banner_categories.innerHTML = subCats.map(cat => {
const isActive = state.currentSubCategory && state.currentSubCategory.id === cat.id;
return `${cat.image_html || imagePlaceholder}
${cat.name}
`;
}).join('');
}
}
function renderCategoryDropdown() {
if (!state.currentMainCategory) return;
const parentId = state.currentMainCategory.id;
let subCats = state.allCategories.filter(cat => cat.parent === parentId);
// 使用WordPress的term_order排序,如果都为0则按名称排序
subCats.sort((a, b) => {
const orderA = parseInt(a.term_order) || 0;
const orderB = parseInt(b.term_order) || 0;
// 如果term_order都为0,按名称排序
if (orderA == 0 && orderB == 0) {
return a.name.localeCompare(b.name);
}
// 否则按term_order排序
return orderA - orderB;
});
let html = `All ${state.currentMainCategory.name}
`;
html += subCats.map(cat => {
const isSelected = state.currentSubCategory && state.currentSubCategory.id === cat.id;
return `${cat.name}
`;
}).join('');
if (DOM.dropdown_menu) DOM.dropdown_menu.innerHTML = html;
}
function updateActiveCategory(catId) {
if(state.currentSelectedCategoryId === catId) return;
if(catId === 0) {
state.currentMainCategory = null; state.currentSubCategory = null; state.currentSelectedCategoryId = null;
} else {
state.currentSelectedCategoryId = catId;
const selectedCat = state.allCategories.find(c => c.id === catId);
if (selectedCat) {
if (selectedCat.parent === 0) {
if (state.currentMainCategory?.id !== selectedCat.id) {
state.currentMainCategory = selectedCat;
state.currentSubCategory = null;
renderSubCategories();
renderCategoryDropdown();
}
} else {
state.currentSubCategory = selectedCat;
const parentCat = state.allCategories.find(c => c.id === selectedCat.parent);
if (parentCat && state.currentMainCategory?.id !== parentCat.id) {
state.currentMainCategory = parentCat;
renderSubCategories();
renderCategoryDropdown();
}
}
}
}
document.querySelectorAll('.banner-category-card.active').forEach(c => c.classList.remove('active'));
const activeCard = DOM.banner_categories.querySelector(`[data-cat-id="${catId}"]`);
if (activeCard) activeCard.classList.add('active');
updateDropdownBtnText();
updateProductsDisplay(true);
}
function updateDropdownBtnText() {
const allSpan = DOM.category_dropdown.querySelector('.dropdown-all');
const maincatSpan = DOM.category_dropdown.querySelector('.dropdown-maincat');
if (!allSpan || !maincatSpan) return;
if (state.currentSubCategory) {
allSpan.textContent = ''; maincatSpan.textContent = state.currentSubCategory.name;
} else if (state.currentMainCategory) {
allSpan.textContent = 'All'; maincatSpan.textContent = ` ${state.currentMainCategory.name}`;
} else {
allSpan.textContent = 'All'; maincatSpan.textContent = ' Categories';
}
}
async function startApp() {
if (!initDOMCache()) {
loadingManager.showError('Failed to initialize page elements.');
return;
}
loadingManager.showInitialLoading();
const categories = await fetchData('vertu_get_categories');
if(!categories) return;
state.allCategories = categories.filter(c => c.name !== 'Payment Link' && typeof c.parent !== 'undefined');
const initialCategorySlug = DOM.catalogWrapper.dataset.initialCategory;
let mainCategories = state.allCategories.filter(cat => cat.parent === 0);
// 使用与PHP后端相同的排序逻辑
mainCategories.sort((a, b) => {
// 优先使用term_order,如果都为0则使用menu_order
if ((a.term_order || 0) != 0 || (b.term_order || 0) != 0) {
return (a.term_order || 0) - (b.term_order || 0);
}
// 如果term_order都为0,使用menu_order
if ((a.menu_order || 0) != 0 || (b.menu_order || 0) != 0) {
return (a.menu_order || 0) - (b.menu_order || 0);
}
// 最后按名称排序
return a.name.localeCompare(b.name);
});
let initialCategory = null;
if(initialCategorySlug) {
initialCategory = state.allCategories.find(cat => cat.slug.toLowerCase() === initialCategorySlug.toLowerCase() && cat.parent === 0);
}
state.currentMainCategory = initialCategory || mainCategories[0] || null;
if (state.currentMainCategory) {
state.currentSelectedCategoryId = state.currentMainCategory.id;
DOM.banner_title.textContent = state.currentMainCategory.name;
DOM.banner_desc.innerHTML = state.currentMainCategory.description || '';
renderSubCategories();
renderCategoryDropdown();
updateDropdownBtnText();
await updateProductsDisplay(true);
} else {
loadingManager.showError('No product categories found.');
}
dropdownManager.init();
initEventListeners();
initScrollButtons();
loadingManager.hideInitialLoading();
}
function initializeCatalog() {
const catalogWrapper = document.querySelector('.vertu-catalog-wrapper');
if (!catalogWrapper) {
let attempts = 0;
const interval = setInterval(function() {
const wrapper = document.querySelector('.vertu-catalog-wrapper');
if (wrapper) {
clearInterval(interval);
startApp();
}
attempts++;
if (attempts > 50) {
clearInterval(interval);
console.error('Catalog wrapper did not appear after 5 seconds. Aborting.');
const errorDiv = document.getElementById('error-state');
if (errorDiv) {
const errorText = errorDiv.querySelector('.error-state-text');
if (errorText) errorText.textContent = 'Failed to load catalog content.';
errorDiv.style.display = 'flex';
}
}
}, 100);
return;
}
startApp();
}
const dropdownManager = { init() { this.menus = { category: DOM.dropdown_menu, sort: DOM.sort_dropdown_menu }; this.buttons = { category: DOM.category_dropdown, sort: DOM.sort_dropdown_btn }; this.currentOpenMenu = null; this.bindEvents(); }, bindEvents() { Object.entries(this.buttons).forEach(([type, button]) => { if (button) button.addEventListener('click', (e) => { e.stopPropagation(); this.toggleMenu(type); }); }); document.addEventListener('click', () => this.closeAllMenus()); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') this.closeAllMenus(); }); }, toggleMenu(type) { this.currentOpenMenu === type ? this.closeAllMenus() : this.openMenu(type); }, openMenu(type) { this.closeAllMenus(); if(this.menus[type]) this.menus[type].style.display = 'block'; if(this.buttons[type]) this.buttons[type].classList.add('active'); this.currentOpenMenu = type; }, closeAllMenus() { if (!this.currentOpenMenu) return; if(this.menus[this.currentOpenMenu]) this.menus[this.currentOpenMenu].style.display = 'none'; if(this.buttons[this.currentOpenMenu]) this.buttons[this.currentOpenMenu].classList.remove('active'); this.currentOpenMenu = null; } };
function initEventListeners() {
if (DOM.banner_categories) DOM.banner_categories.addEventListener('click', e => { const card = e.target.closest('.banner-category-card'); if (card && card.dataset.catId) updateActiveCategory(parseInt(card.dataset.catId, 10)); });
if (DOM.dropdown_menu) DOM.dropdown_menu.addEventListener('click', e => { const item = e.target.closest('.dropdown-item'); if (item && item.dataset.catId) updateActiveCategory(parseInt(item.dataset.catId, 10)); });
if (DOM.sort_dropdown_menu) DOM.sort_dropdown_menu.addEventListener('click', e => {
const item = e.target.closest('.sort-dropdown-item');
if (item && item.dataset.sort) {
state.currentSortBy = item.dataset.sort;
DOM.sort_dropdown_menu.querySelectorAll('.sort-dropdown-item').forEach(i => i.classList.remove('selected'));
item.classList.add('selected');
updateProductsDisplay(true);
dropdownManager.closeAllMenus();
}
});
}
function initScrollButtons() { if (DOM.discover_prev_btn && DOM.discover_next_btn && DOM.banner_categories) { DOM.discover_prev_btn.addEventListener('click', () => { DOM.banner_categories.scrollBy({ left: -300, behavior: 'smooth' }); }); DOM.discover_next_btn.addEventListener('click', () => { DOM.banner_categories.scrollBy({ left: 300, behavior: 'smooth' }); }); } }
const loadingManager = {
getInitialLoadingEl() { return document.getElementById('initial-loading'); },
getErrorStateEl() { return document.getElementById('error-state'); },
showInitialLoading() { const el = this.getInitialLoadingEl(); if (el) el.style.display = 'flex'; },
hideInitialLoading() { const el = this.getInitialLoadingEl(); if (el) el.style.display = 'none'; },
showLoading() { renderSkeletonCards(config.pageSize); },
hideLoading() { /* This function is now intentionally left blank as renderProductsPaged handles content replacement */ },
showError(message) {
this.hideInitialLoading();
if (DOM.product_list) DOM.product_list.innerHTML = '';
const el = this.getErrorStateEl();
if (el) {
const textEl = el.querySelector('.error-state-text');
if (textEl) textEl.textContent = message;
el.style.display = 'flex';
} else {
alert(`Error: ${message}`);
}
}
};
function renderSkeletonCards(count) { let html = ''; for (let i = 0; i < count; i++) { html += ``; } if (DOM.product_list) DOM.product_list.innerHTML = html; }
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeCatalog);
} else {
initializeCatalog();
}
})();
Vertu Bespoke Phones | Start Your Luxury Journey
Skip to content
Bespoke Step into a world where your vision shapes the pinnacle of mobile luxury. The Vertu Bespoke Collection invites you to collaborate with our esteemed artisans, transforming the finest materials and cutting-edge technology into a smartphone that is uniquely yours. From selecting the perfect shade of rare exotic leather to incorporating precious metals and intricate engravings, every detail is a reflection of your personal style and a testament to unparalleled craftsmanship.
Showing 37–48 of 48 results