/**
* Replace your existing nadcab_get_hire_pages_with_seo() body with this implementation.
* Keeps caching, ACF, featured image, etc. — but reliably extracts Rank Math meta & JSON-LD.
*/
function nadcab_get_hire_pages_with_seo() {
// ✅ Unique Hire Page IDs (same as you had)
$include_ids = array_unique([
29072, 22744, 29652, 29276, 29415, 29602, 29430, 27204, 29285, 28931,
29211, 28864, 28859, 28593, 28952, 29121, 28529, 28158, 28457, 28355,
28129, 27816, 27028, 28771, 28650, 27372, 27119, 27659
]);
// Cache key
$cache_key = 'nadcab_hire_pages_api_cache';
$cached_data = get_transient($cache_key);
if ($cached_data !== false) {
return rest_ensure_response($cached_data);
}
// Query pages
$pages = get_posts([
'post_type' => ['page', 'hire', 'services'],
'post__in' => $include_ids,
'posts_per_page' => count($include_ids),
'orderby' => 'post__in',
'order' => 'ASC',
'post_status' => 'publish',
'suppress_filters' => false,
]);
if (empty($pages)) {
return rest_ensure_response(['message' => 'No selected hire pages found']);
}
$data = [];
foreach ($pages as $page) {
$page_id = $page->ID;
// Basic fields
$title = get_the_title($page_id);
$slug = sanitize_title($page->post_name);
$date = get_the_date('Y-m-d H:i:s', $page_id);
$link = esc_url(get_permalink($page_id));
$excerpt = wp_trim_words(wp_strip_all_tags($page->post_content), 50);
$content = apply_filters('the_content', $page->post_content);
// Featured image
$thumb_url = get_the_post_thumbnail_url($page_id, 'full');
$thumb_alt = get_post_meta(get_post_thumbnail_id($page_id), '_wp_attachment_image_alt', true);
// ACF fields (expanded images)
$acf_fields = function_exists('get_fields') ? get_fields($page_id) : [];
$acf_fields = nadcab_expand_acf_images_recursive($acf_fields);
$acf_fields = nadcab_clean_acf_text($acf_fields);
// Prepare SEO container
$seo = [
'title' => get_post_meta($page_id, 'rank_math_title', true) ?: $title,
'description' => get_post_meta($page_id, 'rank_math_description', true) ?: $excerpt,
'focus' => get_post_meta($page_id, 'rank_math_focus_keyword', true),
'canonical' => get_post_meta($page_id, 'rank_math_canonical_url', true) ?: $link,
// fill in below: meta_tags, og, twitter, schema
'meta_tags' => [],
'og' => [],
'twitter' => [],
'schema' => [],
];
// -------------------------
// Extract Rank Math Meta (render meta HTML in page context and parse)
// -------------------------
if (defined('RANK_MATH_VERSION') && function_exists('rank_math')) {
global $wp_query;
$old_query = $wp_query;
// Temporarily set a query for this single page so Rank Math outputs correct meta
$wp_query = new WP_Query(['p' => $page_id, 'post_type' => $page->post_type]);
// Capture meta tags (OG, Twitter) by calling Rank Math frontend methods
ob_start();
try {
if (isset(rank_math()->frontend) && method_exists(rank_math()->frontend, 'get_meta_tags')) {
echo rank_math()->frontend->get_meta_tags();
} elseif (isset(rank_math()->frontend) && method_exists(rank_math()->frontend, 'head')) {
echo rank_math()->frontend->head();
} else {
// fallback to standard wp_head() if Rank Math hooks into it
do_action('wp_head');
}
$meta_html = ob_get_clean();
} catch (Throwable $e) {
ob_end_clean();
$meta_html = '';
}
// parse meta tags like and
if ($meta_html && preg_match_all('/]+>/i', $meta_html, $matches)) {
foreach ($matches[0] as $tag) {
// property="og:..."
if (preg_match('/property=["\']([^"\']+)["\'].*content=["\']([^"\']+)["\']/', $tag, $m)) {
$prop = $m[1];
$cont = html_entity_decode($m[2]);
// OG
if (strpos($prop, 'og:') === 0) {
$og_key = substr($prop, 3);
$seo['og'][$og_key] = $cont;
$seo['meta_tags']["og:$og_key"] = $cont;
}
}
// name="twitter:..."
elseif (preg_match('/name=["\']([^"\']+)["\'].*content=["\']([^"\']+)["\']/', $tag, $m2)) {
$name = $m2[1];
$cont = html_entity_decode($m2[2]);
if (strpos($name, 'twitter:') === 0) {
$tw_key = substr($name, 8);
$seo['twitter'][$tw_key] = $cont;
$seo['meta_tags']["twitter:$tw_key"] = $cont;
} else {
// generic meta name (e.g. description)
$seo['meta_tags'][$name] = $cont;
}
} else {
// also capture itemprop or other meta formats (content attr)
if (preg_match('/content=["\']([^"\']+)["\']/', $tag, $m3) && preg_match('/(property|name|itemprop)=["\']([^"\']+)["\']/', $tag, $m4)) {
$propname = $m4[2];
$cont = html_entity_decode($m3[1]);
$seo['meta_tags'][$propname] = $cont;
}
}
}
}
// Capture Rank Math JSON-LD schema output
ob_start();
try {
if (function_exists('rank_math_the_json_ld')) {
rank_math_the_json_ld();
} elseif (isset(rank_math()->json) && method_exists(rank_math()->json, 'get_schemas')) {
// some versions have a get_schemas method
$schemas = rank_math()->json->get_schemas($page_id);
if (!empty($schemas)) {
// ensure array
$seo['schema'] = $schemas;
}
}
$schema_html = ob_get_clean();
} catch (Throwable $e) {
ob_end_clean();
$schema_html = '';
}
// parse
if ($schema_html && preg_match_all('/