Custom routing paths lead to 404 page

I made custom paths in my Frontity project and those lead to 404 page.
Could you take a look and tell me what I’m missing?

Paths are defined so when I hover over the links to different pages, it shows the paths localhost:3000/about`, but when I go to the page (click or type in the search bar), it shows 404 page.

I also created menuHandler in src/index.js, but this is for fetching from the WordPress site not projecting my project path to the WordPress site? Let me know this is wrong.

theme/src/components/Index.js - Mentions routings with Switch

const Root = ({ state, libraries }) => {
  const data = state.source.get(state.router.link);

  return (
    <>
      <GlobalStyles />
      <Nav />

      <Switch>
        {/* with 'when prop' */}
        <Home when={data.isHome} />

        {/* custom path */}
        <About path="/about" />
        <Contact path="/contact" />
        <TermsOfService path="/terms-of-service" />
        <PrivacyPolicy path="/privacy-policy" />

        <NotFound />
      </Switch>
      <Footer />
    </>
  );
};
export default connect(Root);

theme/src/components/Nav.js

import React from "react";
import styled from "styled-components";
import { connect } from "frontity";
import Link from "@frontity/components/link";

const Nav = () => {
  return (
    <Styles>
      <div className="menu-wrapper">
        <Link link="/about">About</Link>
        <Link link="/contact">Contact</Link>
        <Link link="/terms-of-service">Terms of Service</Link>
        <Link link="/privacy-policy">Privacy Policy</Link>
      </div>
    </Styles>
  );
};

export default connect(Nav);

theme/src/index.js - MenuHandler and custom theme

import Root from "./components";

const menuHandler = {
  name: "menus",
  priority: 10,
  pattern: "/menus/:slug",
  func: async ({ route, params, state, libraries }) => {
    const { api } = libraries.source;
    const { id } = params;

    // fetch data from the endpoint page
    const response = await api.get({
      endpoint: `/menus/v1/locations/${id}`,
    });

    // get an array with each item in json format
    const items = await response.json();

    // add data to source
    const currentPageData = state.source.data[route];

    Object.assign(currentPageData, {
      id,
      items: items.items,
      isMenu: true,
    });
  },
};

export default {
  name: "custom-theme",
  roots: {
    theme: Root,
  },
  state: {
    theme: {
      isMenuOpen: false,
    },
  },
  actions: {
    theme: {
      beforeSSR: ({ actions }) => async () => {
        // Adding both menu location menus to beforeSSR
        await actions.source.fetch("/menus/primary-menu");
        await actions.source.fetch("/menus/footer-menu");
      },
    },
  },
  libraries: {
    source: {
      handlers: [menuHandler],
    },
  },
};

Thank you!

Same issue happened with me :frowning: i did not get any response

Hi @misakimichy

Can you please provide a repo or code-sandbox with your code? This is especially helpful to find solutions of technical issues with specific code

The <Switch> component available from the @frontity/components collection package, allows you to define specific React components to be loaded whenever the value provided to the when prop evaluates to true

So, you can use this structure along with the state.source.get(state.router.link) data to load specific components based on the nature of the link

js
import Switch from "@frontity/components/switch";

const Theme = ({ state }) => {
  const data = state.source.get(state.router.link);

  return (
    <Switch>
      <Loading when={data.isFetching} />
      <Home when={data.isHome} />
      <Archive when={data.isArchive} />
      <Post when={data.isPostType} />
      <ErrorPage /> {/* rendered by default */}
    </Switch>
  );
};

Notice how the React components under this <Switch> component are expected to have a when prop and not a path prop

I guess you’re mixing the <Switch> component component provided by Frontity via its @frontity/components collection package, with the <Switch> component used by React Router

The power of Frontity’s <Switch> component component is that the routing defined with its system it will automatically work in both CSR /(Client Side Rendering) and SSR (Server Side Rendering), this is, those links will work by using internal React link or by loading directly those pages

here my git repo

I’m writing this project for my customer, and their repo is private, so I cannot share this project repo.

I cannot find the documentation mentioning how to make custom paths with the frontity/tiny-router or component, so could you give me instructions on how to do that?
For example, how to add /about path and render component on click of component.

About is a dynamic page in Wordpress. So in Frontity it render as page. If you want custom components for your page you have to check in switch condition data.isPage(pageid) for this check you have to console.log(data) which is pass from state.source.get(state.router.link) in theme index.js.

Thank you @harpreet.freelance for your reply.

I don’t see isPage when I console.log(data), so I’m a little bit confused. data is state.source.get(state.router.link).
This is the screenshot:
Screen Shot 2021-02-25 at 10.57.07

Do you have any idea how to get isPage?

Hi @misakimichy,

In the documentation of the state.source.get() you can read how this method returns an object that gives you info about the type of that link and related entities.

The information to distinguish each type of link is based on the WP Template Hierarchy. So from the content in WordPress you can have posts, categories… and pages

Posts and Pages are easy to locate in a WordPress backend. If you create a new page in WordPress (let’s say /about), you can access to that page directly with Fronttiy and in the data of that page (the one you’ll get through state.source.get(state.router.link) ) you’ll get the property isPage: true


I recommend you to watch this video where you can find an explanation of we can directly display a page from wordPress

and have a look at this demo

Thank you for the link!

I just figured out how to render without leading to 404 page.
I still don’t have isPage property when I go through state.source.get(state.router.link) but there is id property under state.source.get(state.router.link) which each pages has different id, and I could use it to specify which component to render.

This is my routing page looks like:

const Root = ({ state }) => {
  const data = state.source.get(state.router.link);

  return (
    <>
      <Head>
        <meta name="description" content={state.frontity.description} />
        <html lang="en" />
      </Head>
      <GlobalStyles />
      <Nav />
      <Switch>
        <Loading when={data.isFetching} />

        <Home when={data.isHome} />
        <About when={data.id === 8} />
        <Contact when={data.id === 7} />
        <TermsOfService when={data.id === 4} />
        <PrivacyPolicy when={data.id === 41} />
        <NotFound />
      </Switch>
      <Footer />
    </>
  );
};
export default connect(Root);

Yes i think its right, but you have 1 more option to get page content with page id in your api url for example

(http://your-domain.com/wp-json/wp/v2/pages/41) it return single page content and after that you have to make your own custom handler then fetch and populate content in state.source.get(state.router.link);

After all of these, you will get if data.isTerms

1 Like