Closed Barbapapazes closed 9 months ago
If the answer is hard-coded, it's a litle better but it don't support multiple answers:
<template>
<SchemaOrgQuestion>
<template #name>
question 1
</template>
<template #acceptedAnswer>
<div>
anwser 1
</div>
</template>
</SchemaOrgQuestion>
</template>
will produce
{
"@context": "https://schema.org",
"@graph": [
{
"@id": "https://le-classement.fr/#identity",
"@type": "Organization",
"name": "Le Classement des Associations",
"url": "https://le-classement.fr",
"logo": {
"@id": "https://le-classement.fr/#logo"
},
"sameAs": [
"https://www.linkedin.com/company/classement-des-associations/",
"https://www.instagram.com/classementdesassociations/",
"https://twitter.com/Leclassement"
]
},
{
"@id": "https://le-classement.fr/#website",
"@type": "WebSite",
"inLanguage": "fr-FR",
"name": "Le Classement des Associations",
"url": "https://le-classement.fr",
"publisher": {
"@id": "https://le-classement.fr/#identity"
}
},
{
"@id": "https://le-classement.fr/faq/#webpage",
"description": "Retrouve toutes les réponses aux questions les plus fréquentes sur le Classement des Associations.",
"name": "Questions / Réponses",
"url": "https://le-classement.fr/faq",
"@type": [
"WebPage",
"FAQPage"
],
"about": {
"@id": "https://le-classement.fr/#identity"
},
"isPartOf": {
"@id": "https://le-classement.fr/#website"
},
"mainEntity": [
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4"
}
],
"primaryImageOfPage": {
"@id": "https://le-classement.fr/#logo"
}
},
{
"@id": "https://le-classement.fr/faq/#/schema/question/759a0d4",
"@type": "Question",
"inLanguage": "fr-FR",
"name": "question 1",
"acceptedAnswer": {
"@type": "Answer",
"text": "anwser 1"
}
},
{
"@id": "https://le-classement.fr/#logo",
"@type": "ImageObject",
"caption": "Le Classement des Associations",
"contentUrl": "https://le-classement.fr/logo.png",
"inLanguage": "fr-FR",
"url": "https://le-classement.fr/logo.png"
}
]
}
It's like the content from MD files wasn't resolved before the schema.
Hey @Barbapapazes
The issue is that you can't render components within the slot of the Schema, this is actually a Vue limitation in how the render tree works. It will only detect shallow string nodes.
Either you can just provide markdown in the schema content, or you can use the useUnwrap
composable from nuxt content (essentially what <ContentSlot>
does).
HTML is accepted afaik, not sure about markdown but don't think Google would penalize you for it.
<script setup lang="ts">
const { flatUnwrap } = useUnwrap()
</script>
<template>
<SchemaOrgQuestion>
<template #name>
{{ flatUnwrap($slots.question) }}
</template>
<template #acceptedAnswer>
{{ flatUnwrap($slots.answer) }}
</transition>
</template>
It might be easier to work with using useSchemaOrg
with defineQuestion
Try to use composable:
<script lang="ts" setup>
const { unwrap } = useUnwrap();
const slots = useSlots();
const question = slots.question;
const answer = slots.answer;
useSchemaOrg([
defineQuestion({
name: unwrap(question),
acceptedAnswer: "Le classement des associations est un classement des associations les plus influentes en France. Il est établi par un algorithme qui prend en compte les données publiques disponibles sur les associations. Il est mis à jour chaque année.",
}),
]);
</script>
But got this error (same with flatUnwrap
)
You need to call the slot function don't you? Also flat unwrap is better
First, I've an issue with the type.
- MaybeComputedRefOrPromise<string & VNode<RendererNode, RendererElement, { [key: string]: any; }>[]> | undefined
+ MaybeComputedRefOrPromise<string | VNode<RendererNode, RendererElement, { [key: string]: any; }>[]> | undefined
It must be a string or a VNode?
And I've got the same issue when calling slots (I totally forgot to do it)
<script lang="ts" setup>
const { flatUnwrap } = useUnwrap();
const slots = useSlots();
if (!slots.question) {
throw new Error("FaqQuestion: missing question slot");
}
const question = slots.question();
const flatQuestion = flatUnwrap(question);
useSchemaOrg([
defineQuestion({
name: flatQuestion, // question will throw the same issue about reading modules
acceptedAnswer: "Le classement des associations est un classement des associations les plus influentes en France. Il est établi par un algorithme qui prend en compte les données publiques disponibles sur les associations. Il est mis à jour chaque année.",
}),
]);
</script>
Hey @Barbapapazes
The issue is that you can't render components within the slot of the Schema, this is actually a Vue limitation in how the render tree works. It will only detect shallow string nodes.
Either you can just provide markdown in the schema content, or you can use the
useUnwrap
composable from nuxt content (essentially what<ContentSlot>
does).HTML is accepted afaik, not sure about markdown but don't think Google would penalize you for it.
<script setup lang="ts"> const { flatUnwrap } = useUnwrap() </script> <template> <SchemaOrgQuestion> <template #name> {{ flatUnwrap($slots.question) }} </template> <template #acceptedAnswer> {{ flatUnwrap($slots.answer) }} </transition> </template>
It might be easier to work with using
useSchemaOrg
withdefineQuestion
This doesn't work. Vite return an error.
} excerpt=false tag="div" >
[nitro] [dev] [unhandledRejection] [[vite-node] [plugin:vite:import-analysis] [VITE_ERROR] /components/content/molecules/Disclosure.vue
<br><pre>import { SchemaOrgQuestion as __nuxt_component_0 } from "@unhead/schema-org-vue";
import { default as __nuxt_component_1 } from "C:/Users/esoubiran/projects/le-classement.fr/node_modules/@nuxt/content/dist/runtime/components/ContentSlot.vue";
import { default as __nuxt_component_2 } from "C:/Users/esoubiran/projects/le-classement.fr/components/atoms/icons/ArrowBottom.vue";
import { ref } from 'vue';
import { defineComponent as _defineComponent } from "vue";
import { flatUnwrap } from "@nuxt/content/dist/runtime/markdown-parser/utils/node";
const _sfc_main = /* @__PURE__ */ _defineComponent({
__name: "Disclosure",
setup(__props, { expose }) {
expose();
const open = ref(false);
const __returned__ = { open, get flatUnwrap() {
return flatUnwrap;
} };
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
return __returned__;
}
});
import { resolveComponent as _resolveComponent, withCtx as _withCtx, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createVNode as _createVNode, vShow as _vShow, withDirectives as _withDirectives, Transition as _Transition } from "vue";
import { ssrRenderComponent as _ssrRenderComponent, ssrRenderStyle as _ssrRenderStyle, ssrInterpolate as _ssrInterpolate } from "vue/server-renderer";
function _sfc_ssrRender(_ctx, _push, _parent, _attrs, $props, $setup, $data, $options) {
const _component_SchemaOrgQuestion = __nuxt_component_0;
const _component_ContentSlot = __nuxt_component_1;
const _component_AtomsIconsArrowBottom = __nuxt_component_2;
_push(_ssrRenderComponent(_component_SchemaOrgQuestion, _attrs, {
name: _withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`${_ssrInterpolate($setup.flatUnwrap(_ctx.$slots.question))}`);
} else {
return [
_createTextVNode(_toDisplayString($setup.flatUnwrap(_ctx.$slots.question)), 1)
];
}
}),
acceptedAnswer: _withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`<div${_scopeId}>`);
_push2(_ssrRenderComponent(_component_ContentSlot, {
use: _ctx.$slots.answer
}, null, _parent2, _scopeId));
_push2(`</div>`);
} else {
return [
_createVNode("div", null, [
_createVNode(_component_ContentSlot, {
use: _ctx.$slots.answer
}, null, 8, ["use"])
])
];
}
}),
default: _withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`<article class="pb-4 flex flex-col border-b border-[#808080] border-opacity-50"${_scopeId}><button class="flex
flex-row justify-between text-left text-sm md:text-lg leading-4 font-semibold md:font-normal"${_scopeId}><span${_scopeId}>`);
_push2(_ssrRenderComponent(_component_ContentSlot, {
use: _ctx.$slots.question,
unwrap: "p"
}, null, _parent2, _scopeId));
_push2(`</span>`);
_push2(_ssrRenderComponent(_component_AtomsIconsArrowBottom, {
class: ["transition-transform duration-300", $setup.open ? "transform rotate-180" : ""]
}, null, _parent2, _scopeId));
_push2(`</button><div class="mt-4 text-sm leading-[1.125rem]" style="${_ssrRenderStyle($setup.open ? null : { display:
"none" })}"${_scopeId}>`);
_push2(_ssrRenderComponent(_component_ContentSlot, {
use: _ctx.$slots.answer
}, null, _parent2, _scopeId));
_push2(`</div></article>`);
} else {
return [
_createVNode("article", { class: "pb-4 flex flex-col border-b border-[#808080] border-opacity-50" }, [
_createVNode("button", {
onClick: ($event) => $setup.open = !$setup.open,
class: "flex flex-row justify-between text-left text-sm md:text-lg leading-4 font-semibold md:font-normal"
}, [
_createVNode("span", null, [
_createVNode(_component_ContentSlot, {
use: _ctx.$slots.question,
unwrap: "p"
}, null, 8, ["use"])
]),
_createVNode(_component_AtomsIconsArrowBottom, {
class: ["transition-transform duration-300", $setup.open ? "transform rotate-180" : ""]
}, null, 8, ["class"])
], 8, ["onClick"]),
_createVNode(_Transition, {
"enter-active-class": "transition duration-300 ease-out",
"enter-from-class": "opacity-0",
"enter-to-class": "opacity-100",
"leave-active-class": "transition duration-300 ease-out",
"leave-from-class": "opacity-100",
"leave-to-class": "opacity-0",
persisted: ""
}, {
default: _withCtx(() => [
_withDirectives(_createVNode("div", { class: "mt-4 text-sm leading-[1.125rem]" }, [
_createVNode(_component_ContentSlot, {
use: _ctx.$slots.answer
}, null, 8, ["use"])
], 512), [
[_vShow, $setup.open]
])
]),
_: 1
})
])
];
}
}),
_: 1
}, _parent));
}
import { useSSRContext as __vite_useSSRContext } from "vue";
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = __vite_useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/content/molecules/Disclosure.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
import _export_sfc from "\0plugin-vue:export-helper";
export default /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__file", "C:/Users/esoubiran/projects/le-classement.fr/components/content/molecules/Disclosure.vue"]]);
</pre><br>
at /components/content/molecules/Disclosure.vue ] {
statusCode: 500,
fatal: false,
unhandled: false,
statusMessage: 'Vite Error',
__nuxt_error: true
}
Going to lose this for a few issues:
useUnwrap
I'd say isn't related to this module.Going to lose this for a few issues:
- I'm working towards deprecating the components, they are not worth the type issues and the slot unpacking issues.
- The issue with
useUnwrap
I'd say isn't related to this module.- FAQ's are being removed from Google Rich Results so getting this working is no longer as important
Seems ok for me! Was not aware of your last point.
Describe the bug
Expected to have a correct schema when multiple questions are on the same page but with multiples questions, here the results:
mainEntity
aren't good. You can find usage in this component: https://github.com/Barbapapazes/le-classement.fr/pull/88/filesReproduction
https://github.com/Barbapapazes/le-classement.fr/pull/88
System Info
Used Package Manager
yarn
Validations