How to access ACF fields and the featured_media for /blog page

I have created some custom fields for /blog page and want to show those fields and featured_media for on this page.

I just do egā€¦


const data = state.source.get(state.router.link);
const post = state.source[data.type][data.id];  
const foo = post.acf.foo

console.log data and post and youā€™ll see what information is available

For featured media Iā€™m sure thereā€™s an examples in Mars themeā€¦ look for the Boolean in the settings file and check how thatā€™s implemented in the code

for individual post and pages data.id exists but for /blog page (by making the page as blog page in wordpress settings) data.id doesnā€™t exist

const data = state.source.get('/blog');
const page = state.source[data.type][data.id];  

so I canā€™t get page or acf prop from it

This is what I get from state.source.get('/blog')

isArchive: true
isFetching: false
isPostArchive: true
isPostTypeArchive: true
isReady: true
items: [post objects]
link: "/blog/"
next: "/blog/page/2/"
page: 1
query: {}
route: "/blog/"
total: 51
totalPages: 6
type: "post"

So what are your acf fields attached to? Surely individual items in the blog?

The problem youā€™re having is caused by a limitation in the REST API of WordPress (or actually, a limitation of WordPress in general).

When querying /blog/ you will not get a post or page, but instead a collection of posts. WordPress does not know that itā€™s an actual page (even though it exists), so instead will return the contents of the archive.

I guess the only solution is to do a second fetch to ACF directly to retrieve the data from that page.

You could maybe do something like what I did here and create a page called eg /blog_page and manually 404 the route in the browser, but use it to get data over REST

Yes frontity only gives the collection of posts when doing state.source[data.type]. I am not sure why data.id is missing for /blog only.

As the wordpress rest endpoint is giving both the featured_media and acf fields but are missing when getting via frontity.

/blog is set to be postsPage but it is a page. Frontity should also return id for this page so we can get the page details just like other pages.

Because an archive page is not a real page, so it doesnā€™t have a page/post id. Even when you have set a page in WP.

So itā€™s normal behavior in WordPress.

But when listing the pages using wp-rest apis, Iā€™m getting the id, featured_media, acf for the /blog, like this

{
   "id":64,
   "slug":"blog",
   "status":"publish",
   "type":"page",
   "title":{
      "rendered":"Blog"
   },
   "author":1,
   "featured_media":1637,
   "acf":{
      "title":"Blog"
   }
}

My doubt is that why is it missing in frontity source?

Because, as I explained before, when you get the posts archive (/blog) WordPress will not return the page.

The request you sent is:
/wp-json/wp/v2/pages?slug=/blog
This will obviously return the content of the ā€˜blogā€™ page, but does not return anything else (like the posts it should show.

The request that is actually done:
/wp-json/wp/v2/posts
This will return all the posts which is the same as WordPress does on the archive. And since you set ā€˜/blogā€™ as the posts archive URI, it will do this request by default (as it should).

So itā€™s not a bug or missing feature in Frontity, itā€™s how WordPress works and how Frontity implemented it to return the exact same results.

Got it. Thank you for the explanation :+1:

There is a solution though and that is through creating a custom handler.

Here are the general steps:

  1. Change the postsPage in frontity.settings to something else
  2. Create a handler for /blog/
  3. Get /blog by using
        endpoint: 'pages',
        params: {
          slug: 'blog',
          _embed: true,
        },
      });
  1. Get all your blog posts by
await api.get({
      endpoint: 'posts',
      params: {
        per_page: 100,
        _embed: true,
      },
    });
  1. Then build your own state.source.data by setting isPostArchive to true etc.

I can share more in detail if anyone is curious.

Here are some links that might help:

Here is the handler. Not tested!

const blogHandler = {
  pattern: '/blog/',
  priority: 5,
  func: async ({link, params, state, libraries}) => {

    const {api, populate, getTotalPages} = libraries.source;

    // Get the Blog Page
    // 1. search id in state or get the entity from WP REST API
    const {route, query} = libraries.source.parse(link);
    const routeData = state.source.get(route);
    if (!routeData.id) {
      //console.log(routeData);
      // Get the page
      let response = await api.get({
        endpoint: 'pages',
        params: {
          slug: 'blog',
          _embed: true,
        },
      });
      const blogPage = await populate({
        response,
        state,
      });
      console.log("Blog Page", blogPage);
    }

    // 2. Get the Blog List

    let response = await api.get({
      endpoint: 'posts',
      params: {
        per_page: 100,
        _embed: true,
      },
    });
    const firstItems = await populate({
      response,
      state,
    });
    const pages = getTotalPages(response);
    const requests = [];

    // Get the next pages
    for (let page = 2; page <= pages; page++) {
      requests.push(
          api.get({
            endpoint: 'posts',
            params: {
              per_page: 100,
              page,
              _embed: true,
            },
          }),
      );
    }
    const responses = await Promise.all(requests);

    const newItems = await Promise.all(
        responses.map((response) => populate({state, response})),
    );
    const items = firstItems.concat(newItems);

    // 4. add data to source
    const currentPageData = state.source.data['/blog/'];
    const postData = {
      isPostType: true,
      isPostArchive: true,
      type: 'page',
      items,
    };

    Object.assign(currentPageData, postData);
  },
};

export default blogHandler;