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

How to convert the SEOMatic GraphQL data into something I can use for Nuxt JS #863

Closed toddpadwick closed 3 years ago

toddpadwick commented 3 years ago

Problem one: Graph QL result is not an array with keys that I can use.

Nuxt JS, which you mention in your documentation requires the asArray setting, which I've done. But the result is still not something I can pass into the nuxt Head object, which requires an array of keys containing strings. The result from Graph QL even with the array set to true, returns a string, containing a json object rather than a json array containing strings. So I cant simply parse the string as a json object and add to the Nuxt Meta object.

Problem two: Nuxt meta site vars, and meta jsonLd - where does this go?

Im not quite sure where to parse the metaJsonLdContainer or the metaSiteVarContainer in Nuxt. do you know what i should do with this?

Problem three: how to parse in the __dangerouslyDisableSanitizers tag and to what object?

Nuxty has a dangerouslyDisableSanitizers tag option which I believe is required for the script and json meta? how do I pass this into the object?

My code so far

Here is my code so far which I've placed in my default Layout.vue component. This however does not work at all because I am aware the json objects do not contain keys, they instead contain strings and also im not sure where the json or site var objects go. The error I get with this is info.meta.filter is not a function but i expect thats the tip of the ice burg of problems here.

Some help would be really appreciated and I expect you'll know what to do here as I know you mention Nuxt as an example use case for the headless API.

<script>
    import GET_SEOMATIC_CONTAINERS from '~/apollo/queries/getSeomaticContainers.gql';

    export default {
        head() {
        return {
            titleTemplate: JSON.parse(this.seomatic.metaTitleContainer),
            meta: JSON.parse(this.seomatic.metaTagContainer),
            link: JSON.parse(this.seomatic.metaLinkContainer),
            link: JSON.parse(this.seomatic.metaLinkContainer),
            script: JSON.parse(this.seomatic.metaScriptContainer),
            json: JSON.parse(this.seomatic.metaJsonLdContainer),
            ?????: JSON.parse(this.seomatic.metaSiteVarsContainer)
            }
        },
        apollo: {
          seomatic: {
            query: GET_SEOMATIC_CONTAINERS,
            prefetch: ({ route }) => (
                { 
                    uri: route.fullPath, 
                    site:"default"  
                }
            ),
            variables () {
                return { 
                    uri: this.$route.fullPath, 
                    site:"default"
                }
            },
            error (error) {
              console.log("error", error);
            },
            result ({ data, loading, networkStatus }) {
                        console.log(data)
            }
          }
        }
    }
</script>

The output of console logging the data object is:

