PHPwordpressbeginner
FAQ Schema Markup for WordPress Without Plugins
Add FAQPage structured data to WordPress posts and pages for Google rich results without any plugins
Faisal Yaqoob
December 18, 2025
#wordpress#faq#schema#seo#structured-data#rich-snippets#json-ld#google
Code
php
1 /** 2 * Register FAQ Meta Box for Posts and Pages 3 */ 4 function faq_schema_add_meta_box() { 5 $screens = [ 'post', 'page' ]; 6 foreach ( $screens as $screen ) { 7 add_meta_box( 8 'faq_schema_box', 9 'FAQ Schema Markup', 10 'faq_schema_meta_box_html', 11 $screen, 12 'normal', 13 'high' 14 ); 15 } 16 } 17 add_action( 'add_meta_boxes', 'faq_schema_add_meta_box' ); 18
19 function faq_schema_meta_box_html( $post ) { 20 $faqs = get_post_meta( $post->ID, '_faq_schema_data', true ); 21 $faqs = is_array( $faqs ) ? $faqs : []; 22 wp_nonce_field( 'faq_schema_nonce', 'faq_schema_nonce_field' ); 23 ?> 24 <div id="faq-schema-fields"> 25 <?php foreach ( $faqs as $i => $faq ) : ?> 26 <div class="faq-item" style="margin-bottom:15px;padding:10px;border:1px solid #ddd;"> 27 <p><strong>Question <?php echo $i + 1; ?>:</strong></p> 28 <input type="text" name="faq_question[]" value="<?php echo esc_attr( $faq['question'] ); ?>" style="width:100%;" /> 29 <p><strong>Answer:</strong></p> 30 <textarea name="faq_answer[]" rows="3" style="width:100%;"><?php echo esc_textarea( $faq['answer'] ); ?></textarea> 31 </div> 32 <?php endforeach; ?> 33 </div> 34 <button type="button" onclick="addFaqField()" class="button">+ Add FAQ</button> 35 <script> 36 function addFaqField() { 37 var container = document.getElementById('faq-schema-fields'); 38 var count = container.querySelectorAll('.faq-item').length + 1; 39 var html = '<div class="faq-item" style="margin-bottom:15px;padding:10px;border:1px solid #ddd;">' + 40 '<p><strong>Question ' + count + ':</strong></p>' + 41 '<input type="text" name="faq_question[]" value="" style="width:100%;" />' + 42 '<p><strong>Answer:</strong></p>' + 43 '<textarea name="faq_answer[]" rows="3" style="width:100%;"></textarea></div>'; 44 container.insertAdjacentHTML('beforeend', html); 45 } 46 </script> 47 <?php 48 } 49
50 /** 51 * Save FAQ Meta Data 52 */ 53 function faq_schema_save_meta( $post_id ) { 54 if ( ! isset( $_POST['faq_schema_nonce_field'] ) || 55 ! wp_verify_nonce( $_POST['faq_schema_nonce_field'], 'faq_schema_nonce' ) ) { 56 return; 57 } 58
59 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 60 return; 61 } 62
63 if ( ! current_user_can( 'edit_post', $post_id ) ) { 64 return; 65 } 66
67 $questions = isset( $_POST['faq_question'] ) ? array_map( 'sanitize_text_field', $_POST['faq_question'] ) : []; 68 $answers = isset( $_POST['faq_answer'] ) ? array_map( 'sanitize_textarea_field', $_POST['faq_answer'] ) : []; 69
70 $faqs = []; 71 foreach ( $questions as $i => $question ) { 72 if ( ! empty( $question ) && ! empty( $answers[ $i ] ) ) { 73 $faqs[] = [ 74 'question' => $question, 75 'answer' => $answers[ $i ], 76 ]; 77 } 78 } 79
80 update_post_meta( $post_id, '_faq_schema_data', $faqs ); 81 } 82 add_action( 'save_post', 'faq_schema_save_meta' ); 83
84 /** 85 * Output FAQ Schema JSON-LD in <head> 86 */ 87 function faq_schema_output_jsonld() { 88 if ( ! is_singular() ) { 89 return; 90 } 91
92 global $post; 93 $faqs = get_post_meta( $post->ID, '_faq_schema_data', true ); 94
95 if ( empty( $faqs ) || ! is_array( $faqs ) ) { 96 return; 97 } 98
99 $schema = [ 100 '@context' => 'https://schema.org', 101 '@type' => 'FAQPage', 102 'mainEntity' => [], 103 ]; 104
105 foreach ( $faqs as $faq ) { 106 $schema['mainEntity'][] = [ 107 '@type' => 'Question', 108 'name' => $faq['question'], 109 'acceptedAnswer' => [ 110 '@type' => 'Answer', 111 'text' => $faq['answer'], 112 ], 113 ]; 114 } 115
116 echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES ) . '</script>' . "\n"; 117 } 118 add_action( 'wp_head', 'faq_schema_output_jsonld' );
FAQ Schema Markup for WordPress
Add Google-eligible FAQ rich results to your WordPress site without any SEO plugins. FAQ schema can significantly increase your SERP real estate and click-through rate by displaying expandable Q&A directly in search results.
Method 1: Custom Meta Box for FAQ Schema
/**
* Register FAQ Meta Box for Posts and Pages
*/
function faq_schema_add_meta_box() {
$screens = [ 'post', 'page' ];
foreach ( $screens as $screen ) {
add_meta_box(
'faq_schema_box',
'FAQ Schema Markup',
'faq_schema_meta_box_html',
$screen,
'normal',
'high'
);
}
}
add_action( 'add_meta_boxes', 'faq_schema_add_meta_box' );
function faq_schema_meta_box_html( $post ) {
$faqs = get_post_meta( $post->ID, '_faq_schema_data', true );
$faqs = is_array( $faqs ) ? $faqs : [];
wp_nonce_field( 'faq_schema_nonce', 'faq_schema_nonce_field' );
?>
<div id="faq-schema-fields">
<?php foreach ( $faqs as $i => $faq ) : ?>
<div class="faq-item" style="margin-bottom:15px;padding:10px;border:1px solid #ddd;">
<p><strong>Question <?php echo $i + 1; ?>:</strong></p>
<input type="text" name="faq_question[]" value="<?php echo esc_attr( $faq['question'] ); ?>" style="width:100%;" />
<p><strong>Answer:</strong></p>
<textarea name="faq_answer[]" rows="3" style="width:100%;"><?php echo esc_textarea( $faq['answer'] ); ?></textarea>
</div>
<?php endforeach; ?>
</div>
<button type="button" onclick="addFaqField()" class="button">+ Add FAQ</button>
<script>
function addFaqField() {
var container = document.getElementById('faq-schema-fields');
var count = container.querySelectorAll('.faq-item').length + 1;
var html = '<div class="faq-item" style="margin-bottom:15px;padding:10px;border:1px solid #ddd;">' +
'<p><strong>Question ' + count + ':</strong></p>' +
'<input type="text" name="faq_question[]" value="" style="width:100%;" />' +
'<p><strong>Answer:</strong></p>' +
'<textarea name="faq_answer[]" rows="3" style="width:100%;"></textarea></div>';
container.insertAdjacentHTML('beforeend', html);
}
</script>
<?php
}
/**
* Save FAQ Meta Data
*/
function faq_schema_save_meta( $post_id ) {
if ( ! isset( $_POST['faq_schema_nonce_field'] ) ||
! wp_verify_nonce( $_POST['faq_schema_nonce_field'], 'faq_schema_nonce' ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
$questions = isset( $_POST['faq_question'] ) ? array_map( 'sanitize_text_field', $_POST['faq_question'] ) : [];
$answers = isset( $_POST['faq_answer'] ) ? array_map( 'sanitize_textarea_field', $_POST['faq_answer'] ) : [];
$faqs = [];
foreach ( $questions as $i => $question ) {
if ( ! empty( $question ) && ! empty( $answers[ $i ] ) ) {
$faqs[] = [
'question' => $question,
'answer' => $answers[ $i ],
];
}
}
update_post_meta( $post_id, '_faq_schema_data', $faqs );
}
add_action( 'save_post', 'faq_schema_save_meta' );
/**
* Output FAQ Schema JSON-LD in <head>
*/
function faq_schema_output_jsonld() {
if ( ! is_singular() ) {
return;
}
global $post;
$faqs = get_post_meta( $post->ID, '_faq_schema_data', true );
if ( empty( $faqs ) || ! is_array( $faqs ) ) {
return;
}
$schema = [
'@context' => 'https://schema.org',
'@type' => 'FAQPage',
'mainEntity' => [],
];
foreach ( $faqs as $faq ) {
$schema['mainEntity'][] = [
'@type' => 'Question',
'name' => $faq['question'],
'acceptedAnswer' => [
'@type' => 'Answer',
'text' => $faq['answer'],
],
];
}
echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES ) . '</script>' . "\n";
}
add_action( 'wp_head', 'faq_schema_output_jsonld' );
Method 2: Shortcode-Based FAQ Schema
/**
* FAQ Schema via Shortcode
* Usage: [faq question="Your question here?"]Your answer here.[/faq]
*/
function faq_schema_shortcode_collector( $atts, $content = null ) {
global $faq_schema_items;
if ( ! isset( $faq_schema_items ) ) {
$faq_schema_items = [];
}
$atts = shortcode_atts( [ 'question' => '' ], $atts );
if ( ! empty( $atts['question'] ) && ! empty( $content ) ) {
$faq_schema_items[] = [
'question' => sanitize_text_field( $atts['question'] ),
'answer' => wp_kses_post( $content ),
];
}
// Render visible FAQ on the page
$output = '<div class="faq-item" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question">';
$output .= '<h3 class="faq-question" itemprop="name">' . esc_html( $atts['question'] ) . '</h3>';
$output .= '<div class="faq-answer" itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer">';
$output .= '<div itemprop="text">' . wp_kses_post( $content ) . '</div>';
$output .= '</div></div>';
return $output;
}
add_shortcode( 'faq', 'faq_schema_shortcode_collector' );
/**
* Output collected FAQ schema in footer
*/
function faq_schema_shortcode_output() {
global $faq_schema_items;
if ( empty( $faq_schema_items ) ) {
return;
}
$schema = [
'@context' => 'https://schema.org',
'@type' => 'FAQPage',
'mainEntity' => array_map( function( $faq ) {
return [
'@type' => 'Question',
'name' => $faq['question'],
'acceptedAnswer' => [
'@type' => 'Answer',
'text' => $faq['answer'],
],
];
}, $faq_schema_items ),
];
echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES ) . '</script>' . "\n";
}
add_action( 'wp_footer', 'faq_schema_shortcode_output' );
Shortcode Usage in Post Editor
[faq question="What is FAQ Schema?"]
FAQ Schema is structured data markup that tells Google your page
contains frequently asked questions. Google may display these as
expandable rich results in search.
[/faq]
[faq question="Does FAQ Schema improve SEO?"]
Yes. FAQ rich results increase your SERP visibility, improve
click-through rates, and can help you appear for voice search
queries. Pages with FAQ schema often take up more space in results.
[/faq]
[faq question="How many FAQs should I add?"]
Google recommends adding between 3-10 FAQ items per page. Focus
on genuine questions your audience asks. Avoid keyword stuffing.
[/faq]
Best Practices
- Use real questions your audience actually asks — check Google Search Console queries
- Keep answers concise but comprehensive (50-300 words per answer)
- Match visible content — FAQ schema must reflect what users see on the page
- Limit to 3-10 FAQs per page for optimal display
- Avoid promotional content in FAQ answers — Google may penalize sales-heavy FAQs
- Validate with Google Rich Results Test before publishing
Features
- No Plugin Required: Pure PHP implementation
- Two Methods: Meta box for editors, shortcode for content creators
- Google Rich Results: Eligible for FAQ rich snippets
- Voice Search Ready: FAQ schema powers Google Assistant answers
- Visible + Structured: Renders FAQ on page AND outputs JSON-LD
- WordPress Native: Uses WordPress APIs for security and compatibility
Related Snippets
Add JSON-LD Schema to WordPress Without Plugins
Inject dynamic JSON-LD structured data into WordPress without any SEO plugins using functions.php
PHPwordpressintermediate
phpPreview
/**
* Output JSON-LD Schema Markup for WordPress
* Add to your child theme's functions.php
*/
...#wordpress#schema#json-ld+4
12/15/2025
View
Breadcrumb Schema for WordPress Without Plugins
Add BreadcrumbList JSON-LD structured data to WordPress for enhanced Google search navigation
PHPwordpressbeginner
phpPreview
/**
* Output BreadcrumbList JSON-LD Schema
* Automatically detects page type and builds breadcrumb trail
*/
...#wordpress#breadcrumb#schema+5
12/20/2025
View
Local Business Schema for WordPress
Add LocalBusiness JSON-LD structured data to WordPress for Google Maps and local search rich results
PHPwordpressintermediate
phpPreview
/**
* Output LocalBusiness JSON-LD Schema
* Add to child theme functions.php
* Customize the values below for your business
...#wordpress#local-business#schema+5
12/22/2025
View