How to create Custom Pages?

Are you trying to load a post or a page? Could you tell us a bit more about your case to check what could be the best solution?

In my site http://tusjuegos.io/ I want a view that list the blog post instead of linking to blog.tusjuegos.io (because Iā€™m having SEO issues). So the path of the view must be http://tusjuegos.io/blog

This is what I have:

// src/index.js
const blogListHandler = {
    pattern: '/blog/',
    func: ({ state }) => {
        state.source.data['/blog/'].isBlogList = true
    }
}


const marsTheme = {
    ...
    actions: {
        theme: {
            init: ({ libraries }) => {
                libraries.source.handlers.push(blogListHandler )
            }
        }
    },
    ....
}

Then on src/components/index.js


            <Content>
                {(data.isFetching && <Loading />) ||
                    (data.isBlogList && <BlogList />) ||
                    (data.isArchive && <List />) ||
                    (data.isPostType && <Post />) ||
                    (data.is404 && <Page404 />)}
            </Content>

My component looks like this

const BlogList = ({ state }) => {

    const items = Object.keys(state.source.post).map(
        id => state.source.post[id]
    )
    console.log(JSON.parse(JSON.stringify(state)), items)

    return ....
}

export default connect(BlogList)

Oh okay! If I understood it correctly you are trying to fetch the lists of posts in both the home and the /blog but format it differently right?

I think the problem may be cause because in your handler, that is executed if you access "/blog", you are not fetching the posts, you are just adding the isBlogList value.

In order to fix that problem, you could reuse the post archive handler used for the homepage. Something like this:

// src/index.js
const blogListHandler = {
    pattern: '/blog/',
    priority: 10,
    func: async ({ route, params, state, libraries }) => {
      state.source.data["/blog/"].isBlogList = true;
      const archive = libraries.source.handlers.find(
        handler => handler.name == "post archive"
      );
      await archive.func({ route, params, state, libraries });
    }
}

As itā€™s going to have also the property isArchive you may need to change your conditions inside index.js in order to prevent duplicating the content.

@David Could you confirm if reusing the post archive handler is a good approach or should it be done in a different way?

Why not using state.source.homepage and state.source.postsPage to change the homepage to /blog?

Both the homepage and /blog are pointing to latest posts. I thought that it wasnā€™t possible just with state.source.homepage and state.source.postsPage settings because they have to match the WP Settings, and as far as I know you can only point the latest posts to another url if you set the homepage to a static page.

Oh, I see :slight_smile:

Thatā€™s right. I just copied your snipped and it works. :slight_smile:

Could you please clarify this?

ā€¦you may need to change your conditions inside index.js in order to prevent duplicating the content.

Glad it works :slightly_smiling_face:

Sure! As you are reusing the post archive handler, the prop isArchive is going to be passed to /blog url. So in the src/components/index.js itā€™s going to be matching two conditions, both data.isBlogList and data.isArchive:

<Content>
  {(data.isFetching && <Loading />) ||
  (data.isBlogList && <BlogList />) ||
  (data.isArchive && <List />) ||
  (data.isPostType && <Post />) ||
  (data.is404 && <Page404 />)}
</Content>

What I meant is just that you have to be careful to load just the <BlogList /> component, so you donā€™t get your content duplicated.

3 Likes

2 posts were split to a new topic: Link does not render href on the anchor tag

Hi, when I put the handler for my custom page. But when I click on the URL, itā€™s reloading the page as for sure its redirection to a custom page. Is there any way that we donā€™t get the reload effect and get the page in front of us. Like in case of Menus, when we click on any of the menu, the page does not get reloaded instead it only fetch the data of that page.

hereā€™s our website url:
http://app.moosaconsulting.com/
Please check by clicking on strategy under section Who We Work With section.

Cheers,

I added the custom page but when I click on that link I am getting reLoad effect. But when I click on nav-menu link it just loads the body of the page not reload the whole page? Can I do the same for my custom page? Is there any suggestion for this?
Thanks

Hey @hammad, I think you are not using the <Link> component for those links, which internally uses actions.router.set(). Check it out!

