Plugins used for this post: advanced-custom-fields
Before I really get into this article, I want to say that WordPress is the best CMS available. Not only is it free and open source, but it is supported by the largest community of developers in the world. Every day something better comes out for WordPress that jettisons it farther ahead of the competition. With that said, today’s topic is using the loop in WordPress to create relationships between posts.
With the advances in custom-post-types and custom-fields in WordPress 3.0, your content can now be taken to the next level. A project I was working on today created the need for me to relate posts to pages. You say, “That’s easy. That’s what tags and categories are for.” This is true. Tags and categories were created to allow you to sort your collection of data by its content. However, what if you wanted to show a group of posts on a page based on the content in the page? Let me give an example.
Say, for instance, that you have a news feed that you want to show all your posts in your news category. No problem. Then you have a projects section that has all the projects that your business is currently working on (of course keeping the capability to add more projects as they come up). Let’s say that you want to create a project, and have news articles that you want to show relating to each specific project. You could create a category for your project in the news posts that allows you to put only those posts on the page about your project. But then you’d have to have a special template or sidebar for each new project. That’s just not practical. It makes it very difficult for your client to update his projects. You would have to add a new template and apply it to the page every time he created a new project page.
So what’s the solution? How do you relate one piece of content to another piece, be it a post, page, or any custom-post-type? That is where relationship links come in. To do this, you need Elliot Condon’s plugin, advanced-custom-fields. I won’t go into depth on how to use his plugin–he has plenty of documentation for that. Create a new custom field group called “Relate this to another post.” Then you need to add a field to this field group.
Name the field “relationship” with a label of “Relationship.” Select the field type “Page Link.” Check the box to allow null value above choices (this is for all the posts that you won’t need to relate). Give your field some instructions for the end user ,and save your field. Make sure you publish your new field group at the end so it’s available on your posts.
A little further down the page there is a rule you need to set. Make sure the rule says “Post Type is equal to Post.” This ensures that your new custom field will show up in the edit screen of all new posts. You may have noticed in the documentation for the plugin, that this field returns a link to the page you select in the drop down (e.g. http://www.example.com/page). This is not very useful. WordPress already has a built in link-to-another-page feature. What we really need is the id number of the related page so that we can pull the content from that page in a loop. Here’s where it gets a little tricky.
At this point you’ll actually need to modify the plugin just a little bit. If you’re not comfortable modifying the plugin, there are other options, they just take 3 times the amount of code, so I won’t be covering them here. With that said, here’s what you need to modify. Open the page_link.php file found here: wp-content/plugins/advanced-custom-fields/core/fields/page_link.php. Scroll down to lines 220-242. You’ll need to comment out lines 229-239. The final section will look like this:
<?php function format_value_for_api($value, $options = null) { $value = $this->format_value_for_input($value); if($value == 'null') { return false; } if(is_array($value)) { foreach($value as $k => $v) { $value[$k] = get_permalink($v); } } else { $value = get_permalink($value); } return $value; } ?>
This just takes out the part that turns the id number into a permalink. Now you’re set to go with your relationship in place. Now we get into the fun part–the WordPress loop. First you’ll need to make a template for the type of page that you are going to relate. You can basically just create a new file (in my case it’ll be projects.php) and copy the file contents from page.php found here: wp-content/themes/[your_theme_name]/page.php. At the top of the projects.php file, you will need to add the template comment. It’ll look like this when you’re done:
<?php /* * Template Name: Project * Below this comment is the content of page.php */ ?>
Scroll down to the loop and use this code as a template for your relationship code. You will have to modify it to fit the html structure of your site.
<?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?> <div class="entry"> <p><?php the_content('Keep reading »'); ?></p> <div class="clr"></div> </div> <div class="related-entries"> <?php $id = get_the_ID(); $loop = new WP_Query('post_type' => 'post'); if ($loop->have_posts()) : while($loop->have_posts()) : the_post(); $related_id = intval(get_field('relationship'); if ($id==$related_id) : ?> <h3><?php the_title(); ?></h3> <p><?php the_excerpt(); ?></p> <?php endif; endwhile; endif; wp_reset_postdata(); ?> </div> <?php endwhile; ?> <?php endif; ?>
The code explained:
The beginning and ending of the code, you probably noticed, is just a normal WordPress loop for the page. It pulls the content for the main page. Lines 8-20 is where all the action is happening. We started a second loop, inside the first loop. You’ll notice right at the outset that I stored the ID of the current page inside a variable before I started the second loop. This is so I have access to that ID inside the loop to compare it to the “relationship” field that we created inside the post. We then loop through all the posts (post_type => post) looking for one that has a relationship field value (ID) matching the current page ID. There is no limit on this loop, so if there are 100 posts that all are linked to this page, we will see them all on the page. If you want to limit that, just add a 'posts_per_page' => '3'
to the arguments passed to the WP_Query object.
One more thing worth noting is the function that comes right after the second loop is finished–wp_reset_postdata(). This is a very important little piece of code. If you forget to add this, or delete it by accident, WordPress will assume that the rest of the page has to do with your second loop. So if you make a call to the comments, or the tags, or anything in the post, you will see the output from the result of your posts query and not the page you’re on like you would expect.
And that’s it! You have successfully related a post to a page AND accomplished a loop within a loop. You are now on your way to becoming a WordPress ninja.
If you feel like a screencast would’ve been more helpful, post a comment and let me know.
Great post! Is there a way to retrieve an image from a custom field in that post?
Absolutely! But I need to know a little more before I actually give an answer on how to do it. First of all, is the image that you want to retrieve in wordpress’ native custom fields (i.e. the custom fields section that is already in the post edit screen)? Or is the image part of a custom field that was created with the advanced custom fields plugin. They are both easy to use, but the syntax is a little different. Also, is the image part of the first loop, or the internal loop?
Hi Jon –
Found your post from the advanced custom fields forum. Much like Jose I’m wondering how to properly call an image from a post that is associated via the relationships field type.
I’ve got code that sort of works here: https://gist.github.com/1314838 But its spitting out a URL to a default image: http://cl.ly/2p3H070v2h2O092P3p2a
I know this isnt your plugin to support, but I’m wondering if I might be doing something dumb, have a typo in my code or am just not getting something.
I wish there was documentation for this new relationship field. Its pretty awesome!
I’m not sure which image you’re trying to show. If you’re just trying to show the post thumbnail or any image in the post itself, then this should help you: http://bit.ly/rKBcXb. I looked at the code you had, and you’re missing one important detail. wp_get_attachment_image_src() takes the “Attachment ID” as the first parameter, not the “Post ID.” This had me tripped up for a while too. You can use the post id that you got from Elliot’s relationship field, but you still have to do a search for the attachment ids. Hopefully this helps. I’m going to do a long series on custom post types and meta boxes here soon because I have yet to see any site that goes through everything thoroughly to teach you how to use these things properly. It’s been a long time coming. Thanks for your feedback. Hope this helps you.
Would also love to see a screencast explaining your post as well!