Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

Single CPT template with post nav & counter within children WordPress

  • SOLVED

Hey guys!

I have the current setup on my page:

Custom post type parent posts, with a number of children custom post types under each parent. The children are only one level deep.

What I would like:

<strong>1.</strong> On the single template of the children custom post type, I would like to have a post navigation to next/previous post, that only navigates between the children of the parent post.

<strong>2.</strong> If on the last post, I would like the navigation next link to point to the first post. So the navigation should "loop" within the parent post.

<strong>3.</strong> The posts in the parent post are ordered by the number in the custom field <em>_point</em>, so the navigation should also navigate with this order in mind.

<strong>4.</strong> I would also like to display a counter on the single template, saying something like "Post nr 7 of 19 total posts".

This is my code so far, but I'm having a problem getting the order of the posts and the counter to add up. There seems to be a problem with the ordering by the custom field.

<strong>The navigation</strong> (<em>not looping the way I explain under number 2 above</em>):

?php // display nav only if there are child pages
if ($post->post_parent) { // applies only to child pages
$pagelist = get_pages("child_of=".$post->post_parent."&parent=".$post->post_parent."&orderby=date&order=desc&post_type=user_images&post_status=publish");
$pages = array();
foreach ($pagelist as $page) {
$pages[] += $page->ID;
}
$current = array_search($post->ID, $pages);
$prevID = $pages[$current-1];
$nextID = $pages[$current+1];
?>

<nav class="navigation post-navigation" role="navigation">
<div class="nav-links">
<?php if (!empty($prevID)) { /* if we are browsing first child, then link to parent page*/ ?>
<a rel="prev" href="<?php echo get_permalink($prevID); ?>" title="<?php echo get_the_title($prevID); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($prevID); ?></a>
<?php }
else { // else, link to previous child ?>
<a rel="prev" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>
<?php }

if (!empty($nextID)) { ?>
<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>
<?php } ?>
</div>
</nav>
<?php }
else { // if we are browsing parent page, then link to first child
$child_pages = get_pages("child_of=".$post->ID."&parent=".$post->ID."&sort_column=menu_order&sort_order=asc");
$first_child = $child_pages[0]; ?>
<?php if (!empty($first_child)) { ?>
<nav class="navigation post-navigation" role="navigation">
<div class="nav-links">
<a rel="next" href="<?php echo get_permalink($first_child->ID); ?>"><?php echo get_the_title($first_child->ID); ?> <span class="meta-nav">&rarr;</span></a>

</div>
<?php } } ?>


The class for counting the posts (need to be fixed, got it working ordered by date, but not sure how to fix it ordered by the meta_value_num). This is added to functions.php:

class MY_Post_Numbers {

private $count = 0;
private $posts = array();


public function display_count() {
$this->init(); // prevent unnecessary queries
$id = get_the_ID();
echo sprintf( '(%s/%s)', $this->posts[$id], $this->count );
}

private function init() {
if ( $this->count )
return;
$parent = wp_get_post_parent_id( $id );
global $wpdb;
$posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'publish' AND post_type = 'user_images' AND meta_value = '_point' AND post_parent = $parent ORDER BY meta_value_num DESC" ); // can add or change order if you want
$this->count = count($posts);

foreach ( $posts as $key => $value ) {
$this->posts[$value] = $key + 1;
}
unset($posts);
}

}
$GLOBALS['my_post_numbers'] = new MY_Post_Numbers;

function my_post_number() {
$GLOBALS['my_post_numbers']->display_count();
}


The codes above are just to <strong>show you my attempts</strong>, maybe there is a <strong>better approach to solve this?</strong>

Thanks a lot for your help!

Answers (3)

2015-10-19

Sébastien | French WordpressDesigner answers:

just use this code :
<?php


if ($post->post_parent !== 0) { // applies only to child pages

$pagelist = get_posts("post_parent=".$post->post_parent."&meta_key=_point&orderby=meta_value_num&order=desc&post_type=user_images&post_status=publish");

$pages = array();

foreach ($pagelist as $page) {

$pages[] += $page->ID;

}

$current = array_search($post->ID, $pages);

$prevID = $pages[$current-1];

$nextID = $pages[$current+1];

$total = count($pages);

$current_page = $current + 1;

?>



<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<?php if(array_key_exists($current-1, $pages)) { /* link to previous child */ ?>

<a rel="prev" href="<?php echo get_permalink($prevID); ?>" title="<?php echo get_the_title($prevID); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($prevID); ?></a>

<?php }

else { /* if we are browsing first child, link to parent page */ ?>

<a rel="prev" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php }



if(array_key_exists($current+1, $pages)) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php }

else { /* if we are browsing last child, link to parent page */ ?>

<a rel="next" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php } ?>

</div>

</nav>

<div>post <?php echo $page_current ?> of <?php echo $total ?></div>

<?php }

else { // if we are browsing parent page, then link to first child

$child_pages = get_posts("post_parent=".$post->ID."&meta_key=_point&orderby=meta_value_num&order=asc&post_type=user_images&post_status=publish");

$first_child = $child_pages[0];

if (!empty($first_child)) { ?>

<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<a rel="next" href="<?php echo get_permalink($first_child->ID); ?>"><?php echo get_the_title($first_child->ID); ?> <span class="meta-nav">&rarr;</span></a>

</div>

<?php }
} ?>



if get_posts doesn't work, try this code :

<?php


if ($post->post_parent !== 0) { // applies only to child pages


// WP_Query arguments
$args = array (
'post_parent' => $post->post_parent,
'post_type' => 'user_images',
'post_status' => 'publish',
'meta_key' => '_point',
'orderby' => 'meta_value_num',
);

// The Query
$your_query = new WP_Query( $args );

$pages = array();

// The Loop
if ( $your_query->have_posts() ) {
while ( $your_query->have_posts() ) {
$your_query->the_post();

$pages[] += $post->ID;

}
} else {
// no posts found
}

// Restore original Post Data
wp_reset_postdata();


$current = array_search($post->ID, $pages);

$prevID = $pages[$current-1];

$nextID = $pages[$current+1];

$total = count($pages);

$current_page = $current + 1;

?>



<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<?php if(array_key_exists($current-1, $pages)) { /* link to previous child */ ?>

<a rel="prev" href="<?php echo get_permalink($prevID); ?>" title="<?php echo get_the_title($prevID); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($prevID); ?></a>

<?php }

else { /* if we are browsing first child, link to parent page */ ?>

<a rel="prev" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php }



if(array_key_exists($current+1, $pages)) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php }

else { /* if we are browsing last child, link to parent page */ ?>

<a rel="next" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php } ?>

</div>

</nav>

<div>post <?php echo $page_current ?> of <?php echo $total ?></div>

<?php }

else { // if we are browsing parent page, then link to first child

$child_pages = get_posts("post_parent=".$post->ID."&meta_key=_point&orderby=meta_value_num&order=asc&post_type=user_images&post_status=publish");

$first_child = $child_pages[0];

if (!empty($first_child)) { ?>

<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<a rel="next" href="<?php echo get_permalink($first_child->ID); ?>"><?php echo get_the_title($first_child->ID); ?> <span class="meta-nav">&rarr;</span></a>

</div>

<?php }
} ?>


Jens Filipsson comments:

None of the codes are showing the correct total number of child posts I'm afraid, and on the second one the navigation isn't working


Sébastien | French WordpressDesigner comments:

the first code works ? Only the total number of child posts isn't correct ?


Sébastien | French WordpressDesigner comments:

there is a mistake in the code
the code must be
<div>post <?php echo $current_page ?> of <?php echo $total ?></div>
and no
<div>post <?php echo $page_current ?> of <?php echo $total ?></div>

that must be $current_page, not $page_current, sorry


Sébastien | French WordpressDesigner comments:

for the navigation : if we are in the last post, do you want that the link "next" go to the parent... or to the first post ?
and if we are in the first post, do you want that the link "prev" go to the parent... or to the last post ?


Jens Filipsson comments:

Last post to first post.
First post to last post.

Nothing to parent.


Jens Filipsson comments:

The post count right now says total 5 posts, when there are in fact 7 posts.


Jens Filipsson comments:

I see that you're code uses $pages btw, maybe it should be posts?


Sébastien | French WordpressDesigner comments:

ok I have made some modifications.
Could you try this code.
As you can see I "print_r" the array of posts. Could you copy and paste what is returned by the print_r please.


<?php


if ($post->post_parent !== 0) { // applies only to child pages

$pagelist = get_posts("post_parent=".$post->post_parent."&meta_key=_point&orderby=meta_value_num&order=desc&post_type=user_images&post_status=publish");

$array_pages = array();

foreach ($pagelist as $item_page) {

$array_pages[] += $item_page->ID;

}

print_r($array_pages);

$current = array_search($post->ID, $array_pages);

$prevID = $array_pages[$current-1];

$nextID = $array_pages[$current+1];

$total = count($array_pages);

$current_page = $current + 1;

?>



<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<?php if(array_key_exists($current-1, $array_pages)) { /* link to previous child */ ?>

<a rel="prev" href="<?php echo get_permalink($prevID); ?>" title="<?php echo get_the_title($prevID); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($prevID); ?></a>

<?php }

else { /* if we are browsing first child, link to parent page */ ?>

<a rel="prev" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php }



if(array_key_exists($current+1, $array_pages)) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php }

