Consume a feed from a site that doesn’t syndicate using Yahoo Pipes

clownmommy screenshotIt’s surprising how hard it is to subscribe to sites intent on driving traffic to their main page, particularly if you want a subset of content by author or topic.

My wife writes for the nycmoms blog. She wanted to show a list of her recent blogs on her personal blog.

Nycmoms exposes a single feed aggregating recent posts across all authors.

Create a feed

My first iteration was to filter this feed through Yahoo Pipes. Pipes provides a graphical interface for chaining rules for manipulating web content and exposing it in a feed.

I used the “fetch feed” module pointed to the recent posts feed, connected it to the filter module set to only permit items where the author.name contained my wife’s handle.

This produced a correct result. However, only one or two of my wife’s posts are in the “recent posts” feed at any given time.

For the next iteration I found an alternative source outside the blog itself. Being a Yahoo tool, pipes provides a Yahoo search module. So, I searched for the phrase “Posted by KathieH” restricted to the site, nycmomsblog.com.

This produced more but less precise results. It includes additional pages such as my wife’s bio and sorted by relevance not post date.

I used the sort module on the item.updatedon field in the rss feed.

Next I used the filter module to exclude anything that was not an actual post identified by the term: “NYC Moms: KathieH” and piped out to rss.

Then I used the RSS widget in wordpress to expose this feed on my wife’s blog. Done!

Yahoo Pipes Screen Shot

Consume the feed

Except, my wife’s blog began suffering from the dreaded “Fatal Error: Allowed Memory Size” error in the simplepie library used by the RSS widget.

Well documented on the web, this is caused by my service provider’s decision to restrict accounts to 32MB of memory for PHP script execution. This and the 50MB-200MB storage limits were reasonable when I first signed up with my ISP ten years ago but is about as appropriate as using a 80286 processor now.

I decided to switch from server side processing to client side.

Luckily, Yahoo Pipes exposes feeds in the JSONP format. JSON is easily parsed by Javascript in the browser. JSONP is an established workaround (i.e. hack) that allows the client to make requests to third party URL’s without triggering the cross site security restrictions built into current browsers. It simply wraps the data response in a prefix that the browser parses as a function (allowed) as opposed to pure data (not allowed).

WordPress already uses the jQuery library which is well documented by examples on how to request, parse and render a feed.

I used the getJSON function to retrieve and parse the feed. It is exposed as a nested array containing at the top level, key/value pairs associated with the entire feed and an array of items containing the actual posts.

I loop through the value.items format them into HTML and append them into a div with the id nycmoms_posts. Probably overkill given how fast this all works but I display a loading indicator which I fade out when the loop is complete (from Kyle Meyer).

<div id=”nycmoms”>
<h2>Kathie on <a href=”http://www.nycmomsblog.com/kathieh/”>nycmomsblog.com</a></h2>
<div id=”nycmoms_loading” >…</div>
<ul id=”nycmoms_posts” />
</div>

<style>
#nycmoms { width:250px;min-height:125px;}
#nycmoms_loading { position:absolute;top:0;left:0;width:100%;height:100px;padding:100px 0 0 125px;}
#nycmoms .description, #nycmoms .postdate { font-size:small;}
</style>
<script src=”wp-includes/js/jquery/jquery.js?ver=1.3.2″></script>
<script>

var descriptionPattern = /^(.*) … Posted by Kathie H. on (\w+) (\d+), (\d+) .*$/g

