ACF Post Object: Get post data

Iā€™m having trouble understanding how to get data from posts, configured in an ACF Post Object field. Itā€™s possible to configure the Post Object field to return itā€™s value as post IDs or Post Objects. But the Post Object doesnā€™t contain all needed information, like the featured image.

I want to build a slider for my front-page, the slides should contain the link to the configured post and show the title and featured image. The title is passed with ACF, the link Iā€™m able to generate using post_name, but the featured-image isnā€™t available.

So I need to fetch the whole post, I guess. But I canā€™t figure out how to retrieve more data, when Iā€™m working in a component.

This is the wp-json endpoint:
https://frontity.noesteprojecten.nl/wp-json/acf/v3/options/options

This is my slider component

import React from "react";
import { connect, styled } from "frontity";
import SwipeableViews from 'react-swipeable-views';
import { autoPlay, bindKeyboard } from 'react-swipeable-views-utils';

const AutoPlaySwipeableViews = bindKeyboard(autoPlay(SwipeableViews));

const styles = {
   ...
};

const Slider = ({ state, actions }) => {
   const options = state.source.get("acf/options");
   const sliderItems = options.acf.home_slider_items;

   let slides = [];
   for (let i = 0; i < sliderItems.length; i++) {
      const postLinkPrefix = (sliderItems[i].post_type != 'post') ? '/' + sliderItems[i].post_type : '';

      slides.push(<Slide href={postLinkPrefix + "/" + sliderItems[i].post_name} style={Object.assign({}, styles.slide, styles['slide' + i % 3])}>slide nĀ°{i}: {sliderItems[i].post_title}</Slide>);
   }

   return (
      <AutoPlaySwipeableViews enableMouseEvents>
         {slides}
      </AutoPlaySwipeableViews>
   );
}

export default connect(Slider);

Hereā€™s a link to my repository: https://bitbucket.org/noesteijver/frontity/src/master/

Anyone? :smiley:

Is any information missing?

Hi @dominique

Thereā€™s a couple of approaches we could take here. The first is to try adding featured images to the REST API. I found this code snippet that you could add to functions.php or in a custom plugin: https://fancysquares.blog/wordpress-rest-api-add-featured-image-to-acf-relationship-post-object

The other way would be to get the ID of the post that you want and fetch it separately. Let me know how you get on with the first solution and if that fails then we can look at doing this.

Hi @mburridge, for this specific case I guess it would be sufficient to just add the featured-image to the output of ACF. Thanks for the link. I think I can solve this problem that way.

But still, I am wondering how to retrieve information of a specific post/term in a component. Because there are so much more fragments of data which youā€™d want to use, than that ACF is handing over by default. I donā€™t think it should be that way that youā€™d need to manually add this data to ACF, while the data is available if youā€™d be able to retrieve the whole post.

Think about data like:

  • featured image
  • excerpt (ACF only outputs it if youā€™ve manually set it)
  • rendered content (ACF only outputs unrendered post-content)
  • post template
  • attached ACF fields

I am bumping my way through this, and got a bit further now.

Iā€™ve added this filter to my WordPress installation:

function get_featured_image_of_post_object( $item, $request ) {
	if ( isset( $item['acf']['home_slider_items'] ) ) {
		foreach ( $item['acf']['home_slider_items'] as $key => $post_object ) {

      $post_object_id = $post_object->ID;
      $featured = wp_get_attachment_image_src( get_post_thumbnail_id( $post_object_id ), 'full' );
      $featured_image_id = get_post_thumbnail_id($post_object_id);

			if ( $featured_image_id ) {
				$item['acf']['home_slider_items'][ $key ]->featured_media = $featured_image_id;
			}
		}
	}

	return $item;
}
add_filter('acf/rest_api/option/get_fields', 'get_featured_image_of_post_object', 10, 2);

This results in having the ID of the featured-image in the REST output. And I can use this in my slider.js file. However, the featured-image is not being rendered on the front-page. When I visit ā€˜Blogsā€™ and return to the front-page, it is being rendered. So it looks like it isnā€™t fetched when visiting the front-page.

To replicate:

  1. Visit: https://frontity-test-98427dzn9.vercel.app/
  2. Then click ā€˜Blogsā€™ in the nav bar;
  3. Return to ā€˜Homeā€™, now the slider contains images.