else { /* if we are browsing last child, link to parent page */ ?>

<a rel="next" href="<?php echo get_permalink($post->post_parent); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php } ?>

</div>

</nav>

<div>post <?php echo $current_page ?> of <?php echo $total ?></div>

<?php }

else { // if we are browsing parent page, then link to first child

$child_pages = get_posts("post_parent=".$post->ID."&meta_key=_point&orderby=meta_value_num&order=asc&post_type=user_images&post_status=publish");

$first_child = $child_pages[0];

if (!empty($first_child)) { ?>

<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<a rel="next" href="<?php echo get_permalink($first_child->ID); ?>"><?php echo get_the_title($first_child->ID); ?> <span class="meta-nav">&rarr;</span></a>

</div>

<?php }
} ?>


Sébastien | French WordpressDesigner comments:

Andrea P is right : replace

$array_pages[] += $item_page->ID;

by

$array_pages[] = $item_page->ID;



Sébastien | French WordpressDesigner comments:

Jens : have you try the code ? is it ok now ?


Jens Filipsson comments:

Sorry, had to step away from the computer for a while!

This is what the array returns:

Array ( [0] => 8729 [1] => 8736 [2] => 8923 [3] => 8830 [4] => 8727 )

Unfortunately, it still only counts 5 posts, when it is in fact 7 posts.


Jens Filipsson comments:

When I add posts_per_page=999 to the get_post argument, it seems to work


Sébastien | French WordpressDesigner comments:

ok... in this case, use posts_per_page=-1
so, the code is ok.
Is my answer complete and nice for you ?


Jens Filipsson comments:

We're getting there! One thing left: It doesn't "loop", meaning the first post doesn't link to the last and the other way around.


Sébastien | French WordpressDesigner comments:

yes, to loop, you need to use this code

<?php


if ($post->post_parent !== 0) { // applies only to child pages

$pagelist = get_posts("post_parent=".$post->post_parent."&meta_key=_point&orderby=meta_value_num&order=desc&post_type=user_images&post_status=publish&posts_per_page=-1");

$array_pages = array();

foreach ($pagelist as $item_page) {

$array_pages[] = $item_page->ID;

}

//print_r($array_pages);

$current = array_search($post->ID, $array_pages);

$prevID = $array_pages[$current-1];

$nextID = $array_pages[$current+1];

$total = count($array_pages);

$current_page = $current + 1;

$last = $array_pages[$total-1];

?>



<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<?php if(array_key_exists($current-1, $array_pages)) { /* link to previous child */ ?>

<a rel="prev" href="<?php echo get_permalink($prevID); ?>" title="<?php echo get_the_title($prevID); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($prevID); ?></a>

<?php }

else { /* if we are browsing first child, link to parent page */ ?>

<a rel="prev" href="<?php echo get_permalink($last); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php }



if(array_key_exists($current+1, $array_pages)) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php }

else { /* if we are browsing last child, link to parent page */ ?>

<a rel="next" href="<?php echo get_permalink($array_pages[0]); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>

<?php } ?>

</div>

</nav>

<div>post <?php echo $current_page ?> of <?php echo $total ?></div>

<?php }

else { // if we are browsing parent page, then link to first child

$child_pages = get_posts("post_parent=".$post->ID."&meta_key=_point&orderby=meta_value_num&order=asc&post_type=user_images&post_status=publish");

$first_child = $child_pages[0];

if (!empty($first_child)) { ?>

<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<a rel="next" href="<?php echo get_permalink($first_child->ID); ?>"><?php echo get_the_title($first_child->ID); ?> <span class="meta-nav">&rarr;</span></a>

</div>

<?php }
} ?>


Jens Filipsson comments:

This seems to work, but when linking to the first/last post, it still has the title of the parent post instead of the first/last title.


Sébastien | French WordpressDesigner comments:

arf yes Jens !
the code must be :

<?php


