SEO JSON-LD improvement
This commit is contained in:
parent
d6884ba09c
commit
ecd2829c95
@ -24,7 +24,7 @@ export function usePageMeta () {
|
||||
|
||||
// Canonical URL
|
||||
const config = useRuntimeConfig()
|
||||
const canonical = `${config.public.appUrl}${route.path}`
|
||||
const canonical = `${config.public.appUrl}${page.pageLink}`
|
||||
|
||||
// Robots Meta Tag
|
||||
const robotsContent = route.path === '/danke' ? 'noindex, nofollow' : 'index, follow'
|
||||
@ -83,6 +83,7 @@ export function usePageMeta () {
|
||||
{ property: 'og:title', content: metaTitle },
|
||||
{ property: 'og:description', content: metaDescription },
|
||||
{ property: 'og:image', content: metaImage },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ name: 'twitter:title', content: metaTitle },
|
||||
{ name: 'twitter:description', content: metaDescription },
|
||||
{ name: 'twitter:image', content: metaImage }
|
||||
|
||||
@ -17,7 +17,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Nuxt 3 behandelt den 404-Status automatisch
|
||||
import { createError } from 'nuxt/app'
|
||||
|
||||
// Wichtig: Der 404-Status **muss hier geworfen werden**
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Seite nicht gefunden'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
import { useHtmlConverter } from '@/composables/useHTMLConverter'
|
||||
import SideBarNaviSlider from '@/components/SideBarNaviSlider.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
|
||||
const route = useRoute()
|
||||
const slug = route.params.link
|
||||
@ -71,8 +72,6 @@
|
||||
if (!articles.value) return null
|
||||
return articles.value.find(item => item.slug === slug) ?? null
|
||||
})
|
||||
|
||||
|
||||
|
||||
const { convertToHTML } = useHtmlConverter()
|
||||
const htmlContent = (content) => convertToHTML(content)
|
||||
@ -87,6 +86,74 @@
|
||||
const d = new Date(article.value.dateModified)
|
||||
return d.toLocaleDateString('de-DE')
|
||||
})
|
||||
|
||||
// ARTIKEL META AND JSON_LD INFOS
|
||||
watchEffect(() => {
|
||||
if (!article.value) return
|
||||
|
||||
const truncate = (text, maxLength) => {
|
||||
if (!text) return ''
|
||||
return text.length <= maxLength ? text : text.slice(0, maxLength - 1).trimEnd() + '…'
|
||||
}
|
||||
|
||||
const rawTitle = article.value.header
|
||||
const rawDescription = article.value.teaser
|
||||
|
||||
const metaTitle = truncate(rawTitle, 60)
|
||||
const metaDescription = truncate(rawDescription, 160)
|
||||
const metaImage = `${runtimeConfig.public.cmsBaseUrl}${article.value.image?.url}` || 'https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png'
|
||||
const metaKeywords = article.value.SEO?.keywords || ''
|
||||
const metaType = article.value.SEO?.type || 'article'
|
||||
const canonical = `${runtimeConfig.public.appUrl}${route.fullPath}`
|
||||
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'NewsArticle',
|
||||
headline: rawTitle,
|
||||
image: [metaImage],
|
||||
datePublished: article.value.dateCreated,
|
||||
dateModified: article.value.dateModified,
|
||||
author: {
|
||||
'@type': 'Person',
|
||||
name: author
|
||||
},
|
||||
publisher: {
|
||||
'@type': 'Organization',
|
||||
name: 'digimedialoop',
|
||||
logo: {
|
||||
'@type': 'ImageObject',
|
||||
url: 'https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png'
|
||||
}
|
||||
},
|
||||
description: metaDescription
|
||||
}
|
||||
|
||||
useHead({
|
||||
title: metaTitle,
|
||||
meta: [
|
||||
{ name: 'description', content: metaDescription },
|
||||
{ name: 'keywords', content: metaKeywords },
|
||||
{ name: 'robots', content: 'index, follow' },
|
||||
{ property: 'og:title', content: metaTitle },
|
||||
{ property: 'og:description', content: metaDescription },
|
||||
{ property: 'og:image', content: metaImage },
|
||||
{ property: 'og:type', content: metaType },
|
||||
{ name: 'twitter:title', content: metaTitle },
|
||||
{ name: 'twitter:description', content: metaDescription },
|
||||
{ name: 'twitter:image', content: metaImage }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'canonical', href: canonical }
|
||||
],
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLd)
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="sass">
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
format="webp"
|
||||
sizes="100vw"
|
||||
class="background-image"
|
||||
alt=""
|
||||
alt="AI and human"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div class="container-15 content">
|
||||
|
||||
@ -100,12 +100,9 @@ const localePath = useLocalePath()
|
||||
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/stores/main'
|
||||
const mainStore = useMainStore()
|
||||
const { cmsUrl, projects, dataFetched } = storeToRefs(mainStore)
|
||||
const project = computed(() => mainStore.getProjectByLink(route.params.link))
|
||||
const customer = computed(() => {
|
||||
if (!project.value || !project.value.customer) return null
|
||||
@ -125,8 +122,6 @@ watch(project, (newProject) => {
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
import { useHtmlConverter } from '@/composables/useHTMLConverter'
|
||||
const { convertToHTML } = useHtmlConverter()
|
||||
const htmlContent = (data: string) => {
|
||||
@ -138,7 +133,83 @@ const setCurrentImage = (image: any) => {
|
||||
currentImage.value = image
|
||||
}
|
||||
|
||||
// META INFO UND JSON_LD für Projekte
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
watchEffect(() => {
|
||||
if (!project.value) return
|
||||
|
||||
const metaTitle = project.value.projectTitle.length > 60
|
||||
? project.value.projectTitle.slice(0, 57).trim() + '…'
|
||||
: project.value.projectTitle
|
||||
|
||||
const firstParagraph = project.value.projectDescription?.[0]?.children?.[0]?.text || ''
|
||||
const metaDescription = firstParagraph.length > 160
|
||||
? firstParagraph.slice(0, 157).trim() + '…'
|
||||
: firstParagraph
|
||||
|
||||
const customerCompany = project.value.customer?.company || ''
|
||||
const customerCity = project.value.customer?.city || ''
|
||||
|
||||
const technologyKeywords = project.value.technologies?.map(t => t.titel).join(', ') || ''
|
||||
const metaKeywords = [customerCompany, customerCity, technologyKeywords]
|
||||
.filter(Boolean)
|
||||
.join(', ')
|
||||
|
||||
const metaImage = project.value.projectImages?.[0]?.url
|
||||
? `${runtimeConfig.public.cmsBaseUrl}${project.value.projectImages[0].url}`
|
||||
: 'https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png'
|
||||
|
||||
const canonical = `${runtimeConfig.public.appUrl}${route.fullPath}`
|
||||
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "CreativeWork",
|
||||
name: project.value.projectTitle,
|
||||
description: metaDescription,
|
||||
url: canonical,
|
||||
image: metaImage,
|
||||
datePublished: project.value.launchDate,
|
||||
author: {
|
||||
"@type": "Organization",
|
||||
name: "digimedialoop"
|
||||
},
|
||||
publisher: {
|
||||
"@type": "Organization",
|
||||
name: "digimedialoop",
|
||||
logo: {
|
||||
"@type": "ImageObject",
|
||||
url: "https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useHead({
|
||||
title: metaTitle,
|
||||
meta: [
|
||||
{ name: 'description', content: metaDescription },
|
||||
{ name: 'keywords', content: metaKeywords },
|
||||
{ name: 'robots', content: 'index, follow' },
|
||||
{ property: 'og:title', content: metaTitle },
|
||||
{ property: 'og:description', content: metaDescription },
|
||||
{ property: 'og:image', content: metaImage },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ name: 'twitter:title', content: metaTitle },
|
||||
{ name: 'twitter:description', content: metaDescription },
|
||||
{ name: 'twitter:image', content: metaImage }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'canonical', href: canonical }
|
||||
],
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLd)
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
||||
@ -84,7 +84,7 @@ function toggleContactBubble() {
|
||||
// Erstelle das JSON-LD für alle Projekte
|
||||
const jsonLdProjects = computed(() => {
|
||||
if (!projects.value || !Array.isArray(projects.value) || projects.value.length === 0) return null;
|
||||
|
||||
|
||||
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
||||
|
||||
return {
|
||||
@ -92,15 +92,19 @@ const jsonLdProjects = computed(() => {
|
||||
"@type": "ItemList",
|
||||
"itemListElement": projects.value.map((project, index) => ({
|
||||
"@type": "ListItem",
|
||||
"position": index + 1,
|
||||
"url": origin + (project.link ? getProjectLink(project.link) : ''),
|
||||
"position": index + 1,
|
||||
"item": {
|
||||
"@type": "CreativeWork", // alternativ "WebPage", wenn es sich um Projektseiten handelt
|
||||
"@id": origin + (project.link ? getProjectLink(project.link) : ''),
|
||||
"name": project.projectTitle || 'Projekt',
|
||||
"image": cmsUrl + (project.projectImages?.[0]?.url) || '',
|
||||
"image": cmsUrl + (project.projectImages?.[0]?.url || ''),
|
||||
"description": project.projectDescription?.[0]?.children?.[0]?.text || ''
|
||||
}))
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// useHead einbinden, wenn Projekte da sind
|
||||
watchEffect(() => {
|
||||
if (jsonLdProjects.value) {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
src="/uploads/large_DML_Home_Hero_4f27bc7f8e.webp"
|
||||
class="hero-bg"
|
||||
sizes="sm:100vw md:100vw lg:100vw"
|
||||
alt=""
|
||||
alt="website example"
|
||||
aria-hidden="true"
|
||||
priority
|
||||
loading="eager"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user