Skip to content

Commit

Permalink
feat: canonicalQueryWhitelist (#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
harlan-zw authored Aug 6, 2024
1 parent d124e81 commit 568c2b7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 8 deletions.
33 changes: 27 additions & 6 deletions docs/content/0.nuxt-seo/2.guides/2.default-meta.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,36 @@ description: The default meta tags Nuxt SEO sets for you.
To ensure your site is SEO friendly, Nuxt SEO sets some default meta tags for you based
on your [site config](/nuxt-seo/guides/configuring-modules).

## Canonical
## Canonical URL

Ensuring a canonical URL is set helps avoid [duplicate content issues](https://support.google.com/webmasters/answer/66359?hl=en)
when you have multiple domains or subdomains pointing to the same content.
Ensuring a canonical URL is set helps avoid [duplicate content issues](https://support.google.com/webmasters/answer/66359?hl=en).

It can also occur when you have multiple URLs for the same page, such as when you don't redirect
[trailing slashes](/nuxt-seo/guides/trailing-slashes).
This can be an issue when you have multiple domains or subdomains pointing to the same content,
[trailing slashes](/nuxt-seo/guides/trailing-slashes) and non-trailing slashes showing the same content
and when you have query parameters that don't change the content.

The canonical will be set based on your site config `url` and the current route.
The canonical URL is generated from your site config `url`, the current route and the `canonicalQueryWhitelist`.

### canonicalQueryWhitelist

By default, the `canonicalQueryWhitelist` includes a number of common query parameters that will modify the page content:

- `page`
- `sort`
- `filter`
- `search`
- `q`
- `query`

You can override this by providing your own list of query parameters that should be included in the canonical URL.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
seo: {
canonicalQueryWhitelist: ['myCustomQuery']
}
})
```

## I18n

Expand Down
16 changes: 16 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export interface ModuleOptions {
* @default true
*/
automaticDefaults?: boolean
/**
* When enabled, it will whitelist the query parameters that are allowed in the canonical URL.
*/
canonicalQueryWhitelist?: string[]
/**
* When enabled, it will redirect any request to the canonical domain (site url) using a 301 redirect on non-dev environments.
*
Expand Down Expand Up @@ -105,6 +109,18 @@ export default defineNuxtModule<ModuleOptions>({
for (const module of Modules)
await installModule(await resolvePath(module))

nuxt.options.runtimeConfig.public['nuxt-seo'] = {
canonicalQueryWhitelist: config.canonicalQueryWhitelist || [
'page',
'sort',
'filter',
'search',
'q',
'category',
'tag',
],
}

if (config.automaticDefaults) {
// i18n complicates things, we need to run the server plugin at the right time, client is fine
if (hasNuxtModule('@nuxtjs/i18n')) {
Expand Down
18 changes: 16 additions & 2 deletions src/runtime/nuxt/logic/applyDefaults.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import type { UseHeadOptions, UseSeoMetaInput } from '@unhead/vue'
import type { QueryObject } from 'ufo'
import { stringifyQuery } from 'ufo'
import {
computed,
createSitePathResolver,
useHead,
useRoute,
useRuntimeConfig,
useSeoMeta,
useServerHead,
useSiteConfig,
} from '#imports'

export function applyDefaults() {
// get the head instance
const { canonicalQueryWhitelist } = useRuntimeConfig().public['nuxt-seo']
const siteConfig = useSiteConfig()
const route = useRoute()
const resolveUrl = createSitePathResolver({ withBase: true, absolute: true })
const canonicalUrl = computed<string>(() => resolveUrl(route.path || '/').value || route.path)
const canonicalUrl = computed<string>(() => {
const { query } = route
const url = resolveUrl(route.path || '/').value || route.path
// apply canonicalQueryWhitelist to query
const filteredQuery = Object.fromEntries(
Object.entries(query).filter(([key]) => canonicalQueryWhitelist.includes(key)),
) as QueryObject
return Object.keys(filteredQuery).length
? `${url}?${stringifyQuery(filteredQuery)}`
: url
})

const minimalPriority: UseHeadOptions = {
// give nuxt.config values higher priority
Expand All @@ -24,7 +38,7 @@ export function applyDefaults() {
// needs higher priority
useHead({
link: [{ rel: 'canonical', href: () => canonicalUrl.value }],
})
}, minimalPriority)
const locale = siteConfig.currentLocale || siteConfig.defaultLocale
if (locale) {
useServerHead({
Expand Down

0 comments on commit 568c2b7

Please sign in to comment.