boakes.org

Delicious-to-WordPress

Having tried several solutions for publishing delicious bookmarks on WordPress I came to the conclusion that nothing did what I wanted. What I wanted was each link on the front page, interspersed with any articles I write, so that the time-line of links and articles becomes apparent and the main page is a more dynamic thing that is more useful for me (this is, after all, a long-running set of technical experiments and what-ifs rather than a vanity site). So my experimental sync plug-in is now operational and links can be seen (requires a stylesheet reload), currently, as green items, whereas articles show up blue. Simple, huh?

Technical minded folk may be interested to know that the plug-in uses a custom post type to keep the content sane and the formatting and editing simple.
Tags appear to be working in the plug-in, but I need to tweak my theme.

In the spirit of release-early-release-often the code is here:

< ?php
/*
 Plugin Name: Link Republisher
 Plugin Version: 0.17
 Plugin Author: Rich Boakes
 Plugin Author URI: http://boakes.org/
 Plugin URI: http://boakes.org/link_republisher
 Plugin License: GPL v3 ( http://www.gnu.org/licenses/gpl.html )
 Plugin Description: Retrieves the n most recent links from a JSON delicious, feed ordered by date, and creates a slug based on the title of the bookmark.  If the slug does not exist a custom type post is created with the slug, link  name as the title, description as the body, tags set to match those in delicious.  Additionally the custom post type can be set to appear in the loop, so links appear as stories.  Link publish time is set to the time that the link appears on delicious rather than the time the script runs. The internal cron system is used to run the lookup hourly.
*/

// The Delicious feed URI is: http://feeds.delicious.com/v2/{format}/{username}

// TODO
// [   ] Extract default vars for easy tweaking / addition of a UI one day
// [   ] Someone outside of GMT might want to improve the date settings
// [   ] Abstract the uri & data map to work with other JSON feeds such as twitter,
//       e.g. twitter https://twitter.com/statuses/user_timeline/15493170.json
// [   ] Lookup user ID for when writing posts

// Change Log
// [0.1] Get basic functionality working
// [0.2] Add link metadata
// [0.3] Create special post template so link is rendered
// [0.4] Switch default status to Published rather than Draft
// [0.5] load every 15 minutes.
// [0.6] revert load every 15 minutes - silly idea
// [0.7] moved wp_cron registration to plugin activation event and added deactivation event
// [0.8] added cleanup to ensure multiple cron registrations are removed on deactivation
// [0.9] re-added 15 minute refresh
// [0.10] links are now downloaded when plugin is activated
// [0.11] added JSON based log
// [0.12] Get tags importing properly
// [0.13] Make it so that the entries really do show up for tag searches.  Tags included in link pages now appear in /tag/tagname pages making them useful.
// [0.14] Listen for the download links action so the cronjob now has an effect
// [0.15] various tweaks to try, unsuccessfully to make the cron event do anything at all
// [0.16] cron appears to be working again (hurrah!).
// [0.17] include links in RSS feeds 

$link_republisher_debug = false;
$delicious_user_id = "ear1grey";
$delicious_article_count = 10;

// Add a LINK post type
function create_post_type() {
  global $wp_rewrite;
  register_post_type( 'rjb_link',
    array(
      'labels' => array(
        'name' => __( 'Links' ),
        'singular_name' => __( 'Link' )
      ),
      'public' => true,
      'rewrite' => array('slug' => 'links'),
      'supports' => array(
        'title','editor','author','thumbnail','comments', 'custom-fields'
      ),
      'taxonomies' => array('post_tag')
    )
  );
  // is this a performance hit?  RSVP anyone with an answer!
  $wp_rewrite->flush_rules();
}

// include the LINK post type in the feed
function rjb_get_posts( $query ) {
	if ( is_home() &&
            false == $query->query_vars['suppress_filters']
        ) {
	    $query->set( 'post_type', array( 'post', 'rjb_link' ) );
	}
	return $query;
}

function download_links() {
	global $delicious_user_id, $delicious_article_count;
	json_log("Loading links.");
	load_links($delicious_user_id, $delicious_article_count);
}

