Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 100 additions & 23 deletions app/components/wp-seo.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
<template>
<div class="wp-seo">
<!-- Print content to page for SEO gain -->
<h1
v-if="parsedTitle"
v-html="parsedTitle"
/>
>
{{ parsedTitle }}
</h1>
<div
v-if="parsedDescription"
v-html="parsedDescription"
/>
>
{{ parsedDescription }}
</div>
</div>
</template>

<script setup lang="ts">
import keysToCamelCase from '~/utils/keysToCamelCase'

interface WpSeoData {
title?: string
content?: string
featuredMedia?: {
src?: string
}
}

interface SiteSettings {
title?: string
description?: string
themeScreenshotUrl?: string
frontendUrl?: string
}

const siteStore = useSiteStore()
const route = useRoute()

Expand All @@ -33,41 +51,100 @@ const props = defineProps({
imageUrl: {
type: String,
default: ''
},
fetchSeo: {
type: Boolean,
default: true
}
})

// Fetch data from WP
const parsedPath = computed<string>(() => props.path || route.path || '')

// Fetch data from WP
const { data, error } = await useWpFetch(`/post`, {
query: {
uri: parsedPath
// Use useAsyncData for SEO data - must run server-side
const { data: wpData } = useAsyncData(
// Dynamic key based on path for proper caching
() => `seo-${parsedPath.value}`,
async () => {
if (!props.fetchSeo) {
return {} as WpSeoData
}

const baseURL = useRuntimeConfig().public.wordpressApiUrl
const { enabled } = usePreviewMode()

const response = await $fetch(`/post`, {
baseURL,
query: {
uri: parsedPath.value
},
credentials: enabled.value ? 'include' : undefined,
server: !enabled.value
})

const transformedData = keysToCamelCase(response || {}) as WpSeoData
return transformedData
},
pick: ['title', 'excerpt', 'content', 'featuredMedia'],
onResponseError() {
console.warn('<wp-seo> Fetch Error:', parsedPath.value)
}
})

// On error, set data to empty object
if (error.value) {
data.value = {}
}
{
// Run on server side for SEO
server: true,
default: () => ({} as WpSeoData)
}
)

// Computeds
const parsedTitle = computed<string>(() => props.title || data.value?.title || siteStore.settings?.title || undefined)
const parsedDescription = computed<string>(() => props.description || data.value?.excerpt || data.value?.content || siteStore.settings.description || undefined)
const parsedImage = computed<string>(() => props.imageUrl || data.value?.featuredMedia?.src || siteStore.settings?.themeScreenshotUrl || undefined)
const parsedTitle = computed<string | undefined>(() =>
props.title
|| wpData.value?.title
|| (siteStore.settings as SiteSettings)?.title
|| undefined
)

const parsedDescription = computed<string | undefined>(() =>
props.description
|| wpData.value?.content
|| (siteStore.settings as SiteSettings)?.description
|| undefined
)

const parsedImage = computed<string | undefined>(() =>
props.imageUrl
|| wpData.value?.featuredMedia?.src
|| (siteStore.settings as SiteSettings)?.themeScreenshotUrl
|| undefined
)

// Get site URL from store
const siteUrl = computed(() => {
const settings = siteStore.settings as SiteSettings
return settings?.frontendUrl || ''
})

// Set meta tags
useSeoMeta({
title: () => parsedTitle.value,
ogTitle: () => parsedTitle.value,
description: () => parsedDescription.value,
ogDescription: () => parsedDescription.value,
ogImage: () => parsedImage.value
ogImage: () => parsedImage.value,
ogType: () => 'website',
ogUrl: () => `${siteUrl.value}${route.path}`,
twitterCard: () => 'summary_large_image',
twitterTitle: () => parsedTitle.value,
twitterDescription: () => parsedDescription.value,
twitterImage: () => parsedImage.value,
robots: () => 'index, follow'
})

// Set canonical URL
useHead(() => ({
link: [
{
rel: 'canonical',
href: `${siteUrl.value}${route.path}`
}
]
}))
</script>

<style scoped>
Expand Down
34 changes: 34 additions & 0 deletions app/pages/shop.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template>
<div class="shop">
Shop page here
</div>
</template>

<script setup lang="ts">
// Props

// Data

// Computed

// Methods

// Watchers

// Lifecycle Hooks
</script>

<style scoped>
.shop {
/* Hover */
@media (--has-hover) {
}
/* Breakpoints */
@media (--gt-cinema) {
}
@media (--lt-tablet) {
}
@media (--lt-phone) {
}
}
</style>