Add dynamic page (_post)

Hello,

I am working on a website development project for a client. I work with Prismic-NuxtJS.

At the moment, I'm developing the blog part of the site.
For that I created a single document page named "blogpage" that I integrated easily.
The problem is the integration of a dynamic page for the repeatable document named "post".

Here is the architecture of my project:

  • "link-resolver.js" => in the app/prismic folder
  • "_post.vue" => in the pages/_lang folder
  • "_post.vue" => in the pages folder

Here is the code for each file respectively:
link-resolver.js

export default function(doc) {
  if (doc.isBroken) {
    return "/not-found";
  }

  if (doc.type === "homepage") {
    return `/${doc.lang}`;
  }

  if (doc.type === "blogpage") {
    return `/${doc.lang}/blog`;
  }

  if (doc.type === "page") {
    return `/${doc.lang}/${doc.uid}`;
  }

  if (doc.type === "post") {
    return `/${doc.lang}/blog/${doc.uid}`;
  }

  return "/not-found";
}

_post.vue

<template>
  <div>
    <!-- Vue tag to add header component -->
    <header-prismic
      :menuLinks="menuLinks"
      :menuTextProducts="menuTextProducts"
      :menuTextButton="menuTextButton"
      :altLangs="altLangs"
    />
    <div class="outer-container">
      <div class="back">
        <nuxt-link to="../">back to list</nuxt-link>
      </div>
      <!-- Template for page title -->
      <h1 class="blog-title">{{ $prismic.asText(document.title) }}</h1>
      <!-- Template for published date -->
      <p class="blog-post-meta">
        <span class="created-at">{{ formattedDate }}</span>
      </p>
    </div>
    <!-- Slices block component -->
    <slices-block :slices="slices" />
    <!-- FooterPrismic component -->
    <footer-prismic-vue
      :text="text"
      :textSocialNetwork="textSocialNetwork"
      :textJurisdiction="textJurisdiction"
      :textCopyright="textCopyright"
    />
    <!-- Modale -->
    <modale-legal-notice
      :titleModaleLN="titleModaleLN"
      :textModaleLN="textModaleLN"
      :revele="revele"
      :toggelModale="toggelModale"
    />
    <modale-policy
      :titleModalePP="titleModalePP"
      :textModalePP="textModalePP"
      :revelePolicy="revelePolicy"
      :toggelModalePolicy="toggelModalePolicy"
    />
    <modale-cookies
      :titleModaleC="titleModaleC"
      :textModaleC="textModaleC"
      :reveleCooky="reveleCooky"
      :toggelModaleCooky="toggelModaleCooky"
    />
  </div>
</template>

<script>
// Imports for all components
import HeaderPrismic from "~/components/HeaderPrismic.vue";
import SlicesBlock from "~/components/SlicesBlock.vue";
import FooterPrismicVue from "../../components/FooterPrismic.vue";
import ModaleLegalNotice from "~/components/ModaleLegalNotice.vue";
import ModalePolicy from "~/components/ModalePolicy.vue";
import ModaleCookies from "~/components/ModaleCookies.vue";

export default {
  name: "page",
  components: {
    HeaderPrismic,
    SlicesBlock,
    FooterPrismicVue,
    ModaleLegalNotice,
    ModalePolicy,
    ModaleCookies,
  },
  head() {
    return {
      title: "Market Pay | Born in retail to drive payment",
    };
  },
  data() {
    return {
      // initialize revele modale
      revele: false,
      revelePolicy: false,
      reveleCooky: false,
    };
  },
  methods: {
    // toggle method modale legal notice
    toggelModale() {
      this.revele = !this.revele;
    },
    // toggle method modale privacy policy
    toggelModalePolicy() {
      this.revelePolicy = !this.revelePolicy;
    },
    // toggle method modale cookies
    toggelModaleCooky() {
      this.reveleCooky = !this.reveleCooky;
    },
  },
  async asyncData({ $prismic, params, error }) {
    try {
      // Languages from API response
      let languages = $prismic.api.data.languages;
      // Setting Master language as default language option
      let lang = { lang: languages[0].id };
      // If there is a langauge code in the URL set this as language option
      if (params.lang !== undefined || null) {
        lang = { lang: params.lang };
      }

      // Query to get post content
      const post = (await $prismic.api.getByUID("post", params.uid, lang)).data;
      const menuContent = (await $prismic.api.getSingle("top_menu", lang)).data;
      const footerContent = (await $prismic.api.getSingle("footer", lang)).data;
      // const modale
      const modaleLN = (
        await $prismic.api.getByUID("modale", "legal_notice", lang)
      ).data;
      const modalePP = (
        await $prismic.api.getByUID("modale", "privacy_policy", lang)
      ).data;
      const modaleC = (await $prismic.api.getByUID("modale", "cookies", lang))
        .data;

      return {
        // Page content, set slices as variable
        document: post,
        slices: post.body,
        formattedDate: Intl.DateTimeFormat("en-US", {
          year: "numeric",
          month: "short",
          day: "2-digit",
        }).format(new Date(post.date)),
        // Menu
        menuLinks: menuContent.menu_links,
        menuTextProducts: menuContent.product_label,
        menuTextButton: menuContent.button_label,
        altLangs: result.alternate_languages,
        // Footer
        text: footerContent.text,
        textSocialNetwork: footerContent.text_social_network,
        textJurisdiction: footerContent.text_jurisdiction,
        textCopyright: footerContent.copyright,
        // modale
        titleModaleLN: modaleLN.title,
        textModaleLN: modaleLN.text,
        titleModalePP: modalePP.title,
        textModalePP: modalePP.text,
        titleModaleC: modaleC.title,
        textModaleC: modaleC.text,
      };
    } catch (e) {
      // Returns error page
      error({ statusCode: 404, message: "Page not found" });
    }
  },
};
</script>

