Next and Previous Post

Hi All, I am just exploring frontity for an upcoming website. Its basically like an ebook design where we have various chapters organized as posts and we need the functionality of next and previous post so that user can just click and he can read next or come back to previous post.

Also can you refer something about how to include breadcrumbs in post.

Gratitude and love from India!

1 Like

Hi @sumankocher3

Welcome to the community.

The WordPress REST API does not include next/previous links in the JSON response by default. You will need to add them to the REST API yourself.

You can do that by adding the following PHP code to a custom plugin, or to your theme’s functions.php file:

add_filter( 'rest_prepare_post', 'add_prev_next_to_rest' , 10, 3 );

function add_prev_next_to_rest( $response, $post, $request ) {
    global $post;
    // Get the next post.
    $next = get_adjacent_post( false, '', false );
    // Get the previous post.
    $previous = get_adjacent_post( false, '', true );
    // Only send id and slug (or null, if there is no next/previous post).
    $response->data['next'] = ( is_a( $next, 'WP_Post') ) ? array( "id" => $next->ID, "slug" => $next->post_name ) : null;
    $response->data['previous'] = ( is_a( $previous, 'WP_Post') ) ? array( "id" => $previous->ID, "slug" => $previous->post_name ) : null;

    return $response;
}

This will add something similar to this in the returned JSON which you can access from your JS code:

next: {
id: 14,
slug: "san-francisco"
},
previous: {
id: 5,
slug: "chicago"
},

Hope this helps. Do please let us know what you’re building with Frontity. Post a link so we can see your site.

Thanks ! Gratitude again, just trying to learn with all of your help. Hope to build first prototype soon.

Can you also guide about the breadcrumbs ?

Hi @sumankocher3

What do you want to do with breadcrumbs? Breadcrumbs are usually used to indicate a category hierarchy.

What have you already tried?

Yes my posts have categories, subcategories and subcategories so wanted to show user.

Is fetching subcategories different then fetching categories?

Hi @sumankocher3

No, when the posts are fetched all category and sub-category IDs are included in the returned JSON. However, the hierarchy is not preserved, so when you construct your breadcrumbs you will need to know which category ID is a sub-category of which other category ID by looking in the WP admin pages.

Thanks a zillion ! I have noticed a issue here, my category names are in non English in my regional language and when I try to just copy it, its not accepted but when I put its url version its accepted like :

(Original Category : Not Accepted )

category/रामधारी-सिंह-दिनकर/

(This is accepted)

category/%e0%a4%b0%e0%a4%be%e0%a4%ae%e0%a4%a7%e0%a4%be%e0%a4%b0%e0%a5%80-%e0%a4%b8%e0%a4%bf%e0%a4%82%e0%a4%b9-%e0%a4%a6%e0%a4%bf%e0%a4%a8%e0%a4%95%e0%a4%b0/

Is this a standard behaviour with non English links or I am doing something wrong?

So I have implemented this solution in my Wordpress functions.php file and my Post component looks like this:

import React from "react"
import { connect, styled } from "frontity"
import Link from "@frontity/components/link"
import dayjs from "dayjs"
import Gallery from './../molecules/gallery'


const Post = ({ state, libraries }) => {
  const data = state.source.get(state.router.link)
  const post = state.source[data.type][data.id]
  const nextPost = state.source[data.type][post.next.id]
  const prevPost = state.source[data.type][post.previous.id]
  const author = state.source.author[post.author]

  const formattedDate = dayjs(post.date).format("DD MMMM YYYY")
  const Html2React = libraries.html2react.Component;

  return (
<div>
  <h2><Html2React html={post.title.rendered} /></h2>
  <PostInfo>
    <p>
      <strong>Posted: </strong>
      {formattedDate}
    </p>
    <p>
      <strong>Author: </strong>
      {author.name}
    </p>
  </PostInfo>
   <Html2React html={post.content.rendered} />
   <Gallery />
   <Link link={nextPost.link}>Next: <Html2React html={nextPost.title.rendered} /></Link>
   <Link link={prevPost.link}>Previous: <Html2React html={prevPost.title.rendered} /> </Link>
</div>
  )
}

const PostInfo = styled.div`
  background-image: linear-gradient(to right, #f4f4f4, #fff);
  margin-bottom: 1em;
  padding: 0.5em;
  border-left: 4px solid lightseagreen;
  font-size: 0.8em;

  & > p {
margin: 0;
  }
`

export default connect(Post)

This solution works great at first, and if I start from the home page and navigate to the individual post, I see the links and can click to navigate between the posts in this way. However, if I refresh the page, or try to navigate to a specific post by the URL, I get an “Internal Server Error” message on the screen and nothing else rendered.

Any help or insight into this problem is greatly appreciated!

Thank you!

Hi @tommywoodhouse02

I think I’ve managed to get it to work. Try this slightly simplified version of post.js (albeit without your <Gallery /> component:

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

const Post = ({ state, libraries }) => {
  const data = state.source.get(state.router.link);
  const post = state.source[data.type][data.id];
  const author = state.source.author[post.author];
  const formattedDate = dayjs(post.date).format("DD MMMM YYYY");

  const nextPost = post.next
  const prevPost = post.previous

  const Html2React = libraries.html2react.Component;

  return (
    <div>
      <Head>
        <title>{post.title.rendered}</title>
        <meta name="description" content={post.excerpt.rendered} />
      </Head>
      <h2>{post.title.rendered}</h2>
      <PostInfo>
        <p>
          <strong>Posted: </strong>
          {formattedDate}
        </p>
        <p>
          <strong>Author: </strong>
          {author.name}
        </p>
      </PostInfo>
      <Html2React html={post.content.rendered} />

      { nextPost ? <Link link={nextPost.slug}>Next</Link> : ''}
      { prevPost ? <Link link={prevPost.slug}>Previous</Link> : ''}

    </div>
  );
};

export default connect(Post);

const PostInfo = styled.div`
  background-image: linear-gradient(to right, #f4f4f4, #fff);
  margin-bottom: 1em;
  padding: 0.5em;
  border-left: 4px solid lightseagreen;
  font-size: 0.8em;

  & > p {
    margin: 0;
  }
`;

I think the basic problem is that you’re not checking if nextPost/prevPost have a value or is null, so you’re getting an internal server error on the first or last posts because you’re trying to read a value from null.

When you do:

  const nextPost = state.source[data.type][post.next.id]
  const prevPost = state.source[data.type][post.previous.id]

you need to check that post.next or post.previous exists before you try to read the property id from them.

1 Like

Thanks so much for your help @mburridge! You were right, I was calling the value before checking if it existed.

The reason why I was trying to use const nextPost = state.source[data.type][post.next.id] was because I couldn’t use just the slug as the link location as my posts have the categories in their URLs, so the link was going to a URL that was “domain.com/post-name” when I needed it to be “domain.com/category/post-name” so I was trying to reach out to the post using the ID in that const variable, then grabbing the link property from there - I believe this is where I was running into the Internal Server Error issues.

To solve this, I went back to my functions.php file and adjusted the code to include the relative path as a link property in the API with this:

/* Add next & previous links to REST API */
add_filter( 'rest_prepare_post', 'add_prev_next_to_rest' , 10, 3 );

function add_prev_next_to_rest( $response, $post, $request ) {
    global $post;
    
    // Get the next post.
    $next = get_adjacent_post( false, '', false );
    
    //Get next post url and relative link
    $nextPostUrl = get_permalink( get_adjacent_post(false,'',false)->ID ); 
    $nextPostLink = wp_make_link_relative( $nextPostUrl );
    
    // Get the previous post.
    $previous = get_adjacent_post( false, '', true );
    
    //Get previous post url and relative link
    $prevPostUrl = get_permalink( get_adjacent_post( false, '', true )->ID ); 
    $prevPostLink = wp_make_link_relative( $prevPostUrl );
    
    // Only send id and slug (or null, if there is no next/previous post).
    $response->data['next'] = ( is_a( $next, 'WP_Post') ) ? array( "id" => $next->ID, "slug" => $next->post_name, "link" => $nextPostLink ) : null;
    $response->data['previous'] = ( is_a( $previous, 'WP_Post') ) ? array( "id" => $previous->ID, "slug" => $previous->post_name, "link" => $prevPostLink ) : null;

    return $response;
}

Then, I modified your conditional link to be:

{ nextPost ? <Link link={nextPost.link}>Next</Link> : ''}
{ prevPost ? <Link link={prevPost.link}>Previous</Link> : ''}

And this seems to have solved all my issues! Sorry I know that was a lengthy response but I figured I would include everything in case anyone else was looking for a similar solution.

Thanks again, @mburridge! You really helped.

3 Likes

Hi Friends,

Can i use above code for custom post type like portfolios, Gallery, etc…

please reply me…

Thank you.

Hi @bhagvan.vrinsofts

I used this code for my website, with different CPT.

// Add next & previous links to REST API
function add_prev_next_to_rest( $response, $post, $request ) {
    global $post;

    // Get the next post.
    $next = get_adjacent_post( false, '', false );
    //Get next post url and relative link
    $nextPostUrl = get_permalink( get_adjacent_post(false,'',false)->ID ); 
    $nextPostLink = wp_make_link_relative( $nextPostUrl );
    // Get the previous post.
    $previous = get_adjacent_post( false, '', true );
    //Get previous post url and relative link
    $prevPostUrl = get_permalink( get_adjacent_post( false, '', true )->ID ); 
    $prevPostLink = wp_make_link_relative( $prevPostUrl );
    // Only send id and slug (or null, if there is no next/previous post).
    $response->data['next'] = ( is_a( $next, 'WP_Post') ) ? array( "id" => $next->ID, "slug" => $next->post_name, "link" => $nextPostLink ) : null;
    $response->data['previous'] = ( is_a( $previous, 'WP_Post') ) ? array( "id" => $previous->ID, "slug" => $previous->post_name, "link" => $prevPostLink ) : null;

    return $response;
}
add_filter( 'rest_prepare_post', 'add_prev_next_to_rest' , 10, 3 );
add_filter( 'rest_prepare_people', 'add_prev_next_to_rest' , 10, 3 );
add_filter( 'rest_prepare_board', 'add_prev_next_to_rest' , 10, 3 );
add_filter( 'rest_prepare_esg', 'add_prev_next_to_rest' , 10, 3 );

At the bottom you can see that you need to register the fuction for each CPT you want to add it to. So rest_prepare_CPT-NAME

2 Likes

Thank you so much.

It’s working fine.