nystudio107 / craft-seomatic

SEOmatic facilitates modern SEO best practices & implementation for Craft CMS 3. It is a turnkey SEO system that is comprehensive, powerful, and flexible.
https://nystudio107.com/plugins/seomatic
Other
165 stars 70 forks source link

Safari reporting invalid JSON+LD #1408

Closed joshuabaker closed 8 months ago

joshuabaker commented 8 months ago

In Safari, we’re seeing an error parsing the JSON+LD container provided via GraphQL (i.e. metaJsonLdContainer).

Screenshot 2024-01-23 at 15 07 26@2x

Searching online I found a similar issue report on ymmooot/nuxt-jsonld#1280, which ultimately recommends using named graphs when using multi-structured data in one script tag.

Wrapping the JSON+LD response in a @graph also parsed better on the schema.org validator.

Before

{
  "mainEntityOfPage": {
    "@context": "http://schema.org",
    "@type":"WebSite",
    …
  }
}

Screenshot 2024-01-23 at 15 30 21@2x

After

{
  "@context": "http://schema.org",
  "@graph": [
     {
      "@context": "http://schema.org",
      "@type":"WebSite",
      …
    },
    …
  ]
}

Screenshot 2024-01-23 at 15 30 07@2x

I noted that this in included in b9cb42f8ff4b1034a27b3e118d54f3d193cae6d3 and appears to already render out in Twig correctly.

Is this just something that was missed in GraphQL or was that intentional? Are we expected to parse that container and wrap with @graph ourselves.

Versions

khalwat commented 8 months ago

hmmmm. So I did a quick test with this query:

query MyQuery {
  entries(site: ["default"]) {
    url
    language
    seomatic(asArray: false) {
        metaJsonLdContainer
    }
  }
}

...and it returns this data:

