Create new front page and include archive articles

Hey,
I’d like to create a new front page in my theme that is different from any archive page, but which includes recently created articles.

My first step was to add a new homeHandler to index.js:

const homeHandler = {
  name: "home",
  pattern: "/",
  func: ({ state }) => {
    state.source.data["/"].isFrontPage = true;
    state.source.data["/"].isArchive = false;
  }
}

…register it using
libraries.source.handlers.push(homeHandler);
in actions.theme.init and implement the component.

This works fine. But now, I would like to show the newest articles in my home page component. Is there any shorter way to achieve that without implementing a separate fetching logic (calling libraries.source.api.get and populating)? Right now, the data in state.source.get("/") is missing of course and I need to do basically the same which the frontity archive handler does.

Any ideas, information and best practices are welcome :slight_smile:
Thank you!

Hi @cobra! Sorry for the late reply

If I understood the case correctly you don’t need a handler for this. I think the best way would be to check if you are on the homepage (this info is already in Frontity state) and in that case, load a new component.

At the index.js file of your theme you should check if it’s the homepage, and if so load your <Home /> component:

const Theme = ({ state }) => {

  return (
    <>
      ...
      <Main>
        {(data.isFetching && <Loading />) ||
          (data.isHome && <Home />) ||
          (data.isArchive && <List />) ||
          (data.isPostType && <Post />) ||
          (data.is404 && <Page404 />)}
      </Main>
    </>
  );
};

export default connect(Theme);

Apart from that, you should create your <Home /> component where you can load whatever you want, including the latest posts. You could do something like this:

import React from "react";
import { connect, styled } from "frontity";
import Item from "./list-item";

const Home = ({ state }) => {
  // Get the data of the latest posts.
  const data = state.source.get(state.router.link);

  return (
    <Container>
      <div>Some content before the posts</div>

      <div>
          <p>Load the posts here</p>
          <div>
              {data.items.map(({ type, id }) => {
                  const item = state.source[type][id];
                  // Render one Item component for each post.
                  return <Item key={item.id} item={item} />;
              })}
          </div>
      </div>

      <div>Some content after the posts</div>

    </Container>
  );
};

export default connect(Home);

This way, you’ll be importing the list-item that it’s already created (with its title, author, excerpt, etc), but you could also create a new one and import that instead.

That should be enough, let us know if it works in your case and if you have any other questions don’t hesitate to share them :relaxed:

2 Likes

Thank you really much, this solves my problem!
However, I’d like to do one additional thing: Right now, it’s possible to access URLs like /page/1 etc. Is it possible to (easily) prevent that with this solution? I know, it’s not the standard behaviour for a WP blog, but in my current state of the website I would like to restrict that. Thank you!

Not sure about this one, for sure @David can confirm if I am correct. What I thought was to use the parse method (explained here) to check if page is included and in that case return a 404. In your case it could be something like this:

import Page404 from "./page404";

const Home = ({ state, libraries }) => {
  const currentLink = state.router.link;
  // Get the data of the latest posts.
  const data = state.source.get(currentLink);
  // Get the page of the link.
  let { page } = libraries.source.parse(currentLink);

  if (page > 1) {
    return <Page404 />;
  } else {
    return (
      <div>
        <div>Some content before the posts</div>

        <div>
          <p>Load the posts here</p>
          <div>
            {data.items.map(({ type, id }) => {
              const item = state.source[type][id];
              // Render one Item component for each post.
              return <Item key={item.id} item={item} />;
            })}
          </div>
        </div>

        <div>Some content after the posts</div>
      </div>
    );
  }
};

export default connect(Home);

Of course, you could change the page404 for other content if you want. I think this would solve your problem, but tell us if that’s not the case.