Iā€™ve updated my repository with the current code (https://bitbucket.org/noesteijver/frontity/src/master/).

Hi @dominique

You may need to prefetch the items using a beforeSSR action, so you could try adding something like this to your themeā€™s index.js file:

beforeSSR: async ({actions}) => {
   await actions.source.fetch("/acf/options");
}

Here is the documentation for beforeSSR.

Hi @mburridge,

This is my beforeSSR, the fetch that you mentioned was already in it:

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

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

The ACF options are not the problem, otherwise the slides would not be visible. Itā€™s the attachments that arenā€™t available to Frontity at the moment of visiting the front-page.

When visiting the blogs page, apparently they are being fetched, but not when visiting the front page. The slider will only show images that are being loaded on the blogs page, so if the image is not in one of the articles on the blogs page, they wonā€™t show up in the front-page slider either.

@mburridge

Iā€™m very sorry for being so rude, but do you have any more ideas about whatā€™s going on here and how to solve it?

1 Like

Hi @dominique

Sorry for the failure to communicate, Iā€™ve cloned your repo locally and am working on trying to find a solution. Iā€™ll let you know when I have anything to share.

1 Like

Not sure if I understood the case 100%, but if you have the ids or the slugs of the posts you want, wouldnā€™t be better to use something like fetch to populate the state with all the info about each post? This way, you would have any info like the title or the featured image in state.source.post[id].

Hi @SantosGuillamot,

I looked at the documentation of fetch before and tried to use it, but I couldnā€™t get it working the way I needed to.

After reading your post I tried one more time and low and behold: it worked! The posts are now being fetched and the images are being shown. Iā€™m not sure what Iā€™m doing different then before, but of course there must be a difference.

Thanks for encouraging me to try it once more!

For future reference for others, hereā€™s the code for my slider:

const Slider = ({ state, actions }) => {
   const options = state.source.get("acf/options");
   const sliderItems = options.acf.home_slider_items;

   let slides = [];
   for (let i = 0; i < sliderItems.length; i++) {
      const postLinkPrefix = (sliderItems[i].post_type != 'post') ? '/' + sliderItems[i].post_type : '';
      const postLink = postLinkPrefix + "/" + sliderItems[i].post_name;

      useEffect(() => {
         actions.source.fetch(postLink);
      }, []);

      const dataPost = state.source.get(postLink);

      const featuredImageID = (dataPost.isReady) ? state.source[sliderItems[i].post_type][sliderItems[i].ID].featured_media : null;

      slides.push(<Slide href={postLinkPrefix + "/" + sliderItems[i].post_name} style={Object.assign({}, styles.slide, styles['slide' + i % 3])}>slide nĀ°{i}: {sliderItems[i].post_title}<FeaturedMedia id={featuredImageID} /></Slide>)
   }

   return (
      <AutoPlaySwipeableViews enableMouseEvents>
         {slides}
      </AutoPlaySwipeableViews>
   );
}
5 Likes

Awesome @dominique, glad you managed to get this working in the end. :+1:

2 Likes

Hi guys,

Iā€™m also trying to get data from an ACF Post Object field of a Custom Post Type.

I have this Post Object field on the Homepage. This field lets display two posts from a custom post type.

I am not sure how to retrieve the data from these two posts. The custom post type is called ā€œcase_studiesā€.

I have added the postTypes reference in frontity.settings.js, like so

"packages": [
    {
      "name": "wwt-theme",
    },
    {
      "name": "@frontity/wp-source",
      "state": {
        "source": {
          "url": "http://wwt.local",
          "homepage": "/home"
        },
        "postTypes": [
          {
            "type": "case_studies",
            "endpoint": "case_studies",
            "archive": "case_studies"
          }
        ]
      }
    },

Now, in my CaseStudies component I can console.log the Post Object field, which returns this array

Screenshot 2021-03-25 at 19.17.21

I need to get the data from the post with post_type: ā€œcase_studiesā€ and id of 89 but I canā€™t figure out how to do that.

This is what Iā€™ve tried so far but with no success.

<CaseStudiesWrapper>
                {caseStudies && caseStudies.map((caseStudy, index) => {
                    // const caseStudyType = caseStudy.post_type;
                    const caseStudyID = `/case_studies/${caseStudy.ID}`;
                    const caseStudyData = state.source.get(caseStudyID);

                    useEffect(() => {
                        actions.source.fetch(caseStudyID);
                    }, []);

                    return (
                        <CaseStudy key={index}></CaseStudy>
                    );
                })}
            </CaseStudiesWrapper>

Am I missing something and/or what am I doing wrong? Many thanks!

Hi all,

Iā€™ve managed to resolve my own issue. It was easier than I thoughtā€¦! In case anyone else has the same problem I post the answer below.

Iā€™ve put the postTypes arguments in the wrong place, they should go under ā€œsourceā€ and not under ā€œstateā€, like so

"state": {
        "source": {
          "url": "http://wwt.local",
          "homepage": "/home",
          "postTypes": [
            {
              "type": "case_studies",
              "endpoint": "case_studies",
              "archive": "/case_studies"
            }
          ]
        },
      }

and I can retrieve the individual posts like so

<CaseStudiesWrapper>
    {caseStudies && caseStudies.map((caseStudy, index) => {
        const caseStudyType = caseStudy.post_type;
        const caseStudyData = state.source[caseStudyType][caseStudy.ID];
        return (
            <CaseStudy key={index}></CaseStudy>
        );
    })}
</CaseStudiesWrapper>