Wordpress Reddit Upvote

(2012)

A few weeks ago, I wrote a plugin that we ended up not using. It's kinda cool, so I figured I would post it here instead.

Reddit has a nice mostly-json API for programmatically interacting with the site. Helpful people have also developed language-specific clients, such as the reddit-php-sdk on github. Using that library, I made a fun little Wordpress plugin that allows you to track and upvote items from a particular subreddit via the Wordpress Dashboard.

The code uses a couple of Wordpress features that I've had relatively little use for in the past, particularly Wordpress-Ajax and Transients. Here is the plugin code. Please - as always - use at your own risk.

<?php
/*
Plugin Name: My Reddit Dashboard
Description: Upvote on reddit.com via Wordpress Dashboard
Version: 0.1
*/


class ct_reddit_dashboard {

 private $option_key = 'ct_reddit_dashboard';
 private $transient_key = 'ct_reddit_dashboard_transient';

 private $username;
 private $password;
 private $subreddits;
 private $max_items;

 public function __construct() {
   add_action( 'wp_dashboard_setup', array( $this, 'wp_dashboard_setup' ) );
   add_action( 'wp_ajax_ct_reddit_dashboard_do_ajax_request', array( $this, 'wp_ajax_ct_reddit_dashboard_do_ajax_request' ) );

   $options = get_option( $this->option_key, NULL);
   if( $options ) {
     $this->username = $options['username'];
     $this->password = $options['password'];
     $this->subreddits = $options['subreddits'];
     $this->max_items = $options['max_items'];
   }
 }

 public function wp_dashboard_setup() {
   wp_add_dashboard_widget( 'ct_reddit_dashboard', 'Reddit', array( $this, 'callback' ), array( $this, 'control_callback' ) );
 }

 public function callback() {
   $recent_links = $this->get_recent_links();
   ?>
   <table>
   <?php foreach($recent_links as $link): ?>
   <tr>
     <td valign="top"><a class="ct-reddit-dashboard-upvote" href="#" data-name="<?php echo $link->name ?>">[+1]</a></td>
     <td valign="top">[<?php echo $link->ups ?>]</td>
     <td valign="top"><a href="<?php echo $link->permalink ?>"><?php echo $link->title ?></a></td>
   </tr>
   <?php endforeach; ?>
   </table>
   <script>
   jQuery(document).ready(function($) {
     $('.ct-reddit-dashboard-upvote').click(function(e) {
       e.preventDefault();
       var self = $(this),
       data = {
         action: 'ct_reddit_dashboard_do_ajax_request',
         name: self.data('name')
       };
       $.post('/wp-admin/admin-ajax.php', data, function(result) {
         self.text('--');
       });
     });
   });
   </script>
 <?php
 }

 public function control_callback() {
   if( isset($_POST['ct_reddit_dashboard']) && $_POST['ct_reddit_dashboard'] == 1 ) {
     $this->username = $_POST['ct_reddit_dashboard_username'];
     $this->password = $_POST['ct_reddit_dashboard_password'];
     $this->max_items = absint($_POST['ct_reddit_dashboard_max_items']);
     $this->subreddits = $_POST['ct_reddit_dashboard_subreddits'];
     $options = array(
       'username' => $this->username,
       'password' => $this->password,
       'max_items' => $this->max_items,
       'subreddits' => $this->subreddits,
     );
     update_option( $this->option_key, $options );
     delete_transient( $this->transient_key );
   }
 ?>
 <input type="hidden" name="ct_reddit_dashboard" value="1"/>
 <table class="form-table">
 <tr>
   <td><label for="ct_reddit_dashboard_username">Username:</label></td>
   <td><input type="text" name="ct_reddit_dashboard_username" value="<?php echo esc_attr($this->username) ?>"/></td>
   <td><span class="description">(your reddit username)</span></td>
 </tr>
 <tr>
   <td><label for="ct_reddit_dashboard_password">Password:</label></td>
   <td><input type="password" name="ct_reddit_dashboard_password" value="<?php echo esc_attr($this->password) ?>"/></td>
   <td><span class="description">(your reddit password)</span></td>
 </tr>
 <tr>
   <td><label for="ct_reddit_dashboard_max_items">Max Items:</label></td>
   <td><input type="text" name="ct_reddit_dashboard_max_items" value="<?php echo esc_attr($this->max_items) ?>"/></td>
   <td><span class="description">ex. 5</span></td>
 </tr>
 <tr>
   <td><label for="ct_reddit_dashboard_subreddits">Subreddits:<label></td>
   <td><input type="text" name="ct_reddit_dashboard_subreddits" value="<?php echo esc_attr($this->subreddits) ?>"/></td>
   <td><span class="description">(comma-separated, no spaces)</span></td>
 </tr>
 </table>
 <?php
 }


 public function get_recent_links() {
   // try to fetch from transient cache
   if( false !== $cache = get_transient( $this->transient_key ) ) {
     return $cache;
   }

   // no cache, fetch from reddit
   $fresh = $this->fetch_recent_links();
   set_transient( $this->transient_key, $fresh, 3600 );

   return $fresh;
 }

 public function fetch_recent_links() {
   $username = $this->username;
   $password = $this->password;
   $max_items = min(absint($this->max_items), 10);
   $subreddits = explode(',',$this->subreddits);

   if( ! $username ) {
     return array();
   }
   if( ! $password ) {
     return array();
   }
   if( ! $max_items ) {
     return array();
   }
   if( ! $subreddits ) {
     return array();
   }

   include_once('lib/reddit-php-sdk/reddit.php');

   $results = array();
   $reddit = new reddit( $this->username, $this->password );

   foreach( $subreddits as $subreddit ) {
     $listing = $reddit->getListing( $subreddit, $this->max_items);
     $listing_data = $listing->data;
     $listing_data_children = $listing_data->children;
     foreach($listing_data_children as $r) {
       $result = new stdClass;
       $result->name = $r->data->name;
       $result->domain = $r->data->domain;
       $result->title = $r->data->title;
       $result->permalink = 'http://reddit.com' . $r->data->permalink;
       $result->ups = $r->data->ups;
       $results[] = $result;
     }
   }
   return $results;
 }

 public function wp_ajax_ct_reddit_dashboard_do_ajax_request() {
   $username = $this->username;
   $password = $this->password;
   $name = $_POST['name'];

   if( ! $name ) {
     exit('Missing name');
   }
   if( ! $username ) {
     exit('Missing username');
   }
   if( ! $password ) {
     exit('Missing password');
   }

   include_once('lib/reddit-php-sdk/reddit.php');
   $reddit = new reddit( $this->username, $this->password );
   $response = $reddit->addVote( $name, 1 );
 }

}

$ct_reddit_dashboard = new ct_reddit_dashboard();

Note that the php-reddit-sdk library has been downloaded in a /lib folder.

Also, note that the Reddit API requests that you specify a unique user agent when using a bot. I slightly tweaked the library to add a custom user agent in the runCurl($url, $postVals = null) method by adding this line:

CURLOPT_USERAGENT => "My Unique Agent",

(Of course, I named it something else and didn't hard code it in the actual implementation)