Get 'wp_template_part'

Hi,

I just saw the JS for WP Conf Talk from @SantosGuillamot and was very excited about the possibility to load Gutenberg template-parts into Frontity.

So I tried to do the same… But it won’t work for me. I installed WordPress 5.5-beta1-48411, Gutenberg 8.5.1 and enabled Full Site Editing. I also created a template-part, which can be found at this wp-json url:
https://gatsby-wp.noesteprojecten.nl/wp-json/wp/v2/template-parts/

Currently, my beforeSSR looks like this:

beforeSSR: async ({ state, actions }) => {
        // getNameAndDescription,
        await Promise.all(
          [
            actions.source.fetch("acf/options"),
            actions.source.fetch("acf/identity"),
            actions.source.fetch("getWPConfig"),
            actions.source.fetch("/contact"),
            state.theme.templates.map((slug) =>
              actions.source.fetch(`wp_template_part/${slug}`)
            ),
          ]
        );
      },

But I get the following error in my Terminal:

TypeError: Cannot read property 'map' of undefined
      at beforeSSR (webpack-internal:///./packages/mars-theme/src/index.js:21:184)
      at eval (webpack-internal:///./node_modules/@frontity/connect/src/create-store.js:5:1528)
      at eval (webpack-internal:///./node_modules/@frontity/core/src/server/index.tsx:49:88)
      at Array.map (<anonymous>)
      at eval (webpack-internal:///./node_modules/@frontity/core/src/server/index.tsx:49:48)
      at processTicksAndRejections (internal/process/task_queues.js:94:5)
      at eval (webpack-internal:///./node_modules/koa-mount/index.js:16:290)

Am I missing something? Do I need a specific version of Frontity? I’m running version 1.9.0 at the moment.

Hi @dominique

How are you populating state.theme.templates? The map function operates on an array and returns a new array. The result of the map operation needs to be assigned to a variable.

Check out the MDN docs for array.map.

Hope this helps to guide you to a solution. Let us know if you need any further help.

Hi @mburridge,

Thanks for your quick response. Frankly, I really don’t even have a clue about what I am doing here. I saw @SantosGuillamot show this exact code in his Talk and got really excited about the possibilities.

So I just typed over the shown code into my index.js file. As soon as I add this, my project completely fails (‘Internal Server Error’), with the error message above.

Hi @dominique

I would have thought that state.theme.templates needs to be populated with an array before the map function can operate on it. If there’s nothing there then that explains why you’re getting the message that ‘map’ cannot be read on ‘undefined’ since state.theme.templates is indeed undefined.

The other thing that confuses me about your code example is that the return value of the map operation isn’t being assigned to anything.

Maybe @SantosGuillamot can step in here with some guidance.

But this is how beforeSSR works, right? The other fetch commands were working fine.

Maybe I am missing a package for Gutenberg.

Yes, kind of. The other fetch commands will work fine. It’s because your call to the wp_template_part endpoint is called within map, and map is not firing because state.theme.templates is undefined. Unless you’re populating state.theme.templates in frontity.settings.js?

Well… no I didn’t add anything in frontity.settings.js. I am really new to the whole concept of Frontity, so didn’t realize this was needed.

I added the following to postTypes in frontity.settings.js now:

{
type: "wp_template_part",
endpoint: "template-parts",
}

With the additions to beforeSSR disabled I am able to view the template-parts when I specifically visit them in my browser. But when I enable the additions to beforeSSR again, the whole sting still crashes.

Hi @dominique! I’m glad you’re testing template parts after the talk :slightly_smiling_face:

First of all, sorry because I think I didn’t explain this part properly. Template Parts is a Custom Post Type Gutenberg is adding so, in order to make it work you just have to defined them in Frontity as any other Custom Post Type as you did (these are the docs just in case). In you frontity.settings.js you should have something similar to this:

postTypes: [
  {
    type: "/wp_template_part",
    endpoint: "template-parts",
  },
],

From there, what we did was to define all the template-parts slugs we wanted to fetch in state.theme.templates, but note that if you define a slug that doesn’t exist in your WordPress, it isn’t going to find anything so it’s going to return an error. This may be the cause of your problem, so make sure you only include template-parts slugs that are defined in your WordPress.

Once you have created all the template parts you need in your WordPress, and you have included the slugs in state.theme.templates, you can include the function in beforeSSR as you did.

This should allow you to do state.source.get("/wp_template_part/:slug/") and get the content of a specific template-part.

If you have a public repo you can share, I can take a look at the code and check what could be the problem :slightly_smiling_face:

Hi @SantosGuillamot, I haven’t really defined any template-parts in my code (yet). Could that also be the root of the problem?

Here’s my repo:
https://bitbucket.org/noesteijver/frontity/

Yes, that’s problably the root of the problem. In the action you define beforeSSR you’re trying to map state.theme.templates but, as you haven’t defined it yet, it returns an error. Let us know if it works once you add some of them!

@SantosGuillamot I do have them in my WordPress installation, if that’s what you mean. I’m seeing them here:
https://gatsby-wp.noesteprojecten.nl/wp-json/wp/v2/template-parts/

So to recap, I’ve got template-parts posts in my WordPress install.

This is in my frontity.settings.js file:

...
postTypes: [
            ...
            {
              type: "wp_template_part",
              endpoint: "template-parts",
            },
          ]
...

And this as my beforeSSR:

beforeSSR: async ({ state, actions }) => {
        // getNameAndDescription,
        await Promise.all(
          [
            actions.source.fetch("acf/options"),
            actions.source.fetch("acf/identity"),
            actions.source.fetch("getWPConfig"),
            // actions.source.fetch("/contact"),

            state.theme.templates.map((slug) =>
              actions.source.fetch(`wp_template_part/${slug}`)
            ),
          ]
        );
      },

But I’m still getting the Cannot read property 'map' of undefined error.

You still would have to defined all the template-parts slugs you want to fetch in the index.js of your theme. It could look similar to this:

import Theme from "./components";
import image from "@frontity/html2react/processors/image";
import iframe from "@frontity/html2react/processors/iframe";

...

const marsTheme = {
  ...
  state: {
    theme: {
      ...
      templates: [ "tekst-beeld", "versje-tabel", "gewoon-wat-tekst", "formulier" ]
    },
  },
  actions: {
    theme: {
      // beforeSSR: getNameAndDescription,
      beforeSSR: async ({ state, actions }) => {
        // getNameAndDescription,
        await Promise.all(
          [
            actions.source.fetch("acf/options"),
            actions.source.fetch("acf/identity"),
            actions.source.fetch("getWPConfig"),
            // actions.source.fetch("/contact"),

            state.theme.templates.map((slug) =>
              actions.source.fetch(`wp_template_part/${slug}`)
            ),
          ]
        );
      },
      ...
    },
  },
  ...
};

export default marsTheme;

Once you define them in your Frontity code, you shouldn’t get that error.

Right, now I understand. Thanks for that clarification, it’s working well now.

2 Likes

Hi, I am quite new to the Frontity/React/Wordpress development. Seing this thread I wanted to give it a go to create a footer using template-parts.

Here’s the template parts: http://web2020.hei-schule.ch/wordpress/wp-json/wp/v2/template-parts/

the frontity.setting.js looks the following:

...
{
  "name": "@frontity/wp-source",
  "state": {
    "source": {
      "api": "http://web2020.hei-schule.ch/wordpress/wp-json",
      postTypes: [
        {
          type: "wp_template_part",
          endpoint: "template-parts",
        },
      ],
    }
  }
},
...

the index.js of my theme:

const marsTheme = {
  ...
  state: {
    theme: {
      ...
      templates: [ "footer" ],
      ...
      },
    },
  },
  ...
  actions: {
    theme: {
      ....
      beforeSSR: async ({ state, actions }) => {
        // getNameAndDescription,
        await Promise.all(
          [
            state.theme.templates.map((slug) =>
              actions.source.fetch(`wp_template_part/${slug}`)
            ),
          ]
        );
      },
    },
  },
  ...

and in the footer.js of my theme I am trying something like that:

const FooterContent = ({ state, actions, libraries }) => {
   const data = state.source.get("/wp_template_part/footer");
   const post = state.source["wp_template_part"][data.id];
   ...

Now in the frontity.state.source.data I can see “wp_template_part/footer/” but it’s on isFetching == true, and getting the post in the footer. js obviously is not working.

Somebody got an idea on where to look? The WP Site is on /wordpress/ may this have some effect?

I might very well be wrong but I think you might have to use actions.source.fetch(/wp_template_part/${slug}), with a slash before wp_template_part.

Oh, you were right :blush: I added the leading slashes (as well as in footer.js) and now the data can be queried

Thanks for your answer

No problem, I’m trial & errorring my way throught Frontity and React as well and sometimes it can become very hard to see things like these. In those cases I turn to the Frontity Community as well, in hope for answers. :wink:

3 Likes