Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#1 2025-06-03 14:21:46

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 11,778
Website GitHub

Inline Microdata vs JSON-LD

I have a client who is using schema.org microdata extensively for marking up various types of content. Organization, Product, FAQPage, Blog, etc.

Using microdata to wrap visible elements on the page seems logical to me, because any complex conditional logic to display/collect various article bits and pieces, like custom fields, is nearby and in context. For example, product out of stock, is on discount, is of a certain brand, etc.

Google et al consume inline microdata just fine. It works. Data is marked up, collected and spat out in SERPs. However, almost every place I go or everywhere I seek examples as I’m evolving what metadata we describe, exclusively uses JSON-LD format. And it turns out, that’s because Google state they prefer it over microdata. I’m not sure why, when they do the same job.

As far as I can make out, JSON-LD has to all appear in the <head> of the page. So for Textpattern, where I normally have a shared Form containing the ‘head’ data and a shared Form for ‘navbar’ and so forth, this means putting all the metadata info in that form (or a sub-form called from inside it). That requires either one humongous Form with loads of <if::section>… logic to serve the right type of schema to the right page, or a bunch of separate forms – one per schema type – called from the head Form (and the conditional logic can go in there to determine which schema Form to inject via <txp:output_form>).

But because stuff is rendered ahead of the rest of the page, I need an extra article/article_custom tag to put me in article context, and I need to essentially replicate the business logic that appears further down the page so I can serve the correct schema elements (Offer, for marking up price information, is particularly intricate and requires lots of if-this, if-that).

I suppose there’s an argument that I could set up a whole bunch of variables while I’m doing the first article call, and display these variables later on instead of calling a second <txp:article>. That’s fine for individual article pages, but not so good for article lists where things like the Collection schema are handy.

Google tell me that the fastest pagespeed is important, where metrics like first-contentful-paint and all that malarky are what visitors care about. But they also tell me to pre-stuff my page with endless JSON structures describing what’s coming for their spiders to gobble up; stuff that the browser has to consume/skip before it even gets to the first byte of actual displayable content.

Not sure I have a point, really. It just seems at odds with Textpattern’s philosophy of keeping everything compartmentalised for easier maintenance. Farming stuff to reusable forms is great, because you can lace the content with metadata markup to machine-describe its relevance. But if it means I have to maintain two or more copies of the same logic – one for display, one for metadata in the <head> – and issue twice the number of database calls to render the stuff that the visitor actually sees and the bits the machine reads, well, it starts to annoy me and slows the website down.

Does anybody have any views on this? Should we just ignore the pressure from Big G and stick with inline microdata? Or are there real-world benefits to collecting all the machine-readable stuff up-front, and to hell with the performance/memory hit?

If you use JSON-LD, are there any tricks you’ve employed to improve the performance aspects or reduce the server footprint as you render the page content?

I’m curious whether I should dig my heels in and stick with the inline metadata sprinkled in context, or if I’m just being a dinosaur for not bowing to pressure to switch to JSON-LD because it offers more, uhhh… something that benefits site visitors.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#2 2025-06-03 14:43:54

jakob
Admin
From: Germany
Registered: 2005-01-20
Posts: 4,925
Website GitHub

Re: Inline Microdata vs JSON-LD

I hear you! The schema.org microdata has the advantage of stuff being together in one place but it doesn’t half make the markup involved and wordy, and the time I need to debug it as someone without intimate knowledge of every schema.org item is aggravating.

You might be able to tackle rendering the JSON-LD stuff after having processed the tags on the page – as arc_meta used to do – by using process="2" or <txp:tag[1] /> and <txp:tag[2] /> tags. See this thread.

If that helps, please post back showing how it works. I’ve always been meaning to try it out.


TXP Builders – finely-crafted code, design and txp

Offline

#3 2025-06-03 15:40:27

skewray
Member
From: Sunny Southern California
Registered: 2013-04-25
Posts: 225
Website Mastodon

Re: Inline Microdata vs JSON-LD

Although I am not really a website programmer, I have been a programming for over 40 years. IMHO, the only important sentence in all that was, “It just seems at odds with Textpattern’s philosophy of keeping everything compartmentalised for easier maintenance.” You have to maintain what you write, so maintenance should be pretty high on your priority list.

Offline

#4 2025-06-03 16:49:18

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 11,778
Website GitHub

Re: Inline Microdata vs JSON-LD

jakob wrote #339789:

The schema.org microdata has the advantage of stuff being together in one place but it doesn’t half make the markup involved and wordy

Yes it does! When dealing with “Offer” and all its nuances, the currency markup required for just 5 characters of actual content (4 digits and the currency symbol) becomes…. *deep breath* …

