3. Schema Meta Fields | SEO Forge - Rank Higher with AI-Powered SEO
Download Log in

3. Schema Meta Fields

Developer Guide

Schema-related post meta controls JSON-LD output for individual posts.

Meta KeyTypeDescription
_seoforge_schema_typestringManual schema type override (e.g. 'Article', 'FAQ', 'Product'). When set, generates the corresponding JSON-LD automatically.
_seoforge_manual_schemastring (JSON)Full manual JSON-LD schema object as a JSON string. Bypasses all auto-generation.
_seoforge_ai_schemaarray (serialized)AI-generated schema cache containing detected_types, json_ld, generated_at, and source keys.
php
// ----- Reading schema meta -----

$post_id = 42;

// Read the manual schema type override
$schema_type = get_post_meta( $post_id, '_seoforge_schema_type', true );

// Read the full manual schema JSON
$manual_json = get_post_meta( $post_id, '_seoforge_manual_schema', true );
if ( $manual_json ) {
    $schema_array = json_decode( $manual_json, true );
}

// Read AI-detected schema (returns unserialized array)
$ai_schema = get_post_meta( $post_id, '_seoforge_ai_schema', true );
if ( $ai_schema ) {
    $types = $ai_schema['detected_types']; // e.g. ['Article', 'FAQ']
}
php
// ----- Writing schema meta -----

$post_id = 42;

// Set a simple schema type override (SEO Forge generates the JSON-LD)
update_post_meta( $post_id, '_seoforge_schema_type', 'FAQ' );

// Set a complete manual schema (takes full control of JSON-LD output)
$faq_schema = json_encode( [
    '@context'   => 'https://schema.org',
    '@type'      => 'FAQPage',
    'mainEntity' => [
        [
            '@type' => 'Question',
            'name'  => 'What is SEO Forge?',
            'acceptedAnswer' => [
                '@type' => 'Answer',
                'text'  => 'SEO Forge is a WordPress SEO plugin providing comprehensive on-page optimization.',
            ],
        ],
    ],
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );

update_post_meta( $post_id, '_seoforge_manual_schema', $faq_schema );

// Clear AI schema cache (forces re-detection on next analysis)
delete_post_meta( $post_id, '_seoforge_ai_schema' );

// Remove manual schema type to fall back to auto-detection
delete_post_meta( $post_id, '_seoforge_schema_type' );
delete_post_meta( $post_id, '_seoforge_manual_schema' );

Additive emit cascade (April 2026 / R3 F4)

SEOFORGE_Schema::output_schema() is additive, not priority-wins. Setting _seoforge_schema_type to 'FAQ' on a post does not suppress the post-type-default Article schema — instead the post emits [Article, FAQPage, BreadcrumbList]. The cascade is:
  1. Auto-detected default for the post type — Article for posts, Product for product, WebPage everywhere else (auto_detect_type()). Skipped when _seoforge_schema_type resolves to the same @type, since step (3) would generate it anyway.
  2. AI-cached blocks from _seoforge_ai_schema['json_ld'] (a multi-block array — each entry is emitted independently, deduplicated by @type).
  3. Manual _seoforge_schema_type selection. If the type-specific generator returns null (e.g. HowTo without imperative steps — see extract_howto_steps() filter), the block is silently dropped without affecting other layers.
  4. Auto-FAQ — emitted when generate_faq($post_id, $post, only_questions=true) finds 2+ ?-terminated H2/H3 + paragraph pairs. Skipped if FAQPage was already emitted by an earlier layer.
  5. BreadcrumbList (always) and Organization (front page only).

The whole list is deduplicated by @type. Full manual JSON-LD via _seoforge_manual_schema is the only “exclusive” path — when set it owns the entire emit and only BreadcrumbList layers on top.

#### Filters and actions

php
// Opt out of auto-FAQ (returns null to suppress the FAQPage block).
add_filter( 'seoforge_auto_faq_schema', function( $faq, $post_id ) {
    if ( get_post_type( $post_id ) === 'tutorial' ) {
        return null; // tutorials shouldn't auto-trigger FAQPage
    }
    return $faq;
}, 10, 2 );

// Inspect the final list of emitted @types per request — useful for
// debug / analytics / extra dedup. Fires AFTER all schemas are echoed.
add_action( 'seoforge_schemas_emitted', function( $emitted_types, $post_id ) {
    error_log( "Schemas on post {$post_id}: " . implode( ',', $emitted_types ) );
}, 10, 2 );

The seoforge_schemas_emitted action is informational only — schemas are already on the page when it fires. To pre-empt or modify a block, use the per-type generator filters (e.g. seoforge_auto_faq_schema) or hook earlier in wp_head (priority < 5) and call remove_action( 'wp_head', [ SEOFORGE_Schema::instance(), 'output_schema' ] ) if you need to fully replace the emit.

Forge AI Assistant Online

Hi! I'm the SEO Forge AI assistant. Ask me anything about the plugin — setup, features, troubleshooting, or development.

Just now
Powered by Forge AI · Browse docs