nuxt-seomatic-meta
Version:
A Nuxt.js module connecting Nuxt.js to the Craft CMS SEOmatic plugin
136 lines (118 loc) • 4.28 kB
JavaScript
const consola = require('consola')
export default ({ app }) => {
app.seomaticMeta = async function nuxtSeomaticMeta({ fullPath }, id = null) {
const options = <%= serialize(options) %>
// Custom remapping of routes to other routes
// This is so you can grab seomatic data from another page
// Eg: Your nuxt homepage has a slug of '/' but you want data
// from a page in Craft with a slug of 'homepage'
let routeRemapPath
if (
typeof options.routeRemap === 'object' &&
options.routeRemap
) {
const foundRouteRemap = options.routeRemap.find(
({ path }) => path === fullPath,
)
routeRemapPath = foundRouteRemap && foundRouteRemap.getFrom
if (options.debug && routeRemapPath) {
consola.info(
`Getting metadata for '${fullPath}' from '${routeRemapPath}'`,
)
}
}
// Determine route name to use in graphql query
const routeName = routeRemapPath || fullPath
// Retrieve the seomatic graphql data via Axios
if (app.$axios === undefined) {
return consola.error(`SeomaticMeta plugin: Axios not found, add it to your module array like this:\n\nmodules: ['nuxt-seomatic-meta', '@nuxtjs/axios'],`)
}
if (!options.backendUrl) {
return consola.error(`SeomaticMeta plugin: No backendUrl specified`)
}
if (!options.graphqlPath) {
return consola.error(`SeomaticMeta plugin: No graphqlPath specified`)
}
const { data } = await app.$axios.post(
options.backendUrl + options.graphqlPath,
{
query: `
{
seomatic(uri: "${routeName}", asArray: true, siteId: ${id}) {
metaTitleContainer
metaTagContainer
metaLinkContainer
metaScriptContainer
metaJsonLdContainer
}
}
`,
},
{
headers: {
...options.graphqlToken && {Authorization: `Bearer ${options.graphqlToken}`},
},
},
).catch(error => String(error).includes(`failed with status code 403`) ? consola.error(new Error(`SeomaticMeta plugin: Can't connect to Crafts graphQl api, try adjusting the credentials:\n\nbackendUrl: '${options.backendUrl}'\ngraphqlPath: '${options.graphqlPath}'\ngraphqlToken: '${options.graphqlToken}'`)) : '')
if (!data) consola.error(new Error(`No data was returned from Craft`))
if (options.debug) consola.info('Received GraphQl data', data)
// Convert the graphql JSON data to an object so we can work with it
const {
metaTitleContainer: {
title: { title },
},
metaTagContainer,
metaLinkContainer,
metaScriptContainer,
metaJsonLdContainer,
} = Object.entries(data.data.seomatic).reduce(
(acc, [key, value]) => {
acc[key] = JSON.parse(value)
return acc
},
{},
)
// Flatten metaTagContainer values into string
const meta = metaTagContainer
? Object.values(metaTagContainer).reduce((flat, next) =>
{
if (next.name === 'description') {
// Override description tag with updated description
next.hid = 'description';
}
return flat.concat(next);
},
[],
)
: null
// Flatten metaLinkContainer values into string
const link = metaLinkContainer
? Object.values(metaLinkContainer).reduce(
(flat, next) => flat.concat(next),
[],
)
: null
// Convert script data to <script>..</script>
const metaScripts = metaScriptContainer
? Object.values(metaScriptContainer).map(({ script }) => ({
innerHTML: script,
}))
: []
// Convert JsonLd to <script type="application/ld+json">...</script>
const jsonLd = metaJsonLdContainer
? Object.entries(metaJsonLdContainer).map(value => ({
type: 'application/ld+json',
innerHTML: JSON.stringify(value[1]),
}))
: []
// Combine processed script data
const script = [...metaScripts, ...jsonLd]
return {
...(title && { title }),
...(meta && { meta }),
...(link && { link }),
script,
__dangerouslyDisableSanitizers: ['script'],
}
}
}