if ($post->post_parent !== 0) { // applies only to child pages

$pagelist = get_posts("post_parent=".$post->post_parent."&meta_key=_point&orderby=meta_value_num&order=desc&post_type=user_images&post_status=publish&posts_per_page=-1");

$array_pages = array();

foreach ($pagelist as $item_page) {

$array_pages[] = $item_page->ID;

}

//print_r($array_pages);

$current = array_search($post->ID, $array_pages);

$prevID = $array_pages[$current-1];

$nextID = $array_pages[$current+1];

$total = count($array_pages);

$current_page = $current + 1;

$last = $array_pages[$total-1];

?>



<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<?php if(array_key_exists($current-1, $array_pages)) { /* link to previous child */ ?>

<a rel="prev" href="<?php echo get_permalink($prevID); ?>" title="<?php echo get_the_title($prevID); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($prevID); ?></a>

<?php }

else { /* if we are browsing first child, link to parent page */ ?>

<a rel="prev" href="<?php echo get_permalink($last); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($last); ?></a>

<?php }



if(array_key_exists($current+1, $array_pages)) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php }

else { /* if we are browsing last child, link to parent page */ ?>

<a rel="next" href="<?php echo get_permalink($array_pages[0]); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($array_pages[0]); ?></a>

<?php } ?>

</div>

</nav>

<div>post <?php echo $current_page ?> of <?php echo $total ?></div>

<?php }

else { // if we are browsing parent page, then link to first child

$child_pages = get_posts("post_parent=".$post->ID."&meta_key=_point&orderby=meta_value_num&order=asc&post_type=user_images&post_status=publish");

$first_child = $child_pages[0];

if (!empty($first_child)) { ?>

<nav class="navigation post-navigation" role="navigation">

<div class="nav-links">

<a rel="next" href="<?php echo get_permalink($first_child->ID); ?>"><?php echo get_the_title($first_child->ID); ?> <span class="meta-nav">&rarr;</span></a>

</div>

<?php }
} ?>


Sébastien | French WordpressDesigner comments:

Jens, if the response is ok for you and if your problem is resolved, could you complete the process and vote award please ?
Thanks :)


Jens Filipsson comments:

Sorry for the late vote Sébastien, I couldn't reach the site for a while and then I actually forgot about it. Truly sorry, have voted you the price now!

Thanks a lot for your help!

2015-10-19

Andrea P answers:

Hello Jens,

there are a few problems with your code/approach:

1) get_pages() does not support ordering by meta_value_num (and actually I see that you are ordering by date while I understood you wanted the navigation to order by meta field?), so I think you should use a WP_Query to retrieve the child posts:
https://codex.wordpress.org/Class_Reference/WP_Query
https://gist.github.com/luetkemj/2023628
(remember to reset the query at the end of the loop! (and use a custom name for the query name) look the bottom of the second link)

2) the SQL query you are using in the numbers class, it is not correct. it looks like you are mixing up wordpress native queries logic, with sql query sintax. again, you should use a WP_Query to retrieve the child posts.
then you can get the total number of posts queried simply with:
$my_query->post_count
and you can use the same method you have used for the prev-next ids, in order to get the current post order position. (you create an array and qhen you loop the queried posts, you add their ids and keys in the query order)
using WP_Query you can also retrieve only ids if you don't need anything else, using the parameter 'fields' => 'ids'

3) in order to loop the last post's next-link to the first one, you have to change this:

if (!empty($nextID)) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php } ?>


into this:

if ($nextID) { ?>

<a rel="next" href="<?php echo get_permalink($nextID); ?>" title="<?php echo get_the_title($nextID); ?>"><?php echo get_the_title($nextID); ?> <span class="meta-nav">&rarr;</span></a>

<?php }
else { ?>
<a rel="next" href="<?php echo get_permalink($pages[0]); ?>" title="<?php echo get_the_title($pages[0]); ?>"><?php echo get_the_title($pages[0]); ?> <span class="meta-nav">&rarr;</span></a>

<?php } ?>



cheers!


Jens Filipsson comments:

Thanks Andrea!

Can you provide a code example perhaps?


Andrea P comments:

I think Sebastien code should pretty much do the work.

there is a sintax error though (which was present in your code as well)


$array_pages[] += $item_page->ID;


when you add elements to an array, in php you don't have to put +=
put only = and it will automatically add it because the [] is already telling that you want to add the element to an array, instead of replacing the value of the variable.

2015-10-20

Rempty answers:

Change this lines

<a rel="prev" href="<?php echo get_permalink($last); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>
//to
<a rel="prev" href="<?php echo get_permalink($last); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($last); ?></a>

//AND
<a rel="next" href="<?php echo get_permalink($array_pages[0]); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($post->post_parent); ?></a>
//to
<a rel="next" href="<?php echo get_permalink($array_pages[0]); ?>"><span class="meta-nav">&larr;</span> <?php echo get_the_title($array_pages[0]); ?></a>