Implement NewsArticle schema markup correctly to enable rich results in Google News, Top Stories, and search results.
Prerequisites
- Understanding of JSON-LD format
- Access to your CMS template files
- Google Rich Results Test access
- Schema.org documentation familiarity
Step 1: Determine Your Schema Template
Static vs. Dynamic Schema
For news sites, schema must be dynamic—generated per article:
- Headline from article title
- Date from publish timestamp
- Author from article byline
- Image from featured image
Step 2: Base Template Implementation
WordPress Implementation
function generate_news_article_schema() {
if (!is_single()) return;
global $post;
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'NewsArticle',
'headline' => get_the_title(),
'datePublished' => get_the_date('c'),
'dateModified' => get_the_modified_date('c'),
'author' => array(
'@type' => 'Person',
'name' => get_the_author_meta('display_name', $post->post_author),
'url' => get_author_posts_url($post->post_author)
),
'publisher' => array(
'@type' => 'Organization',
'name' => get_bloginfo('name'),
'logo' => array(
'@type' => 'ImageObject',
'url' => 'https://example.com/logo.png'
)
),
'image' => get_the_post_thumbnail_url($post, 'full'),
'description' => get_the_excerpt(),
'mainEntityOfPage' => array(
'@type' => 'WebPage',
'@id' => get_permalink()
)
);
echo '<script type="application/ld+json">' . json_encode($schema) . '</script>';
}
add_action('wp_head', 'generate_news_article_schema');
Next.js Implementation
export function NewsArticleSchema({ article }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'NewsArticle',
headline: article.title,
datePublished: article.publishedAt,
dateModified: article.updatedAt,
author: {
'@type': 'Person',
name: article.author.name,
url: `/author/${article.author.slug}`,
},
publisher: {
'@type': 'Organization',
name: 'Example News',
logo: {
'@type': 'ImageObject',
url: 'https://example.com/logo.png',
},
},
image: article.featuredImage,
description: article.excerpt,
mainEntityOfPage: {
'@type': 'WebPage',
'@id': article.url,
},
articleSection: article.category,
wordCount: article.wordCount,
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
Step 3: Add Advanced Properties
Complete Schema with All Recommended Fields
const fullSchema = {
'@context': 'https://schema.org',
'@type': 'NewsArticle',
// Required
headline: article.title,
datePublished: article.publishedAt,
dateModified: article.updatedAt,
author: {
'@type': 'Person',
name: article.author.name,
url: `/author/${article.author.slug}`,
jobTitle: article.author.title,
sameAs: article.author.socialLinks,
},
publisher: {
'@type': 'Organization',
name: 'Example News',
url: 'https://example.com',
logo: {
'@type': 'ImageObject',
url: 'https://example.com/logo.png',
width: 600,
height: 60,
},
sameAs: ['https://twitter.com/examplenews'],
},
image: {
'@type': 'ImageObject',
url: article.featuredImage,
width: 1200,
height: 630,
},
// Recommended
description: article.excerpt,
articleSection: article.category,
wordCount: article.wordCount,
keywords: article.tags,
genre: 'News',
alternativeHeadline: article.subtitle,
// Free access
isAccessibleForFree: !article.isPaywalled,
// Paywall support
...(article.isPaywalled && {
hasPart: {
'@type': 'WebPageElement',
isAccessibleForFree: false,
cssSelector: '.paywall-content',
},
}),
mainEntityOfPage: {
'@type': 'WebPage',
'@id': article.url,
},
};
Step 4: Validate Your Schema
Testing Process
- Rich Results Test: Test each article URL
- Schema Markup Validator: Validate schema.org compliance
- Search Console: Monitor for errors
- Lighthouse: Check structured data audit
Common Validation Fixes
// Fix: Ensure headline matches H1
headline: document.querySelector('h1').textContent
// Fix: ISO 8601 date format
datePublished: new Date(article.publishedAt).toISOString()
// Fix: Proper image dimensions
image: {
'@type': 'ImageObject',
url: article.featuredImage,
width: 1200,
height: 630
}
Step 5: Monitor and Maintain
Monthly Schema Health Check
- Run Rich Results Test on 10 random articles
- Check Search Console for schema errors
- Verify dateModified updates correctly
- Confirm author schema is accurate
- Test paywall schema if applicable
Automated Schema Testing
// Test schema in CI/CD pipeline
describe('NewsArticle Schema', () => {
it('should have required fields', () => {
const schema = getSchemaFromPage('/article/1');
expect(schema.headline).toBeDefined();
expect(schema.datePublished).toMatch(/^\d{4}-\d{2}-\d{2}/);
expect(schema.author.name).toBeDefined();
expect(schema.publisher.name).toBeDefined();
expect(schema.image).toBeDefined();
});
});
Checklist
- Dynamic schema generation implemented
- All required fields populated
- Recommended fields included
- Schema validates in Rich Results Test
- No Search Console schema errors
- Paywall schema implemented (if needed)
- Author schema includes sameAs links
- Image dimensions specified
- Headline matches page H1
- Dates in ISO 8601 format