window.onload = function() {

jQuery.getJSON(“http://pipes.yahoo.com/pipes/pipe.run?_id=8a8edd5b1e5181a001892cee910c11fc&_render=json&_callback=?”,
function(data) {
jQuery.each(data.value.items, function(i, post) {
jQuery(“#nycmoms_posts”).append(
‘<li><a href=”‘ + post.link +'”>’ + formatTitle(post.title) + “</a>”
+ “<!– “+formatDescription(post.description)+”–>”
+ “</li>”
) , jQuery(‘#nycmoms_loading’).fadeOut(500);
});
});

}

function formatDescription(description)
{
return description.replace(descriptionPattern, ‘<span=”description>”$1 … </span><span id=”postdate”>posted $2 $3, $4</span>’);
}
function formatTitle(title)
{
return title.replace(/^NYC Moms: /, ”);
}

</script>

How to add an options form to a wordpress theme using settings_fields

I spent some time today modifying a WordPress theme to take configuration properties.

I want one theme that I can quickly re-configure to create multiple blogs along different topics with different color/graphic schemes. I want easy maintenance so I’d love to share one instance of the theme across these different instances.

We’re using enough different plugins that WordPress Mu isn’t yet worth fighting. So database options and the Settings API seemed the best way.

The documentation on how to extend a theme this way is not so easy to find but there are plenty of examples. They tend to break the process into steps but don’t give as much sense of what you actually get and how to use it.

I based my code on this example: http://blog.starscapetheme.com/2008/05/31/create-settings-page-for-theme/

After the fact, I found this description which seems well written: http://www.pixelace.com/2009/theme-options-for-wordpress-27/

I created a menu item and a corresponding properties form:

Wordpress Theme Options FormWordpress Theme Menu Item
 

My form adds three properties which are stored in the WordPress wp_options table and easily exposed on template pages

<link rel="stylesheet" href="<?php $options = get_option('vertical'); echo $options['vertical_custom_css_url']; ?>" type="text/css" media="screen" />

Here’s the actual code I added to the functions.php page of the theme. If you don’t have a functions.php you can just create one in your theme folder. You need to make sure the code below is wrapped in “<?php” “?>” tags.

//encapsulate the logic into a class
$cpanel = new ControlPanel();

class ControlPanel {
/* static array to contain default values
the values set an additional css to override standard css in the theme
as well as an image and link that is rendered in the sidebar. These
three settings allow me to use the same theme with minor variations
on different blogs on different topics but with very similar looks and feels */

var $default_settings = Array(
‘vertical_custom_css_url’ => ,
‘topic_banner_img’ => ‘/images/banner.jpg’,
‘topic_url’ => ‘http://www.judykat.com/ken’

);
//constructor
function ControlPanel()
{
//hook to add a menu item in the Theme’s area of the admin sidebar
add_action(‘admin_menu’, array(&$this, ‘vertical_admin_menu’));
/* if options are not already created in the database, add them and set to default values
this creates a single database entry in wp_options with key vertical and
values a hash of key/value pairs */

if (!is_array(get_option(‘vertical’)))
add_option(‘vertical’, $this->default_settings);
//load the existing options into an array accessible as a property of this instance of ControlPanel
$this->options = get_option(‘vertical’);
}
//the function that ties an html form to the hook defined in the constructor.
function vertical_admin_menu() {
add_theme_page(‘Vertical Theme Control Panel’, ‘Customize Theme’, ‘edit_themes’, “vertical”, array(&$this, ‘vertical_theme_page’));
}
//function that defines the form for viewing and setting properties for the theme.
function vertical_theme_page() {
//if the form is being submitted, update the options in the database
if ( isset( $_POST[‘submit’] ) ) {
//if the “Save Changes” button was clicked, set the user entered values from the form
if (‘Save Changes’ == $_POST[‘submit’]) {
$this->options[“vertical_custom_css_url”] = $_POST[‘vertical_custom_css_url’];
$this->options[“topic_banner_img”] = $_POST[‘topic_banner_img’];
$this->options[“topic_url”] = $_POST[‘topic_url’];
$state=“saved”;
} //else if “Defaults” was clicked, reset values to default
else if (‘Defaults’ == $_POST[‘submit’]) {
$this->options[“vertical_custom_css_url”] = $this->default_settings[‘vertical_custom_css_url’];
$this->options[“topic_banner_img”] = $this->default_settings[‘topic_banner_img’];
$this->options[“topic_url”] = $this->default_settings[‘topic_url’];
$state=“reverted to defaults”;
} //commit the changes to the database
update_option(‘vertical’, $this->options);
//render a status message of the above actions in the standard WordPress admin dialog box at the top of the form.
echo ‘<div class=“updated fade” id=“message” style=“background-color: rgb(255, 251, 204); width: 300px; margin-left: 20px”><p>Settings <strong>‘.$state.’</strong>.</p></div>‘;
}
//the actual html form in standard markup to appear standard in the WordPress Admin
?>
<div class=‘wrap’>
<h2><?php _e(‘Customize Vertical Theme’); ?></h2>
<div id=“header”>
<div id=“headwrap”>
<div id=“header”>
<div id=“headerimg”>
<h1><?php bloginfo(‘name’); ?></h1>
<div class=“description”><?php bloginfo(‘description’); ?></div>
</div>
</div>
</div>
</div>
<br>
<form id=“vertical-settings-form” method=“post” action=“”>
<?php settings_fields( ‘vertical-settings’ ); ?>
<table class=“form-table”>
<tr valign=“top”>
<th scope=“row”>Path to Vertical CSS file:</th>
<td>
<input size=“70” type=“text” name=“vertical_custom_css_url” id=“vertical_custom_css_url” value=<?php echo $this->options[“vertical_custom_css_url”]; ?>” />
<br/><small>example: <?php echo(str_replace(get_bloginfo(‘url’),“”,get_bloginfo(‘template_url’).‘/’.str_replace(” “, “-“,strtolower(wptexturize(get_bloginfo( ‘name’ )))))); ?>/style.css</small>
</td>
</tr>
<tr valign=“top”>
<th scope=“row”>Path to Category Page:</th>
<td>
<input size=“70” type=“text” name=“topic_url” id=“topic_url” value=<?php echo $this->options[“topic_url”]; ?>” />
<br/><small>example: http://www.judykat.com/ken</small>
</td>
</tr>
<tr valign=“top”>
<th scope=“row”>Path to Category Banner:</th>
<td>
<input size=“70” type=“text” name=“topic_banner_img” id=“topic_banner_img” value=<?php echo $this->options[“topic_banner_img”]; ?>” />
<br/><small>example: <?php echo(str_replace(get_bloginfo(‘url’),“”,get_bloginfo(‘template_url’).‘/’.str_replace(” “, “-“,strtolower(wptexturize(get_bloginfo( ‘name’ )))))); ?>/images/banner.jpg</small>
</td>
</tr>
</table>
<p class=“submit”>
<input type=“submit” name=“submit” class=“button-primary” value=<?php _e(‘Save Changes’) ?> />
<input type=“submit” name=“submit” class=“button-primary” value=<?php _e(‘Defaults’) ?> />
</p>
<input type=“hidden” name=“saved” value=“true”>
</form>
</div>
<?php
}
}