_post.vue

<script>
import _post from "~/pages/_lang/_post";
export default _post;
</script>

This is the error it gives me

If you can help me to integrate the dynamic page "_post" it would be great thank you very much.

Best regards.

Hello @fr_siteweb_marketpay, thanks for reaching out!

I noticed a couple of things. The first thing is that you must add a blog directory inside _lang to as indicated by your Link Resolver, in any case, the URL that is being generated now would be /:lang/:uid instead of /:lang/blog/:uid. And the second, I see there also a _post.vue file outside of _lang? What is this for? it may be that this also conflicts with the routes.

Hello,

Thank you for your answer.

First of all, concerning the generated path, I didn't know it was /:lang/:uid nor /:lang/blog/:uid I thought it was /:lang/:post.
So I'll fix it and see if the problem will be solved.

Secondly, about the "_post.vue" file outside the "_lang" directory, it is to recover the "_post.vue" file inside "_lang" as for the "_uid.vue" file.

<script>
import _post from "~/pages/_lang/_post";
export default _post;
</script>

PS: I don't know if this is a good practice.

So I wanted to add another dynamic page I will have in my project the files "_uid" and "_post", is it possible ?

Thanks for the additional details.

You can create any dynamic nested routes you need using Nuxt's file system routing. I recommend you take a look at Nuxt's official docs to learn more about how this works:

Hello @Pau

About integration of dynamic pages I know how to do it, besides I referred to the official documentation to learn that.

But what I would like to do is how to introduce new dynamic pages in a project under Prismic.

Here is the new structure that I made but it still does not work.
image

Here is the code of the files that I modified for the integration.

export default function(doc) {
  if (doc.isBroken) {
    return "/not-found";
  }

  if (doc.type === "homepage") {
    return `/${doc.lang}`;
  }

  if (doc.type === "blogpage") {
    return `/${doc.lang}/blog`;
  }

  if (doc.type === "page") {
    return `/${doc.lang}/${doc.uid}`;
  }

  if (doc.type === "post") {
    return `/${doc.lang}/blog/${doc.uid}`;
  }

  return "/not-found";
}

link-resolver.js file

<template>
  <div>
    <!-- Vue tag to add header component -->
    <header-prismic
      :menuLinks="menuLinks"
      :menuTextProducts="menuTextProducts"
      :menuTextButton="menuTextButton"
      :altLangs="altLangs"
    />
    <!-- Slices block component -->
    <slices-block :slices="slices" />
  </div>
</template>

<script>
// Imports for all components
import HeaderPrismic from "~/components/HeaderPrismic.vue";
import SlicesBlock from "~/components/SlicesBlock.vue";

export default {
  name: "post",
  components: {
    HeaderPrismic,
    SlicesBlock,
  },
  head() {
    return {
      title: "Market Pay | Post blog",
    };
  },
  async asyncData({ $prismic, params, error }) {
    try {
      // Languages from API response
      let languages = $prismic.api.data.languages;
      // Setting Master language as default language option
      let lang = { lang: languages[0].id };
      // If there is a langauge code in the URL set this as language option
      if (params.lang !== undefined || null) {
        lang = { lang: params.lang };
      }

      // Query to get post content
      const result = await $prismic.api.getByUID("post", params.uid, lang);
      const menuContent = (await $prismic.api.getSingle("top_menu", lang)).data;

      return {
        // Page content, set slices as variable
        slices: result.data.body,
        // Menu
        menuLinks: menuContent.menu_links,
        menuTextProducts: menuContent.product_label,
        menuTextButton: menuContent.button_label,
        altLangs: result.alternate_languages,
      };
    } catch (e) {
      // Returns error page
      error({ statusCode: 404, message: "Page not found" });
    }
  },
};
</script>

_post.vue file

i would help to understand how to introduce a new dynamic pages with Prismic

Thenk you.

When you say: what I would like to do is how to introduce new dynamic pages in a project under Prismic. are you wondering how to generate these documents inside your Prismic repository?

If that's the case, it just involves generating documents with the same Custom types you already have. In this case, I can see you have Post, Page, Blogpage, and homepage (not sure if this last one is singleton or repeatable)

Hello

Not "how to generate these documents in your Prismic repository?".

In my project I have :

  • document home page (single page)
  • document blog page (single page)
  • document page (repeatable page)

My goal is to add a document post (repeatable page)
and to be able to exploit it on my code by adding a dynamic file _post in pages and to have access thanks to the Link-resolver with this address the /:lang/blog/:post

and that's what I can't do.

Thanks

Ok I get it now. You're only missing to add another _uid.vue file inside blog and query for the post type. Then this option in the link resolver will solve the link routes

  if (doc.type === "post") {
    return `/${doc.lang}/blog/${doc.uid}`;
  }

Hi @Pau

Thank you very much ! it's ok !!!
Thank you