Skip to content

Store Product Schema Data in a Transient #22082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
BFTrick opened this issue Feb 28, 2025 · 6 comments
Open

Store Product Schema Data in a Transient #22082

BFTrick opened this issue Feb 28, 2025 · 6 comments
Labels
compatibility: WooCommerce Possible conflict with the Woocommerce plugin. component: performance enhancement

Comments

@BFTrick
Copy link

BFTrick commented Feb 28, 2025

Is your feature request related to a problem? Please describe.

We're doing some performance audits our WooCommerce site.

One of the items raised was the time to generate structured data for each WooCommerce Product. 🕐

With some profiling tools (Blackfire.io) disabling Yoast's structured data saves us ~1.6s to load the page (once you've added a product to the cart and you're bypassing the cache).

Image

We obviously want to keep the structured data. It's helpful for SEO.

But we don't want every user who has a product in their cart to have to wait 1.6s to load structured data (for robots) instead of viewing the product page and adding more products to their cart and checking out.

Here's a 10-min video showing you our profiling tools and how I came up with the 1.6s number: https://youtu.be/EFxhie7VohA

Describe the solution you'd like

Is there a way to save this data in a transient? Or some other mechanism?

Is there a way to optimize this functionality for stores like ours? It seems like there's a lot of repeated images in the structured data.

Here's a diff with structured data on the left (in dev mode) and no structured data on the right: https://www.diffchecker.com/K6YIZyhN/

Why do you think this feature is something we should consider for the Yoast SEO plugins?

Virtually every WooCommerce store could increase their conversion rates & make shoppers happier for uncached pages if we can skip generating structured data on every page load.

Additional context

Here are the two filters I used for testing

  1. add_filter( 'yoast_seo_development_mode', '__return_true' );
  2. add_filter( 'wpseo_json_ld_output', '__return_false' );

We use Variable Products in WooCommerce. The product in question has 6 styles & 16 sizes per style. So there's 96 variations on this page.

So looping through this functionality ~100 times is probably the cause and why smaller sites might not notice the processing time.

@josevarghese
Copy link
Contributor

Hi @BFTrick

Thanks for creating the issue. As you have tested this on the staging site (from the video), can you please confirm whether the same can be replicated on the live site? If the staging site is not set with the WP_ENVIRONMENT_TYPE and if it's set as production, can you please confirm whether the SEO Data Optimization is already completed within the Yoast SEO > Tools page?

I am asking this because, on the staging site, the SEO Data Optimization won't be completed as we restrict the creation of indexable over it. When the indexable is not created on a staging site, generating the schema and meta tags will take some time to process the data from the database.

We look forward to hearing from you more on this.

@BFTrick
Copy link
Author

BFTrick commented Mar 3, 2025

On Production we've optimized our data

Image

On my local environment it's greyed out.

Image

We sanitize our production DB and regularly pull it into our test environments.

Question: is it possible to confirm if the data is optimized in my local environment (even with the button greyed out)?


[C]an you please confirm whether the same can be replicated on the live site?

We unfortunately, don't have profiling on our production site. 😦

However, from an audit, our host did actually cowboy coded a quick fix disabling Yoast and they saw similar results.

So, I dug deeper and found that WooCommerce Product Structured Data (coming from Woo core) is the main culprit. As it runs many complex db queries, content sanitization (that uses RegEx behind the scenes) and other things with in overall with a large website slowing down the website tremendously.

To combat this, I added this code snippet to disable the WooCommerce Structured Data:

add_action('wp_loaded', function() {
remove_action('woocommerce_single_product_summary',
[$GLOBALS['woocommerce']?->structured_data,
'generate_product_data'], 60);
});

add_filter( 'woocommerce_structured_data_product',
function($markup, $product) {
if( is_product() ) {
$markup = '';
}
return $markup;
}, 10, 2 );

Just with these 3-4 lines of code, the dynamic page execution time was reduced by ~60%.

@josevarghese josevarghese added enhancement compatibility: WooCommerce Possible conflict with the Woocommerce plugin. component: performance and removed needs-more-info labels Mar 5, 2025
@josevarghese
Copy link
Contributor

Hi @BFTrick

Thanks for sharing the details.

What's next?
Our product team will assess the severity of the issue and assign a priority level to the report. Our developers work on the highest priority issues first. We cannot give you an estimate of when they'll start working on the issue.

@BFTrick
Copy link
Author

BFTrick commented May 9, 2025

Hey @josevarghese

This is high priority for us.

We're looking to improve performance by adding transient-based caching to Yoast’s schema output.

🙋 Before submitting a formal PR, we’d like to confirm whether this approach aligns with your team’s architecture preferences.

🔄 Two Transient Approaches

Looking at: wordpress-seo/src/presenters/schema-presenter.php

  1. Presentation Layer (in present() method)
    • Cache the final formatted $output that goes in <script type="application/ld+json">.
    • Keyed by post ID (yoast_schema_{post_id}).
    • Cached for 24 hours.
  2. Data Layer (in get() method)
    • Cache the raw schema array before formatting.
    • Keyed by schema type and post ID (yoast_schema_raw_{type}_{post_id}).
    • Pro: cleaner separation of concerns & allows reuse in multiple formats or debug tools.
    • Con: There's still some formatting processing time

🔁 Cache Invalidation

We plan to clear transients on save_post.

Something simple like this:

function clear_yoast_schema_cache($post_id) {
    delete_transient('yoast_schema_raw_product_' . $post_id);
    delete_transient('yoast_schema_' . $post_id);
}
add_action('save_post', 'clear_yoast_schema_cache');

Post Types

The core of our problem comes from Variable Products in WooCommerce with 90+ variations.

This might not be necessary for blog posts, pages, and other posts. Two more choices:

  1. We could add transients for all post types
  2. or we could just add transients for products.

I'm leaning towards just adding transients for products for now.

Pros:

  • It's a smaller risk to roll this out just for products
  • We can add transients for all post types easily enough if there's a need.

🙋 If your dev team can give us some direction. I'm happy to write a PR & test it.

@josevarghese
Copy link
Contributor

Hi @BFTrick

Thank you for taking the time to share your detailed approach with us. I've passed it to our development team for their review and feedback.

I'll update you once I hear back from them. Alternatively, our development team may comment here directly with further feedback.

@josevarghese
Copy link
Contributor

Internal Slack conversation: https://yoast.slack.com/archives/C01NCRHHN30/p1747043963654449

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compatibility: WooCommerce Possible conflict with the Woocommerce plugin. component: performance enhancement
Projects
None yet
Development

No branches or pull requests

2 participants