TransWikia.com

Next and Previous Posts of Same Parent

WordPress Development Asked by ZackAkai on November 14, 2021

I’m working on a website for a webcomic and I have a custom post type set up for comic pages. I have multiple series on the site and have made each comic page a child post of a parent (one parent for each series) to keep them organized and give the URLs some structure. What I’m trying to do now is add next and previous buttons to each comic page so the reader can easily move between them. I’m currently having two separate but related issues.

1. The comic pages use the same name and URL format, only separated by their parent. So for example the first page of series LCC looks like this:

http://localhost/wordpress/comics/lcc/v01-001/

Whereas the first page of series HTA looks like this:

http://localhost/wordpress/comics/hta/v01-001/

WordPress allows this at a URL/slug level but it creates problems when trying to use the next and previous post functions. What happens is that the children of the parent which was created first (in this case LCC) take priority, which works perfectly when moving back and forward within LCC. However if I go to a page from HTA and try to move back and forward in there, it immediately kicks me out to the page with the appropriate slug but in LCC (so for example clicking "next" on hta/v01-001 should lead to hta/v01-002, but instead leads to lcc/v01-002 – clicking "previous" then leads to lcc/v01-001).

I’ve found some solutions that do away with the next/previous post functions and do it by incrementing the post ID, but that won’t work for me because I’ve set it up to paginate by menu order, which I’ve changed to be alphabetical (I want this all to work independently of post ID number). Here’s the code I used for that:

/* === Reorder Comic Page Pagination Alphabetically === */
function filter_next_post_sort($sort) {
    global $post;
    if (get_post_type($post) == 'comic-page') {
        $sort = "ORDER BY p.post_title ASC LIMIT 1";
    }
    else{
        $sort = "ORDER BY p.post_date ASC LIMIT 1";
    }
    return $sort;
}

function filter_next_post_where($where) {
    global $post, $wpdb;
    if (get_post_type($post) == 'comic-page') {
        return $wpdb->prepare("WHERE p.post_title > '%s' AND p.post_type = '". get_post_type($post)."' AND p.post_status = 'publish'",$post->post_title);
    }
    else{
        return $wpdb->prepare( "WHERE p.post_date > '%s' AND p.post_type = '". get_post_type($post)."' AND p.post_status = 'publish'", $post->post_date);
    }
}

function filter_previous_post_sort($sort) {
    global $post;
    if (get_post_type($post) == 'comic-page') {
        $sort = "ORDER BY p.post_title DESC LIMIT 1";
    }
    else{
        $sort = "ORDER BY p.post_date DESC LIMIT 1";
    }
    return $sort;
}

function filter_previous_post_where($where) {
    global $post, $wpdb;
    if (get_post_type($post) == 'comic-page') {
        return $wpdb->prepare("WHERE p.post_title < '%s' AND p.post_type = '". get_post_type($post)."' AND p.post_status = 'publish'",$post->post_title);
    }
    else{
        return $wpdb->prepare( "WHERE p.post_date < '%s' AND p.post_type = '". get_post_type($post)."' AND p.post_status = 'publish'", $post->post_date);
    }
}

add_filter('get_next_post_sort',   'filter_next_post_sort');
add_filter('get_next_post_where',  'filter_next_post_where');
add_filter('get_previous_post_sort',  'filter_previous_post_sort');
add_filter('get_previous_post_where', 'filter_previous_post_where');

And my custom post code:

/* === Comic Page === */
function post_type_comic_page() {
    
    // Labels
    $labels = array(
        'name' => 'Comic Pages',
        'singular_name' => 'Comic Page',
        'add_new' => 'Add New Comic Page',
        'add_new_item' => 'Add Comic Page',
        'all_items' => 'All Comic Pages',
        'edit_item' => 'Edit Comic Page',
        'not_found' => 'No Comic Pages Found',
        'not_found_in_trash' => 'No Comic Pages Found in Trash',
    );
    
    // Arguments
    $args = array(
        'labels' => $labels,
        'public' => true,
        'menu_icon' => 'dashicons-book-alt',
        'hierarchical' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'publicly_queryable' => true,
        'rewrite' => array( 'slug' => 'comics', 'with_front' => false ),
        'supports' => array(
            'page-attributes', 'title', 'editor', 'something-else',
        ),
    );
    
    // Register Comic Pages Post Type
    register_post_type('comic-page', $args);
}

add_action('init', 'post_type_comic_page');

2. When I solve that problem, I then need to be able to restrict forward and backward navigation to only the siblings under the same parent. So upon reaching the last page of LCC, it should NOT go to the first page of HTA, or vice-versa.

My fallback option for all this is to just use a series taxonomy (which I had set up previously and worked), but I’m trying to eliminate as much unnecessary code and as many necessary things to check on each comic page as possible. I can do literally everything else I need to without a taxonomy just for that, so if it’s at all possible to do this with child/parent relationships please help me out!

One Answer

So I can't give you a complete solution but here are the pieces that I think might help:

  1. Getting parent post ID: wp_get_post_parent_id() - https://developer.wordpress.org/reference/functions/wp_get_post_parent_id/

  2. Getting all posts with a particular parent ID. Here's a WP_Query args to get all posts by parent ID

    $args = array(
        'post_parent' => $parentID,
        'posts_per_page' => -1,
        'orderby' => '???'   // you need to choose how your child posts should be ordered
    );

So you could use the above code to find the parent ID of the current post and then get all the children of that - these would be the 'siblings' of the current post.

  1. Use the above code to find next/prev post IDs. Below is my suggestion for code to read all 'sibling' posts and figure out next and previous URLs. What this does is cycle through all the sibling posts of the post we're on looking for the one before and the one after in order to give you a post ID for previous and next posts. If the current post is at the start, then $prevPostID will be false, so you can use that to not display the previous post link. If the current post as at the end, then $nextPostID will be false, so you can prevent the next post link displaying.

This assumes that you've built an $args using the suggestion for getting all children of the parent post ID as above.

$currentID = ?? // assume we have the current post ID here

$wpq = new WP_Query( $args );
if ( $wpg->have_posts() ) {
    $prevPostID = false;
    $nextPostID = false;
    $previousInLoop = false;

    while ( $wpq->have_posts() ) {
        if (get_the_ID() == $currentID) {
            $prevPostID = $previousInLoop;
        }
        if ($previousInLoop == $currentID) {
            $nextPostID = get_the_ID();
            break;
        }
        $previousInLoop = get_the_ID();
    }
}

This is a suggestion for how you could make this code work and is untested code. Happy to help if you use it and have further problems.

Note, you could also grab the next/prev title and URL while you were in the loop, rather than having to look them up again later, but I'll leave that to you.

Answered by mozboz on November 14, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP