Dynamic post blog link

Hello,

I'm writing this Topic because I'm stuck on a project I'm involved in, creating a website for a company in multilingual, and I ask for your help.

I used the theme proposed by Prismic with NuxtJS "Multilingual website".
However, our client asks us to make a blog.

My problem is with the dynamic links of the articles.
In other words, I would like to know how to generate dynamic links for each article and when we click on an article, I would like to open it in a new window with all the information specific to the selected article?

Thank you very much.

Hi @fr_siteweb_marketpay,

Welcome to the Prismic community, and thanks for posting this question :slight_smile:

It sounds like you need a Link Resolver:

Let me know if that answers your question.

Sam

Hi @samlittlefair
Thank you for your answer and your hospitality.
Concerning my problem, personally I would like to know is there any way to point to a slice component content not to a document type?

If it is not possible and if the best way is to create a repeatable document with our blog post in it. Is it to give me more information about the API integration with Nuxt? Because I'm having trouble understanding the documentation especially for the query by language, as my site is multilingual.

Thank you once again for your help.
Sincerely

Translated with DeepL Translate: The world's most accurate translator (free version)

Hello,

Following your recommendation to learn the link-resolver, I had to follow another approach to make my blog.

My approach is the following:

  • Create a single page called blogpage with all the necessary information and articles.
  • By clicking on a particular article, the user will be redirected to a page that will display the complete information of the selected article and for that I had to create a repeatable document called post.

However, I have some problems with the redirection of the articles.
Indeed, the blog page is integrated simply and easily, but the dynamic routing of the post pages does not work.

I put my code here if you want to see and tell me where the problem is please?

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 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>
import HeaderPrismic from "~/components/HeaderPrismic.vue";
import SlicesBlock from "~/components/SlicesBlock.vue";

export default {
  name: "post",
  components: {
    HeaderPrismic,
    SlicesBlock
  },
  head() {
    return {
      title: "Maket Pay | Blog - Post1"
    };
  },
  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.id };
      }

      // Query to get post content
      const result = await $prismic.api.getByUID("post", params.uid, lang);
      const menuContent = $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 (error) {
      // Returns error page
      error({ statusCode: 404, message: "page not found" });
    }
  }
};
</script>

path: "~/pages/_lang/_post"

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

path: "~/pages/_post"

Thank you very much

Hi @fr_siteweb_marketpay,

Sorry for my slow response — I've been out for the holidays. I'll take a look at this tomorrow and get back to you :slight_smile:

Sam

Hi Sam

Ok thank you, have good holidays

Hi @fr_siteweb_marketpay,

I can see that this line:

      const menuContent = $prismic.api.getSingle("top_menu", lang).data;

Does not have an await, so your menu props should all be undefined and potentially erroring. You could change it to:

      const menuContent = (await $prismic.api.getSingle("top_menu", lang)).data;

But that might not be the problem. What is the behavior you're observing? Are you getting an error message?

PS: I'll be out of the office on Thursday and Friday, returning on Monday.

Hi @samlittlefair

the behavior you're observing

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.

@fr_siteweb_marketpay Thanks for this info! It's a little hard to determine the bug with this info. Could you share your project files with me? You can share them as a GitHub repo or ZIP file. (Feel free to send them in a DM if you want.)