Blog
Wild & Free Tools

Adding Schema Markup to Drupal Sites (Module or Custom JSON-LD)

Last updated: April 2026 8 min read

Table of Contents

  1. Module approach
  2. Custom twig approach
  3. Pulling field values
  4. Combining approaches
  5. Drupal cache gotchas
  6. Frequently Asked Questions

Drupal handles schema markup differently than WordPress or Shopify — it has dedicated modules for structured data, but the modules require configuration and don't always cover the schema types you need. The fallback: add custom JSON-LD via Twig templates in your theme. This guide covers both the module-based approach and the custom code approach for Drupal 9, 10, and 11 sites.

The Module Approach: Metatag + Schema.org Metatag

Drupal's standard schema setup uses two contrib modules: Metatag (handles all meta tags including OG and Twitter cards) and Schema.org Metatag (adds JSON-LD for the most common types).

Setup:

  1. Install both modules via Composer: composer require drupal/metatag drupal/schema_metatag
  2. Enable them: drush en metatag schema_metatag schema_metatag_article schema_metatag_breadcrumb schema_metatag_organization
  3. Configure at /admin/config/search/metatag — add metatag defaults for each content type
  4. Map fields from your content types to schema fields (article title to headline, etc.)

The modules cover Article, BreadcrumbList, Event, Organization, Person, Place, Product, RecipeProduct, and a few others. Each schema type is its own submodule that you enable selectively.

Limitations: configuration is verbose, less common schema types aren't covered, and customization beyond field mapping requires PHP. For straightforward Article + Organization + Breadcrumb sites, the modules work fine. For anything custom, you'll need to extend or fall back to manual JSON-LD.

The Custom Approach: JSON-LD in Twig Templates

For schema types the Metatag modules don't cover, or for full control over the output, write JSON-LD directly in your theme's Twig templates.

Find the template file for the content type you want to add schema to. For Article nodes, it's usually node--article.html.twig in your theme. Add a script block with your JSON-LD:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "{{ node.title.value }}",
  "datePublished": "{{ node.created.value|date('c') }}",
  "dateModified": "{{ node.changed.value|date('c') }}",
  "author": {
    "@type": "Person",
    "name": "{{ node.uid.entity.name.value }}"
  },
  "image": "{{ file_url(node.field_image.entity.uri.value) }}"
}
</script>

This injects schema specific to that node type. Use Twig's filters to format dates, escape strings, and pull field values from the node object.

For schema that should appear on every page, edit page.html.twig or html.html.twig instead. For content-type-specific schema, edit node--{type}.html.twig.

Sell Custom Apparel — We Handle Printing & Free Shipping

Pulling Drupal Field Values Into JSON-LD

The hardest part of Drupal schema is getting field values into the right format. Common patterns:

The biggest gotcha: special characters in field values (apostrophes, quotes, ampersands) can break JSON. Use Twig's |json_encode filter on string fields to escape them safely:

"headline": {{ node.title.value|json_encode|raw }}

This wraps the value in quotes and escapes any characters that would break JSON parsing.

Combining Modules and Custom Code

The cleanest setup for most Drupal sites:

  1. Use Metatag + Schema.org Metatag modules for Article, Breadcrumb, and Organization schema. These are well-supported and the modules handle them cleanly.
  2. Use custom Twig templates for less common types: Service, FAQ, HowTo, Event, Product (if your e-commerce uses Drupal Commerce).
  3. Validate everything with the Rich Results Test after deploying changes — Drupal's aggressive caching can cause stale schema in production.

The combined approach gets you 80% coverage from modules with minimal config and 20% custom for the schema types modules don't handle. Pure module-only leaves gaps; pure custom code is too much work for the common types.

Drupal Cache Gotchas

Drupal's caching system is aggressive. Schema changes you make in templates may not appear immediately because cached pages still serve the old version.

After making schema changes:

  1. Clear all caches: drush cr (or Configuration > Performance > Clear all caches in the UI)
  2. Test the live URL in an incognito window or with cache headers disabled
  3. If using Drupal's internal page cache, verify the cached page actually has the new schema
  4. If using Varnish or a CDN in front of Drupal, purge those caches too

For production sites, test schema changes on a staging environment first. Drupal can be unforgiving about cache invalidation, and broken schema in production is a pain to roll back.

For more on schema validation, see our validator workflow guide.

Try It Free — No Signup Required

Runs 100% in your browser. No data is collected, stored, or sent anywhere.

Open Free Schema Markup Generator

Frequently Asked Questions

Should I use Metatag module or custom Twig for Drupal schema?

Both. Use Metatag + Schema.org Metatag for Article, Breadcrumb, and Organization (well-supported). Use custom Twig for less common types like Service, FAQ, HowTo, Event. The combined approach covers more ground than either alone.

Does Drupal Commerce add Product schema automatically?

Drupal Commerce 2 does add some basic Product schema, but it's often incomplete (missing brand, gtin, aggregateRating). Most stores benefit from extending it via custom Twig templates in their theme.

Why isn't my Drupal schema showing up after I added it?

Almost always a cache issue. Clear all Drupal caches with drush cr, then check the live page in an incognito window. If you're behind Varnish or a CDN, purge those caches too. Drupal's internal caching is aggressive.

How do I escape special characters in Drupal JSON-LD?

Use the |json_encode filter on string fields. Example: "headline": {{ node.title.value|json_encode|raw }}. The filter escapes quotes, ampersands, and other characters that would break JSON parsing.

Does the Schema.org Metatag module support all schema types?

No. It supports the most common types (Article, Breadcrumb, Event, Organization, Person, Place, Product, Recipe, Service) but not less common ones. For unsupported types, write custom Twig templates.

Can I use schema markup on Drupal Views?

Yes, but it's more involved. Override the Views template (views-view.html.twig) to inject JSON-LD that lists the displayed items. Most useful for ItemList schema on category pages or product listing pages.

Launch Your Own Clothing Brand — No Inventory, No Risk