<span itemprop="offers" itemscope="" itemtype="https://schema.org/Offer">,
   <span itemprop="priceCurrency" content="GBP">£</span><span itemprop="price" content="4200">4200</span>
   <link itemprop="availability" href="https://schema.org/InStock">
   <meta itemprop="priceValidUntil" content="2026-01-01">
   <span class="metadata" itemprop="hasMerchantReturnPolicy" itemtype="https://schema.org/MerchantReturnPolicy" itemscope="">
      <meta itemprop="applicableCountry" content="UK">
   </span>
   <span class="metadata" itemprop="shippingDetails" itemscope="" itemtype="https://schema.org/OfferShippingDetails">
      <meta itemtype="FreeShipping" content="0">
      <span class="metadata" itemprop="shippingRate" itemscope="" itemtype="https://schema.org/MonetaryAmount">
         <meta itemprop="value" content="0">
         <meta itemprop="currency" content="GBP">
      </span>
      <span class="metadata" itemprop="shippingDestination" itemscope="" itemtype="https://schema.org/DefinedRegion">
         <meta itemprop="addressCountry" content="UK">
      </span>
      <span class="metadata" itemprop="deliveryTime" itemscope="" itemtype="https://schema.org/ShippingDeliveryTime">
         <span class="metadata" itemprop="transitTime" itemscope="" itemtype="https://schema.org/QuantitativeValue">
            <meta itemprop="minValue" content="1">
            <meta itemprop="maxValue" content="7">
            <meta itemprop="unitCode" content="d">
         </span>
         <span class="metadata" itemprop="handlingTime" itemscope="" itemtype="https://schema.org/QuantitativeValue">
            <meta itemprop="minValue" content="1">
            <meta itemprop="maxValue" content="2">
            <meta itemprop="unitCode" content="d">
         </span>
      </span>
   </span>
</span>

!

That’s an insane bloat. The equivalent JSON-LD is a lot less wordy BUT it comes with necessary surrounding logic like “if product isn’t sold” and “if product has discount” and “if product value is over free shipping threshold” etc, which I dislike duplicating more than I dislike the splurge of microdata <span> tags around the price.

[ EDIT: I could probably have used a <meta> or <link> tags instead of <span class="metadata"> (with .metadata { display:none; }) but some of the stuff when used as containers was rendering bits and bobs on the page, and I couldn’t find a way to nest the tags properly, so I just fell back on the span tags instead ]

You might be able to tackle rendering the JSON-LD stuff after having processed the tags on the page… using process="2" or <txp:tag[1] /> and <txp:tag[2] /> tags.

That’s a good shout, thanks for the idea. Maybe the bits further down the page (the visitor-visible portions) can actually assemble the JSON-LD structure in a <txp:variable> and then that can be splatted on the page afterwards into the <head> using tag sweep delay.

Hmmm. That’s got to be the way to go. When the microdata I’m adding at the moment has bedded in and I get some time, I’ll play with that approach and report back.

Last edited by Bloke (2025-06-03 16:52:28)


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#5 2025-06-03 17:16:30

Pat64
Plugin Author
From: France
Registered: 2005-12-12
Posts: 1,659
GitHub Twitter

Re: Inline Microdata vs JSON-LD

I’m using massively JSON-LD (7 scripts) on this kind of page without any Google Page Speed Insight penalties (global scores : 99/100 for Mobiles; 100/100 for Desktops).

https://pagespeed.web.dev/analysis/https-atelier-clos-mirabel-com-painting-holidays-kat-o-connor-atelier-clos-mirabel-france-french-pyrenees/hcygvgecr2?hl=fr&form_factor=mobile

Note: this website (TXP v 4.8.8) is currently in redesign process (for 4.9).


Patrick.

Github | CodePen | Codier | Simplr theme | Wait Me: a maintenance theme | [\a mi.ni.ma]: a “Low Tech” simple Blog theme.

Offline

#6 2025-06-03 18:06:25

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 11,778
Website GitHub

Re: Inline Microdata vs JSON-LD

Pat64 wrote #339792:

I’m using massively JSON-LD (7 scripts) on this kind of page without any Google Page Speed Insight penalties

Impressive. Pat_speeder I assume, looking at the source? ;)

So how do you build the JSON-LD content? Loop over article tags? And then loop again in the body to render the actual content?

Do you have complex business rules to determine what to display and what not to display on your page in both the head and body areas?

The site I’m working on does. Conditionals for sections, categories, URL params and variables that build various lists and individual article pages from article data.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#7 2025-06-03 19:01:23

jakob
Admin
From: Germany
Registered: 2005-01-20
Posts: 4,925
Website GitHub

