Thought Vectors Code Guts, Part Deux


creative commons licensed ( BY-NC-ND ) flickr photo shared by cszar

If you thought the last post on Under the Hood of the Thought Vectors Site was a gory on code, maybe click next. But for my own sake, some more write-ups of more recent twiddlings.

Got RAND() Post?

A trick I have used on ds106 and some following syndication hub sites is to add a link that generates a randomly chosen syndicated post, like a call to comment on a randomly drawn post. It uses a direct MySQL query that uses the

ORDER BY RAND()

syntax, but I was stumped because in all my tests on thoughtvectors, it was not only bad random, it was ignored. I always got the most recent post.

It was a hunch that the WP Engine hosting might have this bit of MySQL disabled; it is said to be a resource hog. Tom confirmed this; offering to turn it on, but I wanted to dig in a bit for an end around. As usual I found an answer in Stack Overflow to make it part of the WHERE condition.

The previous post had a long section on the shortcode function I wrote to add the list of syndicated blogs (or those within just a category) to use in a sidebar widget. It already knows the category ID if we are on a category archive view.

So we can see on the sidebar of all posts associated with UNIV 200 Section 5

random post link

At the bottom is a link for a random post (oops, the 2 week thing has been removed, but that does not matter for this example)

http://thoughtvectors.net/random/?group=64

The group= parameter represents the WordPress ID number for that category.

To be able to pass custom parameters like this to a wordpress template, you have to add some code to your functions.php file to define the query parameter, like:

add_filter('query_vars', 'fwp_opml_parameter_queryvars' );

function fwp_opml_parameter_queryvars( $qvars )

// allow category parameter to be passed in wp query string
// feel free to devise your own name, but stay away from 'cat"
// since WordPress uses that one
{
	$qvars[] = 'catty';
	return $qvars;
}     

In this case I can then use URLs like http://mycoolsite.org/gizmopage/?catty=42 to send a variable named “catty” to the template for my gizmo page.

Did i lose ya? This is the easy part.

To make the random page thing work, I make a theme template named page-random.php. If I then create a WordPress Page and select it from the Templates menu on the right (or give it a slug of “random”), but template page takes over from the normal display of page content (in my case the content in the body of the page of the WordPress editor is ignored)

The PHP for this template below is pretty basic (hah!). It looks to see if we got a parameter with a category ID; if not we give it a default value. This goes into a custom MySQL query that has the magic condition to pull a random post, between 1 and the maximum ID used in the table.

WHERE wp_posts.ID >= FLOOR(1 + RAND() * 
       (SELECT MAX(ID) FROM wp_posts))

We get one result, where the URL for the post (in Feed WordPress this is the external URL) we fetch from guid, and then use a command to redirect the browser to the random site:

<?php
/*
Template Name: Random Syndicated Content Redirect

Use on a Feed WordPress powered site as a page template that is able to redirect visitor
to a random syndicated piece of content.
?>

<?php
// check for the passed parameter value, set to default category 
// if not specified (replace '23' with your own default ID)
$catid =  (isset($wp_query->query_vars['catty'])) ? $wp_query->query_vars['catty'] : '23';

//--------- global needed to run db query
global 	$wpdb;
 
// custom query to get a random published post from the given category
$custom_query =  
	"
	SELECT wp_posts.guid
			FROM wp_posts
			INNER JOIN wp_term_relationships 
			ON wp_posts.ID = wp_term_relationships.object_id   
			WHERE
				wp_posts.ID >= FLOOR(1 + RAND() * (SELECT MAX(ID) FROM wp_posts))
				AND wp_term_relationships.term_taxonomy_id IN ($catid)
				AND wp_posts.post_type = 'post' 
				AND wp_posts.post_status = 'publish'  
			Limit 0,1
	";
 
// run run run that query
$my_random_post = $wpdb->get_results( $custom_query );

// go browser go, send to the found URL
wp_redirect ( $my_random_post[0]->guid );
?>

Got it?

Some OPML Please

An even more arcane acronym than RSS is Outline Processor Markup Language (OPML) — but they got together. OPML is an XML (that never helps in explaining, does it?) structure for organizing outline lists of data. For our purposes, it is a nifty way to create a subscription list for all feeds in a group, e.g. all feeds for the students in Jon Becker’s section, so you can use it to import into Feed Readers, and in our case, other sites running Feed WordPress.

It allows you to mass import feeds.

Jon actually asked me about it, and it is handy since a number, if not all of the section “Clubhouse sites” (ones specifically managed by course instructors) like Jon’s Team Oneder one may want to run their own syndication.

We have syndication all over da place.

Generating OPML from the Feed WordPress data was something I had also done for ds106 (see sidebar where you can get an OPML for all open participants).

Again, since we are organizing feeds by categories that are applied at the point of syndication, its pretty easy to roll into the archives template; again for UNIV 200 Section 5, at the top right we have an RSS feed (WordPress makes that easy) and an OPML download link.

section 5

Just to be inconsistent, I have this php script, tv-opml.php at the root level of the site; it makes no difference. Here it is in parts…

<?php
/* ----------------------------------
Feedwordpress OPML Generator
a hack and a half method to generate opml feeds from 
categories of feeds
Alan Levine cogdog.it
------------------------------------- */

