Custom Post Types Relationships

- by Anastis Sourgoutsidis

Custom Posts Types Relationships is a WordPress plugin that allows you to define relationships between posts in a manual way. This second version of the plugin now supports posts, pages and custom posts types, as well as allow you to define cross-type relationships. Sure, plugins that automatically get the job done are nice, but cat take you that far as they might link to irrelevant posts or change the output as more posts are added.

This version, renamed, is work based on Gerasimos’ original plugin, Custom Post Relationships, but extended to support custom post types, pages, a shortcode, a theme function, and an admin panel.

Download

You can download the CPTR plugin from our server, or visit the WordPress plugin directory page.

Installation

To install the plugin, you follow the same steps as with any other plugin. You download the plugin to your hard drive, unzip the archive and upload the resulting folder along with all files into the wp-content/plugins directory of your WordPress installation. You may also upload the zip file directly into the wp-content/plugins directory and extract it there using CPanel or whatever tools your host provides. Don’t forget to delete the zip file from your server once extracted. You may now activate the Custom Post Types Relationships plugin from the Plugins admin panel.

WARNING: In order for the thumbnail to be displayed, your theme must support post thumbnails. If it doesn’t, check that the add_theme_support( 'post-thumbnails' ) declaration is in your theme’s functions.php file and add it if necessary. The plugin should work fine without it though, it just won’t show any pictures.

Defining post relationships

Once the plugin is activated, a new box named Custom Post Types Relationships (CPTR) will appear at the bottom of the post editing screen (it will actually on post, page and custom post type editing screens). Depending on the configuration of your WordPress and/or your theme, this box may be shown under the main post editor, at the very bottom of the page, or anywhere in between.

The plugin’s interface is pretty simple, but for completeness sake I’ll include a few screenshots. A picture is worth a thousand words, right?

Configuring the plugin

To configure the default behavior of the CPTR plugin, navigate on your WordPress’ back-end, and under the Settings menu select the Custom Post Types Relationships sub-item.

There, you can set default values for all parameters, namely:

  1. The maximum number of items to display.
  2. Whether to show the excerpt.
  3. The maximum number of words that the excerpt should be.
  4. Whether to display the post’s thumbnail.
  5. The width and height of the post’s thumbnail.

Showing your relationships

The plugin supports a shortcode that can be used in individual posts and pages, as well as a function call that can be used more permanently within the themes. Both the function call and the shortcode, support the same features, although the shortcode does not require a particular order for the supported parameters. There is also a function that just returns the related posts, and then it’s up to you to implement your display logic, exactly the way you want it.

We purposely left out the ability to have a permanent heading showing up before the list of links, so that you can have total control over the output. Don’t want a heading? Don’t write one. Want one? Write it then. Too much of a hassle to always write a heading in each post? Use the theme function!

The easy, amateur or occasional way

So, you’ve written excellent copy, and you want to link it to more excellent copy. How to do it? You just type [cptr] in whatever place in your post you want them to show up. Easy, right? Just remember to write a title, heading or whatever before using the shortcode, so that people will know what they are reading.

The simplest way of using the shortcode is by typing anywhere in your post [cptr]. This will display the list of the related posts using the defaults as defined in the plugin’s admin panel.
If you want to override any of the defaults, you can do it by passing parameters to the shortcode. For example, if you want to show the excerpt you should type [cptr excerpt=1] or if you want to hide it you should type [cptr excerpt=0].

This is a list of all supported parameters that can be used with the shortcode. All parameters are optional.

  1. limit – Max number of relationships to show. 0 means unlimited. E.g. [cptr limit=5]
  2. excerpt – Shows or hides the excerpt. 1 means show, 0 means hide. E.g. [cptr excerpt=1]
  3. words – Max number of words in the excerpt. Default is 55. E.g. [cptr words=10]
  4. thumb – Shows or hides the post thumbnail. 1 means show, 0 means hide. E.g. [cptr thumb=1]
  5. width – Max width of thumbnail in pixels. Needs height to be set as well. E.g. [cptr width=300 height=200]
  6. height – Max height of thumbnail in pixels. Needs width to be set as well. E.g. [cptr width=300 height=200]