{                                                                                                                                                                                                         17:52:31
  seomatic: {
    metaTitleContainer: '{"title":{"title":"🚧 Function & Form Digital | Homepage"}}',
    metaTagContainer: '{"generator":{"content":"SEOmatic","name":"generator"},"keywords":[],"description":[],"referrer":{"content":"no-referrer-when-downgrade","name":"referrer"},"robots":{"content":"all","name":"robots"},"fb:profile_id":[],"fb:app_id":[],"og:locale":{"content":"en_GB","property":"og:locale"},"og:locale:alternate":[],"og:site_name":{"content":"Function & Form Digital","property":"og:site_name"},"og:type":{"content":"website","property":"og:type"},"og:url":{"content":"http://functionandform-api/","property":"og:url"},"og:title":{"content":"Homepage","property":"og:title"},"og:description":[],"og:image":[],"og:image:width":[],"og:image:height":[],"og:image:alt":[],"og:see_also":[{"content":"https://github.com/functionandform/","property":"og:see_also"},{"content":"https://twitter.com/function_n_form","property":"og:see_also"},{"content":"https://www.facebook.com/functionandformdigital/","property":"og:see_also"},{"content":"https://www.instagram.com/functionandformdigital/","property":"og:see_also"},{"content":"https://dribbble.com/functionandform","property":"og:see_also"}],"twitter:card":{"content":"summary_large_image","name":"twitter:card"},"twitter:site":{"content":"@function_n_form","name":"twitter:site"},"twitter:creator":{"content":"@function_n_form","name":"twitter:creator"},"twitter:title":{"content":"Homepage","name":"twitter:title"},"twitter:description":[],"twitter:image":[],"twitter:image:width":[],"twitter:image:height":[],"twitter:image:alt":[],"google-site-verification":[],"bing-site-verification":[],"pinterest-site-verification":[]}',
    metaLinkContainer: '{"canonical":{"href":"http://functionandform-api","rel":"canonical"},"home":{"href":"http://functionandform-api","rel":"home"},"author":{"href":"http://functionandform-api/humans.txt","rel":"author","type":"text/plain"},"publisher":[],"alternate":[]}',
    metaScriptContainer: '[]',
    metaJsonLdContainer: '{"mainEntityOfPage":{"@context":"http://schema.org","@type":"WebPage","author":{"@id":"#identity"},"copyrightHolder":{"@id":"#identity"},"copyrightYear":"2019","creator":{"@id":"#creator"},"dateModified":"2021-04-01T10:23:44+01:00","datePublished":"2019-12-09T14:39:00+00:00","headline":"Homepage","inLanguage":"en-gb","mainEntityOfPage":"http://functionandform-api/","name":"Homepage","publisher":{"@id":"#creator"},"url":"http://functionandform-api"},"identity":{"@context":"http://schema.org","@id":"#identity","@type":"Organization","sameAs":["https://dribbble.com/functionandform","https://www.instagram.com/functionandformdigital/","https://www.facebook.com/functionandformdigital/","https://twitter.com/function_n_form","https://github.com/functionandform/"]},"creator":{"@context":"http://schema.org","@id":"#creator","@type":"Organization"},"breadcrumbList":{"@context":"http://schema.org","@type":"BreadcrumbList","description":"Breadcrumbs list","itemListElement":[{"@type":"ListItem","item":"http://functionandform-api","name":"Homepage","position":1}],"name":"Breadcrumbs"}}',
    metaSiteVarsContainer: '{"siteName":"Function & Form Digital","identity":{"siteType":"Organization","siteSubType":"LocalBusiness","siteSpecificType":"","computedType":"Organization","genericName":"","genericAlternateName":"","genericDescription":"","genericUrl":"","genericImage":"","genericImageWidth":"","genericImageHeight":"","genericImageIds":[],"genericTelephone":"","genericEmail":"","genericStreetAddress":"","genericAddressLocality":"","genericAddressRegion":"","genericPostalCode":"","genericAddressCountry":"","genericGeoLatitude":"","genericGeoLongitude":"","personGender":"","personBirthPlace":"","organizationDuns":"","organizationFounder":"","organizationFoundingDate":"","organizationFoundingLocation":"","organizationContactPoints":[],"corporationTickerSymbol":"","localBusinessPriceRange":"","localBusinessOpeningHours":[],"restaurantServesCuisine":"","restaurantMenuUrl":"","restaurantReservationsUrl":""},"creator":{"siteType":"Organization","siteSubType":"LocalBusiness","siteSpecificType":"","computedType":"Organization","genericName":"","genericAlternateName":"","genericDescription":"","genericUrl":"","genericImage":"","genericImageWidth":"","genericImageHeight":"","genericImageIds":[],"genericTelephone":"","genericEmail":"","genericStreetAddress":"","genericAddressLocality":"","genericAddressRegion":"","genericPostalCode":"","genericAddressCountry":"","genericGeoLatitude":"","genericGeoLongitude":"","personGender":"","personBirthPlace":"","organizationDuns":"","organizationFounder":"","organizationFoundingDate":"","organizationFoundingLocation":"","organizationContactPoints":[],"corporationTickerSymbol":"","localBusinessPriceRange":"","localBusinessOpeningHours":[],"restaurantServesCuisine":"","restaurantMenuUrl":"","restaurantReservationsUrl":""},"twitterHandle":"function_n_form","facebookProfileId":"","facebookAppId":"","googleSiteVerification":"","bingSiteVerification":"","pinterestSiteVerification":"","sameAsLinks":{"dribbble":{"siteName":"Dribbble","handle":"dribbble","url":"https://dribbble.com/functionandform"},"instagram":{"siteName":"Instagram","handle":"instagram","url":"https://www.instagram.com/functionandformdigital/"},"facebook":{"siteName":"Facebook","handle":"facebook","url":"https://www.facebook.com/functionandformdigital/"},"twitter":{"siteName":"Twitter","handle":"twitter","url":"https://twitter.com/function_n_form"},"github":{"siteName":"GitHub","handle":"github","url":"https://github.com/functionandform/"}},"siteLinksSearchTarget":"","siteLinksQueryInput":"","referrer":"no-referrer-when-downgrade","additionalSitemapUrls":[],"additionalSitemapUrlsDateUpdated":null,"additionalSitemaps":[]}',
    __typename: 'SeomaticType'
  }
}
khalwat commented 3 years ago

Here's an example from @wbrowar that might help you:

https://github.com/wbrowar/workbench/blob/main/_install/_scaffolding/_front-end/mv/front-end/_source/_js/seomatic.ts

https://github.com/wbrowar/workbench/blob/main/_install/_scaffolding/nuxt2/mv/front-end/gql/seomaticGql.js

And one from @benrogerson:

https://github.com/ben-rogerson/nuxt-seomatic-meta/blob/master/lib/plugin.js