Advertisement
WordPress

Hack Together a User-Contributed Link Feed with WordPress Comments

by

Although WordPress has a *very* extensive plug-in collection, now and again things come up for which there are no suitable plug-ins available (yet). When I built PSDTUTS I thought it would be cool to have a way for users to submit links and to create a public link feed out of it. Today I'll show you how I hacked together a method using WordPress' comments.

So first of all if you're not sure what I mean by a User Contributed Link Feed, all you need to do is look in the sidebar of NETTUTS and you'll see our public link feed. You can subscribe via RSS or click to submit your own links. It's a neat little way to get more interactivity into the site, and to let readers leverage the traffic of the TUTS sites back to their own blogs and tutorials.

Rough Plan of Action

The first thing to do is come up with a plan of how it's all going to work. Here's our plan:

  1. First we'll create a special Post on our blog that will just have some short submission instructions
  2. Then we'll edit the comments.php file so that when this special Post comes up, it will display comments differently
  3. On those comments we'll change the regular comments form to be relabelled so that the fields fit a link submission
  4. Then we'll change the way comments display both on the post and in the comments RSS so that it makes sense
  5. Finally we'll make a bit of code to pull the latest 10 links and place them in the sidebar

Now the advantage of using the regular WordPress comments system is that there is already an approval and spam-catching workflow in place.

Step 1 - Create the Post

For my example today I'm going to be using the soon-to-launch AUDIOTUTS site that I've been spending the afternoon putting together. So we just make a regular Post with a title and some text, you can see me making mine in the screenshot:

And here it is on the AUDIOTUTS site:

Now it's important to find out what the Post ID is for our post. You can figure this out by editing the post you just created and looking at the URL for the edit post page. My edit post URL is "http://audiotuts.com/wp-admin/post.php?action=edit&post=3" so therefore the Post ID is 3!

Step 2 - Edit Comments.php

Next we're going to alter our comments.php file to look for the post with ID of 3 and to make that particular post's comments look different. Note that if you're interested to learn more about the comments.php file, we have a great tutorial here on NETTUTS called Unravelling the Secrets of Comments.php that is a great place to start.

So basically we're going to add a big if statement and if the Post ID is not 3 then we'll do our regular comments stuff, and if it is 3 then we'll change the way they are displayed AND how the form looks. Here's my comments.php file for AUDIOTUTS (note that I've commented out the regular comments stuff to make it clearer in regards to the link feed)

<? if ($post->ID != 3) { 

	// If the Post ID is *NOT* equal to 3 (our link feed post that we created earlier) then
    // we execute the regular comments.php stuff in this space. 
	//
    // I've deleted mine to make my code snippet a bit clearer

} else { ?> 
	
			<h2 style="margin-top:30px;">Previous User Submissions</h2>
			<a href="#add" class="floated_link">Submit a Link</a>

		
			<?php if ($comments) : ?>
				<ol>
					<?php foreach ($comments as $comment) : ?>
						<?php if (get_comment_type() == "comment"){ ?>					
							<li id="comment-<?php comment_ID() ?>" >
								<?php comment_author_link(); ?> <br />
								<?php comment_text(); ?>
							</li>
						<?php } ?>
					<?php endforeach; /* end for each comment */ ?>
				</ol>
			<?php endif; ?>
			
			
			<div style="clear:both"></div>				
			<a name="add"></a>
			<h2 style="margin-top:30px;">Submit a Link</h2>
	
			<div class="formcontainer">	
			
						<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
						
						<p><input type="text" name="author" id="author" value="" size="22" tabindex="1" />
						<label for="author"><small>Link Title <?php if ($req) echo "(required)"; ?></small></label></p>
						
						<input type="hidden" name="email" id="email" value="USER_LINK_SUBMISSION@AUDIOTUTS.com" size="22" tabindex="2" />
						
						<p><input type="text" name="url" id="url" value="" size="22" tabindex="3" />
						<label for="url"><small>Link URL</small></label></p>
						
						<p><input type="text" name="comment" id="comment" value="" size="22" tabindex="3" />
						<label for="url"><small>Link Description (Max 20 Words)</small></label></p>
						
						
						<p><input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment"  class="button" />
						<input type="hidden" name="comment_post_ID" value="<?php echo $id; ?>" />
						</p>
						<?php do_action('comment_form', $post->ID); ?>
						
						</form>
					
			</div>					
			<div style="clear:both"></div>	

<? } ?>

So let's analyse our code in two parts, first the form and then the comment display.

Step 3 - Altering the Comment Form

By default there are four form fields that WordPress uses to allow input of comments, they are:

  1. Author
  2. Email
  3. URL
  4. Comment

To receive a link submission we need three things:

  1. Link Title
  2. URL
  3. Link Description

So we'll map the four form fields to our three requirements like this:

  1. Author Field > Link Title
  2. URL > URL
  3. Comment > Link Description

And for the email field, we'll switch this to be a hidden form field and give it a value of "USER_LINK_SUBMISSION@AUDIOTUTS.COM", that will make the links a lot easier to spot when they are being approved in the comments approval.

So here's the form I'm using:

						<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
						
						<p><input type="text" name="author" id="author" value="" size="22" tabindex="1" />
						<label for="author"><small>Link Title <?php if ($req) echo "(required)"; ?></small></label></p>
						
						<input type="hidden" name="email" id="email" value="USER_LINK_SUBMISSION@AUDIOTUTS.com" size="22" tabindex="2" />
						
						<p><input type="text" name="url" id="url" value="" size="22" tabindex="3" />
						<label for="url"><small>Link URL</small></label></p>
						
						<p><input type="text" name="comment" id="comment" value="" size="22" tabindex="3" />
						<label for="url"><small>Link Description (Max 20 Words)</small></label></p>
						
						
						<p><input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment"  class="button" />
						<input type="hidden" name="comment_post_ID" value="<?php echo $id; ?>" />
						</p>
						<?php do_action('comment_form', $post->ID); ?>
						
						</form>

As you can see we have three <input type="text"> fields and one <input type="hidden"> for the email address. And though in the HTML these input fields still have their usual id's (author, url, comment), you can see in the text that the user sees they are labelled as link title, URL and link description. So that the form looks like this:

Step 4 - Displaying Previous Link Submissions

Next we'll format how the previous comments appear so that they also make use of our reusing the author, url and comment fields. Here's the code we'll use to display the links:

		
			<?php if ($comments) : ?>
				<ol>
					<?php foreach ($comments as $comment) : ?>
						<?php if (get_comment_type() == "comment"){ ?>					
							<li id="comment-<?php comment_ID() ?>" >
								<?php comment_author_link(); ?> <br />
								<?php comment_text(); ?>
							</li>
						<?php } ?>
					<?php endforeach; /* end for each comment */ ?>
				</ol>
			<?php endif; ?>

So here's what we are doing

  1. First we check if there even are any comments
  2. If there are then we'll generate an ordered list <ol> of entries
  3. For each comment we publish an <li> element with:
    1. A linked author name - remember we've used these fields so that this will actually be the link title linked to the URL
    2. The comment text - or in other words our link description.

Step 5 - Updating the Comments RSS

Now the great thing about using comments is that, by default, there is an RSS feed for each WordPress post. The URL is simply the address for the post followed by '/feed'. So in our case it is: http://audiotuts.com/general/user-link-feed/feed/

The only problem is that by default the formatting of the comments RSS will create a feed that looks like this (in Safari):

So there are three problems:

  1. The title of the feed is "Comments On: User Link Feed"
  2. The link title says "By: ..."
  3. The link doesn't go to the URL, it goes back to AUDIOTUTS

So to solve these problems we have to edit the feed template. So we go into our WordPress install to /wp-includes/feed-rss2-comments.php, which is the template file for the comments RSS. Here's what the file has in it by default (in WordPress 2.5.1):

<?php
/**
 * RSS2 Feed Template for displaying RSS2 Comments feed.
 *
 * @package WordPress
 */

header('Content-Type: text/xml;charset=' . get_option('blog_charset'), true);

echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>';
?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title><?php
		if ( is_singular() )
			printf(__('Comments on: %s'), get_the_title_rss());
		elseif ( is_search() )
			printf(__('Comments for %s searching on %s'), get_bloginfo_rss( 'name' ), attribute_escape($wp_query->query_vars['s']));
		else
			printf(__('Comments for %s'), get_bloginfo_rss( 'name' ) . get_wp_title_rss());
	?></title>
	<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
	<link><?php (is_single()) ? the_permalink_rss() : bloginfo_rss("url") ?></link>
	<description><?php bloginfo_rss("description") ?></description>
	<pubDate><?php echo gmdate('r'); ?></pubDate>
	<?php the_generator( 'rss2' ); ?>
	<?php do_action('commentsrss2_head'); ?>
<?php
if ( have_comments() ) : while ( have_comments() ) : the_comment();
	$comment_post = get_post($comment->comment_post_ID);
	get_post_custom($comment_post->ID);
?>
	<item>
		<title><?php
			if ( !is_singular() ) {
				$title = get_the_title($comment_post->ID);
				$title = apply_filters('the_title_rss', $title);
				printf(__('Comment on %1$s by %2$s'), $title, get_comment_author_rss());
			} else {
				printf(__('By: %s'), get_comment_author_rss());
			}
		?></title>
		<link><?php comment_link() ?></link>
		<dc:creator><?php echo get_comment_author_rss() ?></dc:creator>
		<pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_comment_time('Y-m-d H:i:s', true), false); ?></pubDate>
		<guid isPermaLink="false"><?php comment_guid() ?></guid>
<?php if (!empty($comment_post->post_password) && $_COOKIE['wp-postpass'] != $comment_post->post_password) : ?>
		<description><?php _e('Protected Comments: Please enter your password to view comments.'); ?></description>
		<content:encoded><![CDATA[<?php echo get_the_password_form() ?></content:encoded>
<?php else : // post pass ?>
		<description><?php comment_text_rss() ?></description>
		<content:encoded><![CDATA[<?php comment_text() ?></content:encoded>
<?php endif; // post pass
	do_action('commentrss2_item', $comment->comment_ID, $comment_post->ID);
?>
	</item>
<?php endwhile; endif; ?>
</channel>
</rss>

Now we don't really need to know what most of that does, rather we'll just go through and change a few lines. The first line that we can fix is Line 18, which we change from this:

printf(__('Comments on: %s'), get_the_title_rss());

to this:

printf(__('%s'), get_the_title_rss());

Then we'll change Line 42 from this:

printf(__('By: %s'), get_comment_author_rss());

to this:

printf(__('%s'), get_comment_author_rss());

In both cases we are simply removing the extra words - "Comments on: " and "By: " - so that the feed makes more sense. So that was pretty easy. The next bit is a bit more complicated because we need to change where the URL is pointing. Now currently it points back to the post so that the user can follow comments on that post. Since this template controls *all* comment RSS feeds, we don't want to break that functionality so we need an if statement as follows:

	<link><?php	
		if ($comment_post->ID != 3) {
        	comment_link();
		} else {
			echo $comment->comment_author_url;
		}
		?>
	</link>

So here we are simply checking if the post has an ID of 3 (which in our example is the Post ID of the user link feed) and if it does then we publish the URL, and if not we do the regular comment_link() function. So the final RSS template looks like this:

<?php
/**
 * RSS2 Feed Template for displaying RSS2 Comments feed.
 *
 * @package WordPress
 */

header('Content-Type: text/xml;charset=' . get_option('blog_charset'), true);

echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>';
?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title><?php
		if ( is_singular() )
			printf(__('%s'), get_the_title_rss());
		elseif ( is_search() )
			printf(__('Comments for %s searching on %s'), get_bloginfo_rss( 'name' ), attribute_escape($wp_query->query_vars['s']));
		else
			printf(__('Comments for %s'), get_bloginfo_rss( 'name' ) . get_wp_title_rss());
	?></title>
	<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
	<link><?php (is_single()) ? the_permalink_rss() : bloginfo_rss("url") ?></link>
	<description><?php bloginfo_rss("description") ?></description>
	<pubDate><?php echo gmdate('r'); ?></pubDate>
	<?php the_generator( 'rss2' ); ?>
	<?php do_action('commentsrss2_head'); ?>
<?php
if ( have_comments() ) : while ( have_comments() ) : the_comment();
	$comment_post = get_post($comment->comment_post_ID);
	get_post_custom($comment_post->ID);
?>
	<item>
		<title><?php
			if ( !is_singular() ) {
				$title = get_the_title($comment_post->ID);
				$title = apply_filters('the_title_rss', $title);
				printf(__('Comment on %1$s by %2$s'), $title, get_comment_author_rss());
			} else {
				printf(__('%s'), get_comment_author_rss());
			}
		?>
        </title>
		<link><?php	
		if ($comment_post->ID != 3) {
        	comment_link();
		} else {
			echo $comment->comment_author_url;
		}
		?>
        </link>
		<dc:creator><?php echo get_comment_author_rss() ?></dc:creator>
		<pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_comment_time('Y-m-d H:i:s', true), false); ?></pubDate>
		<guid isPermaLink="false"><?php comment_guid() ?></guid>
<?php if (!empty($comment_post->post_password) && $_COOKIE['wp-postpass'] != $comment_post->post_password) : ?>
		<description><?php _e('Protected Comments: Please enter your password to view comments.'); ?></description>
		<content:encoded><![CDATA[<?php echo get_the_password_form() ?></content:encoded>
<?php else : // post pass ?>
		<description><?php comment_text_rss() ?></description>
		<content:encoded><![CDATA[<?php comment_text() ?></content:encoded>
<?php endif; // post pass
	do_action('commentrss2_item', $comment->comment_ID, $comment_post->ID);
?>
	</item>
<?php endwhile; endif; ?>
</channel>
</rss>

And as a result our comment RSS feeds now look like this (for the user link feed and a regular post):


Step 6 - Displaying the Last 10 Items in the Sidebar

Next we need to display our most recent 10 items in the sidebar. Here's a little piece of code to do that:

<?php
$comment_array = array_reverse(get_approved_comments(3));
$count = 0; 
?>

<ul class="linkfeed"> 
	<? foreach($comment_array as $comment){ ?>
		<? if ($count++ <= 10) { ?>
			<li><?php comment_author_link(); ?> <br /><?php comment_text(); ?></li>
		<? } ?>
	<? } ?>
</ul>

So you can see here we are:

  1. Grabbing all approved comments from the post with Post ID = 3 as an array and reversing them so that we get the most recent first
  2. Then we create a <ul> element and for each comment in the array up to 10 we print out an <li> element with the link, title and description

And with a bit of styling here's how the result looks:

Finished!

So that's it! I also like to burn the feed via Feedburner so I can track how many people subscribe. So far it's been quite a useful feature, here at NETTUTS we have about 150 subscribers to the link feed, at PSDTUTS we have close to 500. So they are a good way of letting the community know about new links and they keep the site regularly updated.

I've recently contracted the fabulously talented Joshua Blount to build this into a WordPress plugin. Once it's all finished I'll make sure he releases it here as our first bit of NETTUTS open source :-)

Related Posts
  • Code
    Theme Development
    Custom Controls in the Theme CustomizerTheme customizer custom control 400
    In the last article, we explored the advanced controls available in the Theme Customizer, and how to implement them. We’re going to look at how to create our own custom control, allowing you to choose which Category of Posts are displayed on the home page. To get started, download version 0.6.0 of our Theme Customizer Example.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme from Static HTML: Creating an Archive TemplateCreating wordpress theme from html 400
    If you've been working your way through this series, you now have a functioning theme with two page templates. The steps I've demonstrated to this point are: preparing your markup for WordPress converting your HTML to PHP and splitting your file into template files editing the stylesheet and uploading your theme to WordPress adding a loop to your index file adding meta tags, the wp_head hook and the site title and description to your header file adding a navigation menu adding widget areas to the header and sidebar adding widget areas, a colophon and the wp_footer hook to the footer file creating template files for static pages. Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Adding a LoopCreating wordpress theme from html 400
    In the first three parts of this series, you learned how to prepare static HTML for WordPress and to create a theme by splitting your HTML file into a set of template files and editing the stylesheet. You then uploaded your theme to WordPress and activated it. The theme still isn't displaying any content you add via the WordPress admin however; to do that you need to add a loop to your template files.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Creating Template FilesCreating wordpress theme from html 400
    In the first part of this series, I showed you how to prepare your HTML and CSS files for WordPress, ensuring the structure would work, the code was valid and that the correct classes were being used. In this tutorial you'll learn how to take your index.html file and split it up into a set of template files for use by WordPress.Read More…
  • Code
    PhoneGap
    PhoneGap: Build a Feed Reader - Project StructurePhonegap feed reader@2x
    Although not specifically created to work together, jQuery Mobile and Cordova (also known as PhoneGap) are a very powerful duo to create hybrid, mobile apps. This series will teach you how to develop a feed reader using web technologies and these two frameworks. Over the course of this series, you'll also become familiar with the Cordova Connection and Storage Core Plugins and the Google Feed API.Read More…
  • Code
    WP101 Training
    Beginning With WordPress: Editing the Structure of Your SiteBeginning with wordpress
    So, you've got your CSS chops up to speed, and your site should now at least be a fair way down the track to being customised with a colour scheme and maybe even some custom fonts to make it really start to feel like it's much more 'you' than it was. But, you're thinking you'd also like to make some other changes and those changes aren't exactly style related. So it's likely you're going to have to to start getting into editing some of the hard-coded, inbuilt structure, and that means starting to dig into the PHP files of your site.Read More…