{"id":7013,"date":"2026-06-19T06:37:36","date_gmt":"2026-06-19T06:37:36","guid":{"rendered":"https:\/\/eievss.com\/website\/wordpress\/?page_id=7013"},"modified":"2026-06-19T06:37:45","modified_gmt":"2026-06-19T06:37:45","slug":"test-api","status":"publish","type":"page","link":"https:\/\/eievss.com\/website\/wordpress\/test-api\/","title":{"rendered":"Test API"},"content":{"rendered":"    <div id=\"eiev_check_925320\" class=\"eiev-check\"\n         data-event-id=\"11402\"\n         data-selected-race=\"37035\"\n         data-race-map='[{&quot;id&quot;:37035,&quot;name&quot;:&quot;CEI 3* 160km, Compi\\u00e8gne Endurance Ride at Jun. 20, 2026&quot;,&quot;short&quot;:&quot;3* 160&quot;,&quot;date&quot;:&quot;2026-06-20&quot;},{&quot;id&quot;:37036,&quot;name&quot;:&quot;CEI 3* 140km, Compi\\u00e8gne Endurance Ride at Jun. 20, 2026&quot;,&quot;short&quot;:&quot;3* 140&quot;,&quot;date&quot;:&quot;2026-06-20&quot;},{&quot;id&quot;:37037,&quot;name&quot;:&quot;CEI 1* 100km, Compi\\u00e8gne Endurance Ride at Jun. 20, 2026&quot;,&quot;short&quot;:&quot;1* 100 Jun 20&quot;,&quot;date&quot;:&quot;2026-06-20&quot;},{&quot;id&quot;:37038,&quot;name&quot;:&quot;CEI 2* CIM 120km, Compi\\u00e8gne Endurance Ride at Jun. 21, 2026&quot;,&quot;short&quot;:&quot;2* 120&quot;,&quot;date&quot;:&quot;2026-06-21&quot;},{&quot;id&quot;:37039,&quot;name&quot;:&quot;CEIYJ 2* 120km, Compi\\u00e8gne Endurance Ride at Jun. 21, 2026&quot;,&quot;short&quot;:&quot;YJ2* 120&quot;,&quot;date&quot;:&quot;2026-06-21&quot;},{&quot;id&quot;:37040,&quot;name&quot;:&quot;CEI 1* 100km, Compi\\u00e8gne Endurance Ride at Jun. 21, 2026&quot;,&quot;short&quot;:&quot;1* 100 Jun 21&quot;,&quot;date&quot;:&quot;2026-06-21&quot;}]'>\n\n        <section class=\"eiev-check-card eiev-check-hero\">\n            <div>\n                <h1>EIEV Event 11402 Deployment Check<\/h1>\n                <p>Official API and website readiness verification<\/p>\n            <\/div>\n            <strong class=\"eiev-check-ready\">READY<\/strong>\n        <\/section>\n\n        <div class=\"eiev-check-alert\" style=\"display:none;\"><\/div>\n\n        <section class=\"eiev-check-card\">\n            <h2>Server requirements<\/h2>\n            <div class=\"eiev-check-grid eiev-check-server\"><\/div>\n        <\/section>\n\n        <section class=\"eiev-check-card\">\n            <h2>Official Event 11402<\/h2>\n            <div class=\"eiev-check-grid eiev-check-event\"><\/div>\n            <div class=\"eiev-check-actions\">\n                <button type=\"button\" class=\"eiev-check-refresh\">Refresh official API<\/button>\n                <button type=\"button\" class=\"eiev-check-clear\">Clear cache and retest<\/button>\n            <\/div>\n        <\/section>\n\n        <section class=\"eiev-check-card\">\n            <h2>Official rides returned by the API<\/h2>\n            <div class=\"eiev-check-table-wrap\">\n                <table class=\"eiev-check-races\">\n                    <thead>\n                        <tr>\n                            <th>Race ID<\/th>\n                            <th>Ride name<\/th>\n                            <th>Date<\/th>\n                            <th>Status<\/th>\n                            <th>Entries<\/th>\n                            <th>Test<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody><\/tbody>\n                <\/table>\n            <\/div>\n        <\/section>\n\n        <section class=\"eiev-check-card eiev-check-selected\">\n            <h2>Selected race detail: <span class=\"eiev-check-selected-id\">37035<\/span><\/h2>\n            <div class=\"eiev-check-grid eiev-check-race-detail\"><\/div>\n            <div class=\"eiev-check-actions\">\n                <button type=\"button\" class=\"eiev-check-open-live\">Open Live Event<\/button>\n                <button type=\"button\" class=\"eiev-check-open-results\">Open Results<\/button>\n                <button type=\"button\" class=\"eiev-check-open-riders\">Open Riders<\/button>\n            <\/div>\n            <div class=\"eiev-check-note\"><\/div>\n        <\/section>\n\n        <section class=\"eiev-check-card\">\n            <strong>Final security step:<\/strong> delete this testing page\/plugin after deployment reports READY.\n        <\/section>\n    <\/div>\n\n    <script>\n    (function(){\n        const root = document.getElementById('eiev_check_925320');\n        const eventId = root.dataset.eventId || '11402';\n        let selectedRace = root.dataset.selectedRace || '37035';\n        const raceMap = JSON.parse(root.dataset.raceMap || '[]');\n\n        const serverBox = root.querySelector('.eiev-check-server');\n        const eventBox = root.querySelector('.eiev-check-event');\n        const racesBody = root.querySelector('.eiev-check-races tbody');\n        const raceDetailBox = root.querySelector('.eiev-check-race-detail');\n        const alertBox = root.querySelector('.eiev-check-alert');\n        const selectedTitle = root.querySelector('.eiev-check-selected-id');\n        const noteBox = root.querySelector('.eiev-check-note');\n\n        const API = {\n            server: \"https:\/\/eievss.com\/website\/wordpress\/wp-json\/eiev-check\/v1\/server\",\n            events: \"https:\/\/eievss.com\/website\/wordpress\/wp-json\/eiev-check\/v1\/events\",\n            races: \"https:\/\/eievss.com\/website\/wordpress\/wp-json\/eiev-check\/v1\/races\/\",\n            race: \"https:\/\/eievss.com\/website\/wordpress\/wp-json\/eiev-check\/v1\/race\/\",\n            clear: \"https:\/\/eievss.com\/website\/wordpress\/wp-json\/eiev-check\/v1\/clear-cache\"\n        };\n\n        function esc(v){\n            return String(v ?? '').replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;').replace(\/'\/g,'&#039;');\n        }\n\n        function val(obj, keys, fallback=''){\n            for (const k of keys) {\n                if (obj && obj[k] !== undefined && obj[k] !== null && String(obj[k]) !== '') return obj[k];\n            }\n            return fallback;\n        }\n\n        function asArray(data){\n            if (Array.isArray(data)) return data;\n            if (!data || typeof data !== 'object') return [];\n            for (const k of ['data','events','races','items','records','result','list']) {\n                if (Array.isArray(data[k])) return data[k];\n            }\n            for (const k in data) if (Array.isArray(data[k])) return data[k];\n            return [];\n        }\n\n        async function get(url){\n            const res = await fetch(url, { credentials: 'same-origin' });\n            const json = await res.json();\n            if (!json.success) throw new Error(json.message || 'Request failed');\n            return json.data;\n        }\n\n        async function post(url){\n            const res = await fetch(url, { method:'POST', credentials:'same-origin' });\n            const json = await res.json();\n            if (!json.success) throw new Error(json.message || 'Request failed');\n            return json;\n        }\n\n        function pill(ready){\n            return ready ? '<span class=\"ready\">Ready<\/span>' : '<span class=\"fail\">Fail<\/span>';\n        }\n\n        function metric(label, value, ready=true){\n            return `<div class=\"eiev-check-metric\"><span>${esc(label)}<\/span><b>${esc(value)}<\/b>${pill(ready)}<\/div>`;\n        }\n\n        function showAlert(message){\n            alertBox.style.display = 'block';\n            alertBox.textContent = message;\n        }\n\n        function hideAlert(){\n            alertBox.style.display = 'none';\n            alertBox.textContent = '';\n        }\n\n        function dateOnly(v){\n            if (!v) return '-';\n            return String(v).split(' ')[0];\n        }\n\n        function matchingOfficialRace(index, apiRace){\n            const mapped = raceMap[index] || {};\n            return {\n                id: mapped.id || val(apiRace, ['race_code','id','race_id','raceId'], ''),\n                name: mapped.name || val(apiRace, ['name','name_en','race_name'], 'Ride'),\n                short: mapped.short || val(apiRace, ['name'], 'Race'),\n                date: mapped.date || dateOnly(val(apiRace, ['start_time','date'], '')),\n                status: val(apiRace, ['race_status','status'], 'Upcoming'),\n                entries: val(apiRace, ['start_list_count','entries'], 0)\n            };\n        }\n\n        async function loadServer(){\n            serverBox.innerHTML = metric('Server', 'Checking...', true);\n            const data = await get(API.server);\n            serverBox.innerHTML = data.checks.map(c => metric(c.label, c.ready ? 'Ready' : c.value, c.ready)).join('');\n        }\n\n        async function loadEvent(){\n            eventBox.innerHTML = metric('Official API', 'Checking...', true);\n            const data = await get(API.events);\n            const events = asArray(data);\n            const event = events.find(e => String(e.id) === String(eventId)) || events[0] || {};\n            const eventName = val(event, ['name_en','name','event_name'], '-');\n            const raceCount = val(event, ['race_count'], raceMap.length);\n            const mappingReady = raceMap.length === 6;\n\n            eventBox.innerHTML =\n                metric('Event name', eventName, !!eventName && eventName !== '-') +\n                metric('Official rides', raceCount, Number(raceCount) === 6) +\n                metric('Race ID mapping', mappingReady ? 'Ready' : 'Missing', mappingReady);\n        }\n\n        async function loadRaces(){\n            racesBody.innerHTML = '<tr><td colspan=\"6\">Loading races...<\/td><\/tr>';\n            const data = await get(API.races + eventId);\n            const races = asArray(data);\n            const rows = raceMap.map((mapped, index) => matchingOfficialRace(index, races[index] || {}));\n\n            racesBody.innerHTML = rows.map(r => `\n                <tr>\n                    <td><strong>${esc(r.id)}<\/strong><\/td>\n                    <td>${esc(r.name)}<\/td>\n                    <td>${esc(r.date)}<\/td>\n                    <td>${esc(r.status)}<\/td>\n                    <td>${esc(r.entries)}<\/td>\n                    <td><button type=\"button\" class=\"eiev-check-test-race\" data-race=\"${esc(r.id)}\">Check<\/button><\/td>\n                <\/tr>\n            `).join('');\n\n            root.querySelectorAll('.eiev-check-test-race').forEach(btn => {\n                btn.addEventListener('click', function(){\n                    selectedRace = this.dataset.race;\n                    loadRaceDetail(selectedRace);\n                });\n            });\n        }\n\n        function findRiders(data, seen = new WeakSet()){\n            if (!data) return [];\n            if (Array.isArray(data)) {\n                return data.some(item => item && (item.rider_name || item.horse_name || item.start_no)) ? data : [];\n            }\n            if (typeof data !== 'object') return [];\n            if (seen.has(data)) return [];\n            seen.add(data);\n\n            for (const key of ['riders','results','race_results','participants','entries','start_list']) {\n                if (Array.isArray(data[key])) return data[key];\n            }\n            for (const key in data) {\n                const found = findRiders(data[key], seen);\n                if (found.length) return found;\n            }\n            return [];\n        }\n\n        function countRiderGateRows(riders){\n            return riders.reduce((sum, rider) => {\n                return sum + (Array.isArray(rider.rider_race_gates) ? rider.rider_race_gates.length : 0);\n            }, 0);\n        }\n\n        async function loadRaceDetail(raceId){\n            selectedTitle.textContent = raceId;\n            raceDetailBox.innerHTML = metric('Race Details API', 'Loading...', true);\n            noteBox.textContent = '';\n\n            try {\n                const race = await get(API.race + raceId);\n                const riders = findRiders(race);\n                const gates = Array.isArray(race.racegates) ? race.racegates : [];\n                const riderGateRows = countRiderGateRows(riders);\n                const raceName = val(race, ['name','name_en','race_name'], raceMap.find(r => String(r.id) === String(raceId))?.name || '-');\n\n                raceDetailBox.innerHTML =\n                    metric('Race Details API', 'Loaded', true) +\n                    metric('Official ride name', raceName, true) +\n                    metric('Riders returned', riders.length, riders.length > 0) +\n                    metric('Race gates returned', gates.length, gates.length > 0) +\n                    metric('Rider gate rows', riderGateRows, riderGateRows > 0);\n\n                if (!riders.length) {\n                    noteBox.textContent = 'The Race Details endpoint loaded correctly, but this race currently contains no rider rows. Try another Race ID or refresh when official results are available.';\n                } else {\n                    noteBox.textContent = 'Race details, gates, riders and rider gate rows loaded successfully.';\n                }\n            } catch(e) {\n                raceDetailBox.innerHTML = metric('Race Details API', 'Failed', false);\n                noteBox.textContent = e.message;\n            }\n        }\n\n        async function runAll(){\n            hideAlert();\n            try {\n                await loadServer();\n                await loadEvent();\n                await loadRaces();\n                await loadRaceDetail(selectedRace);\n            } catch(e) {\n                showAlert(e.message);\n            }\n        }\n\n        root.querySelector('.eiev-check-refresh').addEventListener('click', runAll);\n        root.querySelector('.eiev-check-clear').addEventListener('click', async function(){\n            try {\n                const res = await post(API.clear);\n                showAlert(res.message || 'Cache cleared.');\n                await runAll();\n            } catch(e) {\n                showAlert(e.message);\n            }\n        });\n\n        root.querySelector('.eiev-check-open-live').addEventListener('click', function(){\n            window.location.href = '#live-event-' + eventId;\n        });\n        root.querySelector('.eiev-check-open-results').addEventListener('click', function(){\n            window.location.href = '#results-' + selectedRace;\n        });\n        root.querySelector('.eiev-check-open-riders').addEventListener('click', function(){\n            window.location.href = '#riders-' + selectedRace;\n        });\n\n        runAll();\n    })();\n    <\/script>\n    \n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"pgc_sgb_lightbox_settings":"","footnotes":""},"class_list":["post-7013","page","type-page","status-publish","hentry"],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"_links":{"self":[{"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/pages\/7013","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/comments?post=7013"}],"version-history":[{"count":1,"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/pages\/7013\/revisions"}],"predecessor-version":[{"id":7014,"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/pages\/7013\/revisions\/7014"}],"wp:attachment":[{"href":"https:\/\/eievss.com\/website\/wordpress\/wp-json\/wp\/v2\/media?parent=7013"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}