My first widget! Random quote of the day/aphorism/fact etc

In response to a question from a friend of mine, I’ve just finished writing a quick widget/plugin to present a random aphorism (or whatever) as a sidebar widget.  Much like Hello Dolly but widgetised.

here it is for those who want it.  I will, at some stage, write a management interface to allow upload/management of aphorisms. Also add a configuration option to make the aphorism daily cached instead of re-generated each page refresh.

Update: second version now updated with management interface.  Or at least a partial interface! 

<?php
/*
Plugin Name: random Fact Widget
Plugin URI: 
Description: This widget looks up a random fact from a database
Author: Justin Adie
Version: 0.2.0
Author URI: http://rathercurious.net
*/
 
/*
 * installation:	
 * drop this file in your wordpress/wp-content/plugins directory
 * go to your plugins management and activate this plugin
 * 
 * then go to your widget dashboard in Design->Widget (within the admin menu) and click Add . Place where you want.
 * Don't forget to save the changes...
 * 
 */
 
/**
 * namespace mono-instance class for WP widget/plugin
 * 
 * class allows a widget to display a random aphorism/fact or whatever, in widgetised themes.
 * assumption is that there is a table in the WP database with a field called id (as primary key) and randomFact 
 */
class randomFact_Widget{
	public $factTable = '';
	public $aph ='';
	public $version = '0.2.0';
 
	/**
	 * method called by the add_action hook.  this registers the sidebar widget
	 * 
	 * has to be done quite late in the process
	 * 
	 * @return void
	 */
	public function init(){
 
		register_sidebar_widget("Daily Random", array($this, "widgetDisplay"));
		add_action('admin_menu', array($this, 'addManagementPage'));
 
	}
	public function __construct(){
		global $wpdb;
		//$wpdb->show_errors(true);  //for debugging
		$this->factTable = $wpdb->prefix . 'randomFact';	
	}
 
	public function addManagementPage(){
		add_management_page('Random Facts', 'Random Facts', 8, __FILE__, array($this, "pageDisplay"));
	}
 
 	/**
 	 * method to manage the installation routine
 	 * 
 	 * @return 
 	 */
 	public function install(){
 		global $wpdb;
		$result = $wpdb->query("create table if not exists {$this->factTable} (id mediumint(9) NOT NULL AUTO_INCREMENT PRIMARY KEY, randomFact longtext)");
		if ($result){
		update_option ('randomFact_Version', $this->version);
		}
 	}
 
	/**
	 * private function to retrieve and cache the aphorism/fact
	 * 
	 * @return void 
	 */
	private function getAph(){
		global $wpdb;
		/*
		 * this is an optimised method of retrieving random rows from a large dataset
		 */
		$sql = <<<SQL
		SELECT 
			randomFact 
		FROM 
			{$this->factTable}
		order by rand()
		LIMIT 1
SQL;
		$aph = $wpdb->get_var($sql);
		$this->aph = empty($aph) ? $this->getErrorMessage() : $aph;
	}
 
	/**
	 * private method to return a nil results string.
	 * to debug this turn on $wpdb->show_errors or define WP_DEBUG as true in wp-config.php
	 * 
	 * @return error string
	 */
	private function getErrorMessage(){
		return "No facts found in the database, or a database error occurred";
	}
 
	/**
	 * public method to output the aphorism to the widget
	 * 
	 * the args are automatically provided by Wordpress.  
	 * @return void
	 * @param $args array
	 */
	public function widgetDisplay($args){
		extract ($args);
		if (empty($this->aph)){
			$this->getAph();
		}
		echo <<<HTML
$before_widget
$before_title
Random Fact 
$after_title
{$this->aph}
$after_widget
HTML;
	}
 
	/**
	 * set up the management page for the random Facts
	 * 
	 * @return void
	 */
 
