How to Add FAQ Schema in WordPress Without a Plugin

•

Adding an entire plugin just to output one small block of code always feels like overkill to me — especially for something as small as FAQ schema. Here’s what that structured data format actually is, a plugin-free way to add it yourself, and an honest caveat about what it currently does and doesn’t get you in Google’s search results.

What FAQPage structured data actually is

FAQPage is a type of “structured data” — a standardized way of describing your page’s content so search engines can read it directly, rather than trying to guess at it from your headings and paragraphs. In this case, it tells search engines: “this page contains a list of questions and their answers,” laid out in a specific, machine-readable format.

It’s added as a block of code called JSON-LD, sitting inside a <script> tag on your page. JSON-LD stands for “JavaScript Object Notation for Linked Data” — in practice, it’s just a structured way of writing out data that doesn’t render visibly on the page at all. It sits quietly alongside your normal, visible FAQ content, doing nothing but describing it to machines.

The caveat, up front, because overpromising here isn’t useful

For a while, FAQ rich results — the expandable question-and-answer dropdowns you’d sometimes see directly inside a Google search listing — were available fairly broadly to any site that marked up genuine FAQ content. Google has since narrowed eligibility for that specific rich result significantly. According to Google’s own developer documentation, FAQ rich results are now generally limited to well-known, authoritative government and health websites, rather than being available to sites broadly.

So don’t add this schema expecting an automatic rich snippet to show up in your search listing. For most sites, that particular visual outcome simply isn’t on the table right now.

That said, I still add valid FAQPage schema whenever a page genuinely has FAQ content, for a few reasons that have nothing to do with that one rich-result feature:

  • It’s a widely understood, standardized format that other tools — including newer AI-driven search and answer features — can read and parse.
  • It costs nothing to maintain once it’s hooked in properly, rather than added by hand to each page.
  • Eligibility criteria shift over time, and having accurate structured data already in place means you’re not scrambling to add it later if a criterion changes back in your favor.

Just don’t market this to a client as “will get you the rich snippet” — right now, for most sites, it won’t.

The actual JSON-LD structure

Here’s what a valid FAQPage entry actually looks like, in the raw format search engines expect:

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Do I need a plugin to add FAQ schema?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. A small function hooked into wp_head can output valid JSON-LD directly, without adding another plugin to maintain."
      }
    },
    {
      "@type": "Question",
      "name": "Will this get my site a rich snippet in Google?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Not guaranteed. Google has narrowed FAQ rich result eligibility mainly to certain authoritative site types, so treat this as accurate structured data rather than a guaranteed visual result."
      }
    }
  ]
}

Every question needs a Question entry with a name (the question text) and an acceptedAnswer, which contains an Answer with the actual answer text. The answer text should match what’s genuinely visible on the page — Google’s own guidelines are explicit that structured data should reflect visible content, not be used to sneak in extra text visitors never actually see.

A shortcode that outputs both the visible FAQ and the schema together

I prefer tying the visible text and the JSON-LD to the exact same data, so the two can never drift out of sync with each other. A simple shortcode — a bracketed tag you type directly into your content, like [faq] — handles this well:

function mytheme_faq_shortcode( $atts, $content = null ) {
    // Usage:
    // [faq q="Question text here"]Answer text here.[/faq]
    $atts = shortcode_atts( array(
        'q' => '',
    ), $atts, 'faq' );

    if ( empty( $atts['q'] ) || empty( $content ) ) {
        return '';
    }

    // Collect items on the page so we can output one combined JSON-LD block.
    global $mytheme_faq_items;
    if ( ! is_array( $mytheme_faq_items ) ) {
        $mytheme_faq_items = array();
    }

    $mytheme_faq_items[] = array(
        'question' => wp_strip_all_tags( $atts['q'] ),
        'answer'   => wp_strip_all_tags( $content ),
    );

    return sprintf(
        '<div class="faq-item"><h3 class="faq-question">%s</h3><div class="faq-answer">%s</div></div>',
        esc_html( $atts['q'] ),
        wp_kses_post( $content )
    );
}
add_shortcode( 'faq', 'mytheme_faq_shortcode' );