Re: Inline Microdata vs JSON-LD

Bloke wrote #339791:

Maybe the bits further down the page (the visitor-visible portions) can actually assemble the JSON-LD structure in a <txp:variable> and then that can be splatted on the page afterwards into the <head> using tag sweep delay.

Yes, that’s what I was thinking. You (sort of) have your logic and output together in one place in your form template (likely several variables that get assembled into a variable holding the relevant json object), but you output the variable with the entire object on second pass at the top (assuming that works).


TXP Builders – finely-crafted code, design and txp

Offline

#8 Yesterday 06:10:39

Pat64
Plugin Author
From: France
Registered: 2005-12-12
Posts: 1,659
GitHub Twitter

Re: Inline Microdata vs JSON-LD

Bloke wrote #339793:

Do you have complex business rules to determine what to display and what not to display on your page in both the head and body areas?

No sorcery. Only forms, as you mentioned. With a combination of if_individual_article and article_custom tags.

Sure, I use pat_speeder, but maybe the website is fast because Textpattern is a good CMS.

Last edited by Pat64 (Yesterday 06:10:59)


Patrick.

Github | CodePen | Codier | Simplr theme | Wait Me: a maintenance theme | [\a mi.ni.ma]: a “Low Tech” simple Blog theme.

Offline

#9 Yesterday 09:02:26

etc
Developer
Registered: 2010-11-11
Posts: 5,393
Website GitHub

Re: Inline Microdata vs JSON-LD

jakob wrote #339794:

You (sort of) have your logic and output together in one place in your form template (likely several variables that get assembled into a variable holding the relevant json object), but you output the variable with the entire object on second pass at the top (assuming that works).

You can use negative values in the processing order to count from the end:

<txp:variable[-1] name="json-ld" />

will be processed last among its txp siblings.

Offline

#10 Yesterday 10:21:53

jakob
Admin
From: Germany
Registered: 2005-01-20
Posts: 4,925
Website GitHub

Re: Inline Microdata vs JSON-LD

I’m not sure what among its txp siblings means, but that works great. You can use

<txp:if_variable[-1] name="json-ld">
<script type="application/ld+json">
{
<txp:variable[-1] name="json-ld" />
}
</script>
</txp:if_variable>

in the <head> and the following (or similar) in your article form:

<txp:variable name="json-ld">
"@context": "https://schema.org/",
"@type": "BlogPosting",
"@id": "<txp:permlink />",
"mainEntityOfPage": "<txp:permlink />",
"headline": "<txp:title escape="json" />",
"name": "<txp:title escape="json" />",
"datePublished": "<txp:posted format="iso8601" />",
"dateModified": "<txp:modified format="iso8601" />",
</txp:variable>

and then add further entries depending on conditionals, e.g.: (see the next post for a neater variant)

<txp:if_comments>
<txp:variable name="json-ld">
<txp:variable name="json-ld" />
"commentCount": "<txp:comments_count />",
</txp:variable>

and so on …

Nice!

PS: I found you also need [-1] after the tag name if using txp:if_variable or txp:evaluate to test for second-pass content.


TXP Builders – finely-crafted code, design and txp

Offline

#11 Yesterday 10:28:23

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 11,778
Website GitHub

Re: Inline Microdata vs JSON-LD

That’s really neat. Maybe I’ll become a JSON-LD convert after all. Thanks for testing.

Is it possible to do this?

<txp:if_comments>
<txp:variable name="json-ld" add>
"commentCount": "<txp:comments_count />",
</txp:variable>
</txp:if_comments>

Docs say the add attribute:

Adds value to the current variable value. If both are numeric and separator is not set, the result is their sum. Otherwise, value is appended as a string, optionally separated by separator

But I’m not sure if that means the value has to be put inside the add attribute itself, or if the container contents will be used if it’s valueless.

If the latter behaviour isn’t available, it sure would be nice if it could do it :) Might require separator="\n" but the newline inside the container may be sufficient.

Failing that, maybe:

<txp:if_comments>
<txp:variable name="json-ld" add='"commentCount": "<txp:comments_count />",' />
</txp:if_comments>

Might work?

Last edited by Bloke (Yesterday 10:32:40)


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#12 Yesterday 11:10:39

jakob
Admin
From: Germany
Registered: 2005-01-20
Posts: 4,925
Website GitHub

Re: Inline Microdata vs JSON-LD

I plugged that all back into the dev demo and … yes, both variants work. That’s even neater. Cool!

(and the new line in the container suffices)


TXP Builders – finely-crafted code, design and txp

Offline

Board footer

Powered by FluxBB