Skip to content

Conversation

nikunj8866
Copy link

@nikunj8866 nikunj8866 commented Sep 3, 2025

Meta Trac: https://meta.trac.wordpress.org/ticket/4695

This PR enhances the existing JSON-LD schema output on plugin detail pages to include a FAQPage node when such FAQ content is available.

Schema Verification link: https://search.google.com/test/rich-results/result?id=NcC3jhx4MFOkZgdLgnMlOg

Screenshots

image image

Schema Output

<script type="application/ld+json">
[
{
"@context": "http://schema.org",
"@type": [
"SoftwareApplication",
"Product"
],
"applicationCategory": "Plugin",
"operatingSystem": "WordPress",
"name": "Jetpack by WordPress.com",
"url": "http://wordpressorg.test/plugins/jetpack/",
"description": "The one plugin you need for stats, related posts, search engine optimization, social sharing, protection, backups, speed, and email list management.",
"softwareVersion": "4.8.1",
"fileFormat": "application/zip",
"downloadUrl": "https://downloads.wordpress.org/plugin/jetpack.4.8.1.zip",
"dateModified": "2017-04-05T19:59:54+00:00",
"aggregateRating": {
"@type": "AggregateRating",
"worstRating": 1,
"bestRating": 5,
"ratingValue": "4.1",
"ratingCount": 1312,
"reviewCount": 1312
},
"interactionStatistic": {
"@type": "InteractionCounter",
"interactionType": "http://schema.org/DownloadAction",
"userInteractionCount": 35787898
},
"image": [
"https://ps.w.org/jetpack/assets/icon.svg?rev=969908",
"https://ps.w.org/jetpack/assets/banner-1544x500.png?rev=1173629"
],
"offers": {
"@type": "Offer",
"url": "http://wordpressorg.test/plugins/jetpack/",
"price": "0.00",
"priceCurrency": "USD",
"seller": {
"@type": "Organization",
"name": "WordPress.org",
"url": "https://wordpress.org"
}
}
},
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Installation Instructions",
"acceptedAnswer": {
"@type": "Answer",
"text": "<h4>Automated Installation</h4>\n\n<p>Installation is free, quick, and easy. <a href=\"https://jetpack.com/install?from=wporg\">Install Jetpack from our site</a> in minutes.</p>\n\n<h4>Manual Alternatives</h4>\n\n<p>Alternatively, install Jetpack via the plugin directory, or upload the files manually to your server and follow the on-screen instructions. If you need additional help <a href=\"http://jetpack.com/support/installing-jetpack/\">read our detailed instructions</a>.</p>"
}
},
{
"@type": "Question",
"name": "Is Jetpack Free?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>Yes! Jetpack's core features are and always will be free.</p>\n\n<p>These include: <a href=\"https://jetpack.com/features/traffic/site-stats\">site stats</a>, a <a href=\"https://jetpack.com/features/writing/content-delivery-network/\">high-speed CDN</a> for images, <a href=\"https://jetpack.com/features/traffic/related-posts\">related posts</a>, <a href=\"https://jetpack.com/features/security/downtime-monitoring\">downtime monitoring</a>, brute force <a href=\"https://jetpack.com/features/security/brute-force-attack-protection\">attack protection</a>, <a href=\"https://jetpack.com/features/traffic/automatic-publishing/\">automated sharing</a> to social networks, <a href=\"https://jetpack.com/features/writing/sidebar-customization/\">sidebar customization</a>, and many more.</p>"
}
},
{
"@type": "Question",
"name": "Should I purchase a paid plan?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>Jetpack's paid services include automated backups, security scanning, spam filtering, video hosting, site monetization, SEO tools, and priority support.</p>\n\n<p>If you're interested in learning more about the extra layers of protection and advanced tools available, learn more about our <a href=\"https://jetpack.com/pricing?from=wporg\">paid plans</a>.</p>"
}
},
{
"@type": "Question",
"name": "Why do I need a WordPress.com account?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>Since Jetpack and its services are provided and hosted by WordPress.com, a WordPress.com account is required for Jetpack to function.</p>"
}
},
{
"@type": "Question",
"name": "I already have a WordPress account, but Jetpack isn't working. What's going on?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>A WordPress.com account is different from the account you use to log into your self-hosted WordPress. If you can log into <a href=\"https://wordpress.com\">WordPress.com</a>, then you already have a WordPress.com account. If you can't, you can easily create one <a href=\"https://jetpack.com/install?from=wporg\">during installation</a>.</p>"
}
},
{
"@type": "Question",
"name": "How do I view my stats?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>Once you've installed Jetpack your stats will be available on <a href=\"https://wordpress.com/stats\">WordPress.com/Stats</a>, on the official <a href=\"https://apps.wordpress.com/mobile/\">WordPress mobile apps</a>, and on your Jetpack dashboard.</p>"
}
},
{
"@type": "Question",
"name": "How do I contribute to Jetpack?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>There are opportunities for developers at all levels to contribute. <a href=\"https://jetpack.com/contribute\">Learn more about contributing to Jetpack</a> or consider <a href=\"https://jetpack.com/beta\">joining our beta program</a>.</p>"
}
}
]
}
]
</script>


$document_internal_errors = libxml_use_internal_errors( true );

$document = new \DOMDocument();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of using DomDocument like this on every page load.

We should either: Store the FAQs as post_meta, or use WP_HTML_Tag_Processor if absolutely required to extract from the HTML.

We can run a migration process to backfill the postmeta, so no need for doing both.
We could also migrate the existing FAQ markup to a block that pulls from that metadata..

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dd32 I agree with your suggestion, the postmeta approach seems the cleanest long-term solution.

For new uploads, we can parse the readme during the upload process (e.g. in class-upload-handler.php) and store _plugin_faqs postmeta immediately.

For existing plugins, have we handled this kind of migration process in the past?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've done migrations for data regularly enough. It's a PITA but it's easier than building legacy code upon legacy code upon legacy code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dd32 How were these migrations typically handled in the past? Is there any sample code or a PR I can look at as a reference to follow the same approach for FAQ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikunj8866 Generally either manually run or a bin script, I don't really have any good references for you.

One option in this case would be Just run the plugin import process for each plugin with FAQ items

What I'd suggest is ignoring back-compat and just work with:

  • Store FAQ items as meta values
  • Add a block, or shortcode, in place of the FAQ HTML markup in the post_content when it's built
  • Leave older imported plugins without FAQPage schema items to start with, with the assumption that either a) a re-import will update it or b) a migration will be run.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dd32 Thanks for the guidance.

As I understand it:

  • I'll add code to store FAQ content in post meta when plugins are uploaded.
  • I'll create a block for FAQs. Just to confirm, should this block output both the FAQ HTML Markup and the FAQ schema, or do you prefer to keep schema generation separate?
  • For older plugins, we could hook into import_from_svn so that FAQs are stored into post meta whenever a plugin is updated.

Does that align with what you had in mind?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants