Ali Jafarian

This tutorial provides an elegant way to display previous and next posts using Advanced Custom Fields and it’s Relationship/Post Object fields.


I use Advanced Custom Fields in most of my WordPress projects, and I often get tasked with creating custom courses. So here’s an example of where I’d like to show the previous and next posts for a specific course on every post, much like the standard prev/next links in WordPress. However, in this case I’m using the Advanced Custom Fields Relationship and Post Object fields, so I don’t have access to the normal WP the_post_navigation() function. So we’ll have to create our own!

Note – this is a more advanced tutorial. If you’re unfamiliar with code and WordPress or Advanced Custom Fields you will have a tough time understanding this, so please don’t come here expecting to copy/paste a solution! I also like to call my course posts modules in this example, but you can substitute modules for whatever you prefer or use.

The Code

<?php $parent_course = get_field('parent_course'); ?>

<?php if ( $parent_course ) : ?>
	<div class="post-nav nav-modules">
		<?php
			// get modules for parent course
			$modules = get_field( 'course_modules', $parent_course->ID );

			// create empty array for module ids
			$module_ids = array();

			// loop through modules and add them to array
			foreach( $modules as $module ) :
				$module_ids[] = $module->ID;
			endforeach;

			// get the current index
			$current_index = array_search( $current_post_id, $module_ids );

			// find the prev/next items
			$prev_module = $current_index - 1;
			$next_module = $current_index + 1;

			// find first and last modules
			$first_module = $module_ids[0];
			$last_module = end($module_ids);
		?>
		<div class="nav-links">
			<div class="nav-previous">
				<?php if ( $module_ids[$prev_module] ) : ?>
					<a href="<?php echo get_permalink( $module_ids[$prev_module] ); ?>">
						<span class="link-title"><?php echo get_the_title( $module_ids[$prev_module] ); ?></span>
					</a>
				<?php else : ?>
					<span class="no-link">This is the first module.</span>	
				<?php endif; ?>
			</div>
			<!--/.nav-previous-->
			<div class="nav-next">
				<?php if ( $module_ids[$next_module] ) : ?>
					<a href="<?php echo get_permalink( $module_ids[$next_module] ); ?>">
						<span class="link-title"><?php echo get_the_title( $module_ids[$next_module] ); ?></span>
					</a>
				<?php else : ?>
					<span class="no-link">This is the last module.</span>	
				<?php endif; ?>
			</div>
			<!--/.nav-next-->
		</div>
		<!--/.nav-links-->
	</div> 
	<!--/.post-nav-->
<?php endif; ?>
Now let’s break this down –

For starters, this post (module) has a custom field for a Parent Course, which is a Post Object type in ACF. I grab that and store it in a variable using the code below:

$parent_course = get_field('parent_course');

Next, we have to get our list of modules for the parent course. This just returns a list of post objects via the ACF Relationship field.

$modules = get_field( 'course_modules', $parent_course->ID );

Then we will create an empty array to store the module list in, and loop through them to order them properly. We’ll call this new array $module_ids.

// create empty array for module ids
$module_ids = array();

// loop through modules and add them to array
foreach( $modules as $module ) :
	$module_ids[] = $module->ID;
endforeach;

Finally, we’ll create some variables to extract where we are in the array of modules. These will be useful when we’re trying to display things in the UI.

// get the current index
$current_index = array_search( $current_post_id, $module_ids );

// find the prev/next items
$prev_module = $current_index - 1;
$next_module = $current_index + 1;

// find first and last modules
$first_module = $module_ids[0];
$last_module = end($module_ids);

Now we have everything we need to create an intuitive post navigation for our course modules. I also provide some logic to show a message if it’s the first or last module in the course, instead of leaving it blank.

<div class="nav-links">
	<div class="nav-previous">
		<?php if ( $module_ids[$prev_module] ) : ?>
			<a href="<?php echo get_permalink( $module_ids[$prev_module] ); ?>">
				<span class="link-title"><?php echo get_the_title( $module_ids[$prev_module] ); ?></span>
			</a>
		<?php else : ?>
			<span class="no-link">This is the first module.</span>	
		<?php endif; ?>
	</div>
	<!--/.nav-previous-->
	<div class="nav-next">
		<?php if ( $module_ids[$next_module] ) : ?>
			<a href="<?php echo get_permalink( $module_ids[$next_module] ); ?>">
				<span class="link-title"><?php echo get_the_title( $module_ids[$next_module] ); ?></span>
			</a>
		<?php else : ?>
			<span class="no-link">This is the last module.</span>	
		<?php endif; ?>
	</div>
	<!--/.nav-next-->
</div>
<!--/.nav-links-->

And that’s all there is to it. A nice and logical way to create previous/next posts (modules) with Advanced Custom Fields.

I hope this is helpful in your projects!

Discussion

5 thoughts on “How To Create Previous and Next Posts with Advanced Custom Fields”
  1. Thank you for posting this! Really helped me out.

    To anybody else seeing “Undefined offset” warnings (because WP debug is turned on) you can keep them hidden by changing to (and do the same thing with $next_module)

  2. Thanks for the tutorial. It is very clean example. It would be great to see more basic LMS functions being built around ACF, like Leason & Course completion button/element, course progress, course prerequisites, etc

  3. I know this was created ages ago and this is a long shot but I’m having one issue with how this is looping through the CPT with the relationship field.

    I have a CPT named Artwork and the a CPT named Artists. Each Artist (there are 50+) has a relationship field that pulls in their specific artworks which then you can click to get to the individual Artwork page. On the artwork CPT, I have a post object field that connects to the Artist page.

    I have tested your code and I can pull the array but something gets lost in the Prev/Next loop. Every Artwork post (module) has This is the first Module for Next and the actual first module title for Prev. If I print_r the $first_module and $last_module, it shows the correct post ID. If I do the same with $prev_module and $next_module, it just lists the -1 and 1 respectively. Somewhere there is an issue with $current_index = array_search( $current_post_id, $module_ids ); and I’m just at a loss. Thought I would comment and hope for the best. I appreciate your time and this post.

    1. @Jeff – thanks for posting, however, I wouldn’t be able to comment or help without seeing your actual code and ACF setup. I’m also not currently critiquing other developers’ code, so don’t bother posting here 🙂

      You took the right action in ACF forums to see if someone has time to review your code and point you in the right direction.

      – Ali

Leave a Comment

Your email address will not be published. Required fields are marked *