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:

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', 'a5ef2d6a717f47ddaf78d98a04e28e20');
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]+;)/', '&', $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]+;)/', '&', $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', 'a5ef2d6a717f47ddaf78d98a04e28e20');
// ----------------------------
// 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;
}
});