Home / Admin / Cortex Schema API
Duplicate Snippet

Embed Snippet on Your Site

Cortex Schema API

<10
Code Preview
php
<?php
/**
 * Cortex Schema API v2.2 - Complete Schema Audit with Global Detection
 * 
 * Elite-level schema auditing for WordPress.
 * Now includes global/site-wide schemas and source identification.
 * 
 * v2.2 Changes:
 * - Added global schema detection from RankMath wp_options
 * - Each schema now has 'source' field: 'local', 'global', or 'auto'
 * - New /schema/global endpoint to view site-wide schema settings
 * - Enhanced /schema/all includes global schemas applied to pages
 * - Live schema extraction now identifies source
 * 
 * Installation: Add as WPCode snippet (PHP, Run Everywhere)
 * 
 * @version 2.2
 * @requires WordPress 5.0+
 * @requires RankMath SEO
 */
// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}
/**
 * Register REST API Routes
 */
add_action('rest_api_init', function () {
    $namespace = 'cortex/v1';
    
    // ===========================================
    // SCHEMA AUDIT ENDPOINTS
    // ===========================================
    
    // API info and supported types
    register_rest_route($namespace, '/schema/types', [
        'methods' => 'GET',
        'callback' => 'cortex_get_schema_types',
        'permission_callback' => 'cortex_api_permissions',
    ]);
    
    // NEW: Get global/site-wide schema settings
    register_rest_route($namespace, '/schema/global', [
        'methods' => 'GET',
        'callback' => 'cortex_get_global_schemas',
        'permission_callback' => 'cortex_api_permissions',
    ]);
    
    // Get ALL schemas (pages + posts) - MCP COMPATIBLE
    register_rest_route($namespace, '/schema/all', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_schemas',
        'permission_callback' => 'cortex_api_permissions',
    ]);
    
    // Get all schemas filtered by type - MCP COMPATIBLE
    register_rest_route($namespace, '/schema/all/(?P<type>page|post)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_schemas',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'type' => ['required' => true, 'type' => 'string'],
        ],
    ]);
    
    // Get single schema by post ID
    register_rest_route($namespace, '/schema/(?P<id>\d+)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_schema',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'id' => ['required' => true, 'type' => 'integer'],
        ],
    ]);
    
    // Get live rendered schema from page
    register_rest_route($namespace, '/schema/live/(?P<id>\d+)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_live_schema',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'id' => ['required' => true, 'type' => 'integer'],
        ],
    ]);
    
    // ===========================================
    // SEO META ENDPOINTS
    // ===========================================
    
    // Get SEO meta for single post
    register_rest_route($namespace, '/seo-meta/(?P<id>\d+)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_seo_meta',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'id' => ['required' => true, 'type' => 'integer'],
        ],
    ]);
    
    // Get all pages with SEO meta
    register_rest_route($namespace, '/seo-meta/page', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_pages_seo',
        'permission_callback' => 'cortex_api_permissions',
    ]);
    
    // Get all posts with SEO meta (paginated via path)
    register_rest_route($namespace, '/seo-meta/post', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_posts_seo',
        'permission_callback' => 'cortex_api_permissions',
    ]);
    
    // Get posts with pagination via path - MCP COMPATIBLE
    register_rest_route($namespace, '/seo-meta/post/(?P<per_page>\d+)/(?P<page_num>\d+)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_posts_seo',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'per_page' => ['required' => true, 'type' => 'integer'],
            'page_num' => ['required' => true, 'type' => 'integer'],
        ],
    ]);
    
    // ===========================================
    // FEATURED IMAGE ENDPOINTS
    // ===========================================
    
    // Get featured image for single post
    register_rest_route($namespace, '/featured-image/(?P<id>\d+)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_featured_image',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'id' => ['required' => true, 'type' => 'integer'],
        ],
    ]);
    
    // Get all featured images - MCP COMPATIBLE
    register_rest_route($namespace, '/featured-image/all', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_featured_images',
        'permission_callback' => 'cortex_api_permissions',
    ]);
    
    // Get all featured images filtered by type - MCP COMPATIBLE
    register_rest_route($namespace, '/featured-image/all/(?P<type>page|post)', [
        'methods' => 'GET',
        'callback' => 'cortex_get_all_featured_images',
        'permission_callback' => 'cortex_api_permissions',
        'args' => [
            'type' => ['required' => true, 'type' => 'string'],
        ],
    ]);
});
function cortex_api_permissions() {
    return current_user_can('edit_posts');
}
// ===========================================
// HELPER FUNCTION - Extract LOCAL schemas from post meta
// ===========================================
function cortex_extract_local_schemas($post_id) {
    $schemas = [];
    
    // Check rank_math_schema_Service
    $schema_service = get_post_meta($post_id, 'rank_math_schema_Service', true);
    if (!empty($schema_service)) {
        $schema_service['_source'] = 'local';
        $schemas['Service'] = $schema_service;
    }
    
    // Check rank_math_schema_Article
    $schema_article = get_post_meta($post_id, 'rank_math_schema_Article', true);
    if (!empty($schema_article)) {
        $schema_article['_source'] = 'local';
        $schemas['Article'] = $schema_article;
    }
    
    // Check rank_math_schema_LocalBusiness
    $schema_local = get_post_meta($post_id, 'rank_math_schema_LocalBusiness', true);
    if (!empty($schema_local)) {
        $schema_local['_source'] = 'local';
        $schemas['LocalBusiness'] = $schema_local;
    }
    
    // Check rank_math_schema_JobPosting
    $schema_job = get_post_meta($post_id, 'rank_math_schema_JobPosting', true);
    if (!empty($schema_job)) {
        $schema_job['_source'] = 'local';
        $schemas['JobPosting'] = $schema_job;
    }
    
    // Check rank_math_schema_FAQPage
    $schema_faq = get_post_meta($post_id, 'rank_math_schema_FAQPage', true);
    if (!empty($schema_faq)) {
        $schema_faq['_source'] = 'local';
        $schemas['FAQPage'] = $schema_faq;
    }
    
    // Check rank_math_schema_HowTo
    $schema_howto = get_post_meta($post_id, 'rank_math_schema_HowTo', true);
    if (!empty($schema_howto)) {
        $schema_howto['_source'] = 'local';
        $schemas['HowTo'] = $schema_howto;
    }
    
    // Check rank_math_schema_Person
    $schema_person = get_post_meta($post_id, 'rank_math_schema_Person', true);
    if (!empty($schema_person)) {
        $schema_person['_source'] = 'local';
        $schemas['Person'] = $schema_person;
    }
    
    // Check rank_math_schema_VideoObject
    $schema_video = get_post_meta($post_id, 'rank_math_schema_VideoObject', true);
    if (!empty($schema_video)) {
        $schema_video['_source'] = 'local';
        $schemas['VideoObject'] = $schema_video;
    }
    
    // Check rank_math_schema_CreativeWork
    $schema_creative = get_post_meta($post_id, 'rank_math_schema_CreativeWork', true);
    if (!empty($schema_creative)) {
        $schema_creative['_source'] = 'local';
        $schemas['CreativeWork'] = $schema_creative;
    }
    
    // Check rank_math_schema (array of schemas - RankMath's primary storage)
    $schema_data = get_post_meta($post_id, 'rank_math_schema', true);
    if (!empty($schema_data) && is_array($schema_data)) {
        foreach ($schema_data as $key => $schema) {
            if (isset($schema['@type'])) {
                $type = is_array($schema['@type']) ? implode('/', $schema['@type']) : $schema['@type'];
                // Don't overwrite if already found in specific meta
                if (!isset($schemas[$type])) {
                    $schema['_source'] = 'local';
                    $schemas[$type] = $schema;
                }
            }
        }
    }
    
    return $schemas;
}
// ===========================================
// HELPER FUNCTION - Get GLOBAL schemas from wp_options
// ===========================================
function cortex_get_global_schema_settings() {
    $global_schemas = [
        'local_business' => null,
        'organization' => null,
        'website' => null,
        'person' => null,
        'settings' => [],
    ];
    
    // RankMath stores settings in rank_math-options-titles
    $titles_options = get_option('rank_math-options-titles', []);
    
    // RankMath general options
    $general_options = get_option('rank_math-options-general', []);
    
    // Check for Local Business / Organization settings
    if (!empty($titles_options)) {
        // Local Business settings
        $local_business_fields = [
            'local_business_type',
            'local_seo_name',
            'local_business_name', 
            'local_address',
            'local_address_format',
            'local_phone',
            'local_email',
            'local_url',
            'local_logo',
            'local_geo',
            'local_opening_hours',
            'local_price_range',
            'local_currencies_accepted',
            'local_payment_accepted',
            'local_area_served',
        ];
        
        $local_data = [];
        foreach ($local_business_fields as $field) {
            if (isset($titles_options[$field])) {
                $local_data[$field] = $titles_options[$field];
            }
        }
        
        if (!empty($local_data)) {
            $global_schemas['local_business'] = $local_data;
        }
        
        // Organization settings
        $org_fields = [
            'org_name',
            'org_logo',
            'org_url',
            'org_legal_name',
            'org_founding_date',
            'org_contact_type',
            'org_phone',
            'org_email',
        ];
        
        $org_data = [];
        foreach ($org_fields as $field) {
            if (isset($titles_options[$field])) {
                $org_data[$field] = $titles_options[$field];
            }
        }
        
        if (!empty($org_data)) {
            $global_schemas['organization'] = $org_data;
        }
        
        // Person/Knowledgegraph settings
        if (isset($titles_options['knowledgegraph_type'])) {
            $global_schemas['settings']['knowledgegraph_type'] = $titles_options['knowledgegraph_type'];
        }
        
        // Social profiles (used in Organization/Person schema)
        $social_fields = [
            'social_url_facebook',
            'social_url_twitter', 
            'social_url_linkedin',
            'social_url_instagram',
            'social_url_youtube',
            'social_url_pinterest',
            'social_url_yelp',
            'social_url_google_places',
        ];
        
        $social_data = [];
        foreach ($social_fields as $field) {
            if (!empty($titles_options[$field])) {
                $social_data[$field] = $titles_options[$field];
            }
        }
        
        if (!empty($social_data)) {
            $global_schemas['social_profiles'] = $social_data;
        }
        
        // Schema settings per post type
        $schema_settings = [];
        foreach ($titles_options as $key => $value) {
            if (strpos($key, 'pt_') === 0 && strpos($key, '_schema') !== false) {
                $schema_settings[$key] = $value;
            }
        }
        
        if (!empty($schema_settings)) {
            $global_schemas['post_type_schemas'] = $schema_settings;
        }
    }
    
    // Check for JSON-LD code in RankMath options (sometimes stored as raw JSON)
    if (!empty($titles_options['local_seo']) && is_array($titles_options['local_seo'])) {
        $global_schemas['local_seo_raw'] = $titles_options['local_seo'];
    }
    
    // Homepage settings
    if (!empty($titles_options['homepage_custom_schema'])) {
        $global_schemas['homepage_custom_schema'] = $titles_options['homepage_custom_schema'];
    }
    
    return $global_schemas;
}
// ===========================================
// HELPER - Determine which global schemas apply to a page
// ===========================================
function cortex_get_applicable_global_schemas($post_id, $post_type = 'page') {
    $applicable = [];
    $global = cortex_get_global_schema_settings();
    $post = get_post($post_id);
    $is_homepage = (int) get_option('page_on_front') === (int) $post_id;
    
    // Homepage gets LocalBusiness/Organization
    if ($is_homepage) {
        if (!empty($global['local_business'])) {
            $applicable['LocalBusiness'] = [
                '_source' => 'global',
                '_location' => 'RankMath Titles & Meta → Local SEO',
                'settings' => $global['local_business'],
            ];
        }
        
        if (!empty($global['organization'])) {
            $applicable['Organization'] = [
                '_source' => 'global',
                '_location' => 'RankMath Titles & Meta → Local SEO',
                'settings' => $global['organization'],
            ];
        }
        
        if (!empty($global['social_profiles'])) {
            $applicable['_social_profiles'] = [
                '_source' => 'global',
                'profiles' => $global['social_profiles'],
            ];
        }
    }
    
    // All pages get auto-generated WebSite and WebPage schemas
    $applicable['WebSite'] = [
        '_source' => 'auto',
        '_note' => 'Auto-generated by RankMath for all pages',
    ];
    
    $applicable['WebPage'] = [
        '_source' => 'auto', 
        '_note' => 'Auto-generated by RankMath for all pages',
    ];
    
    // Posts get BlogPosting/Article auto-schema based on settings
    if ($post_type === 'post') {
        if (!empty($global['post_type_schemas']['pt_post_schema_type'])) {
            $applicable['_default_post_schema'] = [
                '_source' => 'global',
                '_location' => 'RankMath Titles & Meta → Posts',
                'type' => $global['post_type_schemas']['pt_post_schema_type'],
            ];
        }
    }
    
    return $applicable;
}
// ===========================================
// SCHEMA AUDIT FUNCTIONS
// ===========================================
function cortex_get_schema_types($request) {
    return rest_ensure_response([
        'success' => true,
        'api_version' => '2.2',
        'api_mode' => 'audit_only',
        'note' => 'This API is read-only. Generate JSON-LD for manual paste into RankMath.',
        'mcp_compatible' => true,
        'schema_sources' => [
            'local' => 'Page-specific schema added directly in RankMath Schema tab',
            'global' => 'Site-wide schema from RankMath Titles & Meta settings',
            'auto' => 'Auto-generated by RankMath (WebSite, WebPage, etc.)',
        ],
        'supported_templates' => [
            'LocalBusiness' => 'Homepage - main business entity',
            'Service' => 'Service pages',
            'JobPosting' => 'Careers/Jobs pages',
            'BlogPosting' => 'Blog posts',
            'FAQPage' => 'FAQ pages',
            'HowTo' => 'Tutorial/Guide pages',
            'Person' => 'Founder/Team pages',
            'VideoObject' => 'Video content',
            'CreativeWork' => 'Creative works',
        ],
        'local_business_types' => [
            'Electrician', 'Plumber', 'HVACBusiness', 'RoofingContractor',
            'GeneralContractor', 'HomeAndConstructionBusiness', 'LocksmithService',
            'MovingCompany', 'PestControlService',
        ],
        'endpoints' => [
            'GET /cortex/v1/schema/types' => 'API info + supported types',
            'GET /cortex/v1/schema/global' => 'NEW: Site-wide schema settings',
            'GET /cortex/v1/schema/all' => 'All schemas from pages + posts (with source)',
            'GET /cortex/v1/schema/all/page' => 'All schemas from pages only',
            'GET /cortex/v1/schema/all/post' => 'All schemas from posts only',
            'GET /cortex/v1/schema/{id}' => 'Schema for single post',
            'GET /cortex/v1/schema/live/{id}' => 'Rendered JSON-LD from page (with source detection)',
            'GET /cortex/v1/seo-meta/{id}' => 'SEO meta for single post',
            'GET /cortex/v1/seo-meta/page' => 'All pages with SEO meta',
            'GET /cortex/v1/seo-meta/post' => 'All posts with SEO meta (first 50)',
            'GET /cortex/v1/seo-meta/post/{per_page}/{page}' => 'Posts with pagination',
            'GET /cortex/v1/featured-image/{id}' => 'Featured image for post',
            'GET /cortex/v1/featured-image/all' => 'All featured images',
            'GET /cortex/v1/featured-image/all/page' => 'Featured images for pages',
            'GET /cortex/v1/featured-image/all/post' => 'Featured images for posts',
        ],
    ]);
}
function cortex_get_global_schemas($request) {
    $global = cortex_get_global_schema_settings();
    $homepage_id = get_option('page_on_front');
    $homepage = $homepage_id ? get_post($homepage_id) : null;
    
    return rest_ensure_response([
        'success' => true,
        'api_version' => '2.2',
        'note' => 'These are site-wide schemas configured in RankMath settings',
        'homepage' => [
            'id' => $homepage_id ?: null,
            'title' => $homepage ? $homepage->post_title : null,
            'url' => $homepage_id ? get_permalink($homepage_id) : home_url('/'),
        ],
        'global_schemas' => $global,
        'schema_locations' => [
            'local_business' => 'RankMath → Titles & Meta → Local SEO',
            'organization' => 'RankMath → Titles & Meta → Local SEO',
            'social_profiles' => 'RankMath → Titles & Meta → Social Meta',
            'post_type_schemas' => 'RankMath → Titles & Meta → [Post Type]',
        ],
    ]);
}
function cortex_get_all_schemas($request) {
    $post_type = $request->get_param('type');
    $post_types = empty($post_type) ? ['page', 'post'] : [$post_type];
    
    $posts = get_posts([
        'post_type' => $post_types,
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'orderby' => 'title',
        'order' => 'ASC',
    ]);
    
    $results = [];
    $with_schema = 0;
    $without_local_schema = 0;
    $schema_type_counts = [];
    $source_counts = ['local' => 0, 'global' => 0, 'auto' => 0];
    $missing_local_schema = [];
    
    $homepage_id = (int) get_option('page_on_front');
    
    foreach ($posts as $post) {
        $local_schemas = cortex_extract_local_schemas($post->ID);
        $global_schemas = cortex_get_applicable_global_schemas($post->ID, $post->post_type);
        $is_homepage = $post->ID === $homepage_id;
        
        // Combine schemas
        $all_schemas = [];
        
        // Add local schemas first
        foreach ($local_schemas as $type => $schema) {
            $all_schemas[$type] = $schema;
            $source_counts['local']++;
        }
        
        // Add global schemas (don't overwrite local)
        foreach ($global_schemas as $type => $schema) {
            if (!isset($all_schemas[$type]) && strpos($type, '_') !== 0) {
                $all_schemas[$type] = $schema;
                $source = isset($schema['_source']) ? $schema['_source'] : 'global';
                $source_counts[$source]++;
            }
        }
        
        $has_local_schema = !empty($local_schemas);
        $has_any_schema = !empty($all_schemas);
        
        if ($has_local_schema) {
            $with_schema++;
            foreach (array_keys($local_schemas) as $type) {
                $schema_type_counts[$type] = isset($schema_type_counts[$type]) ? $schema_type_counts[$type] + 1 : 1;
            }
        } else {
            $without_local_schema++;
            $missing_local_schema[] = [
                'id' => $post->ID,
                'title' => $post->post_title,
                'url' => get_permalink($post->ID),
                'post_type' => $post->post_type,
                'is_homepage' => $is_homepage,
                'has_global_schema' => !empty(array_filter($global_schemas, function($s) {
                    return isset($s['_source']) && $s['_source'] === 'global';
                })),
            ];
        }
        
        $results[] = [
            'id' => $post->ID,
            'post_type' => $post->post_type,
            'title' => $post->post_title,
            'url' => get_permalink($post->ID),
            'is_homepage' => $is_homepage,
            'has_local_schema' => $has_local_schema,
            'local_schema_types' => array_keys($local_schemas),
            'local_schemas' => $local_schemas,
            'global_schemas_applied' => $global_schemas,
            'all_schema_types' => array_keys($all_schemas),
        ];
    }
    
    return rest_ensure_response([
        'success' => true,
        'api_version' => '2.2',
        'filter' => empty($post_type) ? 'all' : $post_type,
        'summary' => [
            'total' => count($results),
            'with_local_schema' => $with_schema,
            'without_local_schema' => $without_local_schema,
            'local_schema_type_counts' => $schema_type_counts,
            'source_counts' => $source_counts,
        ],
        'missing_local_schema' => $missing_local_schema,
        'results' => $results,
        'note' => 'Each schema now includes _source field: local, global, or auto',
    ]);
}
function cortex_get_schema($request) {
    $post_id = $request->get_param('id');
    $post = get_post($post_id);
    
    if (!$post) {
        return new WP_Error('not_found', 'Post not found', ['status' => 404]);
    }
    
    $local_schemas = cortex_extract_local_schemas($post_id);
    $global_schemas = cortex_get_applicable_global_schemas($post_id, $post->post_type);
    $homepage_id = (int) get_option('page_on_front');
    
    // Also get raw meta for debugging
    $raw_meta = [];
    $schema_keys = [
        'rank_math_schema',
        'rank_math_schema_Service',
        'rank_math_schema_Article',
        'rank_math_schema_LocalBusiness',
        'rank_math_schema_JobPosting',
        'rank_math_schema_FAQPage',
        'rank_math_schema_HowTo',
        'rank_math_schema_Person',
        'rank_math_schema_VideoObject',
        'rank_math_schema_CreativeWork',
    ];
    
    foreach ($schema_keys as $key) {
        $value = get_post_meta($post_id, $key, true);
        if (!empty($value)) {
            $raw_meta[$key] = $value;
        }
    }
    
    return rest_ensure_response([
        'success' => true,
        'api_version' => '2.2',
        'post_id' => $post_id,
        'post_type' => $post->post_type,
        'post_title' => $post->post_title,
        'post_url' => get_permalink($post_id),
        'is_homepage' => $post_id === $homepage_id,
        'local_schemas' => $local_schemas,
        'global_schemas_applied' => $global_schemas,
        'has_local_schema' => !empty($local_schemas),
        'local_schema_types' => array_keys($local_schemas),
        'raw_meta' => $raw_meta,
        'test_url' => 'https://search.google.com/test/rich-results?url=' . urlencode(get_permalink($post_id)),
    ]);
}
function cortex_get_live_schema($request) {
    $post_id = $request->get_param('id');
    $post = get_post($post_id);
    
    if (!$post) {
        return new WP_Error('not_found', 'Post not found', ['status' => 404]);
    }
    
    $url = get_permalink($post_id);
    $response = wp_remote_get($url, ['timeout' => 15, 'sslverify' => false]);
    
    if (is_wp_error($response)) {
        return new WP_Error('fetch_failed', 'Could not fetch page: ' . $response->get_error_message(), ['status' => 500]);
    }
    
    $body = wp_remote_retrieve_body($response);
    $schemas = [];
    $schema_sources = [];
    
    // Get local schemas for comparison
    $local_schemas = cortex_extract_local_schemas($post_id);
    $local_types = array_keys($local_schemas);
    
    // Auto-generated schema types (by RankMath)
    $auto_types = ['WebSite', 'WebPage', 'BreadcrumbList', 'ImageObject', 'SearchAction'];
    
    // Global schema types (applied site-wide)
    $global_types = ['Organization', 'LocalBusiness', 'Electrician', 'HomeAndConstructionBusiness', 'Place'];
    
    if (preg_match_all('/<script[^>]*type=["\']application\/ld\+json["\'][^>]*>(.*?)<\/script>/si', $body, $matches)) {
        foreach ($matches[1] as $json) {
            $decoded = json_decode(trim($json), true);
            if ($decoded) {
                $schemas[] = $decoded;
                
                // Analyze schema types and determine source
                if (isset($decoded['@graph'])) {
                    foreach ($decoded['@graph'] as $item) {
                        if (isset($item['@type'])) {
                            $types = is_array($item['@type']) ? $item['@type'] : [$item['@type']];
                            foreach ($types as $type) {
                                // Determine source
                                if (in_array($type, $local_types)) {
                                    $source = 'local';
                                } elseif (in_array($type, $auto_types)) {
                                    $source = 'auto';
                                } elseif (in_array($type, $global_types)) {
                                    $source = 'global';
                                } else {
                                    // Check if it's in our local schemas
                                    $source = in_array($type, $local_types) ? 'local' : 'unknown';
                                }
                                
                                $schema_sources[$type] = $source;
                            }
                        }
                    }
                } elseif (isset($decoded['@type'])) {
                    $types = is_array($decoded['@type']) ? $decoded['@type'] : [$decoded['@type']];
                    foreach ($types as $type) {
                        if (in_array($type, $local_types)) {
                            $source = 'local';
                        } elseif (in_array($type, $auto_types)) {
                            $source = 'auto';
                        } elseif (in_array($type, $global_types)) {
                            $source = 'global';
                        } else {
                            $source = 'unknown';
                        }
                        $schema_sources[$type] = $source;
                    }
                }
            }
        }
    }
    
    // Extract unique types found
    $types_found = array_keys($schema_sources);
    
    return rest_ensure_response([
        'success' => true,
        'api_version' => '2.2',
        'post_id' => $post_id,
        'post_title' => $post->post_title,
        'url' => $url,
        'live_schemas' => $schemas,
        'schema_types_found' => $types_found,
        'schema_sources' => $schema_sources,
        'source_legend' => [
            'local' => 'Page-specific schema (RankMath Schema tab)',
            'global' => 'Site-wide schema (RankMath Titles & Meta)',
            'auto' => 'Auto-generated by RankMath',
            'unknown' => 'Source could not be determined',
        ],
        'count' => count($schemas),
        'test_url' => 'https://search.google.com/test/rich-results?url=' . urlencode($url),
        'validator_url' => 'https://validator.schema.org/',
    ]);
}
// ===========================================
// SEO META FUNCTIONS
// ===========================================
function cortex_get_seo_meta($request) {
    $post_id = $request->get_param('id');
    $post = get_post($post_id);
    
    if (!$post) {
        return new WP_Error('not_found', 'Post not found', ['status' => 404]);
    }
    
    $meta = [
        'rank_math_title' => get_post_meta($post_id, 'rank_math_title', true),
        'rank_math_description' => get_post_meta($post_id, 'rank_math_description', true),
        'rank_math_focus_keyword' => get_post_meta($post_id, 'rank_math_focus_keyword', true),
    ];
    
    $focus_keywords = [];
    if (!empty($meta['rank_math_focus_keyword'])) {
        $focus_keywords = array_map('trim', explode(',', $meta['rank_math_focus_keyword']));
    }
    
    return rest_ensure_response([
        'success' => true,
        'post_id' => $post_id,
        'post_type' => $post->post_type,
        'post_title' => $post->post_title,
        'post_url' => get_permalink($post_id),
        'post_date' => $post->post_date,
        'post_modified' => $post->post_modified,
        'seo_meta' => $meta,
        'focus_keywords_array' => $focus_keywords,
        'primary_keyword' => !empty($focus_keywords) ? $focus_keywords[0] : null,
    ]);
}
function cortex_get_all_pages_seo($request) {
    $pages = get_posts([
        'post_type' => 'page',
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'orderby' => 'title',
        'order' => 'ASC',
    ]);
    
    $results = [];
    
    foreach ($pages as $page) {
        $focus_keyword = get_post_meta($page->ID, 'rank_math_focus_keyword', true);
        $focus_keywords = !empty($focus_keyword) ? array_map('trim', explode(',', $focus_keyword)) : [];
        
        $results[] = [
            'id' => $page->ID,
            'title' => $page->post_title,
            'url' => get_permalink($page->ID),
            'slug' => $page->post_name,
            'parent_id' => $page->post_parent,
            'rank_math_title' => get_post_meta($page->ID, 'rank_math_title', true),
            'rank_math_description' => get_post_meta($page->ID, 'rank_math_description', true),
            'rank_math_focus_keyword' => $focus_keyword,
            'focus_keywords_array' => $focus_keywords,
            'primary_keyword' => !empty($focus_keywords) ? $focus_keywords[0] : null,
            'has_featured_image' => has_post_thumbnail($page->ID),
        ];
    }
    
    return rest_ensure_response([
        'success' => true,
        'count' => count($results),
        'pages' => $results,
    ]);
}
function cortex_get_all_posts_seo($request) {
    $per_page = $request->get_param('per_page') ?: 50;
    $page = $request->get_param('page_num') ?: 1;
    
    $posts = get_posts([
        'post_type' => 'post',
        'post_status' => 'publish',
        'posts_per_page' => $per_page,
        'paged' => $page,
        'orderby' => 'date',
        'order' => 'DESC',
    ]);
    
    $total = wp_count_posts('post')->publish;
    $results = [];
    
    foreach ($posts as $post) {
        $focus_keyword = get_post_meta($post->ID, 'rank_math_focus_keyword', true);
        $focus_keywords = !empty($focus_keyword) ? array_map('trim', explode(',', $focus_keyword)) : [];
        $categories = wp_get_post_categories($post->ID, ['fields' => 'names']);
        
        $results[] = [
            'id' => $post->ID,
            'title' => $post->post_title,
            'url' => get_permalink($post->ID),
            'date' => $post->post_date,
            'modified' => $post->post_modified,
            'categories' => $categories,
            'rank_math_title' => get_post_meta($post->ID, 'rank_math_title', true),
            'rank_math_description' => get_post_meta($post->ID, 'rank_math_description', true),
            'rank_math_focus_keyword' => $focus_keyword,
            'focus_keywords_array' => $focus_keywords,
            'primary_keyword' => !empty($focus_keywords) ? $focus_keywords[0] : null,
            'has_featured_image' => has_post_thumbnail($post->ID),
        ];
    }
    
    return rest_ensure_response([
        'success' => true,
        'count' => count($results),
        'total' => (int) $total,
        'page' => (int) $page,
        'per_page' => (int) $per_page,
        'total_pages' => ceil($total / $per_page),
        'posts' => $results,
    ]);
}
// ===========================================
// FEATURED IMAGE FUNCTIONS
// ===========================================
function cortex_get_featured_image($request) {
    $post_id = $request->get_param('id');
    $post = get_post($post_id);
    
    if (!$post) {
        return new WP_Error('not_found', 'Post not found', ['status' => 404]);
    }
    
    $thumbnail_id = get_post_thumbnail_id($post_id);
    
    if (!$thumbnail_id) {
        return rest_ensure_response([
            'success' => true,
            'post_id' => $post_id,
            'post_title' => $post->post_title,
            'has_featured_image' => false,
            'featured_image' => null,
        ]);
    }
    
    $image_url = wp_get_attachment_image_url($thumbnail_id, 'full');
    $image_meta = wp_get_attachment_metadata($thumbnail_id);
    $image_alt = get_post_meta($thumbnail_id, '_wp_attachment_image_alt', true);
    
    return rest_ensure_response([
        'success' => true,
        'post_id' => $post_id,
        'post_title' => $post->post_title,
        'has_featured_image' => true,
        'featured_image' => [
            'id' => $thumbnail_id,
            'url' => $image_url,
            'width' => isset($image_meta['width']) ? $image_meta['width'] : null,
            'height' => isset($image_meta['height']) ? $image_meta['height'] : null,
            'alt' => $image_alt,
        ],
    ]);
}
function cortex_get_all_featured_images($request) {
    $post_type = $request->get_param('type');
    $post_types = empty($post_type) ? ['page', 'post'] : [$post_type];
    
    $posts = get_posts([
        'post_type' => $post_types,
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'orderby' => 'title',
        'order' => 'ASC',
    ]);
    
    $results = [];
    $with_image = 0;
    $without_image = 0;
    $missing_images = [];
    
    foreach ($posts as $post) {
        $thumbnail_id = get_post_thumbnail_id($post->ID);
        $has_image = !empty($thumbnail_id);
        
        if ($has_image) {
            $with_image++;
            $image_url = wp_get_attachment_image_url($thumbnail_id, 'full');
            $image_meta = wp_get_attachment_metadata($thumbnail_id);
            $image_alt = get_post_meta($thumbnail_id, '_wp_attachment_image_alt', true);
            
            $results[] = [
                'id' => $post->ID,
                'post_type' => $post->post_type,
                'title' => $post->post_title,
                'url' => get_permalink($post->ID),
                'has_featured_image' => true,
                'featured_image' => [
                    'id' => $thumbnail_id,
                    'url' => $image_url,
                    'width' => isset($image_meta['width']) ? $image_meta['width'] : null,
                    'height' => isset($image_meta['height']) ? $image_meta['height'] : null,
                    'alt' => $image_alt,
                ],
            ];
        } else {
            $without_image++;
            $missing_images[] = [
                'id' => $post->ID,
                'post_type' => $post->post_type,
                'title' => $post->post_title,
                'url' => get_permalink($post->ID),
            ];
            
            $results[] = [
                'id' => $post->ID,
                'post_type' => $post->post_type,
                'title' => $post->post_title,
                'url' => get_permalink($post->ID),
                'has_featured_image' => false,
                'featured_image' => null,
            ];
        }
    }
    
    return rest_ensure_response([
        'success' => true,
        'filter' => empty($post_type) ? 'all' : $post_type,
        'summary' => [
            'total' => count($results),
            'with_image' => $with_image,
            'without_image' => $without_image,
        ],
        'missing_images' => $missing_images,
        'results' => $results,
    ]);
}

Comments

Add a Comment