3 Likes

yeah, I have corrected an hour ago after reading the doc.

https://docs.frontity.org/api-reference-1/router

btw A ton of thanks for your response. :slight_smile:

3 Likes

Hi there,
I have to add different custom pages to my website so every time I have to add a custom handler to add my page to chakra-theme. Is it possible to create my custom posts on WordPress with all applied styles and then load them dynamically from WordPress?
Or I have to style the post/page in frontity again?

@hammad, I think you should use gutenberg blocks. Adding more styles in the content has usually been an anti pattern in WordPress, I think.


By the way, the other day I realized that there is another way to add a custom, non-WordPress page to Frontity.

Instead of creating a custom handler, like this:

const signUpHandler = {
  pattern: "/sign-up/",
  func: ({ state }) => {
    state.source.data["/sign-up/"].isSignUp = true;
  }
}

You can add the data to the state:

const myPackage = {
  state: {
    source: {
      data: {
        "/sign-up/": {
          isReady: true,
          isFetching: false,
          isSignUp: true
        }
      }
    }
  }
}

actions.source.fetch("/sign-up") wonā€™t do the fetch because isReady is true.

The only case where it wouldnā€™t work is if someone does actions.source.fetch("/sign-up", { force: true }) but that should never happen with a custom page like this.

3 Likes

Can someone help me with adding a custom page to the frontity project.

I added the following ā€¦

const signUpHandler = {

  pattern: "/signup/",

  func: ({ route, state }) => {

    Object.assign(state.source.data[route], {

      type: "page",

      isSignUp: true,

    });

  },

};

ā€¦

actions: {

    theme: {

      actions: {

        init: ({ libraries }) => {

          libraries.source.handlers.push(signUpHandler);

        },

      },

      beforeSSR: before,

      beforeCSR: before,

      toggleMobileMenu: ({ state }) => {

        state.theme.isMobileMenuOpen = !state.theme.isMobileMenuOpen;

      },

      closeMobileMenu: ({ state }) => {

        state.theme.isMobileMenuOpen = false;

      },

    },

  },

ā€¦
frontity.settings

 ["Sign up", "/signup/"],

ā€¦

signup.js

import React, { useEffect } from "react";

//import { connect, styled } from "frontity";

const Signup = () => {

  return (

    <div>

      <h2>Sign up Page</h2>

    </div>

  );

};

export default Signup;

ā€¦

theme index.js

<Switch>

          <Signup when={data.isSignUp} />

          <Loading when={data.isFetching} />

          <List when={data.isArchive} />

          <Post when={data.isPostType} />

          <PageError when={data.isError} />

ā€¦

I keep getting 404 error. and react_devtools_backend.js:2273 ServerError: post type from endpoints ā€œposts,pages,mediaā€ with slug ā€œsignupā€ not found

Any guidance is much appreciated.

I think you forgot to add a priority to the handler. For example priority: 10.

By the way, instead of a handler, you can try adding that data to the state:

const myPackage = {
  state: {
    source: {
      data: {
        "/signup/": {
          isReady: true,
          isFetching: false,
          isSignUp: true,
        },
      },
    },
  },
};

Let me know if that works :slightly_smiling_face:

3 Likes

Yes adding the priority:10 to the handler fixed it!!! And also I added the init wrong, if you see code above, I inserterted the init in actions.theme.actions.init whilst it should have been actions.theme.initā€¦ Thank you so much!!!

2 Likes

Hi ! I created a new route to custom component when I will call an external API using your code. I can get a listing without any problem. Now I want to fetch to a specific id to fetch to a new component

data: {
        "/hello/:id": {
          isReady: true,
          isFetching: false,
          isHello: true,
        },
      },

However it wonā€™t workā€¦ any suggestion ?

If you want to use a pattern you need to create a handler:

const helloHandler = {
  pattern: "/hello/:id",
  func: ({ state, link, params }) => {
    state.source.data[link].isReady = true;
    state.source.data[link].isHello = true;
    state.source.data[link].id = params.id;
  },
};

And then add it to libraries.source.handlers.