function load_links($user, $count=10) {
	$raw_content = file("http://feeds.delicious.com/v2/json/ear1grey?count=10");
//	$raw_content = file("http://feeds.delicious.com/v2/json/$user?count=$count");
	$content = json_decode($raw_content[0]);
	foreach ($content as &$bookmark) {
		import_link($bookmark);
	}
}

function slug_exists($slug) {
	global $wpdb;
	return $wpdb->get_row(
            "SELECT post_name FROM wp_posts WHERE post_name = '$slug';"
        );
}

function import_link($bookmark) {
	$slug = sanitize_title( $bookmark->d );
	if (!slug_exists($slug)) {
		// Create array for wp_update_post or wp_insert_post
		$id = wp_insert_post(
			array(
				'post_status' => 'publish',
				'post_type' => 'rjb_link',
				'post_title' => $bookmark->d,
				'post_content' => $bookmark->n,
				'post_name' => sanitize_title( $bookmark->d ),
				'post_date' => date('Y-m-d H:i:s', strtotime($bookmark->dt)),
				'post_date_gmt' => date('Y-m-d H:i:s', strtotime($bookmark->dt)),
				'tags_input' => $bookmark->t
			)
		);

		update_post_meta($id, 'url', $bookmark->u);

		wp_set_post_terms($id,$bookmark->t,'post_tag',true);
		json_log("Add: " . $bookmark->u);
	} else {
		json_log("Ignoring: " . $bookmark->u);
	}
}

register_deactivation_hook( __FILE__, 'linkrepublisher_off' );
register_activation_hook(__FILE__, 'linkrepublisher_on');
add_action( 'init', 'create_post_type' );
add_filter( 'pre_get_posts', 'rjb_get_posts' );

function linkrepublisher_on() {
	reset_log();
	json_log("link republisher on");
	wp_schedule_event(time()+200, 'hourly', 'link_republisher_update');
	wp_schedule_event(time()+1100, 'hourly', 'link_republisher_update');
	wp_schedule_event(time()+2000, 'hourly', 'link_republisher_update');
	wp_schedule_event(time()+2900, 'hourly', 'link_republisher_update');
	json_log("events scheduled");
	download_links();
}

add_action('link_republisher_update', 'download_links');

function linkrepublisher_off() {
	json_log("link republisher off");
	// ensure any and all crons are killed.
	wp_clear_scheduled_hook( 'link_republisher_update' );
}

function reset_log() {
	$log = array();
	update_option('json_log',json_encode($log));
}

function json_log($msg) {
	$raw_log = get_option('json_log');
	if ($raw_log) {
		$log = json_decode($raw_log);
	} else {
		$log = array();
	}
	$date = date('Y-m-d H:i:s',time());
	$log[] = array("t" => $date, "m" => $msg);
	update_option('json_log',json_encode($log));
}

add_filter('posts_where', 'include_rjb_links' );

function include_rjb_links( $q ) {
  if( is_tag() ) {
    // regex used under GPL from:
    // http://www.michelem.org/wordpress-plugin-tags4page/
    return preg_replace(
       "/ ([0-9a-zA-Z_]*\.?)post_type = 'post'/",
       "(${1}post_type = 'post' OR ${1}post_type = 'rjb_link')", $q );
   }

  return $q;
}

/*
 * Debug Page
 */
function lr_debug_menu() {
	$raw_log = get_option('json_log');
	$log = json_decode($raw_log);
	echo "
";
	print_r($log);
	echo "

“;
}
function add_admin_menu($s) {
add_submenu_page(‘tools.php’, ‘LR Debug’, ‘LR Debug’, ‘administrator’, dirname(__FILE__) , ‘lr_debug_menu’);
return $s;
}
add_action(‘admin_menu’, ‘add_admin_menu’);

// add rjb_link entries to the any rss feed
function myfeed_request($qv) {
if (isset($qv['feed']) && !isset($qv['post_type']))
$qv['post_type'] = array(‘post’, ‘rjb_link’);
return $qv;
}
add_filter(‘request’, ‘myfeed_request’);

?>

Released under the GPLv2 license as always.