Of course, you can mix and match the attributes, so it’s perfectly fine to have a shortcode like this: [cptr thumb=1 words=40 excerpt=1 limit=10]

The hard, pro, permanent way

So, you want to integrate the CPTR plugin with the theme you are using or developing. For that, you can use the cptr() function call within your theme.

Like any PHP function with default parameters, all parameters of the cptr() function are optional but you have to follow a few rules. Have a look at the PHP documentation regarding default parameters, if you don’t know what I’m talking about.

All parameters to the function call are optional, but if set, they follow the default parameter rules of PHP. If you want to define some of the parameters but not a few preceding ones, you can pass a null value to that parameters, and it will use the default set in the plugin’s admin panel. The function’s signature is:
function cptr($echo=null, $limit=null, $excerpt=null, $words=null, $thumb=null, $width=null, $height=null)

Let’s examine the parameters:

  1. $echo – Boolean. When true it echoes the list and when false it returns it. Default is true.
  2. $limit – Integer. When 0 shows all relations. Any positive integer limits the number of relations. Default is 0.
  3. $excerpt – Boolean. When true it shows the excerpt and when false it hides it. Default is false.
  4. $words – Integer. Limits the number of words in the excerpt. Default is 55.
  5. $thumb – Boolean. When true it show the post’s thumbnail, and when false it hides it. Default is false.
  6. $width – Integer. The width of the thumbnail in pixels. Needs the height to be set as well. Default is 100.
  7. $height – Integer. The height of the thumbnail in pixels. Needs the width to be set as well. Default is 100.

So, for example, if you wanted all the default options, you would just call:
cptr();

If you wanted to return a max of 3 relations you would call:
cptr(false, 3);

And if you wanted everything to be default, but display the thumb, you would call:
cptr(null, null, null, null, true);

Implementing Custom Display Logic

So you don’t care about shortcodes and ease of use. You want to do something extraordinary with your theme, but you wish there was a way to get all the related items of that post. Wish no more, cptr_populate($postID) is here for you.

cptr_populate() accepts one parameter, the post ID of the post you want to retrieve the related items for, and returns an array of post objects. If no related posts are defined, an empty array is returned.

Displaying simple bits of info

The following example, coded into single.php will display a simple list of the titles of the related posts.

global $post;
$related = cptr_populate( $post->ID );
foreach ( $related as $item )
{
echo "<p>" . $item->post_title . "</p>";
}

A full list of the available object properties that can be used, is given in the WordPress Codex.

Using template tags

The following example prints a simple list of titles linked to their posts, showing how you can use template tags in your code, such as the_title() and get_the_title(), the_permalink() and get_permalink(), etc.

global $post;
$original_post = $post;
$related = cptr_populate($post->ID);
foreach ( $related as $post )
{
setup_postdata($post);
echo '<p><a href="' . get_permalink() . '">' . get_the_title() . '</a></p>';
}
$post = $original_post;
setup_postdata($post);

Notice that because we overwrite the $post object when we use setup_postdata() within the foreach loop, we must keep a backup of it beforehand, hence the $original_post = $post; and restore it when we are finished, as done on the last 2 lines.

Conclusion

We take pride on our little plugin. Do you think it’s useful? We definitely think so. Is there any room for improvement? Let us know in the comments, and show us where and how you use it.

Download – Changelog

  • version 2.4 (7/Jan/2012)
    • Fixed a bug where the normal post object was not restored after the execution of cptr_category_selector(), when selecting related posts. (Thanks Pascal Rosin).
  • version 2.3 (14/Nov/2011)
    • Fixed a bug where the relations outputted wrongly by the shortcode.
  • version 2.2 (8/Nov/2011)
    • All functions/pages/settings etc that included the acronym CPT have been renamed to CPTR. Functions have been deprecated and will be available until v3.0.
    • Implemented automatic upgrade of settings etc for earlier version users.
  • version 2.1 (18/Feb/2011)
    • Version number changed to match the plugin repo.
    • Fixed a bug where the last related post was the current for $post after the plugin run.
    • Thumbnail now links to the post too.
    • The cpr_populate() function now always returns an array, even if empty.
  • version 1.0 (08/Oct/2010)
    • Initial release
Post comment as twitter logo facebook logo
Sort: Newest | Oldest

Hi Anastis,

This plugin works great. It's very easy to associate custom post types with others cpt's; it's pretty much self-explanatory. It's great when plugins are simple and work as they should. Thank you.

Question: I'm not using Featured Images, but instead meta boxes to upload images, and consequently, haven't been able to show the thumbnails per related post. Is there a way to display the first photo of a cpt instead of the featured photo?

Also, is it possible to display the word "Similar" before the list of related posts/cpt's? I know I can add it before the , but I don't want it to appear when there aren't related posts. So, I want it to be included in the php. Could you please provide a tip on how to achieve this?

Thanks again for your plugin and tips. I've been wanting something like this for a long time.

Hi, and thanks for your kind words.

Unfortunately, there is currently no way you can grab any other image than the post's thumbnail. Using the plugin that is.
If you examine the function get_the_post_thumbnail() in the file wp-includes/post-thumbnail-template.php you will see there is a filter executing when returning the html of the image. You can hook a function on that 'post_thumbnail_html' filter, and have it return the html of your custom field images (the html string will be empty in your case anyway, since you don't use featured images). In that hooked function, you could also use something like this function to get your first image. I'm not sure it will work though, as it will depend on when and how the things are run, i.e. your custom fields may be included in your content later than the hook, or not included in the content at all).

For your second question, the editor may have stripped whatever you wrote in the &lt;code> block, so I don't know to what exactly you are referring to. I'll assume you use the function call of the plugin though, and not the shortcode.
You can have the function return the related articles instead of echoing them, (see first parameter of cptr() in the documentation) into a variable, and test if empty. The function returns an unordered list of posts only if one or more are related. Otherwise it returns an empty string.
So you could do something like:

$related = cptr(false);
if( !empty( $related ) )
{
echo "&lt;h2>Similar&lt;/h2>";
echo $related;
}

Hope this helps.

Wow, I appreciate the responsive and extensive reply. Much appreciated.

So, the second tip worked out quickly. Thank you. In regards to the first issue, yes, we can probably just filter the photo. Makes sense. Good idea, thanks.

I seriously appreciate this plugin and tutorial. Have a good one.

Hi,

We use your plugin in all our articles. Even though it's powerfull, it has some limitations for a several-times-a-day use :

1. Why load all the articles before the filter kicks in ? High server charge, slow and you have to wait a good 20s every time (when using the 500 posts option). Would be better to ask for the filter first, and use it as a search query.

2.the 500 post limit is too small for us, only puting us back 2 months. Impossible to add older posts: bad for rarely talked-about subjects

3. I don't know if it's our config, but it only looks for the filter words in the title of the posts, ignoring tags and the main text. Not very good exept for SEO-only minded titles.

4. By default, it charges the posts by title and ascending order. In my experience, default should be by date and descending order (the most recent first). Or at least there should be an option to change this, again saving time for us.

Otherwise it's a very good plugin. I also want to mention I'm only an end user, with no specific coding skills ^^

Hi Jeff,
yes, the plugin is currently operating in a very specific manner. Searching only searches titles, because that's all you can see. If it looked on tags and main text, it would be impossible for you to tell what exactly matched.

Setting the default order is a good idea, and I'll try to implement it in the next version. You'll be able to change it from within the settings page.

Now, about the 500 posts limit you are mentioning, there isn't such a thing. The limits that are implemented are 10, 50, 100 and "All". Make sure you have updated to the latest version.

Thanks for your sharing. It helped me a lot :)

Amazing plugin! One thing lacking though, the ability to apply a reciprocity when creating a conexion. Would be awesome to get this option so we could navigate between connected posts without having to create the conexion twice in the admin.

Great job anyway, it saved me on a site i'm working on right now.

Cheers

It's on my to-do list quite some time now :)

I just downloaded the upgrade and sincerely wish I hadn't. For some reason it inserts the related posts link always above my content, instead of wherever I place [cptr] on the page, as the old version used to. So frustrating! I wish I could roll back to the old version but I didn't keep it. ..

Hi Rachel,
you can download the previous version 2.1 from the Changelog. The version number is also a link for download.
Meanwhile, I will look into it and release an update as soon as I get it fixed.

I've just pushed the update (version 2.3) to the plugins repository. It should be available for update any minute now. Or download it from this page.

There is a serious bug in cptr_category_selector(). You are altering the global $post variable without setting it back (and without need). This causes code loaded after the CPTR editor to use the last related post and not the actual post.

The problem can be fixed by changing line 88 of cptr.php from

global $post_ID, $post;

to

global $post_ID;

You are right. I'll push an update later today.

Hi Anastis

Thanks for your reply.

I was able to get the thumbnails working by ticking the featured images box in screen options =)

My next question is -
How can I increase the space between the text above and the [cptr]
ie The related post(s) (with beautiful thumbnails) are stuck right underneath the text above it on the page. Be nice to have a space after the text before the first related post excerpt.

Can't believe you know Bridgwater! Did you see the awful crash on the M5 this weekend?

Olly

Hi Olly,
this is really a CSS question. You can edit your theme's style.css file, and add a line similar to the following:

#cptr_related_posts { margin-top: 20px; }

Play around with that "20" and see what works best for you.

I left Bridgewater in 2000 and haven't been able to revisit yet, the memories are still vivid though. I also loved Weston-super-mare, as it had a Greek restaurant and sea! Taunton never really did it for me.

Hi,

I'm loving this plugin. It's working great so far, after a day full of trial and error with other options. So, thanks!

I do have a question. I'm using a custom post type with custom fields/data/meta, and there isn't an excerpt or thumbnail. How might I get all the info from each of these posts to show up when CPTR calls them? I know I'd need to modify cpr.php with a $text, but I wanted to see if you recommended a way that would work well with the plugin.

Thanks!

Dave

Hi Dave,
unfortunately there is no straightforward way to do what you ask.

You should implement custom display logic directly into your theme files. You can do this by calling the undocumented cpr_populate() function manually from within your template, passing the post id as the parameter. It returns an array of post objects, or an empty array if no related posts have been found. You then use those posts' IDs and fetch whatever you want with get_post_meta() for example.

(Note to self: I really need to document this function and create some examplar code, soon!)

I don't recommend editing the cpr.php file directly, as any future plugin updates will overwrite your code.

Great, I'll give that a shot. Thanks.

I'll check back soon for the documentation too, to see if I did it right as well, haha.

Dave

Hey Anastis,

I'm trying to get the cpr_populate() to work, but I'm not so confident in my php-from-scratch skills. I've been looking at the WP Codex for hints, but can't seem to figure it out.

I have started, but would you be able to show me how to pull one post meta item (e.g. exhibitor_table) from my custom post type? I can figure out how to get the rest if I know how to do one.

I really appreciate the help.
Thanks,
Dave

E.g. in your single.php file:

global $post;
$related = cpr_populate($post->ID);
foreach ($related as $article)
{
$meta = get_post_meta($article->ID, "exhibitor_table", true);
echo $meta;
}

I hope this makes sense.

Great! On my way I think.

That code pulls all of the data in all of the "exhibitor_table" fields. Shouldn't the "true" of the get_post_meta make it return only one per post? Or I guess it might be echoing them individually, but without any html wrapping, right?

I guess, here's a screenshot of what I'm trying to do: http://thegallerymusic.com/EventListingFormat.png
You'll see the "Exhibitors" section at the bottom (This is for a client. Not my site). I just need each piece of data from the related post(thanks to your plugin), wrapped in a span, div, etc.

By the way, did you just update your plugin to version 2.2? I just got an update notice.

Thanks again for any help,
Dave

That code gets the related articles/posts/whatever and for each one it pulls the "exhibitor_table" field (not plural). It then echoes them on the page. You can build around this code if you want extra markup, e.g.
echo '&lt;p>'.$meta.'&lt;/p>';

The default behavior of get_post_meta() is to return an array of the history of the values that where saved on that custom field. "true" makes it return just the most current value.

Now, for your problem, it all depends on what you store and where. For example, if you have a separate custom field for each piece of info, you might have to do:

$name = get_post_meta($article->ID, "exhibitor_name", true);
$booth = get_post_meta($article->ID, "exhibitor_booth", true);
etc...and then echo them appropriately...

or you may be storing an array within "exhibitor_table", so you would do something like:

$meta = get_post_meta($article->ID, "exhibitor_table", true);
echo "&lt;p>".$meta['exhibitor_name']."&lt;/p>"

Yes, I updated the plugin to v2.2 today. Everything CPR was renamed to CPTR, so cpr_populate() is renamed to cptr_populate(); Apart from custom code, all internal options should be updated automatically.

Thanks, you've really been a huge help! And got a jump on that documentation haha.

I've got a jump on this now. I really appreciate it. Love the plugin. Keep up the good work.

Hi
This looks great.

I am not getting any thumbnails however.
I have set it to show thumbnails in the plugin's settings, but I just get a bullet point with the link and excerpt on the page.

My theme is Oriental.

I don't see a way of linking a thumbnail picture to my posts. Could this be the Theme's doing?

Many thanks for your advice.
Olly

Hi Olly,
thumbnails are created automatically from the "Featured Image" of each post. Images uploaded before the plugins' installation, may not be displayed as the thumbnails will not have been created. In this case, I would suggest using a plugin to regenerate the thumbnails, such as this one.

Hope this helps.

P.S. I love Somerset. I've been studying in Bridgwater college back in 1999.

Is it possible to create two types of relationships for one CPT? Eg I have a CPT "product" that needs an "Associated products"-relationship for related products and another "Also available with"-relationship for products that only have a different color (but are treated as an separate products).

Hi Marco.
There is no "simple" way to do this with this plugin. Not without two separate instances of it anyway, which is not currently supported.

One way you could do it, would be to select all your "associated products" AND your "also available with" products, and then implement custom display logic differentiating the two. You can do this by calling the undocumented cpr_populate() function manually from within your template, passing the post id as the parameter. It returns an array of post objects, or an empty array if no related posts have been found.

So, depending on your setup, you could check the categories, titles or some custom fields if you have, and you could know if it is the same product but different color.

Having an odd issue, when used on posts, using [cptr] to call the stated relevant post list.

The last added post to be displayed (in the selected posts area) has its 'all in one seo' title, description and keywords settings placed in the fields on the new post, instead of the original all in one settings for the new post (this ONLY occurs after the new post is published once)

If the post is then re published, the last posts all in one settings are used, ouch....

Using all in one seo Version 1.6.13.4, wp 3.2.1 and Version 2.0

Hi Stuart,
I don't really understand your situation. Could you provide screenshots of what's happening?

Great plugin, I just want to be sure I have the latest version. There appears to be a link you shared in January...(look below) but when you go to the wp repo. the last updated date is in 2010. What is the most current... repo or the link you've provided below.

Thanks.

in a Gerasimos says:
January 25, 2011 at 8:56 pm
Hi Guys,

We have updated the plugin and it should be ok now. Grab the version from our server and we will update the one at the wp repo too

Here’s the link...

Hi, and sorry for the late response.
Both are the same version, so no worries :)

Has anyone used this plugin for 50,000 plus posts? Run into scalability issues yet? Anyone try the posts-to-posts plugin?

Looks great, I'll have to give it a try.

Great plugin guys!

Before CPTR being released, I used to use CPR. In CPR's plugin page you had provided a piece of code which it had to be placed in single.php. It was something like this:

Related Entries
&lt;?php
$relations = cpr_populate(get_the_ID());
if (!empty($relations)) {
echo &quot;";
foreach ($relations as $related) {
echo "ID)."'&gt;".$related-&gt;post_title."";
}
echo "";
}
else {
echo "No related entries";
}
?&gt;

