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

[FR] GraphQL query by slug or ID - useful for headless mode #485

Closed dstrunk closed 4 years ago

dstrunk commented 5 years ago

In Craft 3.3, if the headlessMode is set to true, all template routes and URIs are hidden, which makes entry-specific GraphQL SEOmatic queries difficult (if not impossible … I haven't figured out a way, at least). Would it be possible to add the ability to query by slug, or perhaps query by entry ID?

khalwat commented 5 years ago

SEOmatic isn't going to be useful to you if you run Craft in headless mode, because it matches entries for SEO data based on the route.

You can still use Craft CMS "headless" without enabling Headless mode, which is what I'd suggest doing.

khalwat commented 5 years ago

Actually, going to re-open this as a FR

ben-rogerson commented 5 years ago

Wondering if it's possible to add a slug filter? Slug seems to be available while in headlessMode.

Eg:

{
  seomatic(slug:"/", asArray: true) {
    #...
  }
}
Jones-S commented 5 years ago

That would be great. Just before headlessMode I was fetching seomatic like this:

query Seomatic($slug: String!) {
  seomatic(uri: $slug, asArray: true) {
    metaTitleContainer
    metaTagContainer
    metaLinkContainer
    metaJsonLdContainer
  }
}

I don't really understand why this would not work anymore. I do get a return object, but it does not contain my entry SEO.

khalwat commented 5 years ago

SEOmatic will not work if you have headlessMode -- and you do not need headlessMode to be on to use Craft CMS headless.

It removes all concepts of routing and URLs from the CMS, and SEOmatic depends on URLs for the SEO information @Jones-S

To be clear, this is not working:

query Seomatic($slug: String!) {
  seomatic(uri: $slug, asArray: true) {

...because a slug is not the same as a URI, and slugs are not unique site-wide (two sections can have the same slug, for instance)

khalwat commented 5 years ago

@ben-rogerson it's not that simple as just using slug -- many things depend on some concept of URLs.routing, at least currently.

For instance, what should it return for the canonical URL? What about things like HrefLang?

How can it build a sitemap if no entries have URLs? etc, etc.

In most cases, I don't think you should be using headlessMode when running Craft CMS as a headless CMS.

Jones-S commented 5 years ago

Hm but URLs for entries were reintroduced. So that would work again (maybe this is only available on v3.4.x-dev craft branch...)

This should then resolve the question about canonical URLs. Either we could introduce an ENV variable to define the frontendURL, or my frontend can do the completion of the url on its own: /de/my-entry-slug => https://www.frontend.com/de/my-entry-slug.

Also I see that certain things may get difficult, like the sitemap, but I handle this anyway in my nuxt app. So what I really need is just the entry specific SEO and the page-wide SEO.

I like the headlessMode, because it hides a few things, and I think especially it allows to set preview targets for sections: where I can point to my frontend app to display previews. So I really need headlessMode.

khalwat commented 5 years ago

I like headlessMode too! But my current recommendation is to not have it on, unless URLs for entries are re-introduced.

I'm guessing that it is in the 3.4.x branch, because I don't see anything in the changelog about URLs being re-introduced?

https://github.com/craftcms/cms/blob/develop/CHANGELOG-v3.md

As for the preview targets, you can do that whether headless mode is on or off; have a look here:

Headless Preview in Craft CMS

So my current recommendation is to leave headlessMode at default (that is, set to false) to work with SEOmatic. I don't think you'll run into any limitations, people have been using it this way long before the headlessMode flag was introduced.

I get what you're going for, and it's something I need too -- so rest assured, I will make this work. There are just a number of assumptions in SEOmatic about it keying off of a URI-based system, and many SEO tags that by their very nature require URLs.

For the reasons mentioned previously, just using slug alone will not work... slugs are not globally unique.

Jones-S commented 5 years ago

Ok, alright. I was mistaken with the preview targets then :). But anyway, URLs are back as you can see: https://github.com/craftcms/cms/issues/4520#issuecomment-531040417

So I am looking forward to a headlessMode-supporting version. 👍 Thanks for the very quick responses and the good work. Appreciate it.

khalwat commented 5 years ago

Correct, but it is in 3.4.x-dev -- I will be testing that branch with SEOmatic as things proceed.

For now, I would suggest just leaving headlessMode at the default (false) -- everything should work fine.

Jones-S commented 4 years ago

Now that 3.4 is in beta and I see that https://github.com/craftcms/cms/blob/3.4/CHANGELOG-v3.4.md#changed #4520 is in the changelog, do you have an estimate on when we could expect seo to work with graphql in headless mode again?

Just want to plan out an approaching project and decide whether we could be counting on this feature or not. Thank you in advance and cheers.

khalwat commented 4 years ago

To be clear, SEOmatic currently does support GraphQL right now (just with Headless Mode off), and if I'm understanding the changes that were made to Craft CMS, it should work with Headless Mode On in Craft CMS 3.4 without me making any changes.

Have you given it a whirl @Jones-S ?

Jones-S commented 4 years ago

No not yet. I thought if 3.4.x-dev was not supporting it with headless mode true that it would not run with 3.4.beta either. If the thing I did before (mentioned in: https://github.com/nystudio107/craft-seomatic/issues/485#issuecomment-547825595) works again, I am all happy.

As said, haven't had the chance to try ever since (also wasn't expecting that I had to :) )

khalwat commented 4 years ago

It should work -- give it a try with the latest SEOmatic and Craft CMS 3.4.0-beta.5 or later.

I'll leave this issue open until we hear back from you on it.

Jones-S commented 4 years ago

Alright. Thank you for your quick reply. I will try it out, but that won't happen this week anymore... Too busy. I will get back as soon as I tested it. 👍

khalwat commented 4 years ago

Any word on this @Jones-S ?

Jones-S commented 4 years ago

I have not forgotten this, but unfortunately I have been pretty busy with non-development work. I will probably find time for this next week, and I will then get back here. Sorry for the delay.

khalwat commented 4 years ago

Going to assume this is good to go unless I head back otherwise

Jones-S commented 4 years ago

Finally I have time to look into this. Apology for the delay. Unfortunately it does not work like expected. Either I am missing something, which is definitely very probable or it really does not work:

Short wrap up of what I have:

Craft v3.4.8 installed Seomatic v3.2.43 installed.

Craft in Headless mode: true

I should have uris/slugs within headless mode to target specific pages, which I am trying to use with seomatic like:

query Seomatic($slug: String!) {
  seomatic(uri: $slug, asArray: true) {
    metaTitleContainer
    metaTagContainer
    metaLinkContainer
    metaJsonLdContainer
  }
}

and

{
  "slug": "my-page-slug"
}

This only returns a thing like;

{
  "data": {
    "seomatic": {
      "metaTitleContainer": "{\"title\":{\"title\":\"🚧 Craft Demo |\"}}",
      "metaTagContainer": "{\"generator\":{\"content\":\"SEOmatic\",\"name\":\"generator\"},\"keywords\":[],\"description\":[],\"referrer\":{\"content\":\"no-referrer-when-downgrade\",\"name\":\"referrer\"},\"robots\":{\"content\":\"none\",\"name\":\"robots\"},\"fb:profile_id\":[],\"fb:app_id\":[],\"og:locale\":{\"content\":\"en_US\",\"property\":\"og:locale\"},\"og:locale:alternate\":[{\"content\":\"de_CH\",\"property\":\"og:locale:alternate\"},{\"content\":\"en_US\",\"property\":\"og:locale:alternate\"}],\"og:site_name\":{\"content\":\"Craft Demo\",\"property\":\"og:site_name\"},\"og:type\":{\"content\":\"website\",\"property\":\"og:type\"},\"og:url\":{\"content\":\"http://localhost:3000/actions/graphql/api\",\"property\":\"og:url\"},\"og:title\":[],\"og:description\":[],\"og:image\":[],\"og:image:width\":[],\"og:image:height\":[],\"og:image:alt\":[],\"og:see_also\":[],\"google-site-verification\":[],\"bing-site-verification\":[],\"pinterest-site-verification\":[]}",
      "metaLinkContainer": "{\"canonical\":{\"href\":\"http://localhost:3000/meine-deutsche-seite\",\"rel\":\"canonical\"},\"home\":{\"href\":\"http://localhost:3000/\",\"rel\":\"home\"},\"author\":{\"href\":\"http://localhost:3000/humans.txt\",\"rel\":\"author\",\"type\":\"text/plain\"},\"publisher\":[],\"alternate\":[{\"href\":\"http://localhost:3000\",\"hreflang\":\"de-ch\",\"rel\":\"alternate\"},{\"href\":\"http://localhost:3000/meine-deutsche-seite\",\"hreflang\":\"en-us\",\"rel\":\"alternate\"},{\"href\":\"http://localhost:3000/meine-deutsche-seite\",\"hreflang\":\"x-default\",\"rel\":\"alternate\"}]}",
      "metaJsonLdContainer": "{\"mainEntityOfPage\":{\"@context\":\"http://schema.org\",\"@type\":\"WebSite\",\"author\":{\"@id\":\"#identity\"},\"copyrightHolder\":{\"@id\":\"#identity\"},\"creator\":{\"@id\":\"#creator\"},\"mainEntityOfPage\":\"http://localhost:3000/actions/graphql/api\",\"url\":\"http://localhost:3000/actions/graphql/api\"},\"identity\":{\"@context\":\"http://schema.org\",\"@id\":\"#identity\",\"@type\":\"Organization\"},\"creator\":{\"@context\":\"http://schema.org\",\"@id\":\"#creator\",\"@type\":\"Organization\"},\"breadcrumbList\":{\"@context\":\"http://schema.org\",\"@type\":\"BreadcrumbList\",\"description\":\"Breadcrumbs list\",\"itemListElement\":[{\"@type\":\"ListItem\",\"item\":\"http://localhost:3000\",\"name\":\"Homepage\",\"position\":1}],\"name\":\"Breadcrumbs\"}}"
    }
  }
}

I have clearly set some custom SEO values for this page:

image

But they don't show up in the result.

I then thought that maybe my multisite setup has something to do with it. Normally I can pass a "site": "default" for other graphql requests. Seomatic only offers siteId.

I then tried to add that the siteId:

query Seomatic($slug: String!) {
  seomatic(uri: $slug, asArray: true, siteId: 1) {
    metaTitleContainer
    metaTagContainer
    metaLinkContainer
    metaJsonLdContainer
  }
}

but with either siteId = 1, 0, 2. I would always get the empty results from above.

Anything you see I have to change? Anything I am missing? Thank you in advance.

khalwat commented 4 years ago

@Jones-S the screenshot just below "I have clearly set some custom SEO values for this page:" -- what is this from?

Is this from Content SEO settings? Or from an SEO Settings field?

If the latter, what happens if you put settings into Content SEO?

khalwat commented 4 years ago

@Jones-S I think what you are missing is that you need to pass in a full URI

You cannot just pass in a slug

So you'd need something like this:

/blog/my-page-slug

Not just the my-page-slug example you have. Probably you're thinking it's a slug because you have written:

query Seomatic($slug: String!) {

But that parameter is actually a $uri -> https://nystudio107.com/docs/seomatic/Advanced.html#headless-spa-api

Slugs are not unique across sections, so we cannot have you just passing in a slug. You need to pass in a URI.

Jones-S commented 4 years ago

It does indeed work if I change it to /my-page-slug (in this case the page is on root). 👍🏼 Thanks for that!

Unfortunately it does not work with a multilang page, where I have to pass in the language part of the URI:

image

This is where I add the SEO content. It is set on a page entry within the SEO tab. The Seomatic SEO preview shows things correctly.

If I use this: (I will change the name to uri but for now I left it to be slug)

image

It does not show the custom seo text I set for this page.

I tried to pass in the URI as follows: /de/meine-deutsche-seite de/meine-deutsche-seite /meine-deutsche-seite

But none of them works...

(Yesterday I only tried the German entry, that's probably why I did not find anything...)

------ EDIT ------

Sorry, wait. It does work, but now I have to pass in the siteId!

image

Summary:

👍🏼

Jones-S commented 4 years ago

Another question: In my multisite setup I would normally tell graphql which page I want to get content from with the siteHandle.

I now fear that if I use the siteId that this id changes if the craft installation is installed somewhere else. (Just being a burnt child with WordPress experience where everything was linked to changing page ids...)

Am I safe to use the Id that is currently set or would it even be possibility for you to add a distinction of the site via siteHandle as well?

khalwat commented 4 years ago

in Craft, IDs won't change from one site to another but: https://github.com/nystudio107/craft-seomatic/issues/564