Update of /cvsroot/php-blog/jBlog
In directory sc8-pr-cvs1:/tmp/cvs-serv14991
Modified Files:
db.sql jBlog_admin.php jBlog_admin_installer.inc.php
jBlog_functions.inc.php jBlog_layout.php
Added Files:
jBlog_admin_plugins.inc.php jBlog_plugin_api.php
jBlog_sidebar_items.php
Log Message:
Implement plugin api.
For the moment, only built-in plugins are supported, although adding support
for third-party plugins is not far away.
Upgrade notes: (the installation should cover these anyway):
CREATE TABLE {PREFIX}plugins (
name varchar(128) not null,
placement enum ('left', 'right', 'hide') not null default 'right',
sort_order int(4) not null,
PRIMARY KEY(name)
);
mkdir plugins
chmod appropriate_perms plugins
visit http://yourblog/jBlog_admin.php, click on "Configure Plugins"
(this will register the built-in plugins; this is done at install time,
but you need to bootstrap if you upgraded with reinstalling from scratch).
What works:
You can change the positioning left, right or hidden of each plugin.
What can be implemented now:
You can also change the order in which the plugins appear within their
side bars; if you can be bothered to hack together one of those sortable
listbox thingies, just update the sort_order field of jBlog_plugins.
What I will implement later this week, unless someone beats me to it:
Upload third party plugin; plugin gets its own dir; the dir name is the
name field in the jBlog_plugins table.
Loading this kind of plugin does an include "plugins/name/name.php" then
does a new $name;
Easy.
You might want to steal my CSS again (updating it shortly).
--- NEW FILE: jBlog_admin_plugins.inc.php ---
<?php
if (IN_JBLOG !== true) die ("Don't hack!");
session_start();
include_once "jBlog_plugin_api.php";
include_once "jBlog_sidebar_items.php";
/* Temporary hack to ease dev's lives:
* Force registration of the built-in plugins for now */
jblog_plugin_api::register_default_plugins();
if (isset($_POST['jBlog']['placement'])) {
foreach ($_POST['jBlog']['placement'] as $plugin_name => $placement) {
jblog_plugin_api::update_plugin_placement(
addslashes($plugin_name),
addslashes($placement)
);
}
}
/* very simple configuration for the moment; just change the placement */
$plugins = jblog_plugin_api::enum_plugins();
?>
<form action="?jBlog[adminModule]=plugins" method="post">
<table border="1" cellpadding="5">
<tr>
<th>Plugin</th>
<th>Description</th>
<th>Placement</th>
</tr>
<?php
function placement_box($name, $val)
{
static $opts = array(
'left' => 'Left',
'right' => 'Right',
'hide' => 'Hidden'
);
$x = "<select name=\"$name\">";
foreach ($opts as $k => $v) {
$x .= "<option value=\"$k\"";
if ($k == $val)
$x .= " selected";
$x .= ">$v</option>";
}
return $x . "</select>";
}
foreach ($plugins as $plugin_data) {
$plugin =& jblog_plugin_api::load_plugin($plugin_data['name']);
/* query for its name, description and configuration data */
$bag = new jBlog_property_bag;
$plugin->introspect($bag);
$name = htmlentities($bag->get('name'));
$desc = htmlentities($bag->get('description'));
$place = placement_box("jBlog[placement][" . $plugin_data['name'] . "]", $plugin_data['placement']);
if ($bag->is_set('configuration')) {
$url = "#fixme";
$desc = "<a href=\"$url\">$desc</a>";
$name = "<a href=\"$url\">$name</a>";
}
echo "<tr><td>$name</td><td>$desc</td><td>$place</td></tr>\n";
}
?>
</table>
<input type="submit" name="SAVE" value="Save">
</form>
--- NEW FILE: jBlog_plugin_api.php ---
<?php
if (IN_JBLOG !== true) die ("Don't hack!");
/* This file defines the plugin API for jBlog.
* By extending these classes, you can add your own code
* to appear in the sidebar(s) of jBlog.
*/
class jblog_plugin_api {
function register_default_plugins()
{
jblog_plugin_api::register_plugin(array(
'jBlog_calendar_plugin',
'jBlog_quicksearch_plugin',
'jBlog_archives_plugin',
'jBlog_topreferrers_plugin',
'jBlog_syndication_plugin',
'jBlog_superuser_plugin',
'jBlog_plug_plugin',
));
}
/* This should be used for built-in plugins only.
* run-time registration of an existing class as a plugin */
function register_plugin($class_names)
{
global $jBlog;
if (!is_array($class_names)) {
$class_names = array($class_names);
}
foreach ($class_names as $class_name) {
/* is it already registered ? */
$reg = jBlog_db_query("SELECT * from $jBlog[dbPrefix]plugins where name='@$class_name'", true);
if ($reg === false) {
/* no, so register it */
jBlog_db_query("INSERT INTO $jBlog[dbPrefix]plugins (name) values ('@$class_name')");
}
}
}
/* Retrieves a list of plugin records */
function enum_plugins($filter = '*')
{
global $jBlog;
$sql = "SELECT * from $jBlog[dbPrefix]plugins ";
if ($filter !== '*') {
$sql .= "WHERE placement='$filter' ";
}
$sql .= " ORDER BY placement, sort_order";
return jBlog_db_query($sql);
}
/* Creates an instance of a named plugin */
function &load_plugin($name)
{
if ($name{0} == '@') {
$class_name = substr($name, 1);
} else {
/* plugin from the plugins/ dir */
return false;
}
$p =& new $class_name;
return $p;
}
function update_plugin_placement($name, $placement, $order=null)
{
global $jBlog;
$sql = "UPDATE $jBlog[dbPrefix]plugins set placement='$placement' ";
if ($order !== null)
$sql .= ", sort_order=$order ";
$sql .= "WHERE name='$name'";
return jBlog_db_query($sql);
}
function generate_plugins($side)
{
$plugins = jblog_plugin_api::enum_plugins($side);
if (!is_array($plugins))
return;
echo "<td class=\"jBlog" . ucfirst($side) . "SideBar\" valign=\"top\">\n";
foreach ($plugins as $plugin_data) {
$plugin =& jblog_plugin_api::load_plugin($plugin_data['name']);
$title = get_class($plugin);
ob_start();
$plugin->generate_content($title);
$content = ob_get_contents();
ob_end_clean();
echo "<div class=\"jBlogSideBarItem\"><div class=\"jBlogSideBarTitle\">$title</div><div class=\"jBlogSideBarContent\">$content</div></div>\n";
}
echo "</td>\n";
}
}
/* holds a bunch of properties; you can have multiple
* properties with the same name */
class jBlog_property_bag {
var $properties = array();
var $name = null;
function add($name, $value)
{
$this->properties[] = array(
'name' => $name,
'value' => $value
);
}
function get($name)
{
$v = array();
foreach ($this->properties as $data) {
if ($data['name'] == $name) {
$v[] = $data['value'];
}
}
return implode(", ", $v);
}
function is_set($name)
{
foreach ($this->properties as $data) {
if ($data['name'] == $name) {
return true;
}
}
return false;
}
}
class jBlog_plugin {
/* Called by jBlog when it wants to display information
* about your plugin.
* You need to override this method in your child class.
*/
function instrospect(&$propbag)
{
$propbag->add('copyright', 'MIT License');
$propbag->add('name', get_class($this));
// $propbag->add('configuration', array(
// 'text field',
// 'foo bar'
// ));
return true;
}
/* Called by jBlog when it wants to display the configuration
* editor for your plugin.
* $name is the name of a configuration item you added in
* your instrospect method.
* You need to fill the property bag with appropriate items
* that describe the type and value(s) for that particular
* configuration option.
* You need to override this method in your child class if
* you have configuration options.
*/
function instrospect_config_item($name, &$propbag)
{
return false;
}
/* Called by jBlog when it wants your plugin to display itself.
* You need to set $title to be whatever text you want want to
* appear in the item caption space.
* Simply echo/print your content to the output; jBlog will
* capture it and make things work.
* You need to override this method in your child class.
*/
function generate_content(&$title)
{
$title = "Sample!";
echo "This is a sample!";
}
/* Fetches a configuration value for this plugin */
function get_config($name, $defaultvalue = null)
{
$name = get_class($this) . ":" . $name;
return jBlog_get_config_var($name, $defaultvalue);
}
}
?>
--- NEW FILE: jBlog_sidebar_items.php ---
<?php
class jBlog_calendar_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Calendar');
$propbag->add('description', 'QuickJump Calendar');
}
function generate_content(&$title)
{
global $jBlog;
$title = "Quickjump:";
if (!$jBlog["GET"]["calendarZoom"]) {
if (!$jBlog["GET"]["range"]) {
$jBlog["GET"]["calendarZoom"] = date("Y").date("m");
}
else {
$jBlog["GET"]["calendarZoom"] = $jBlog["GET"]["range"];
}
}
jBlog_drawCalendar(substr($jBlog["GET"]["calendarZoom"], 4, 2),
substr($jBlog["GET"]["calendarZoom"], 0,4));
}
}
class jBlog_quicksearch_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Quicksearch');
$propbag->add('description', 'Search for an entry');
}
function generate_content(&$title)
{
global $jBlog;
$title = "Quicksearch:";
echo "<form action=\"$jBlog[jBlogHTTPPath]search.php\" METHOD=\"GET\">\n"
. "<input type=\"hidden\" name=\"jBlog[action]\" value=\"search\">\n"
. "<INPUT TYPE=\"TEXT\" name=\"jBlog[searchTerm]\" ONFOCUS=\"value='';\">\n"
. "</form>";
}
}
class jBlog_archives_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Archives');
$propbag->add('description', 'Browse archives by month');
}
function generate_content(&$title)
{
global $jBlog;
$title = "Archives:";
$ts = mktime(0,0,0,(date("m")+1), 1, date("Y"));
for($x=0; $x<3; $x++) {
$ts-=1;
if ($jBlog["rewrite"] === true)
$link = $jBlog["jBlogHTTPPath"]."archives/d_".date("Ym", $ts).".html";
else
$link = "fixme";
echo "<a href='$link'>".$jBlog["months"][date("n", $ts)]." ".date("Y", $ts)."</a><br />";
$ts = mktime(0,0,0,date("m", $ts), 1, date("Y", $ts));
}
echo "<a href='?jBlog[action]=archives'>Older...</a>";
}
}
class jBlog_topreferrers_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Top Referrers');
$propbag->add('description', 'Shows top sites that linked to your blogs');
}
function generate_content(&$title)
{
global $jBlog;
$title = "Top Referrers";
echo jBlog_displayTopReferrers();
}
}
class jBlog_syndication_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Syndication');
$propbag->add('description', 'Shows RSS syndication links');
}
function generate_content(&$title)
{
global $jBlog;
$title = "Syndicate This Blog";
?>
<a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php'><img src="<?= $jBlog['jBlogHTTPPath'] ?>xml.gif" border=0></a>
<a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php'>RSS 0.91 feed</a>
<br/>
<a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php?version=2.0'><img src="<?= $jBlog['jBlogHTTPPath'] ?>xml.gif" border=0></a>
<a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php?version=2.0'>RSS 2.0 feed</a>
<?php
}
}
class jBlog_superuser_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Superuser');
$propbag->add('description', 'Allows you to configure and publish your blog');
}
function generate_content(&$title)
{
global $jBlog;
$title = "Superuser:";
echo "<a href=\"$jBlog[jBlogHTTPPath]jBlog_admin.php\">\$ su -</a>";
}
}
class jBlog_plug_plugin extends jBlog_plugin {
function introspect(&$propbag)
{
$propbag->add('name', 'Plug');
$propbag->add('description', 'Advertises the origins of your blog');
}
function generate_content(&$title)
{
global $jBlog;
$title = "";
echo "<div class=\"jBlogPlug\">This blog powered by <a href=\"http://sourceforge.net/projects/php-blog\">jBlog</a>!</div>";
}
}
?>
Index: db.sql
===================================================================
RCS file: /cvsroot/php-blog/jBlog/db.sql,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- db.sql 6 Mar 2003 20:16:30 -0000 1.11
+++ db.sql 10 Mar 2003 02:13:37 -0000 1.12
@@ -95,4 +95,9 @@
unique key (url, ip)
) TYPE=MyISAM;
-
+CREATE TABLE {PREFIX}plugins (
+ name varchar(128) not null,
+ placement enum ('left', 'right', 'hide') not null default 'right',
+ sort_order int(4) not null,
+ PRIMARY KEY(name)
+);
Index: jBlog_admin.php
===================================================================
RCS file: /cvsroot/php-blog/jBlog/jBlog_admin.php,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- jBlog_admin.php 9 Mar 2003 02:27:55 -0000 1.11
+++ jBlog_admin.php 10 Mar 2003 02:13:37 -0000 1.12
@@ -78,6 +78,7 @@
<div class="jBlogSideBarTitle">Appearance:</div>
<div class="jBlogSideBarContent">
• <a href='?jBlog[adminModule]=css'>Manage css</a><br>
+ • <a href='?jBlog[adminModule]=plugins'>Configure Plugins</a><br>
</div>
</div>
@@ -111,6 +112,10 @@
case "css":
include("jBlog_admin_css.inc.php");
break;
+
+ case "plugins":
+ include "jBlog_admin_plugins.inc.php";
+ break;
case "logout":
session_destroy();
Index: jBlog_admin_installer.inc.php
===================================================================
RCS file: /cvsroot/php-blog/jBlog/jBlog_admin_installer.inc.php,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- jBlog_admin_installer.inc.php 6 Mar 2003 01:25:59 -0000 1.8
+++ jBlog_admin_installer.inc.php 10 Mar 2003 02:13:37 -0000 1.9
@@ -178,6 +178,14 @@
$errs[] = " -> and <i>chmod g+rwx ".$_POST["jBlogPath"]."archives</i>";
}
+ // Attempt to create the plugins dir
+ if (!is_dir($_POST['jBlogPath'] . "plugins") &&
+ @mkdir($_POST['jBlogPath'] . "plugins", 0770) !== true) {
+ $errs[] = "Couldn't create the plugins directory, you do it.";
+ $errs[] = " -> Run <i>mkdir ".$_POST["jBlogPath"]."</i>";
+ $errs[] = " -> and <i>chmod g+rwx ".$_POST["jBlogPath"]."plugins</i>";
+ }
+
// Check imagick
if ($_POST["magick"] == "true" && !is_executable($_POST["convert"])) {
$errs[] = "Can't execute convert binary!";
@@ -256,7 +264,10 @@
if (!mysql_query($query)) {
echo mysql_error();
}
-
+
+ /* register default plugins */
+ include_once "jBlog_plugin_api.php";
+ jblog_plugin_api::register_default_plugins();
echo "<p>Welcome to jBlog!</b><p>";
echo "Write down your password: ".$_POST["pass"]." and <a href='".$_POST["jBlogHTTPPath"]."'>check out your blog</a>";
Index: jBlog_functions.inc.php
===================================================================
RCS file: /cvsroot/php-blog/jBlog/jBlog_functions.inc.php,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- jBlog_functions.inc.php 9 Mar 2003 11:45:55 -0000 1.38
+++ jBlog_functions.inc.php 10 Mar 2003 02:13:38 -0000 1.39
@@ -1215,6 +1215,43 @@
<?php
}
+/* Issues a query to the underlying database;
+ * returns:
+ * false if there was an error,
+ * true if the query succeeded but did not generate any rows
+ * array of field values if it returned a single row and $single is true
+ * array of array of field values if it returned row(s)
+ */
+function jBlog_db_query($sql, $single = false)
+{
+ global $jBlog;
+ $c = mysql_db_query($jBlog['dbName'], $sql);
+ if (!$c) {
+ print mysql_error();
+ return false;
+ }
+ if ($c === true) {
+ return true;
+ }
+ switch(mysql_num_rows($c)) {
+ case 0:
+ if ($single) {
+ return false;
+ }
+ return true;
+ case 1:
+ if ($single) {
+ return mysql_fetch_assoc($c);
+ }
+ default:
+ $rows = array();
+ while (($row = mysql_fetch_assoc($c))) {
+ $rows[] = $row;
+ }
+ return $rows;
+ }
+}
+
function jBlog_authenticate_author($username, $password) {
global $jBlog;
Index: jBlog_layout.php
===================================================================
RCS file: /cvsroot/php-blog/jBlog/jBlog_layout.php,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- jBlog_layout.php 7 Mar 2003 23:58:31 -0000 1.10
+++ jBlog_layout.php 10 Mar 2003 02:13:38 -0000 1.11
@@ -9,6 +9,8 @@
# #
##########################################################################
include_once("jBlog_config.inc.php");
+include_once("jBlog_plugin_api.php");
+include_once("jBlog_sidebar_items.php");
// This is a sample layout file for jBlog! You can adjust it to your needs
// or, if you have a more complex layout, use the functions as seen in this
@@ -39,9 +41,14 @@
}
?>
</table>
-<table class="jBlog" cellpadding="20">
+<table class="jBlog">
<tr>
- <td class="jBlogLeftBox" valign="top">
+
+<?php
+ jblog_plugin_api::generate_plugins('left');
+?>
+
+ <td class="jBlogEntriesBox" valign="top">
<?php
if (!is_numeric($jBlog["GET"]["range"]))
$jBlog["GET"]["range"] = date("Ymd");
@@ -72,85 +79,10 @@
}
?>
</td>
- <td class="jBlogRightBox" valign="top">
- <div class="jBlogSideBarItem">
- <div class="jBlogSideBarTitle">Quickjump:</div>
- <div class="jBlogQuickJump">
- <?php
- // Draw the calendar
- if (!$jBlog["GET"]["calendarZoom"]) {
- if (!$jBlog["GET"]["range"]) {
- $jBlog["GET"]["calendarZoom"] = date("Y").date("m");
- }
- else {
- $jBlog["GET"]["calendarZoom"] = $jBlog["GET"]["range"];
- }
- }
- jBlog_drawCalendar(substr($jBlog["GET"]["calendarZoom"], 4, 2),
- substr($jBlog["GET"]["calendarZoom"], 0,4));
- ?><br />
- </div>
- </div>
-
- <div class="jBlogSideBarTitle">Quicksearch:</div>
- <div class="jBlogSideBarContent">
- <form action="<?=$jBlog['jBlogHTTPPath'] ?>search.php" METHOD="GET">
- <input type="hidden" name="jBlog[action]" value="search">
- <INPUT TYPE="TEXT" name="jBlog[searchTerm]" ONFOCUS="value='';">
- </form>
- </div>
- </div>
-
- <div class="jBlogSideBarItem">
- <div class="jBlogSideBarTitle">Archives:</div>
- <div class="jBlogSideBarContent">
- <?php
- $ts = mktime(0,0,0,(date("m")+1), 1, date("Y"));
- for($x=0; $x<3; $x++) {
- $ts-=1;
- if ($jBlog["rewrite"] === true)
- $link = $jBlog["jBlogHTTPPath"]."archives/d_".date("Ym", $ts).".html";
- else
- $link = "fixme";
- echo "<a href='$link'>".$jBlog["months"][date("n", $ts)]." ".date("Y", $ts)."</a><br />";
- $ts = mktime(0,0,0,date("m", $ts), 1, date("Y", $ts));
- }
- ?>
- <a href='?jBlog[action]=archives'>Older...</a>
- </div>
- </div>
-
- <div class="jBlogSideBarItem">
- <div class="jBlogSideBarTitle">Top Referrers</div>
- <div class="jBlogSideBarContent">
- <?= jBlog_displayTopReferrers() ?>
- </div>
- </div>
-
- <div class="jBlogSideBarItem">
- <div class="jBlogSideBarTitle">Syndicate This Blog</div>
- <div class="jBlogSide">
- <a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php'><img src="<?= $jBlog['jBlogHTTPPath'] ?>xml.gif" border=0></a>
- <a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php'>RSS 0.91 feed</a>
- <br/>
- <a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php?version=2.0'><img src="<?= $jBlog['jBlogHTTPPath'] ?>xml.gif" border=0></a>
- <a href='<?= $jBlog['jBlogHTTPPath'] ?>rss.php?version=2.0'>RSS 2.0 feed</a>
- <br/>
- </div>
- </div>
-
- <div class="jBlogSideBarItem">
- <div class="jBlogSideBarTitle">Superuser:</div>
- <div class="jBlogSideBarContent">
- <a href="<?=$jBlog['jBlogHTTPPath']?>jBlog_admin.php">$ su -</a>
- <br />
- <br />
- </div>
- </div>
+<?php
+ /* Find any plugins for the RHS */
+ jblog_plugin_api::generate_plugins('right');
- <div class="jBlogPlug">
- This blog powered by <a href="http://sourceforge.net/projects/php-blog">jBlog</a>!
- </div>
- </td>
+?>
</tr>
</table>
|