SEO PHP Intermediate

Add FAQ Schema Markup Without a Plugin

Last updated: May 6, 2026

Google’s FAQ rich result displays question and answer pairs directly in the search results page beneath your listing, significantly expanding your visual footprint in the SERP and providing immediate value to searchers without requiring a click. When implemented correctly, a single result with FAQ schema can occupy three to five times the vertical space of a standard result. This snippet implements FAQ schema without requiring a dedicated SEO plugin, using a simple custom field to store the question and answer pairs per post or page.

The Code

Add this to your functions.php or a site-specific plugin. It consists of three parts: the front-end schema output, an admin meta box for entering FAQ data, and a save handler that stores the data securely.

How to Add FAQs to a Post

After adding this snippet, open any post or page in the editor. A new meta box labelled “FAQ Schema” appears in the sidebar. Enter your FAQ data as a JSON array of objects, where each object has a question and an answer key. Save the post, and the schema will be output automatically in the page head.

The JSON format keeps the implementation lightweight, no complex UI is needed, and the data is stored in a single post meta field that’s easy to query, export, or manipulate programmatically. For teams that prefer a more visual interface, this meta box can be replaced with a repeater field from ACF or Meta Box that builds the same JSON structure.

Schema Structure

The output is a FAQPage schema with a mainEntity array of Question objects. Each Question has a name (the question text) and an acceptedAnswer containing an Answer object with the answer text. The answer text is passed through wp_kses_post(), which allows basic HTML formatting, bold, links, lists, while stripping potentially unsafe tags.

Google’s FAQ Guidelines

Google requires that FAQ content be genuinely present on the page, you cannot output FAQ schema for questions that aren’t visible in the page content. Include an FAQ section in the post body that matches or closely mirrors the schema data. Pages that implement schema for content that doesn’t appear on the page risk manual actions from Google’s search quality team.

Google also limits FAQ rich results to sites it considers authoritative on the topic. New sites or posts on thin domains may not see rich results immediately, schema eligibility improves over time as the page accumulates authority signals.

Testing

Test the output using Google’s Rich Results Test. The tool will confirm whether the schema is valid and whether the page is eligible for FAQ rich results. It also renders a preview of how the expanded FAQ might appear in search results, which is useful for evaluating whether the question and answer length works well visually.

functions.php
// Store FAQ data as JSON in a custom field named '_faq_items'
// Format: [{"question":"Q1","answer":"A1"},{"question":"Q2","answer":"A2"}]

add_action( 'wp_head', function() {
    if ( ! is_singular() ) return;

    $faq_json = get_post_meta( get_the_ID(), '_faq_items', true );
    if ( ! $faq_json ) return;

    $items = json_decode( $faq_json, true );
    if ( ! is_array( $items ) || empty( $items ) ) return;

    $entities = array_map( function( $item ) {
        return [
            '@type'          => 'Question',
            'name'           => sanitize_text_field( $item['question'] ?? '' ),
            'acceptedAnswer' => [
                '@type' => 'Answer',
                'text'  => wp_kses_post( $item['answer'] ?? '' ),
            ],
        ];
    }, $items );

    $schema = [
        '@context'   => 'https://schema.org',
        '@type'      => 'FAQPage',
        'mainEntity' => $entities,
    ];

    echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>' . "\n";
} );

// Add a meta box to enter FAQ items in the admin
add_action( 'add_meta_boxes', function() {
    add_meta_box( 'nsl_faq', 'FAQ Schema', function( $post ) {
        $value = get_post_meta( $post->ID, '_faq_items', true );
        wp_nonce_field( 'nsl_faq_save', 'nsl_faq_nonce' );
        echo '<p style="color:#64748b;font-size:12px">JSON array of {question, answer} objects. Example:<br><code>[{"question":"What is X?","answer":"X is..."}]</code></p>';
        echo '<textarea name="nsl_faq_items" style="width:100%;height:120px;font-family:monospace;font-size:12px">' . esc_textarea( $value ) . '</textarea>';
    }, [ 'post', 'page' ], 'side', 'default' );
} );

add_action( 'save_post', function( $post_id ) {
    if ( ! isset( $_POST['nsl_faq_nonce'] ) || ! wp_verify_nonce( $_POST['nsl_faq_nonce'], 'nsl_faq_save' ) ) return;
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( ! current_user_can( 'edit_post', $post_id ) ) return;
    if ( isset( $_POST['nsl_faq_items'] ) ) {
        update_post_meta( $post_id, '_faq_items', sanitize_textarea_field( $_POST['nsl_faq_items'] ) );
    }
} );

Built by Nahnu Plugins

Need something more powerful than a snippet?

Our commercial plugins go further, built for serious WordPress sites with full support, updates, and documentation included.

Browse All Plugins →

This website uses cookies to enhance your browsing experience and ensure the site functions properly. By continuing to use this site, you acknowledge and accept our use of cookies.

Accept All Accept Required Only