How to access ACF Options pages

Hi heroes of Frontity,

I started playing around with Frontity this week and am very excited about it!

Now, I want to try and rebuild our corporate site with Frontity. We use ACF to expand WordPress. I started trying to access an options page called ā€˜theme-identity-settingsā€™, but it just wonā€™t work. I want to use the content of this endpoint on multiple pages, so I figured it should be added in the beforeSSR?

I came across this topic, where it seems to work out for countfak. Either Iā€™m messing up the information in this topic, or something has changed?

The url of my endpoint is: https://gatsby-wp.noesteprojecten.nl/wp-json/acf/v3/options/theme-identity-settings. Excuse me for having ā€˜Gatsbyā€™ in it, I was testing out Gatsby previously and saw no point in creating a new WordPress installation when I could just use this one. :wink:

So, this is my index.js:

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

    // Custom handler for ACF options
    const acfOptionsHandler = {
      pattern: "theme-identity-settings",
      func: async ({ route, state, libraries }) => {
        // 1. Get ACF option page from REST API.
        const response = await libraries.source.api.get({
          endpoint: `/acf/v3/options/options`
        });
        const option = await response.json();

        // 2. Add data to `source`.
        const data = state.source.get(route);
        Object.assign(data, { ...option, isAcfOptionsPage: true });
      }
    };

    const marsTheme = {
      name: "@frontity/mars-theme",
      roots: {
        /**
         *  In Frontity, any package can add React components to the site.
         *  We use roots for that, scoped to the `theme` namespace.
         */
        theme: Theme,
      },
      state: {
        /**
         * State is where the packages store their default settings and other
         * relevant state. It is scoped to the `theme` namespace.
         */
        theme: {
          menu: [],
          isMobileMenuOpen: false,
          featured: {
            showOnList: false,
            showOnPost: false,
          },
        },
      },
      /**
       * Actions are functions that modify the state or deal with other parts of
       * Frontity like libraries.
       */
      actions: {
        theme: {
          beforeSSR: async ({ state, actions }) => {
            await Promise.all([
              actions.source.fetch("/theme-identity-settings"),
            ]);
          },
          toggleMobileMenu: ({ state }) => {
            state.theme.isMobileMenuOpen = !state.theme.isMobileMenuOpen;
          },
          closeMobileMenu: ({ state }) => {
            state.theme.isMobileMenuOpen = false;
          },
        },
      },
      libraries: {
        html2react: {
          /**
           * Add a processor to `html2react` so it processes the `<img>` tags
           * inside the content HTML. You can add your own processors too
           */
          processors: [image, iframe],
        },
        handlers: [acfOptionsHandler]
      },
    };

    export default marsTheme;

And this is on my frontpage.js, which is called when isHome is true.

const MyComp = ({ state }) => {
  const options = state.source.get("theme-identity-settings");
  console.log(options);
  return <div>...</div>;
}

And this is the content of that console.log:

    {ā€¦}
    isFetching: false
    isReady: false
    link: "theme-identity-settings/"
    page: 1
    query: Object {  }
    route: "theme-identity-settings/"
    <prototype>: Object { ā€¦ }
    frontpage.js:8:10

Iā€™m not sure where Iā€™m going wrong, if I have all the needed functionality implemented, or even too much. Any help is greatly appreciated!

Hi @dominique! :wave:

I think that youā€™ve just forgotten the initial slash in:

const MyComp = ({ state }) => {
  const options = state.source.get("theme-identity-settings");
  return <div>...</div>;
}

So, this should be:

const options = state.source.get("/theme-identity-settings");

I hope this should resolve it, but if this does not work it would mean that the data is not being fetched from your acf endoint. You can verify that simply in your browser console by checking that you have data under:

frontity.state.data["/theme-identity-setings"]

Hi @mmczaplinski,

Thanks for your answer!

I tried this out and now Iā€™m seeing this in errorStatusText: ā€‹"post type from endpoints ā€œposts,pages,mediaā€ with slug ā€œtheme-identity-settingsā€ not found".

When I do frontity.state.data["/theme-identity-setings"]) in my browser console, I get undefined as a result. So I guess something in index.js is wrong, but Iā€™m unable to figure it out.

The pattern in acfOptionsHandler should be without a slash before it, right?

What I also canā€™t figure out is that my endpoint in WordPress is https://gatsby-wp.noesteprojecten.nl/wp-json/acf/v3/options/theme-identity-settings, but in the example of the other topic, I see that the acfOptionsHandler has an extra /options in between, so I copied that to my code as well. But is this correct?

Hi @dominique

Welcome to the Community!

In order to provide the best possible help as quickly and as efficiently as possible please provide the info suggested here

