[date:html_year] token used on the SEO Tools recipe for meta tags causes the site to be uncacheable

Created on 16 April 2025, 4 days ago

Problem/Motivation

After applying the SEO Tools recipe, the site's x-drupal-dynamic-cache header becomes uncacheable.

The token [date:html_year] relies on the current date, which changes daily and annually. Since the value changes with time but is not tied to user-specific or request-specific cache contexts, Drupal cannot safely cache it without risking outdated output.

Steps to reproduce

Install Drupal CMS. Verify x-drupal-dynamic-cache is a HIT for non-logged in users.
Login and apply the SEO Tools recipe.
Verify x-drupal-dynamic-cache is UNCACHEABLE for non-logged in users.

Proposed resolution

Replace the token with a hard coded year in the 3 metatags. Updated them in 2026.

User interface changes

N/A

Configuration changes

Three meta tag configs.

πŸ› Bug report
Status

Active

Component

Track: SEO

Created by

πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @thejimbirch
  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts

    MR added that replaces the uncacheable token with the current year.

    Steps to validate

    • Install Drupal CMS. Verify x-drupal-dynamic-cache is a HIT for non-logged in users.
    • Login and apply the SEO Tools recipe.
    • Verify x-drupal-dynamic-cache is UNCACHEABLE for non-logged in users.
    • Checkout this issue's branch.
    • Reinstall Drupal CMS using ddev rebuild
    • Login and apply the SEO Tools recipe.
    • Verify x-drupal-dynamic-cache is a HIT for non-logged in users.
  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts
  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    I don't love this, because we are definitely not going to remember to update these in 2026.

    To me, a better solution -- and probably not something we can fix in Drupal CMS specifically -- is that the tokens should influence the cache lifetime. It shouldn't make the page uncacheable. It's just that, if you use, say, the [date:html_year] token, then the maximum cache lifetime is reduced to a day.

    What module defines the [date:html_year] token? If it's core, maybe this is a core bug.

  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts

    I don't love it either, but it will make Drupal CMS cacheable until an upstream solution is finished.

    I believe the date token comes from the Token module.
    https://git.drupalcode.org/project/token/-/blob/8.x-1.x/token.tokens.inc...

    But, I am not 100% sure. I didn't think core would be able to create tokens as it does not require the token module.

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    I still am -1 on implementing this workaround because it's almost guaranteed to turn into long-standing technical debt if the underlying issue doesn't get fixed in a timely fashion.

    A little more research would be ideal, I think -- what would it take to fix this upstream, or at least mitigate it? If the fix is complicated, then okay, what you propose here would be okay as a temporary workaround. But if it's relatively simple -- especially since it's in a contrib module -- we might just be better off getting it fixed there.

  • πŸ‡¦πŸ‡ΊAustralia pameeela

    Wow what a pain. Agree on not hard coding it.

    Do we really need a copyright meta tag? I have never once done this in 14 years of building websites.

  • πŸ‡¬πŸ‡§United Kingdom catch

    There is logic in DateFormatter::format() to dynamically build a max-age based on when the resultant date will turn over. So if there are 200 days until the end of the year, it should produce a max-age that will last for 199 days, but if there are two days, it'd last for 2. Original issue/discussion was in #2500525: Time ago/hence date/time formatting breaks caching; needs appropriate max age β†’ .

    However, I think for rendering dates (for comment posted timestamps etc.) rather than diffs, we concentrated on πŸ› Allow TimestampFormatter to show as a fully cacheable time difference with JS Fixed , this relies on js to transform the timestamp into the date, which won't work for tokens/metatags very well.

    I think that if we could determine the maximum granularity of the date format, we could do a similar max-age trick for any formatted dates too - that would work really well for year, less well for minute. Don't think there is an issue for this.

    More questions though: πŸ› [pp-3] Bubbling of elements' max-age to the page's headers and the page cache Postponed is sort of related but would more likely cause a bug in the other direction (page cache not respecting the max age), so do we actually know where the uncacheable cache metadata is being added? I'm not sure core by default will actually cause this behaviour so it might be a contrib module setting the max-age to 0.

    Also agreed with @pameela in #8, is it needed at all?

  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts

    The use of the "rights" meta tag came from the Drupal 8 SEO Book's recommendations.

    Since Google does not say they support it, lets remove it rather than hard coding it. As a note, Drupal.org doesn't even have a copyright in their footer. General consensus is that copyright is assumed just by publishing websites.

    Moving to Needs Work, and will update MR to remove the tags.

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    In addition to a new issue title and summary, it would be nice to have test coverage in seo_tools to confirm that our meta tags result in a HIT for the x-drupal-dynamic-cache header. Since the recipe already has functional test coverage, this shouldn't be too hard to do.

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    This will also need a change record, since fixing the bug on existing sites will require manual steps.

Production build 0.71.5 2024