function mytheme_output_faq_schema() {
    global $mytheme_faq_items;

    if ( empty( $mytheme_faq_items ) || ! is_array( $mytheme_faq_items ) ) {
        return;
    }

    $main_entity = array();
    foreach ( $mytheme_faq_items as $item ) {
        $main_entity[] = array(
            '@type'          => 'Question',
            'name'           => $item['question'],
            'acceptedAnswer' => array(
                '@type' => 'Answer',
                'text'  => $item['answer'],
            ),
        );
    }

    $schema = array(
        '@context'   => 'https://schema.org',
        '@type'      => 'FAQPage',
        'mainEntity' => $main_entity,
    );

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

A few implementation notes worth calling out, if you’re handing this to a developer to add:

  • The schema output runs on wp_footer — a hook that fires near the bottom of the page — rather than wp_head, near the top. That’s deliberate: the shortcode has to actually run and collect its questions during content rendering first, and by the time wp_head fires, the content hasn’t been processed yet on most themes.
  • wp_strip_all_tags() is used for the JSON-LD text fields since the schema values need to be plain text, not HTML, even though the visible answer on the page can keep its formatting.
  • Using a simple shared list to collect items keeps this easy for a single page. If you need this across multiple independent FAQ sections with different groupings, that collection would need to be scoped per page instead.

Verifying it actually works

After adding this, view the page’s source code and look for the <script type="application/ld+json"> block. Then paste that JSON into Google’s Rich Results Test or the Schema Markup Validator to confirm it parses as valid FAQPage markup with no errors.

That confirms the structured data itself is technically correct. It doesn’t guarantee any specific search result treatment, for the reasons above — but it does mean the data is sound and ready if eligibility changes again down the line. If you’re already tightening up how search engines see your site, it’s worth also looking at whether noindexing thin tag and author archive pages makes sense for your setup, and whether your theme’s block or classic setup is helping or hurting — see my post on block themes versus classic themes for SEO.

Frequently Asked Questions About FAQ Schema in WordPress

Do I need a developer to add this to my site?

Yes, for this particular approach — it involves adding PHP code to your theme’s functions file, which isn’t something you’d do from the regular WordPress dashboard. If you’d rather avoid touching code entirely, a plugin like Yoast SEO or Rank Math can add FAQ schema through its block editor interface instead, at the cost of one more plugin running on your site.

Will adding FAQ schema get me a featured snippet or rich result?

Probably not directly. As covered above, Google currently limits the visible FAQ dropdown result mostly to large government and health sites, so most site owners shouldn’t expect that specific visual outcome just from adding this markup.

Is it risky to add code like this to my site myself?

The risk is fairly low since this code only adds a hidden script tag — it doesn’t touch your content, your database, or anything visitors can see. The main thing to get right is matching your visible FAQ text exactly to the schema text, since mismatched content can run against Google’s structured data guidelines.

What happens if my FAQ answers don’t match what’s visible on the page?

Google’s guidelines say structured data should reflect visible content, and mismatched schema can, in theory, lead to Google ignoring the structured data or acting against it. In practice this mostly just means wasted effort rather than something actively harmful, but it’s still worth keeping the two in sync.

Can I use this same approach for other types of schema, like HowTo or Review?

Yes, the underlying idea is the same for any schema.org type — you build a PHP array matching that type’s required fields, then output it as JSON-LD in the same way. The exact fields required differ by type, so check schema.org’s own documentation for whichever type you’re adding next.

How do I check if my FAQ schema is already showing up correctly?

Paste your page’s URL, or the JSON-LD snippet itself, into Google’s Rich Results Test. It will tell you whether the markup is valid and recognized, even though — as covered above — validity alone doesn’t guarantee a visible rich result in search.

One response to “How to Add FAQ Schema in WordPress Without a Plugin”

Leave a Reply

Your email address will not be published. Required fields are marked *