āœ“ Description of your issue
āœ“ Specific errors youā€™re getting in the terminal
āœ“ Specific errors youā€™re getting in the browserā€™s console
āœ“ A repository with the code of your project
āœ“ A deployed version of your site
āœ“ The URL of your WP REST API

You donā€™t have to provide them all but the more info you provide about your issue the better. Providing a repo or code-sandbox with your code is especially helpful to deal with technical questions from specific code

Hi Juanma,

I donā€™t seem to be able to edit the OP any more, but hereā€™s a deployed version of the current code:
https://frontity-test-kej63c1mx.vercel.app/

I see the following error in my terminal:

ServerError: post type from endpoints "posts,pages,media" with slug "theme-identity-settings" not found
    at Object.eval (webpack-internal:///./node_modules/@frontity/wp-source/src/libraries/handlers/postType.ts:9:21)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:94:5)
    at eval (webpack-internal:///./node_modules/@frontity/wp-source/src/actions.ts:22:101) {
  name: 'ServerError',
  status: 404,
  statusText: 'post type from endpoints "posts,pages,media" with slug "theme-identity-settings" not found'
}

Hi @dominique

Can you also provide a repo or code-sandbox with your code? By being able to check directly your code, the community (or any member of the Frontity team) will be able to help you with your issue in a quicker and more efficient way

Hi @juanma,

I have opened up access to the repo on BitBucket: https://bitbucket.org/noesteijver/frontity/admin
Is this what you mean?

Hi @dominique,

Yes, thanks a lot. With this repo ā†’ https://bitbucket.org/noesteijver/frontity
any member of the community (and the Frontity team) can clone the project, check it locally and debug it to help your with your issue

Let me have a look at it and Iā€™ll get back to you ASAP

Hi @dominique,

Iā€™ve asked the dev team to have a look at your issue and this what they have detected

Hope this helps

Itā€™s working now! Thanks for helping me, @juanma and @mmczaplinski, and please send my thanks to the dev team! :smiley:

3 Likes

Iā€™m a bit confused about something.

My ACF endpoint for the options page (https://gatsby-wp.noesteprojecten.nl/wp-json/acf/v3/options/theme-identity-settings) is now returning different data then before, as Iā€™ve added a new option and changed the content of another one. However, the data in Frontity isnā€™t updating. Itā€™s still showing the old image I chose and the new option isnā€™t showing.

Am I not using the endpoint right? Is there some kind of caching for this endpoint that Iā€™m not aware of?

Hi, @dominique

Frontity does some kind of caching, if something was fetched from the WP REST API then is not fetched again when you call actions.source.fetch. You can override that passing a force option to fetch:

await actions.source.fetch(link, { force: true });

Anyway, I guess the problem you have is that the request to "theme-identity-settings" is being done in beforeSSR so it only happens on the server. That means the value wonā€™t update while you are navigating your Frontity site, you will have to refresh to get the new values (i.e. to make a new request to the Frontity server).

There was something wrong with my endpoint, indeed.

I canā€™t figure out how to access an ACF sub options page. For now Iā€™ve added everything on the main options page (acf_add_options_page()) but options from acf_add_options_sub_page() I canā€™t read out.

The endpoints seem quite different. The endpoint for the main options page is:
https://gatsby-wp.noesteprojecten.nl/wp-json/acf/v3/options/options/

The endpoint for the sub page is:
https://gatsby-wp.noesteprojecten.nl/wp-json/acf/v3/options/theme-identity-settings

Hey, @dominique

For accessing to the main options or a subpage, you can write a pattern for your handler that extract parameters from the link, like this one:

const acfOptionsHandler = {
  // This pattern gets an `option` param from the link.
  pattern: "acfOptions/:option",

  // Parameters extracted from the link are included in `params`.
  func: async ({ route, params, state, libraries }) => {
    // 1. Get ACF option page from REST API using `option` from `params`.
    const response = await libraries.source.api.get({
      endpoint: `/acf/v3/options/${params.option}`,
    });
    const option = await response.json();

    // 2. Add data to `source`.
    const data = state.source.get(route);
    Object.assign(data, { ...option, isAcfOptionsPage: true });
  },
};

Then, to fetch the options you can do

await Promise.all([
  actions.source.fetch("acfOptions/options"),
  actions.source.fetch("acfOptions/theme-identity-settings"),
  actions.source.fetch("getWPConfig"),
]);

And the same to get their content.

const options = state.source.get("acfOptions/options");

Hope it helps. :slightly_smiling_face:

Alright, now I understand the way a pattern in a handler works. Thatā€™s very cool!
Thanks, @David!

1 Like