Reddit Upvoting from the Wordpress Dashboard

WARNING: This article features ANCIENT code! I'm keeping it online because it's interesting to see what I was thinking 10+ years ago. But you DEFINITELY should not be using this code. Anything you're reading about on this page has changed significantly since this was written.

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: CT Reddit Dashboard
Description: Upvote on reddit.com via Wordpress Dashboard
Version: 0.1
Author: Craige T
Author URI: http://craiget.com
*/

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