When I started building wordpress themes PHP and most of the advanced wordpress functions went over my head. I’ve learned quite a bit since then, but one step taught me a lot about wordpress and PHP. While I was coding my premium wordpress theme I decided to make a very simple related posts widget. There are plenty of plugins that do this but I wanted to learn about writing widgets and further my PHP and I had a pretty good idea on how to do it, so I did it.
Functions.php
I suspect most people creating themes never even create a functions file, much less know what it does. Used correctly it can be a very powerful tool. This is how advanced theme authors create theme options, custom wordpress theme tags, widgets and more. I won’t go into too much detail on the functions.php file for now as that can be a tutorial in itself. There are a few resources for learning what can be done with the file, and I’ll be writing much more about it on this blog in the future.
Making a widget
First you need to create a functions.php file in your theme directory. The file must start with <?php and end with ?> with no empty lines before or after. Now we are going to create a new function which will become our related posts widget.
<?php
//Super Simple Related Posts Widget
//Gets posts from the first category of the current post
function widget_ch_related_posts() {
}
if ( function_exists('register_sidebar_widget') )
register_sidebar_widget(__('CH Related Posts'), 'widget_ch_related_posts');
?>
This is the beginning of our widget. I like to put comments at the top to identify what the widget is and does but this isn’t necessary. First we declare a function called widget_ch_related_posts(); try to create a unique name, you don’t want it clashing with any other widgets or function names.
The if statement simply registers the sidebar widget with wordpress and gives it a more pleasant name. The ‘CH Related Posts‘ is what you will see in the widgets section of wordpress, so give it a name you will recognize.
To learn more about exactly what that code is doin, here is the documentation from Automattic. Essentially we are widgetizing a plugin, we just haven’t created the plugin, yet.
Next up, a plugin!
Now we have a widget, but it doesn’t do anything. We need to stuff some cornbread in our widget (I like cornbread). In most of my themes I alter the sidebars to use divs for the containers and h3 for the headers, but by default widgets use list items for containers and h2 for the headings. I tell you this because you need to know what scheme your theme is using for your code to work right. You can learn more about this at another Automattic page. I’ll use the default way for this example, below is the example of our plugin.
<li class="ch_related_posts">
<h2>Related Posts</h2>
<?php
//get post categories and set $cat to first category
$cat = get_the_category(); $cat = $cat[0];
//set arguments for the get_posts function more options found at wordpress codex
$args = array(
'numberposts' => '5',
'offset' => '1',
'category' => $cat->cat_ID //calls category ID number
); ?>
<ul>
<?php
global $post;
$myposts = get_posts($args); //gets arguments from array above
foreach($myposts as $post) : //loops through posts
setup_postdata($post); //sets up posts
?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ul>
</li>
I’ll break this down MC Hammer style for you. The list item is contained in our themes sidebar(which should be a unordered list, hence no <ul> tag). You can dump the class=”ch_related_posts” if you don’t need to style it individually. The h2 header is the title of your widget, so far pretty basic html.
The php is where we get to start having fun. First thing I do is create a variable called $cat, I then use get_the_category to get all the categories the current post belongs to. Now $cat is holding an array, I set $cat to the first category using $cat = $cat[0] (arrays in php start with zero not 1). But hold one a sec! This is a good place to experiment with the plugin, I made it very simple but you could get posts from all the categories, certain categories, get tags instead of categories. You have plenty of options, and I encourage everyone to play around and see what happens.
For the next trick I’ll create $args tada, args stands for arguments. Arguments for what? For get_posts but more on that later. I create an array and input the arguments that I want to pass along to get_posts further down in the code. This is just an easy clean way that I like to pass the arguments, it makes for easy changes and readable code.
<?php 'category' => $cat->cat_ID //calls category ID number
This little line of code sets the category argument to the ID of the current posts first category…I think that makes sense. See $cat is holding a lot of information about the category and all we want is the ID.
Output something already!
OK! Now we need to list all the posts, pretty normal wordpress stuff now.
<ul>
<?php
global $post;
$myposts = get_posts($args); //gets arguments from array above
foreach($myposts as $post) : //loops through posts
setup_postdata($post); //sets up posts
?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ul>
I set up the posts using global $post then set $myposts using get_posts and the arguments we just specified. We loop through the posts and output them into nice little happy list items. We end the loop and close the list out and we are done! Sorta.
That was easy.
Ok so now you got your widget, you got your plugin, now you need to put them together. This is really easy, copy your plugin code and paste it right smack in the middle of the widget code like so:
<?php
//Super Simple Related Posts Widget
//Gets posts from the first category of the current post
function widget_ch_related_posts() {
<li class="ch_related_posts">
<h2>Related Posts</h2>
<?php
//get post categories and set $cat to first category
$cat = get_the_category(); $cat = $cat[0];
//set arguments for the get_posts function more options found at wordpress codex
$args = array(
'numberposts' => '5',
'offset' => '1',
'category' => $cat->cat_ID //calls category ID number
); ?>
<ul>
<?php
global $post;
$myposts = get_posts($args); //gets arguments from array above
foreach($myposts as $post) : //loops through posts
setup_postdata($post); //sets up posts
?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ul>
</li>
}
if ( function_exists('register_sidebar_widget') )
register_sidebar_widget(__('CH Related Posts'), 'widget_ch_related_posts');
?>
And there it is, save your functions.php and check to see if everything works. If it doesn’t it is probably my fault, but you should try to fix it, cause that will help you learn, at least that is my excuse. This is just a itty bitty taste of what you can do with functions.php file.
To read more about how to create widgets and plugins visit Automattic’s page for the complete API.
Hi Curtis,
Thanks for this article! Currently, I’m looking for a solution regarding related posts in WordPress. Being a PHP newbie myself, I would like to ask a bit of your help.
The case is: I have 2 categories of posts (”reviews” and “dvds”) and I’m looking for a way to display bits of related dvd posts inside review posts, based on tags.
For example: a review tagged “David Lynch” should contain dvds with the same tag.
Do you think your solution can be of help, or would you recommend some sort of related posts plugin?
Many thanks!
Best wishes,
Martin
March 24 08 at 6:21 am
I think this plugin will work for you. It matches posts based on tags and even puts them into your RSS feed.
You could write your own, but my example above might not work exactly the way you want. Say you have a post with a tag “David Lynch”, instead of using get_the_category() you would use get_the_tag(). But this won’t work if you have more than one tag you want to match DVDs to. If you have two tags “David Lynch”, and “Eraserhead” the above code will only match one tag (the first one, but you could change that where it says $cat=> $cat[0]).
You will also have to use query_posts() instead of get_posts() because I don’t think get_posts() can use tags.
If you want to use more than one tag there are two ways to go about it. One you can match all the tags to DVDs, this way is much easier but is very limiting.
Two you’ll have to loop through each tag and find posts matching those tags, this is a bit harder but think it could be done without too much cussing.
Anyway, with all that being said, I would try the plugin first, unless you are a glutton for headaches like me :)
If you decide to program your own let me know how it goes, and if you need any help getting it all to work.
March 24 08 at 9:35 am
Thanks for the tip! I got the plugin up and running, and it works. Still, I’d like to try and make a custom script, based on your function. Especially because I would love to have it display some more DVD info than just a link (like thumbnail image, region, subtitle info and vendor links…). But let’s see if I got the basics correct first. So far, I’ve got this script:
——————————————-
——————————————-
Can you tell me where the taglooping should be?
Many thanks!
March 25 08 at 8:02 am
Sorry I had to delete the code in your comment because wordpress was still reading it and that caused an error in the page, even with the code tag.
I think I’ve fixed the problem with wordpress reading things in the code tag now, can you post your code again?
March 25 08 at 10:42 am