	public function pageDisplay() {
 
		$hidden_field_name = "randomFact_Widget_uploadAphorism_Type";
		$upload = '';
		if (	!empty($_POST[$hidden_field_name]) && 
				$_POST[$hidden_field_name] == 'Y'){
			if ($this->checkNonce()){}
			$upload = $_POST['randomFact_Widget_Fact'];
			$upload = str_replace("\r\n", "\n", $upload);
			$facts = explode("\n",$upload);
			$num = 0;
			foreach ($facts as $fact){
				if (empty($fact)) continue;
				$result = $this->insertFact ($fact);
				if($result) {
					$num++;
				}
			}
			$upload = <<<HTML
 
	<div class="updated">
		<p><strong>{$num} new facts saved to database</strong></p>
	</div>
 
HTML;
		} 
		$formUrl = str_replace( '%7E', '~', $_SERVER['REQUEST_URI']);
 
		$facts = $this->getFacts();
		$rows = '';
		foreach ($facts as $fact){
			$rows .= <<<HTML
 
				<tr>
					<td id="randomFact_{$fact->id}">{$fact->randomFact}</td>
					<td>&nbsp;</td>
				</tr>
HTML;
		}
		echo <<<HTML
<div class="wrap">
	<h2>Random Facts - Management</h2>
	<h3>Upload Facts</h3>
	{$upload}
	<form name="form1" method="post" action="{$formUrl}">
			<p>Paste your fact below.  Insert multiple facts separated by a line break</p>
			<p><textarea name="randomFact_Widget_Fact" rows="8" wrap="soft"></textarea></p>
			<hr />
 
			<p class="submit">
			<input type="submit" name="Submit" value="Insert Fact" />
			<input type="hidden" name="{$hidden_field_name}" value="Y">
			{$this->deliverNonce()}
			</p>
	</form>
	<hr/>
	<h3>Current Facts</h3>
		<p>
		<table class="widefat">
			<thead>
			<tr>
				<th scope="col">Random Fact</th><th scope="col">&nbsp;</th>
			</tr>
			</thead>
			<tbody>
				{$rows}
			</tbody>
		</table>
		</p>
</div>
HTML;
 
	}
 
	/**
	 * method to add facts to the database
	 * 
	 * @return bool if the fact is in the database, or there is a db error, it will return fale, else true
	 * @param object $fact
	 */
	private function insertFact($fact){
		global $wpdb;
		$oldValue = $wpdb->show_errors(true);
		//check that the fact is not in the database
		$chk = $wpdb->get_var($wpdb->prepare("select count(*) from {$this->factTable} where randomFact=%s", $fact));
		if ($chk > 0){
			return false;
		}
 
		$result = $wpdb->query($wpdb->prepare("insert into {$this->factTable} (id, randomFact) values (NULL, %s)", $fact));
		if ($result){
			return true;	
		} else {
			return false;
		}
	}
 
	/**
	 * method to return an associative array of fact objects
	 * 
	 * @return array of objects
	 */
	private function getFacts(){
		global $wpdb;
		$sql = "Select id, randomFact from {$this->factTable} order by id asc";
		$results = $wpdb->get_results($sql);
		return $results;
	}
 
	/**
	 * wrapper method to deliver a nonce
	 * 
	 * @return void
	 */
	private function deliverNonce(){
		if (function_exists('wp_nonce_field')){
			wp_nonce_field($this->nonce);
		}
	}
 
	/**
	 * method to check a nonce
	 * @return 
	 */
	private function checkNonce(){
		check_admin_referer();
	}
}
 
/*
 * this is my preference for plugins/widgets.  
 * using a class prevents namespace clashes
 */
$randomFact_Widget = new randomFact_Widget;
 
/*
 * this is the hook to make sure that this widget is enabled in WP
 */
add_action ('plugins_loaded', array(&$randomFact_Widget, 'init'));
 
/* 
 * register the activation hook for the plugin
 */
register_activation_hook(__FILE__, array(&$randomFact_Widget, 'install'));
?>

2 Comments

AndyOctober 10th, 2008 at 11:28 pm

Have installed this and populated a table called facts. Have kept your fields id and randomFact and changed the table to facts.

Getting this message:
>>>
No facts found in the database, or a database error occurred
<<<

JustinOctober 11th, 2008 at 9:46 am

Andy
I think you may be using the wrong version of the code. The first version had a small SQL error that always resulted in nil results. the query was also not compatible with my sqlite driver for PDO For WP. So i have migrated to a simpler, more traditional form of randomisation. This does not scale well on large datasets and I may post a code (rather than sql) based optimisation in the next few days.

Leave a comment

Your comment