{"id":4311,"date":"2025-12-20T11:07:30","date_gmt":"2025-12-20T03:07:30","guid":{"rendered":"https:\/\/phicycling.com\/vertriebspartner-finden\/"},"modified":"2026-04-08T09:42:26","modified_gmt":"2026-04-08T01:42:26","slug":"vertriebspartner-finden","status":"publish","type":"page","link":"https:\/\/phicycling.com\/de\/vertriebspartner-finden\/","title":{"rendered":"Vertriebspartner finden"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"4311\" class=\"elementor elementor-4311 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>Unser H\u00e4ndlernetz umspannt den ganzen Globus und sorgt daf\u00fcr, dass unsere Produkte \u00fcberall leicht zug\u00e4nglich sind. Jeder H\u00e4ndler kennt sich mit der PHi Kollektion bestens aus und kann Sie daher fachkundig beraten und Ihnen einen erstklassigen Service bieten. <\/p><p>Finden Sie Ihren n\u00e4chstgelegenen H\u00e4ndler und entdecken Sie eine Reihe von Produkten, die Ihr Raderlebnis ver\u00e4ndern werden.  <br>Fahren Sie mit Zuversicht, ausger\u00fcstet mit der besten Fahrradausr\u00fcstung der Welt.<\/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-6a91146242a46\"><strong>Filter by Country:<\/strong><\/label>\r\n                    <select id=\"stores-country-select-osm-stores-map-6a91146242a46\">\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-6a91146242a46\" placeholder=\"Enter customer address to find nearby stores...\" \/>\r\n                    <button id=\"stores-search-btn-osm-stores-map-6a91146242a46\">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-6a91146242a46\" 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-6a91146242a46', 'stores-search-btn-osm-stores-map-6a91146242a46', 'stores-search-input-osm-stores-map-6a91146242a46', null, 'stores-country-select-osm-stores-map-6a91146242a46');\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>Unser H\u00e4ndlernetz umspannt den ganzen Globus und sorgt daf\u00fcr, dass unsere Produkte \u00fcberall leicht zug\u00e4nglich sind. Jeder H\u00e4ndler kennt sich mit der PHi Kollektion bestens aus und kann Sie daher fachkundig beraten und Ihnen einen erstklassigen Service bieten. Finden Sie Ihren n\u00e4chstgelegenen H\u00e4ndler und entdecken Sie eine Reihe von Produkten, die Ihr Raderlebnis ver\u00e4ndern werden. [&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-4311","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/pages\/4311","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/comments?post=4311"}],"version-history":[{"count":1,"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/pages\/4311\/revisions"}],"predecessor-version":[{"id":4313,"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/pages\/4311\/revisions\/4313"}],"wp:attachment":[{"href":"https:\/\/phicycling.com\/de\/wp-json\/wp\/v2\/media?parent=4311"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}