{"id":4666,"date":"2025-12-20T11:07:30","date_gmt":"2025-12-20T03:07:30","guid":{"rendered":"https:\/\/phicycling.com\/trova-un-distributore\/"},"modified":"2026-04-08T09:42:26","modified_gmt":"2026-04-08T01:42:26","slug":"trova-un-distributore","status":"publish","type":"page","link":"https:\/\/phicycling.com\/it\/trova-un-distributore\/","title":{"rendered":"Trova un distributore"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"4666\" class=\"elementor elementor-4666 elementor-1261\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-693777e e-flex e-con-boxed e-con e-parent\" data-id=\"693777e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e9a1148 elementor-widget elementor-widget-text-editor\" data-id=\"e9a1148\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>La nostra rete di distributori si estende in tutto il mondo, assicurando che i nostri prodotti siano facilmente accessibili ovunque tu sia. Ogni distributore conosce bene la collezione PHi e pu\u00f2 quindi fornire consigli esperti e un servizio di prima classe. <\/p><p>Trova il distributore pi\u00f9 vicino a te e scopri una gamma di prodotti che trasformeranno la tua esperienza ciclistica.  <br>Pedala con fiducia, equipaggiato con la migliore attrezzatura da ciclismo del pianeta.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e201d22 elementor-widget elementor-widget-shortcode\" data-id=\"e201d22\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">        <div id=\"osm-stores-container\" class=\"osm-stores-wrapper osm-responsive-layout\">\r\n            <!-- \u63a7\u5236\u533a\uff1a\u7b5b\u9009\u5668\u548c\u641c\u7d22\u6846 -->\r\n            <div class=\"controls-section\">\r\n                <div class=\"stores-country-filter\">\r\n                    <label for=\"stores-country-select-osm-stores-map-6a914331f1182\"><strong>Filter by Country:<\/strong><\/label>\r\n                    <select id=\"stores-country-select-osm-stores-map-6a914331f1182\">\r\n                        <option value=\"\">All Countries<\/option>\r\n                                                    <option value=\"Andorra\">Andorra<\/option>\r\n                                                    <option value=\"Czech Republic\">Czech Republic<\/option>\r\n                                                    <option value=\"France\">France<\/option>\r\n                                                    <option value=\"Germany\">Germany<\/option>\r\n                                                    <option value=\"Italy\">Italy<\/option>\r\n                                                    <option value=\"Portugal\">Portugal<\/option>\r\n                                                    <option value=\"Spain\">Spain<\/option>\r\n                                                    <option value=\"United States (US)\">United States (US)<\/option>\r\n                                            <\/select>\r\n                <\/div>\r\n\r\n                <div class=\"stores-search-box\">\r\n                    <input type=\"text\" id=\"stores-search-input-osm-stores-map-6a914331f1182\" placeholder=\"Enter customer address to find nearby stores...\" \/>\r\n                    <button id=\"stores-search-btn-osm-stores-map-6a914331f1182\">Search<\/button>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- \u4e3b\u4f53\u5185\u5bb9\u533a\uff1aGoogle \u5730\u56fe -->\r\n            <div class=\"main-content-section\">\r\n                <div id=\"osm-stores-map-6a914331f1182\" class=\"store-map-element store-map-js-init\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <script type=\"text\/javascript\">\r\n        (function(mapId, buttonId, inputId, resultsId, countrySelectId) {\r\n            'use strict';\r\n\r\n            let globalMap = null;\r\n            let globalMarkers = [];\r\n            const useGoogle = true;\r\n            const geocodeNonce = \"3e332e6f52\";\r\n\r\n            if (document.readyState === 'loading') {\r\n                document.addEventListener('DOMContentLoaded', () => initializeMap(mapId, buttonId, inputId, resultsId, countrySelectId));\r\n            } else {\r\n                initializeMap(mapId, buttonId, inputId, resultsId, countrySelectId);\r\n            }\r\n\r\n            function initializeMap(mapId, buttonId, inputId, resultsId, countrySelectId) {\r\n                try {\r\n                    const mapElement = document.getElementById(mapId);\r\n                    if (!mapElement) {\r\n                        console.error('[StoreMap] ERROR: Map element with ID \"' + mapId + '\" not found.');\r\n                        return;\r\n                    }\r\n\r\n                    if (typeof google === 'undefined' || !google.maps) {\r\n                        console.error('[StoreMap] ERROR: Google Maps library is not available.');\r\n                        mapElement.innerHTML = '<div style=\"color: red; padding: 20px; text-align: center;\">Google Maps failed to load.<\/div>';\r\n                        return;\r\n                    }\r\n\r\n                    globalMap = new google.maps.Map(mapElement, {center:{lat:20,lng:0}, zoom:2, mapTypeControl:false});\r\n\r\n                    bindSearchEvents(buttonId, inputId, resultsId);\r\n                    bindCountryFilterEvent(countrySelectId, resultsId);\r\n                    loadAllStores(resultsId);\r\n\r\n                } catch (e) {\r\n                    console.error('[StoreMap] FATAL ERROR during initialization:', e);\r\n                    const elem = document.getElementById(mapId);\r\n                    if (elem) elem.innerHTML = '<div style=\"color: red; padding: 20px; text-align: center;\">Init Error: ' + e.message + '<\/div>';\r\n                }\r\n            }\r\n\r\n            function bindSearchEvents(buttonId, inputId, resultsId) {\r\n                const btn = document.getElementById(buttonId);\r\n                const inp = document.getElementById(inputId);\r\n\r\n                if (btn) {\r\n                    btn.onclick = () => locateCustomerAddress(inputId, resultsId);\r\n                }\r\n                if (inp) {\r\n                    inp.onkeypress = (e) => { if (e.key === 'Enter') { e.preventDefault(); locateCustomerAddress(inputId, resultsId); } };\r\n                }\r\n            }\r\n\r\n            async function locateCustomerAddress(inputId, resultsId) {\r\n                const input=document.getElementById(inputId);const address=input?input.value.trim():'';if(!address)return;\r\n                await performSearch(null,resultsId,'','init');\r\n                const geocoder=new google.maps.Geocoder();geocoder.geocode({address:address},(results,status)=>{if(status==='OK'&&results[0]){globalMap.setCenter(results[0].geometry.location);globalMap.setZoom(10);}else alert('Address could not be located: '+status);});\r\n            }\r\n\r\n            function bindCountryFilterEvent(selectId, resultsId) {\r\n                const selectElement = document.getElementById(selectId);\r\n                if (selectElement) {\r\n                    selectElement.onchange = (e) => {\r\n                        const selectedCountry = e.target.value;\r\n                        performSearch(null, resultsId, selectedCountry, 'filter');\r\n                    };\r\n                }\r\n            }\r\n\r\n            function loadAllStores(resultsId) {\r\n                performSearch(null, resultsId, '', 'init');\r\n            }\r\n\r\n            async function performSearch(inputId, resultsId, termOverride = null, triggerSource = 'search') {\r\n                let term = termOverride;\r\n                \r\n                if (triggerSource === 'search' && inputId) {\r\n                    const inputElement = document.getElementById(inputId);\r\n                    if (inputElement) {\r\n                        term = inputElement.value.trim();\r\n                    }\r\n                }\r\n                \r\n                if (triggerSource === 'filter' && termOverride !== null) {\r\n                    term = termOverride;\r\n                }\r\n                \r\n                if (triggerSource === 'init') {\r\n                    term = '';\r\n                }\r\n\r\n                try {\r\n                    const formData = new FormData();\r\n                    formData.append('action', 'search_stores');\r\n                    formData.append('search_term', term);\r\n                    formData.append('search_type', triggerSource === 'search' && term ? 'city' : (triggerSource === 'filter' && term ? 'country' : 'all'));\r\n                    formData.append('nonce', Date.now()); \/\/ \u4f7f\u7528\u65f6\u95f4\u6233\u4ee3\u66ffnonce\r\n\r\n                    const response = await fetch(window.ajaxurl || '\/wp-admin\/admin-ajax.php', {\r\n                        method: 'POST',\r\n                        body: formData\r\n                    });\r\n\r\n                    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\r\n\r\n                    const data = await response.json();\r\n                    console.log('[StoreMap] AJAX Response Data:', data);\r\n\r\n                    if (data && data.success && Array.isArray(data.data)) {\r\n                        clearMarkers();\r\n                        const stores = data.data;\r\n                        await geocodeMissingStores(stores);\r\n\r\n                        \/\/ \u66f4\u65b0\u53f3\u4fa7\u5217\u8868\r\n                        if (resultsId) {\r\n                            const resultsElement = document.getElementById(resultsId);\r\n                            if (resultsElement) {\r\n                                let listHtml = '';\r\n                                if (stores.length === 0 && term) {\r\n                                    listHtml = '<p class=\"no-results\">No stores found for \"' + escapeHtml(term) + '\" in this category.<\/p>';\r\n                                } else if (stores.length > 0) {\r\n                                    listHtml = '<div class=\"stores-grid\">';\r\n                                    stores.forEach(s => {\r\n                                        \/\/ \u5b89\u5168\u68c0\u67e5\u6bcf\u4e2a\u5bf9\u8c61\u7684\u5c5e\u6027\r\n                                        if (!s || typeof s !== 'object') return;\r\n                                        \r\n                                        const title = s.title || 'Unknown Store';\r\n                                        const address = s.address || 'Address not provided';\r\n                                        const phone = s.phone || 'Phone not provided';\r\n                                        const city = s.city || 'City not provided';\r\n                                        const country = s.country || 'Country not provided';\r\n                                        const lat = s.lat;\r\n                                        const lng = s.lng;\r\n                                        \r\n                                        listHtml += '<div class=\"store-item\"><h3>' + escapeHtml(title) + '<\/h3>';\r\n                                        listHtml += '<p><strong>Address:<\/strong> ' + escapeHtml(address) + '<\/p>';\r\n                                        listHtml += '<p><strong>Phone:<\/strong> ' + escapeHtml(phone) + '<\/p>';\r\n                                        listHtml += '<p><strong>Location:<\/strong> ' + escapeHtml(city) + ', ' + escapeHtml(country) + '<\/p>';\r\n                                        if (lat && lng) {\r\n                                            listHtml += '<button class=\"view-on-map-btn\" onclick=\"focusOnStore_' + mapId + '(' + lat + ',' + lng + ',\\'' + escapeHtml(title) + '\\',\\'' + escapeHtml(address) + '\\')\">View on Map<\/button>';\r\n                                        }\r\n                                        listHtml += '<\/div>';\r\n                                        if (lat && lng) addMarker(s);\r\n                                    });\r\n                                    listHtml += '<\/div>';\r\n                                } else if (triggerSource === 'init') {\r\n                                    \/\/ \u521d\u59cb\u5316\u65f6\u52a0\u8f7d\u5168\u90e8\r\n                                    listHtml = '<div class=\"stores-grid\">';\r\n                                    stores.forEach(s => {\r\n                                        \/\/ \u5b89\u5168\u68c0\u67e5\u6bcf\u4e2a\u5bf9\u8c61\u7684\u5c5e\u6027\r\n                                        if (!s || typeof s !== 'object') return;\r\n                                        \r\n                                        const title = s.title || 'Unknown Store';\r\n                                        const address = s.address || 'Address not provided';\r\n                                        const phone = s.phone || 'Phone not provided';\r\n                                        const city = s.city || 'City not provided';\r\n                                        const country = s.country || 'Country not provided';\r\n                                        const lat = s.lat;\r\n                                        const lng = s.lng;\r\n                                        \r\n                                        listHtml += '<div class=\"store-item\"><h3>' + escapeHtml(title) + '<\/h3>';\r\n                                        listHtml += '<p><strong>Address:<\/strong> ' + escapeHtml(address) + '<\/p>';\r\n                                        listHtml += '<p><strong>Phone:<\/strong> ' + escapeHtml(phone) + '<\/p>';\r\n                                        listHtml += '<p><strong>Location:<\/strong> ' + escapeHtml(city) + ', ' + escapeHtml(country) + '<\/p>';\r\n                                        if (lat && lng) {\r\n                                            listHtml += '<button class=\"view-on-map-btn\" onclick=\"focusOnStore_' + mapId + '(' + lat + ',' + lng + ',\\'' + escapeHtml(title) + '\\',\\'' + escapeHtml(address) + '\\')\">View on Map<\/button>';\r\n                                        }\r\n                                        listHtml += '<\/div>';\r\n                                        if (lat && lng) addMarker(s);\r\n                                    });\r\n                                    listHtml += '<\/div>';\r\n                                }\r\n                                resultsElement.querySelector('.stores-list-content').innerHTML = listHtml;\r\n                            }\r\n                        } else {\r\n                            stores.forEach(s => {\r\n                                if (s && s.lat && s.lng) addMarker(s);\r\n                            });\r\n                        }\r\n\r\n                        if (stores.length > 0) fitBounds();\r\n                    } else {\r\n                        console.error('[StoreMap] Search API returned invalid data:', data);\r\n                        if (resultsId) {\r\n                            document.getElementById(resultsId).querySelector('.stores-list-content').innerHTML = '<p class=\"error\">API Error: Invalid response format<\/p>';\r\n                        }\r\n                    }\r\n                } catch (error) {\r\n                    console.error('[StoreMap] Error during search:', error);\r\n                    if (resultsId) {\r\n                        document.getElementById(resultsId).querySelector('.stores-list-content').innerHTML = '<p class=\"error\">An error occurred during search: ' + error.message + '<\/p>';\r\n                    }\r\n                }\r\n            }\r\n\r\n            async function geocodeMissingStores(stores) {\r\n                const geocoder = new google.maps.Geocoder();\r\n                for (const store of stores) {\r\n                    if (!store || (store.lat && store.lng) || !store.address) continue;\r\n                    try {\r\n                        const result = await new Promise((resolve, reject) => geocoder.geocode({address:store.address}, (results,status) => status === 'OK' && results[0] ? resolve(results[0]) : reject(new Error(status))));\r\n                        const location = result.geometry.location;store.lat = location.lat();store.lng = location.lng();\r\n                        const formData = new FormData();formData.append('action','phi_cache_store_coordinates');formData.append('nonce',geocodeNonce);formData.append('store_id',store.id);formData.append('address',store.address);formData.append('lat',store.lat);formData.append('lng',store.lng);\r\n                        fetch(window.ajaxurl || '\/wp-admin\/admin-ajax.php',{method:'POST',body:formData}).catch(()=>{});\r\n                        await new Promise(resolve => setTimeout(resolve, 120));\r\n                    } catch (error) { console.warn('[StoreMap] Google geocoding failed for store '+store.id+':',error.message); }\r\n                }\r\n            }\r\n\r\n            function addMarker(s) {\r\n                if (!globalMap || !s || typeof s !== 'object' || !s.lat || !s.lng) return;\r\n                const lat = parseFloat(s.lat);\r\n                const lng = parseFloat(s.lng);\r\n                if (isNaN(lat) || isNaN(lng)) return;\r\n\r\n                const title = s.title || 'Unknown Store';\r\n                const address = s.address || 'Address not provided';\r\n                const phone = s.phone || 'Phone not provided';\r\n                const city = s.city || 'City not provided';\r\n                const country = s.country || 'Country not provided';\r\n\r\n                const popupContent = '<div class=\"phi-google-popup\" style=\"min-width:200px;color:#202124;background:#fff;\">' +\r\n                    '<h3 style=\"color:#111827;margin:0 0 10px\">' + escapeHtml(title) + '<\/h3>' +\r\n                    '<p style=\"color:#202124\"><strong>Address:<\/strong> ' + escapeHtml(address) + '<\/p>' +\r\n                    '<p style=\"color:#202124\"><strong>Phone:<\/strong> ' + escapeHtml(phone) + '<\/p>' +\r\n                    '<p style=\"color:#202124\"><strong>Location:<\/strong> ' + escapeHtml(city) + ', ' + escapeHtml(country) + '<\/p>' +\r\n                    '<\/div>';\r\n\r\n                let marker = new google.maps.Marker({position:{lat:lat,lng:lng}, map:globalMap, title:title});\r\n                marker.phiInfo = new google.maps.InfoWindow({content:popupContent});\r\n                marker.addListener('click', () => marker.phiInfo.open({anchor:marker,map:globalMap}));\r\n                globalMarkers.push(marker);\r\n            }\r\n\r\n            function clearMarkers() {\r\n                if (!globalMap) return;\r\n                globalMarkers.forEach(m => m.setMap(null));\r\n                globalMarkers = [];\r\n            }\r\n\r\n            function fitBounds() {\r\n                if (!globalMap || globalMarkers.length === 0) return;\r\n                const bounds = new google.maps.LatLngBounds(); globalMarkers.forEach(m => bounds.extend(m.getPosition())); globalMap.fitBounds(bounds);\r\n            }\r\n\r\n            window['focusOnStore_' + mapId] = function(lat, lng, title, address) {\r\n                if (!globalMap) return;\r\n                const parsedLat = parseFloat(lat);\r\n                const parsedLng = parseFloat(lng);\r\n                if (isNaN(parsedLat) || isNaN(parsedLng)) return;\r\n                globalMap.setCenter({lat:parsedLat,lng:parsedLng}); globalMap.setZoom(14);\r\n                globalMarkers.forEach(m => {\r\n                    const mLat = m.getPosition().lat();\r\n                    const mLng = m.getPosition().lng();\r\n                    if (Math.abs(mLat - parsedLat) < 0.0001 && Math.abs(mLng - parsedLng) < 0.0001) m.phiInfo.open({anchor:m,map:globalMap});\r\n                });\r\n            };\r\n\r\n            function escapeHtml(text) {\r\n                if (!text) return text;\r\n                const map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#039;' };\r\n                return text.replace(\/[&<>\"']\/g, m => map[m]);\r\n            }\r\n\r\n        })('osm-stores-map-6a914331f1182', 'stores-search-btn-osm-stores-map-6a914331f1182', 'stores-search-input-osm-stores-map-6a914331f1182', null, 'stores-country-select-osm-stores-map-6a914331f1182');\r\n        <\/script>\r\n        <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>La nostra rete di distributori si estende in tutto il mondo, assicurando che i nostri prodotti siano facilmente accessibili ovunque tu sia. Ogni distributore conosce bene la collezione PHi e pu\u00f2 quindi fornire consigli esperti e un servizio di prima classe. Trova il distributore pi\u00f9 vicino a te e scopri una gamma di prodotti che [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-4666","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/pages\/4666","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/comments?post=4666"}],"version-history":[{"count":1,"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/pages\/4666\/revisions"}],"predecessor-version":[{"id":4668,"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/pages\/4666\/revisions\/4668"}],"wp:attachment":[{"href":"https:\/\/phicycling.com\/it\/wp-json\/wp\/v2\/media?parent=4666"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}