Now, which piece of code should I use for the related entries to appear? (I didn't understand how to use shortcodes)

Also, in the metabox I can see only "Post" and "Pages" and not all the post types (image, quote, etc). Any idea to fix this?

Disclaimer: i'm a novice user.

Thank you.

What's your WordPress version? Also have you grabbed the latest version of CPTR?

I use WordPress 3.2.1 and version 2.0 of CPTR.

The simplest way to use the plugin within your single.php file, is by adding a line such as this:
&lt;?php cptr(); ?>

Hello there,
Thanks a lot guys. You've been really helpful.
Is there any chance for the related entries to appear in a vertical way? Like this for example: http://goo.gl/fxYce?

Thank you.

It's a matter of styling it with CSS.
Adding something like this should get you started:

.cptr_related_posts li{
float: left;
width: 100px;
padding: 5px;
}

Hi!

I'm trying your plugin...i think it could be very useful, thank you very much!

I have 1 question...

How does the permalinks works with the plugin?

I have a great headache about permalinks...

How are contructed the permalinks using the pluguin?

misite.com/post1/linked-post/?

The plugin doesn't affect your current permalink structure. It will produce permalinks depending on your Settings -&gt; Permalinks

I have a question/suggestion:
Want a little comment as text on each related posts. The excerpt isn't what im looking for. Maybe just a small textfield that appears after the post has been added to "related posts box".

Awsome plugin btw!

Hi guys, thank you first of all for an awesome plugin, you have saved me hours of pain. If it's not asking too much I wondered if there's a way I could make one small change to the plugin to serve what I need, what I would like is:

- In the search box inside at the bottom of a post, I would like it to only return posts/pages/custom posts created by that author and no others. In other words I only want a user to be able to use your plugin to link to other posts that they created (and not anybody else)

This is because on the site I am hoping to launch it is essential that users only see the posts they have made when in the admin screen.

I have already managed to successfully hack the functions.php file to stop them viewing other user's posts in the general posts view thanks to the following code I got from the WordPress Codex:

function posts_for_current_author($query) {
global $pagenow;

if( 'edit.php' != $pagenow || !$query-&gt;is_admin )
return $query;

if( !current_user_can( 'manage_options' ) ) {
global $user_ID;
$query-&gt;set('author', $user_ID );
}
return $query;
}
add_filter('pre_get_posts', 'posts_for_current_author');

I know it's probably asking a lot in terms of support for a free plugin, but I wondered if there is a simple way that you knew of (perhaps a similar line of code) that could do the same with your plugin?

Thanks for reading and really appreciate any help you can give

Nick

Beautiful plugin, works like a charm, will you add WPML compatibility in the feature?

Hi, I have a problem with WP Version 3.1.1 in German language. The plugin is all in English besides the dropdown menue "posts, pages, ..." It says 'Artikel' and 'Seiten' instead (and nothing further like 'audio'). That means I cannot filter several hundred posts/pages.

Any help is appreciated!
Thanks in advance.

Is there a way to have the plugin just return a list of the related post ID's.

The reason I as ask is that the site I'm using this on would like to have different views of the related post on different pages .. ie, some with an excerpt, some with some custom imagery etc .. so I figured it would be easier to just get a list of the related IDs and create the loops manually on each page.

Sure. There are two ways.
1) you can do something like $posts = cpr_populate($post->ID) and get an array of the related post objects, so for example if you do $p = $posts[0]; $p->ID will hold your first id, and likewise you can access all properties mentioned in http://codex.wordpress.org/Function_Reference/get_...
or
2) do a get_post_meta($post->ID, CI_CPR_POST_RELATED, true); and get an array of related post IDs

Fantastic! .. thanks for the speedy response. Much appreciated.

Anastis, thank you!

I have been looking for something like this for ages - just simply creating relationships and links between custom post types.

Just installed it and its working perfectly

:-)

Trackbacks

  1. [...] A while ago we released CPR (Custom Post Relationships), a plugin that lets you create manual relationships among your posts. Problem was that custom post types were not supported. Custom Post Types Relationships (CPTR) is now available and solves this exact problem. Assign everything with everything. Posts, pages, post types, you name it. For detailed documentation please refer to the original post at cssigniter.com [...]

  2. [...] Go here to see the original: Custom Post Types Relationships | cssigniter.com – premium WordPress themes and more.. [...]

  3. [...] also utilizes cssigniter’s popular Custom Post Types Relationships (CPTR) plugin, giving you total control over your related tutorials / posts. It allows you to manually select the [...]

  4. [...] also utilizes cssigniter’s popular Custom Post Types Relationships (CPTR) plugin, giving you total control over your related tutorials / posts. It allows you to manually select the [...]

  5. [...] our now popular Custom Post Types Relationships (CPTR) plugin, you have total control over you related tutorials / [...]