{
  "data": {
    "entries": [
      {
        "url": "http://localhost:8004/blog/my-first-blog",
        "language": "en-US",
        "seomatic": {
          "metaJsonLdContainer": "<script type=\"application/ld+json\">\n{\n    \"@context\": \"http://schema.org\",\n    \"@graph\": [\n        {\n            \"@type\": \"WebPage\",\n            \"author\": {\n                \"@id\": \"#identity\"\n            },\n            \"copyrightHolder\": {\n                \"@id\": \"#identity\"\n            },\n            \"copyrightYear\": \"2021\",\n            \"creator\": {\n                \"@id\": \"#creator\"\n            },\n            \"dateCreated\": \"2021-03-15T11:41:19-04:00\",\n            \"dateModified\": \"2021-03-15T12:17:36-04:00\",\n            \"datePublished\": \"2021-03-15T11:40:00-04:00\",\n            \"headline\": \"My first blog\",\n            \"inLanguage\": \"en-us\",\n            \"mainEntityOfPage\": \"http://localhost:8004/blog/my-first-blog\",\n            \"name\": \"My first blog\",\n            \"publisher\": {\n                \"@id\": \"#creator\"\n            },\n            \"url\": \"http://localhost:8004/blog/my-first-blog\"\n        },\n        {\n            \"@id\": \"#identity\",\n            \"@type\": \"Organization\"\n        },\n        {\n            \"@id\": \"https://nystudio107.com/#creator\",\n            \"@type\": \"Organization\",\n            \"address\": {\n                \"@type\": \"PostalAddress\",\n                \"addressCountry\": \"US\",\n                \"addressLocality\": \"Webster\",\n                \"addressRegion\": \"NY\",\n                \"postalCode\": \"14580\"\n            },\n            \"alternateName\": \"nys\",\n            \"description\": \"We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO\",\n            \"email\": \"info@nystudio107.com\",\n            \"founder\": \"Andrew Welch, Polly Welch\",\n            \"foundingDate\": \"2013-05-02\",\n            \"foundingLocation\": \"Webster, NY\",\n            \"image\": {\n                \"@type\": \"ImageObject\",\n                \"height\": \"1042\",\n                \"url\": \"https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/site/nys_logo_seo.png\",\n                \"width\": \"1042\"\n            },\n            \"name\": \"nystudio107\",\n            \"url\": \"https://nystudio107.com\"\n        },\n        {\n            \"@type\": \"BreadcrumbList\",\n            \"description\": \"Breadcrumbs list\",\n            \"itemListElement\": [\n                {\n                    \"@type\": \"ListItem\",\n                    \"item\": \"http://localhost:8004\",\n                    \"name\": \"Homepage\",\n                    \"position\": 1\n                },\n                {\n                    \"@type\": \"ListItem\",\n                    \"item\": \"http://localhost:8004/blog/my-first-blog\",\n                    \"name\": \"My first blog\",\n                    \"position\": 2\n                }\n            ],\n            \"name\": \"Breadcrumbs\"\n        }\n    ]\n}\n</script>"
        }
      },
      {
        "url": "http://localhost:8004/",
        "language": "en-US",
        "seomatic": {
          "metaJsonLdContainer": "<script type=\"application/ld+json\">\n{\n    \"@context\": \"http://schema.org\",\n    \"@graph\": [\n        {\n            \"@type\": \"WebPage\",\n            \"author\": {\n                \"@id\": \"#identity\"\n            },\n            \"copyrightHolder\": {\n                \"@id\": \"#identity\"\n            },\n            \"copyrightYear\": \"2020\",\n            \"creator\": {\n                \"@id\": \"#creator\"\n            },\n            \"dateCreated\": \"2020-03-27T09:38:49-04:00\",\n            \"dateModified\": \"2024-01-19T14:27:02-05:00\",\n            \"datePublished\": \"2020-03-27T09:38:00-04:00\",\n            \"headline\": \"Homepage\",\n            \"inLanguage\": \"en-us\",\n            \"mainEntityOfPage\": \"http://localhost:8004/\",\n            \"name\": \"Homepage\",\n            \"publisher\": {\n                \"@id\": \"#creator\"\n            },\n            \"url\": \"http://localhost:8004\"\n        },\n        {\n            \"@id\": \"#identity\",\n            \"@type\": \"Organization\"\n        },\n        {\n            \"@id\": \"https://nystudio107.com/#creator\",\n            \"@type\": \"Organization\",\n            \"address\": {\n                \"@type\": \"PostalAddress\",\n                \"addressCountry\": \"US\",\n                \"addressLocality\": \"Webster\",\n                \"addressRegion\": \"NY\",\n                \"postalCode\": \"14580\"\n            },\n            \"alternateName\": \"nys\",\n            \"description\": \"We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO\",\n            \"email\": \"info@nystudio107.com\",\n            \"founder\": \"Andrew Welch, Polly Welch\",\n            \"foundingDate\": \"2013-05-02\",\n            \"foundingLocation\": \"Webster, NY\",\n            \"image\": {\n                \"@type\": \"ImageObject\",\n                \"height\": \"1042\",\n                \"url\": \"https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/site/nys_logo_seo.png\",\n                \"width\": \"1042\"\n            },\n            \"name\": \"nystudio107\",\n            \"url\": \"https://nystudio107.com\"\n        },\n        {\n            \"@type\": \"BreadcrumbList\",\n            \"description\": \"Breadcrumbs list\",\n            \"itemListElement\": [\n                {\n                    \"@type\": \"ListItem\",\n                    \"item\": \"http://localhost:8004\",\n                    \"name\": \"Homepage\",\n                    \"position\": 1\n                }\n            ],\n            \"name\": \"Breadcrumbs\"\n        }\n    ]\n}\n</script>"
        }
      }
    ]
  }
}

...which does have the @context in there... what are we doing different?

joshuabaker commented 8 months ago

We’ve got asArray set to true. Perhaps a misunderstanding, but we’d expected that to just return the raw tag content.

I can see that the docs show the response is keyed by the schema type. Is there a reason for that?

khalwat commented 8 months ago

Yeah if you request it asArray: true you're expected to then render the data using whatever framework you're using on your end. Some of them will already wrap it in @graph, some won't.

The rationale is that if you do asArray: true you just want the data, and what you do with it after that is up to you and the framework you're using to do the rendering.

joshuabaker commented 8 months ago

Safari is expecting @context at the top level. Chrome and others seem to silently handle just passing an object in, which I think might actually be invalid.

I’ve added a fix to the Next components we use: joshuabaker/next-seomatic@f7f64692306b5953ff743591bae9ef84d29b2ffe. Is this how you imagined front-ends would handle this?

joshuabaker commented 8 months ago

Thanks, @khalwat. Really appreciate the speedy response. 🙏🏻

Will sort this end.