//--------  a little config goes a long way

$default_cat = 23; // id for default category
$pretty_title = 'Thought Vectors OMPL Feed'; // base for title

// load wordpress functionality so we can do stuff
require( 'wp-load.php' );

We start by defining the default category ID (in case none are passed), and the base for the title string of the OPML output. Asking for wp-load.php is a way we can access the WordPress functionality but where we are not doing any output related to the theme (in this case the output is downloaded).

// get the parameters from url parameters
// these should be set up in functions.php
$catid = ( isset( $_GET['group'] )) ? $_GET['group'] : $default_cat;

// keep a reference for the current category for an archive page
$mycat = get_category($catid);

$pretty_title .= ' for ' . $mycat->name;

Next we look for a parameter group=XX in the URL to define the category ID used in the database query. The get_category lets us get at info related to the category, such as its full name $mycat->name.

//--------- set up db query
global 	$wpdb;

// custom query to get subscribed blogs from the links table
$custom_query =  
	"
	SELECT DISTINCT      
		   wpl.link_name, wpl.link_url, wpl.link_rss
	FROM       $wpdb->links wpl,  $wpdb->postmeta wpm
	WHERE      wpm.meta_key='syndication_feed_id' AND 
				wpm.meta_value = wpl.link_id AND 
				wpl.link_notes LIKE '%%{category#" . $catid . "}%%'
	ORDER BY    wpl.link_name ASC
	";

// run run run that query
$feedblogs = $wpdb->get_results( $custom_query );

// bail if we got nothing
if ( count( $feedblogs ) == 0 ) die ( "No blogs found for '"  . $mycat->name . "'" );

No we run the query- we are searching the links table, where Feed WordPress stores its info, specifically for a string like “{category#45}” to if 45 is the category id we are looking for.

We should up with results of all links that match the category ID.

// headers to generate downloaded XML file
header ('Content-disposition: attachment; filename=thoughtvectors-' . $mycat->slug . '.opml');
header ("Content-Type:text/xml"); 

// start output
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<opml version="1.0">
    <head>
        <title><?php echo $pretty_title ?></title>
    </head>
    <body>
        <outline title="<?php echo $pretty_title ?>" text="<?php echo $pretty_title ?>">

<?php 
// output each item, 
foreach ( $feedblogs as $item ) 
{
 	echo "\t\t" . '<outline text="' . htmlspecialchars($item->link_name)   . '" title="' . htmlspecialchars($item->link_name)  . '" type="rss"
                xmlUrl="' . htmlspecialchars($item->link_rss)  . '" htmlUrl="' . htmlspecialchars($item->link_url) . '"/>' . "\n";              
}			
?>	    </outline>
    </body>
</opml>

Lastly, we start returning the output in OPML structure. The header() function lets us generate a download rather than something that appears in the browser, the rest is just the formatting that makes it an OPML file.

But Wait, There’s More!

The code fun never stops, but I will break this one here. The latest bits happened last night, and what we have in a trial version is a site that is syndicating all of the comments from the UNIV 200 blogs; generating an OPML for comment feeds was just an extension of the function above.

Stay tuned for that stuff.

Let’s see how the patient is doing.


creative commons licensed ( BY-NC-ND ) flickr photo shared by cszar

Excellent.

Creative Commons License
Thought Vectors Code Guts, Part Deux by CogDogBlog, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

2 Responses to “Thought Vectors Code Guts, Part Deux”

  1. Gardner says:

    Butcher cover got nothing on you, baby.

    Oh, and have I said “thanks for the miracles” lately?

  2. […] in case you have not had your fill of the previous two code dumps for the workings of the VCU Thought Vectors site… heres more. I can’t stop […]

Leave a Reply

Recent Barks and Howls: