<?php
/*
Hack Name: WordPress Theme Toolkit
Hack URI: http://planetozh.com/blog/my-projects/wordpress-theme-toolkit-admin-menu/
What is does: Helps theme authors set up an admin menu. Helps theme users customise the theme.
Version: 1.2
Author: Ozh
Author URI: http://planetOzh.com/
*/
/************************************************************************************
* DO NOT MODIFY THIS FILE !
************************************************************************************/
/* RELEASE HISTORY :
* 1.0 : initial release
* 1.1 : update for WordPress 2.0 compatibility
* 1.11 : added {separator} template
* 1.12 : more or less minor bug fixing (one when no plugin activated, other with rare mod_security issue) and better compliancy with WP 2.0 roles
* 1.2 : check for WordPress 2.3, a few improvements & typos, better error handling, improved security, added 'select', added localization
*/
if (!function_exists('themetoolkit')) {
function themetoolkit($theme='',$array='',$file='') {
global ${$theme};
if ($theme == '' or $array == '' or $file == '') {
die ($this->__('No theme name, theme option, or parent defined in Theme Toolkit'));
}
${$theme} = new ThemeToolkit($theme,$array,$file);
}
}
if (!class_exists('ThemeToolkit')) {
class ThemeToolkit{
var $option, $infos;
function ThemeToolkit($theme,$array,$file){
global $wp_version;
// is it WP 2.0+ and do we have plugins like "../themes/foo/functions.php" running ?
if ( $wp_version >= 2 and count(@preg_grep('#^\.\./themes/[^/]+/functions.php$#', get_settings('active_plugins'))) > 0 ) {
wp_cache_flush();
$this->upgrade_toolkit();
}
$this->infos['path'] = '../themes/' . basename(dirname($file));
load_plugin_textdomain('themetoolkit', 'wp-content/themes/'.basename(dirname($file)));
// I use load_plugin_textdomain() and not load_theme_domain() to be able to specify a filename, ie themetoolkit-{locale}.mo
/* Create some vars needed if an admin menu is to be printed */
if ($array['debug']) {
if ((basename($file)) == $_GET['page']) $this->infos['debug'] = 1;
unset($array['debug']);
}
if ((basename($file)) == $_GET['page']){
$this->infos['menu_options'] = $array;
$this->infos['classname'] = $theme;
}
$this->option=array();
/* Check this file is registered as a plugin, do it if needed */
$this->pluginification();
/* Get infos about the theme and particularly its 'shortname'
* which is used to name the entry in wp_options where data are stored */
$this->do_init();
/* Read data from options table */
$this->read_options();
/* Nonce wrapper for old WP versions */
if ( !function_exists('wp_nonce_field') ) {
$this->nonce = -1;
} else {
$this->nonce = 'theme-toolkit';
}
add_action('explain_nonce_theme-toolkit', array(&$this,'nonce_explain'));
/* Are we in the admin area ? Add a menu then ! */
$this->file = $file;
add_action('admin_menu', array(&$this, 'add_menu'));
}
/* Nonce confirmation */
function nonce_explain() {
return( sprintf($this->__('You are about to modify your preferences or settings for your theme "%s". Are you sure you want to do this ?'), $this->infos['theme_name']) );
}
/* Nonce wrapper function, for older WP compatibility */
function nonce_field($action = -1) {
if ( !function_exists('wp_nonce_field') ) {
return;
} else {
return wp_nonce_field($action);
}
}
/* Wrappers for translating functions */
function __($string) {
return __($string, 'themetoolkit');
}
/* Add an entry to the admin menu area */
function add_menu() {
global $wp_version;
if ( $wp_version >= 2 ) {
$level = 'edit_themes';
} else {
$level = 9;
}
add_theme_page(sprintf($this->__('Configure %s') , $this->infos['theme_name']), $this->__($this->infos['theme_name']), 'edit_themes', basename($this->file), array(&$this,'admin_menu'));
/* Thank you MCincubus for the array($this,'admin_menu') bit */
}
/* Get infos about this theme */
function do_init() {
$themes = get_themes();
$shouldbe= basename($this->infos['path']);
foreach ($themes as $theme) {
$current= basename($theme['Template Dir']);
if ($current == $shouldbe) {
if (get_settings('template') == $current) {
$this->infos['active'] = TRUE;
} else {
$this->infos['active'] = FALSE;
}
$this->infos['theme_name'] = $theme['Name'];
$this->infos['theme_shortname'] = $current;
$this->infos['theme_site'] = $theme['Title'];
$this->infos['theme_version'] = $theme['Version'];
$this->infos['theme_author'] = preg_replace("#>\s*([^<]*)</a>#", ">\\1</a>", $theme['Author']);
}
}
}
/* Read theme options as defined by user and populate the array $this->option */
function read_options() {
$options = get_option('theme-'.$this->infos['theme_shortname'].'-options');
$options['_________junk-entry________'] = 'ozh is my god';
foreach ($options as $key=>$val) {
$this->option["$key"] = stripslashes($val);
}
array_pop($this->option);
return $this->option;
/* Curious about this "junk-entry" ? :) A few explanations then.
* The problem is that get_option always return an array, even if
* no settings has been previously saved in table wp_options. This
* junk entry is here to populate the array with at least one value,
* removed afterwards, so that the foreach loop doesn't go moo. */
}
/* Prepare options for display */
function sanitize_options() {
foreach($this->option as $key=>$val) {
$this->option["$key"] = $this->sanitize($val);
}
}
/* Write theme options as defined by user in database */
function store_options($array) {
// Remove nonce informations before storing
if (isset($array['_wpnonce'])) unset($array['_wpnonce']);
if (isset($array['_wp_http_referer'])) unset($array['_wp_http_referer']);
update_option('theme-'.$this->infos['theme_shortname'].'-options','');
if (update_option('theme-'.$this->infos['theme_shortname'].'-options',$array)) {
return $this->__('Options successfully stored');
} else {
return $this->__('Could not save options !');
}
}
/* Delete options from database */
function delete_options() {
/* Remove entry from database */
delete_option('theme-'.$this->infos['theme_shortname'].'-options');
/* Unregister this file as a plugin (therefore remove the admin menu) */
$this->depluginification();
/* Revert theme back to default theme if this theme was activated */
if ($this->infos['active']) {
update_option('template', 'default');
update_option('stylesheet', 'default');
do_action('switch_theme', 'Default');
}
/* Go back to Theme admin */
print '<meta http-equiv="refresh" content="0;URL=themes.php?activated=true">';
echo "<script> self.location(\"themes.php?activated=true\");</script>";
exit;
}
/* Check if the theme has been loaded at least once (so that this file has been registered as a plugin) */
function is_installed() {
global $wpdb;
$where = 'theme-'.$this->infos['theme_shortname'].'-options';
$check = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->options WHERE option_name = '$where'");
if ($check == 0) {
return FALSE;
} else {
return TRUE;
}
}
/* Theme used for the first time (create blank entry in database) */
function do_firstinit() {
global $wpdb;
$options = array();
foreach(array_keys($this->option) as $key) {
$options["$key"]='';
}
add_option('theme-'.$this->infos['theme_shortname'].'-options',$options, 'Options for theme '.$this->infos['theme_name']);
$this->firstinit = true;
return sprintf($this->__('Theme options added in database (1 entry in table "%s"'), $wpdb->options);
}
/* The mother of them all : the Admin Menu printing func */
function admin_menu () {
global $cache_settings, $wpdb;
/* Process things when things are to be processed */
if (@$_POST['action']) {
check_admin_referer($this->nonce);
if (@$_POST['action'] == 'store_option') {
unset($_POST['action']);
$msg = $this->store_options($_POST);
} elseif (@$_POST['action'] == 'delete_options') {
$this->delete_options();
}
} elseif (!$this->is_installed()) {
$msg = $this->do_firstinit();
}
// ze debug print_r
// echo "<pre>";print_r($this);echo "</pre>";
if (@$msg) print "<div class='updated'><p><b>" . $msg . "</b></p></div>\n";
echo '<div class="wrap">';
if ($this->firstinit) {
echo '<h2>'.$this->__('Thank you !').'</h2>';
echo '<p>';
printf($this->__('Thank you for installing "%s", a theme for WordPress.'), $this->infos['theme_site'] );
printf($this->__('This theme was made by %s'), $this->infos['theme_author']);
echo "</p>\n";
if (!$this->infos['active']) { /* theme is not active */
echo '<p>('.$this->__('Please note that this theme is currently <strong>not activated</strong> on your site as the default theme.').'</p>';
}
}
$cache_settings = '';
$check = $this->read_options();
$this->sanitize_options();
echo '<h2>'.$this->__('Configure').' <em>'.$this->__($this->infos['theme_name']).'</em> </h2>';
echo '<p>'.$this->__('This theme allows you to configure some variables to suit your blog, which are :').'</p>
<form action="" name="ttkform" id="ttkform" method="post">';
echo '
<table cellspacing="2" cellpadding="5" border="0" width=100% class="editform">';
/* Print form, here comes the fun part :) */
$firstelement = '';
foreach ($this->infos['menu_options'] as $key=>$val) {
if (!$firstelement) $firstelement = $key;
$items='';
preg_match('/\s*([^{#]*)\s*({([^}]*)})*\s*([#]*\s*(.*))/', $val, $matches);
if ($matches[3]) {
$items = split("\|", $matches[3]);
}
echo "<tr valign='top'><th scope='row' width='33%'>\n";
if (@$items) {
$type = array_shift($items);
switch ($type) {
case 'text':
$s = array_shift($items);
$m = array_shift($items);
echo "<label for='$key'>".$this->__($matches[1])."</label></th>\n<td>";
echo "<input type='text' name='$key' id='$key' size='$s' maxlength='$m' value='" . $this->option[$key] . "' />";
break;
case 'separator':
echo '<h3>'.$this->__($matches[1])."</h3></th>\n<td> </td>";
break;
case 'select':
case 'dropdown':
echo $this->__($matches[1])."</th>\n<td>";
echo "<select id='${key}' name='${key}'>";
while ($items) {
$v=array_shift($items);
$t=array_shift($items);
$selected='';
if ($v == $this->option[$key]) $selected=' selected';
echo "<option value='$v' $selected>".$this->__($t)."</option>\n";
}
echo "</select>\n";
break;
case 'radio':
echo $this->__($matches[1])."</th>\n<td>";
while ($items) {
$v=array_shift($items);
$t=array_shift($items);
$checked='';
if ($v == $this->option[$key]) $checked='checked';
echo "<label for='${key}${v}'><input type='radio' id='${key}${v}' name='$key' value='$v' $checked />".$this->__($t).'</label>';
if (@$items) echo "<br />\n";
}
break;
case 'textarea':
$rows=array_shift($items);
$cols=array_shift($items);
echo "<label for='$key'>".$this->__($matches[1])."</label></th>\n<td>";
echo "<textarea name='$key' id='$key' rows='$rows' cols='$cols'>" . $this->option[$key] . "</textarea>";
break;
case 'checkbox':
echo $this->__($matches[1])."</th>\n<td>";
while ($items) {
$k=array_shift($items);
$v=array_shift($items);
$t=array_shift($items);
$checked='';
if ($v == $this->option[$k]) $checked='checked';
echo "<label for='${k}${v}'><input type='checkbox' id='${k}${v}' name='$k' value='$v' $checked />".$this->__( $t).'</label>';
if (@$items) echo "<br />\n";
}
break;
default:
echo '<span style="color:red">'.$this->__('Unrecognized token').'</span></th><td class="updated"> '.$matches[2];
break;
}
} else {
// default to plain input text field
echo "<label for='$key'>".$this->__($matches[1])."</label></th>\n<td>";
echo "<input type='text' name='$key' id='$key' value='" . $this->option[$key] . "' />";
}
if ($matches[5]) echo '<br/>'. $this->__($matches[5]);
echo "</td></tr>\n";
}
echo '</table>
<p class="submit"><input type="submit" value="'.$this->__('Store Options').' »" /></p>';
$this->nonce_field($this->nonce);
echo '
<input type="hidden" name="action" value="store_option">
</form>';
if ($this->infos['debug'] and $this->option) {
$g = '<span style="color:#006600">';
$b = '<span style="color:#0000CC">';
$o = '<span style="color:#FF9900">';
$r = '<span style="color:#CC0000">';
echo '<h2>'.$this->__("Programmer's corner").'</h2>';
echo '<p>'.sprintf($this->__('The array <em>$%s->option</em> is actually populated with the following keys and values'),$this->infos['classname']).' :</p>
<p><pre class="updated">';
$count = 0;
foreach ($this->option as $key=>$val) {
$val=str_replace('<','<',$val);
if ($val) {
print '<span class="ttkline">'.$g.'$'.$this->infos['classname'].'</span>'.$b.'-></span>'.$g.'option</span>'.$b.'[</span>'.$g.'\'</span>'.$r.$key.'</span>'.$g.'\'</span>'.$b.']</span>'.$g.' = "</span>'. $o.$val.'</span>'.$g."\"</span></span>\n";
$count++;
}
}
if (!$count) print "\n\n";
echo '</pre><p>'.$this->__('To disable this report (for example before packaging your theme and making it available for download), remove the line " <em>\'debug\' => \'debug\'</em> " in the array you edited at the beginning of this file.').'</p>';
}
echo '<h2>'.$this->__('Delete Theme options').'</h2>
<p>'.sprintf($this->__('To completely remove these theme options from your database (reminder: they are all stored in a single entry, in WordPress options table <em>%s</em>), click on the following button. You will be then redirected to the <a href="themes.php">Themes admin interface</a>'), $wpdb->options);
if ($this->infos['active']) {
echo ' '.$this->__('and the Default theme will have been activated');
}
echo '.</p>';
echo '<p>'.$this->__('<strong>Special notice for people allowing their readers to change theme</strong> (i.e. using a Theme Switcher on their blog)');
echo '<br/>';
echo $this->__('Unless you really remove the theme files from your server, this theme will still be available to users, and therefore will self-install again as soon as someone selects it.').' ';
echo $this->__('Also, all custom variables as defined in the above menu will be blank, this could lead to unexpected behaviour.').' ';
echo $this->__('Press "Delete" only if you intend to remove the theme files right after this.').'</p>
<form action="" method="post">';
$this->nonce_field($this->nonce);
echo '
<input type="hidden" name="action" value="delete_options">
<p class="submit"><input type="submit" value="'.$this->__('Delete Options').' »" onclick="return confirm(\''.$this->__('Are you really sure you want to delete ?').'\');"/></p>
</form>';
// Little javascript bit to set focus on first element, if applicable
echo "
<script type='text/javascript'>
if (document.getElementById('$firstelement')) {
document.getElementById('$firstelement').focus();
}
</script>";
echo '<h2>'.$this->__('Credits').'</h2>';
echo '<p>'.sprintf($this->__('%s has been created by %s'),$this->infos['theme_site'],$this->infos['theme_author']).'. ';
printf($this->__('This administration menu uses <a href="%s">WordPress Theme Toolkit</a> by %s.'),'http://planetozh.com/blog/my-projects/wordpress-theme-toolkit-admin-menu/','<a href="http://planetozh.com/" title="planetOzh">Ozh</a>');
echo '</p>
</div>';
}
/***************************************
* Self-Pluginification
*
* Prior to WP 2.0 this files registers
* itself as a plugin. Ow, that's smart.
**************************************/
function pluginification () {
global $wp_version;
if ($wp_version<2) {
$us = $this->infos['path'].'/functions.php';
$them = get_settings('active_plugins');
/* Now, are we members of the PPC (Plugins Private Club) yet ? */
if (!in_array($us,$them)) {
/* No ? Jeez, claim member card ! */
$them[]=$us;
update_option('active_plugins',$them);
/* Wow. We're l33t now. */
return TRUE;
} else {
return FALSE;
}
}
}
/***************************************
* De-Pluginification
**************************************/
function depluginification () {
global $wp_version;
if ($wp_version<2) {
$us = $this->infos['path'].'/functions.php';
$them = get_settings('active_plugins');
if (in_array($us,$them)) {
$here = array_search($us,$them);
unset($them[$here]);
update_option('active_plugins',$them);
return TRUE;
} else {
return FALSE;
}
}
}
/* attribute_escape() compatibility for older installs */
function sanitize($text) {
if (function_exists('attribute_escape')) {
return attribute_escape($text);
} else {
// All this taken from wp_specialchars()
$text = str_replace('&&', '&&', $text);
$text = str_replace('&&', '&&', $text);
$text = preg_replace('/&(?:$|([^#])(?![a-z1-4]{1,8};))/', '&$1', $text);
$text = str_replace('<', '<', $text);
$text = str_replace('>', '>', $text);
$text = str_replace('"', '"', $text);
$text = str_replace("'", ''', $text);
return $text;
}
}
/* Clean plugins lists in order to work with WordPress 2.0 */
function upgrade_toolkit () {
$plugins=get_settings('active_plugins');
$delete=@preg_grep('#^\.\./themes/[^/]+/functions.php$#', $plugins);
$result=array_diff($plugins,$delete);
$temp = array();
foreach($result as $item) $temp[]=$item;
$result = $temp;
update_option('active_plugins',$result);
wp_cache_flush;
}
}
}
/***** Pretend we're a plugin to abuse WordPress updater *****/
/*
Plugin Name: WordPress Theme Toolkit
Plugin URI: http://planetozh.com/blog/my-projects/wordpress-theme-toolkit-admin-menu/
Description: <strong>This is not a plugin</strong>, do not put in <code>/wp-content/plugins/</code>, do not activate!</span>
*/
?>
Return to listing of minimalissimplistic.zip