2

I would like to join endpoints and return result (in Wordpress). After I get the results, I want to import with WP All Import plugin, Hotels and Locations. I'm using Traveler theme.

The API is: https://www.postman.com/filipnet-team/karpaten-webservice/collection/4gcaetc/karpaten-webservice

I made a diagramm too: enter image description here

It should be joined the following way: Countries (->CountryDetails) -> Regions -> Resorts -> Hotels (->HotelDetails)

The results must be shown in a blank page.

What I tried - The other parts are working fine, except the 6th, where I tried to join the API Endpoints - Error: No countries returned from API / There has been a critical error on this website:

// ----------------------------
// 0. API_SECRET_TOKEN API 
// ----------------------------
// Generate a long random token once and paste it here
define('API_SECRET_TOKEN', 'xxx');
add_action('init', function () {
 $api_pages = array(
 'kcountrylist-api' => array( /*CountryList*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetCountriesList</service>
 </head>
 <main></main>
 </root>'
 ),
 'kcountrydet-api' => array( /*CountryDetails*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetCountryDetails</service>
 </head>
 <main>
 <CountryID>{{CountryID}}</CountryID>
 </main>
 </root>'
 ),
 'kregionlist-api' => array( /*RegionList*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetRegionsList</service>
 </head>
 <main>
 <CountryID>{{CountryID}}</CountryID>
 </main>
 </root>'
 ),
 'kregiondet-api' => array( /*RegionDetails*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<?xml version="1.0" encoding="UTF-8"?>
 <root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetRegionDetails</service>
 </head>
 <main>
 <RegionID>{{RegionID}}</RegionID>
 </main>
 </root>'
 ),
 'kresortlist-api' => array( /*ResortList*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<?xml version="1.0" encoding="UTF-8"?>
 <root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetResortsList</service>
 </head>
 <main>
 <CountryID>{{CountryID}}</CountryID>
 <RegionID>{{RegionID}}</RegionID>
 </main>
 </root>'
 ),
 'kresortdet-api' => array( /*ResortDet*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<?xml version="1.0" encoding="UTF-8"?>
 <root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetResortDetails</service>
 </head>
 <main>
 <ResortID>{{ResortID}}</ResortID>
 </main>
 </root>'
 ),
 'khotelslist-api' => array( /*Hotels*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<?xml version="1.0" encoding="UTF-8"?>
 <root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetHotelsList</service>
 </head>
 <main>
 <!-- <ResortID>{{ResortID}}</ResortID> -->
 <RegionID>{{RegionID}}</RegionID>
 <CountryID>{{CountryID}}</CountryID>
 </main>
 </root>'
 ),
 'khoteldet-api' => array( /*Hotel Details*/
 'endpoint' => 'https://webservice.karpaten.ro/webservice/',
 'method' => 'POST',
 'headers' => array('Content-Type' => 'text/xml; charset=utf-8'),
 'body' => '<?xml version="1.0" encoding="UTF-8"?>
 <root>
 <head>
 <auth>
 <username>XML.naturatravel</username>
 <password>naturatravel</password>
 </auth>
 <service>GetHotelDetails</service>
 </head>
 <main>
 <HotelID>{{HotelID}}</HotelID>
 </main>
 </root>'
 )
 );
 if (isset($_GET['api_page']) && isset($api_pages[$_GET['api_page']])) {
 if (!isset($_GET['token']) || $_GET['token'] !== API_SECRET_TOKEN) {
 status_header(403);
 wp_die('Forbidden: Invalid token');
 }
 $config = $api_pages[$_GET['api_page']];
 $method = strtoupper($config['method']);
 $body = $config['body'];
 // ---- Handle dynamic parameters ----
 if ($method === 'POST') {
 foreach ($_GET as $key => $value) {
 if (in_array($key, ['api_page','token','format'])) continue;
 $value = sanitize_text_field($value);
 $body = str_replace('{{'.$key.'}}', $value, $body);
 }
 if (stripos($config['headers']['Content-Type'], 'json') !== false) {
 $body_arr = json_decode($body, true);
 if (isset($body_arr['root']['main'])) {
 foreach ($_GET as $key => $value) {
 if (in_array($key, ['api_page','token','format'])) continue;
 $body_arr['root']['main'][$key] = sanitize_text_field($value);
 }
 }
 $body = json_encode($body_arr);
 }
 elseif (stripos($config['headers']['Content-Type'], 'xml') !== false) {
 $body = preg_replace('/&(?![a-zA-Z#0-9]+;)/', '&amp;', $body);
 $xml = new DOMDocument();
 $xml->loadXML($body);
 $main = $xml->getElementsByTagName('main')->item(0);
 foreach ($_GET as $key => $value) {
 if (in_array($key, ['api_page','token','format'])) continue;
 $found = $xml->getElementsByTagName($key)->item(0);
 if (!$found) {
 $el = $xml->createElement($key, htmlspecialchars($value, ENT_XML1 | ENT_COMPAT, 'UTF-8'));
 $main->appendChild($el);
 } else {
 $found->nodeValue = htmlspecialchars($value, ENT_XML1 | ENT_COMPAT, 'UTF-8');
 }
 }
 $body = $xml->saveXML();
 }
 }
 // ---- Build request ----
 $args = array(
 'method' => $method,
 'headers' => $config['headers']
 );
 if ($method === 'POST') {
 $args['body'] = $body;
 $url = $config['endpoint'];
 } else {
 $params = $_GET;
 unset($params['api_page'], $params['token'], $params['format']);
 $url = add_query_arg($params, $config['endpoint']);
 }
 // ---- Send ----
 $response = wp_remote_request($url, $args);
 if (is_wp_error($response)) {
 wp_die($response->get_error_message());
 }
 $body = wp_remote_retrieve_body($response);
 // ---- Clean ----
 $body = html_entity_decode($body, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8');
 $body = preg_replace('/>\s+</', '><', $body);
 $body = preg_replace('/<!--.*?-->/s', '', $body);
 //$body = preg_replace('/<!\[CDATA\[(.*?)\]\]>/', '1ドル', $body);
 $body = preg_replace('/&(?![a-zA-Z#0-9]+;)/', '&amp;', $body);
 // ---- Output ----
 $format = isset($_GET['format']) ? strtolower($_GET['format']) : 'json';
 if ($format === 'xml') {
 if (stripos($body, '<?xml') === 0) {
 header('Content-Type: application/xml; charset=utf-8');
 } else {
 header('Content-Type: application/json; charset=utf-8');
 }
 echo $body;
 exit;
 }
 // Else: convert to JSON
 $data = null;
 if (stripos($body, '<?xml') === 0 || stripos($body, '<root') !== false) {
 libxml_use_internal_errors(true);
 $xml = simplexml_load_string($body, 'SimpleXMLElement', LIBXML_NOCDATA);
 if ($xml !== false) {
 $data = simplexml_to_array_keep_html($xml,false);
 }
 }
 if ($data === null) {
 $json = json_decode($body, true);
 if (json_last_error() === JSON_ERROR_NONE) {
 $data = $json;
 } else {
 $data = ['raw' => $body];
 }
 }
 header('Content-Type: application/json; charset=utf-8');
 echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
 exit;
 }
});
function simplexml_to_array_keep_html($xml, $encode_html = true)
{
 $arr = [];
 foreach ($xml->children() as $key => $child) {
 if ($child->count() > 0) {
 $value = simplexml_to_array_keep_html($child, $encode_html);
 } else {
 $raw = trim($child->asXML());
 $inner = preg_replace('/^<[^>]+>|<\/[^>]+>$/', '', $raw);
 // Encode HTML if requested
 if ($encode_html) {
 $inner = htmlentities($inner, ENT_QUOTES | ENT_HTML5, 'UTF-8');
 }
 $value = $inner;
 }
 if (isset($arr[$key])) {
 if (!is_array($arr[$key]) || !isset($arr[$key][0])) {
 $arr[$key] = [$arr[$key]];
 }
 $arr[$key][] = $value;
 } else {
 $arr[$key] = $value;
 }
 }
 return $arr;
}
// ----------------------------
// 5. Examples
// ----------------------------
/*1. https://test.naturatravel.ro/?api_page=kcountrylist-api&token=a5ef2d6a717f47ddaf78d98a04e28e20*/
/*2. https://test.naturatravel.ro/?api_page=kcountrydet-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&CountryID=187*/
/*3. https://test.naturatravel.ro/?api_page=kregionlist-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&CountryID=215*/
/*4. https://test.naturatravel.ro/?api_page=kregiondet-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&RegionID=325*/
/*5. https://test.naturatravel.ro/?api_page=kresortlist-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&CountryID=215&RegionID=325*/
/*6. https://test.naturatravel.ro/?api_page=kresortdet-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&ResortID=2133*/
/*7. https://test.naturatravel.ro/?api_page=khotelslist-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&RegionID=75&CountryID=7 */
/*8. https://test.naturatravel.ro/?api_page=khoteldet-api&token=a5ef2d6a717f47ddaf78d98a04e28e20&HotelID=29274 */
// ----------------------------
// Preserve HTML in post_content
// ----------------------------
add_filter('wpgetapi_api_to_posts_before_insert_post', function($post_data, $item, $map) {
 // Apply only to st_location posts
 if ($post_data['post_type'] === 'st_location') {
 foreach($map as $field_map) {
 if($field_map['post_field'] === 'post_content') {
 $api_field = $field_map['api_field'];
 if(isset($item[$api_field])) {
 // Insert raw HTML from API
 $post_data['post_content'] = $item[$api_field];
 }
 }
 }
 }
 return $post_data;
}, 10, 3);
// ----------------------------
// 6. Custom Combined Hotels API
// ----------------------------
// ----------------------------
// 0. API_SECRET_TOKEN
// ----------------------------
//define('API_SECRET_TOKEN', 'xxx');
// ----------------------------
// Helper: fetch JSON from URL
// ----------------------------
function fetch_json($url) {
 $res = wp_remote_get($url);
 if (is_wp_error($res)) return null;
 $body = wp_remote_retrieve_body($res);
 $data = json_decode($body, true);
 return $data ?: null;
}
// ----------------------------
// Full Hotels JSON
// ----------------------------
add_action('init', function() {
 if(isset($_GET['api_page']) && $_GET['api_page'] === 'kfull-hotels-json') {
 if(!isset($_GET['token']) || $_GET['token'] !== API_SECRET_TOKEN){
 status_header(403);
 wp_die('Forbidden: Invalid token');
 }
 $endpoint = 'https://test.naturatravel.ro/';
 $token = $_GET['token'];
 $final = [];
 // 1️⃣ Countries
 $countries_data = fetch_json("$endpoint?api_page=kcountrylist-api&token=$token");
 if(!$countries_data || !isset($countries_data['GetCountriesList']['CountriesList']['Country'])) {
 wp_die('No countries returned from API');
 }
 $countries = (array)$countries_data['GetCountriesList']['CountriesList']['Country'];
 foreach($countries as $country) {
 $c_id = $country['ID'];
 $c_name = $country['Name'];
 $c_code = $country['CodIso2'] ?? '';
 // 2️⃣ CountryDetails
 $c_det_data = fetch_json("$endpoint?api_page=kcountrydet-api&token=$token&CountryID=$c_id");
 $c_desc = $c_det_data['GetCountryDetails']['Country']['Description'] ?? '';
 // 3️⃣ Regions list
 $regions_data = fetch_json("$endpoint?api_page=kregionlist-api&token=$token&CountryID=$c_id");
 $regions_arr = [];
 if(isset($regions_data['GetRegionsList']['RegionsList']['Region'])) {
 $regions = (array)$regions_data['GetRegionsList']['RegionsList']['Region'];
 foreach($regions as $region) {
 $r_id = $region['ID'];
 $r_name = $region['Name'];
 // 4️⃣ Resort list
 $resorts_data = fetch_json("$endpoint?api_page=kresortlist-api&token=$token&CountryID=$c_id&RegionID=$r_id");
 $resorts_arr = [];
 if(isset($resorts_data['GetResortsList']['ResortsList']['Resort'])) {
 $resorts = (array)$resorts_data['GetResortsList']['ResortsList']['Resort'];
 foreach($resorts as $resort) {
 $res_id = $resort['ID'];
 $res_name = $resort['Name'];
 // 5️⃣ Hotels list
 $hotels_data = fetch_json("$endpoint?api_page=khotelslist-api&token=$token&CountryID=$c_id&RegionID=$r_id");
 $hotels_arr = [];
 if(isset($hotels_data['GetHotelsList']['HotelsList']['Hotel'])) {
 $hotels = (array)$hotels_data['GetHotelsList']['HotelsList']['Hotel'];
 foreach($hotels as $hotel) {
 $h_id = $hotel['ID'];
 $h_name = $hotel['Name'];
 $h_stars = $hotel['Stars'] ?? '';
 // 6️⃣ HotelDetails
 $h_det_data = fetch_json("$endpoint?api_page=khoteldet-api&token=$token&HotelID=$h_id");
 $h_desc = $h_det_data['GetHotelDetails']['Hotel']['Description'] ?? '';
 $h_policies = $h_det_data['GetHotelDetails']['Hotel']['Policies'] ?? '';
 $hotels_arr[] = [
 'hotel_id' => $h_id,
 'hotel_name' => $h_name,
 'stars' => $h_stars,
 'description' => $h_desc,
 'policies' => $h_policies
 ];
 }
 }
 $resorts_arr[] = [
 'resort_id' => $res_id,
 'resort_name' => $res_name,
 'hotels' => $hotels_arr
 ];
 }
 }
 $regions_arr[] = [
 'region_id' => $r_id,
 'region_name' => $r_name,
 'resorts' => $resorts_arr
 ];
 }
 }
 $final[] = [
 'country_id' => $c_id,
 'country_name' => $c_name,
 'country_code' => $c_code,
 'description' => $c_desc,
 'regions' => $regions_arr
 ];
 }
 header('Content-Type: application/json; charset=utf-8');
 echo json_encode($final, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
 exit;
 }
});
Markus Zeller
9,2432 gold badges34 silver badges39 bronze badges
asked Oct 8, 2025 at 7:58
7
  • 4
    You probably shouldnt share your secret along with your domain here... Commented Oct 8, 2025 at 8:13
  • I will change it , this is a temporary code and test subdomain. Thanks for the warning. 👍 Commented Oct 8, 2025 at 8:14
  • 4
    $countries_data = fetch_json(...) - so what does $countries_data actually contain after this line? Commented Oct 8, 2025 at 9:19
  • @C3roe ` $countries_data = fetch_json("$endpoint?api_page=kcountrylist-api&token=$token"); echo 'Countries-data'.$countries_data;` returns: 'Countries-data', so it's empty Commented Oct 9, 2025 at 6:48
  • 2
    Go check what the response body contained, before the attempt to decode it as JSON. Commented Oct 9, 2025 at 7:08

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.