Skip to content

Instantly share code, notes, and snippets.

@amereservant
Created October 12, 2011 17:36
Show Gist options
  • Save amereservant/1281927 to your computer and use it in GitHub Desktop.
Save amereservant/1281927 to your computer and use it in GitHub Desktop.
WordPress Options Framework
<?php
/**
* TC Framework Base
*
* This is an abstract class that creates a standard base for all TC projects.
*
* All options are stored under two WordPress options, one for the standard options
* and another for the multisite options (if the theme/plugin has need for these).
*
* @author Amereservant <amereservant@gmail.com>
* @version 0.0.1
*/
abstract class tc_base
{
/**
* Theme/Plugin Options
*
* Since all plugin/theme options are stored as a single WordPress option, this
* property is used to store that array so they can be accessed.
*
* @var array
* @since 0.0.1
* @access protected
*/
protected $_options = array();
/**
* Theme/Plugin Multisite Options - (Multisite only)
*
* This is very similar to the {@link $options} property, but it stores network-wide
* options when WordPress is setup as a Multisite.
* See {@link http://codex.wordpress.org/Function_Reference/get_site_option} for a
* better understanding of this.
*
* @var array
* @since 0.0.1
* @access protected
*/
protected $_site_options = array();
/**
* Default Theme/Plugin Options
*
* These are the default options that are used if the option(s) haven't been set yet.
*
* @var array
* @since 0.0.1
* @access protected
*/
protected $_default_options = array();
/**
* Default Theme/Plugin Multisite Options
*
* These are the default multisite options that are used if the multisite option(s)
* haven't been set yet. Only applies to Multisite installs.
*
* @var array
* @since 0.0.1
* @access protected
*/
protected $_default_site_options = array();
/**
* Deleted Options
*
* Since all options are stored in an array and if they aren't set, the {@link $_default_options}
* value will be applied to them, this allows for specifying which values ARE deleted
* and shouldn't be replaced by default values.
*
* For values that don't have a default value, they will not be included in this.
*
* @var array
* @since 0.0.1
* @access private
*/
private $_deleted_options = array();
/**
* Deleted Site Options
*
* This is the same as the {@link $_deleted_options} property, but for multisite options.
*
* @var array
* @since 0.0.1
* @access private
*/
private $_deleted_site_options = array();
/**
* Unique Slug
*
* This is used in multiple ways to uniquely identify the plugin/theme extending this
* class, such as in hooks, filters, and menu slugs etc.
* This MUST be unique and not match any other plugin/theme's slug or else it will
* collide with them and result in undesired behavior.
*
* @var string
* @since 0.0.1
* @access public
*/
public $slug = '';
/**
* Error Messages
*
* @var array
* @since 0.0.1
* @access public
*/
public $errors = array();
/**
* Class Constructor
*
* Since this class is an abstract class, it cannot be istantiated directly, however
* child classes must use parent::__construct() to run this as it sets up this class
* for child class support.
*
* @param void
* @return void
* @access protected
*/
protected function __construct()
{
}
/**
* Get Option
*
* This is used to access the theme/plugin options, which retrieves them from the
* {@link $_options} property. This immitates the functionality of
* {@link http://codex.wordpress.org/Function_Reference/get_option}, but is only for
* the plugin/theme's options.
*
* If the value doesn't exist, then the value of the $default parameter will be returned.
*
* @uses apply_filters() Calls '$this->slug_pre_option_$option' before checking the option.
* Any value other than false will "short-cut" the retrieval of the option and
* return the returned filter value instead.
* @uses apply_filters() Calls '$this->slug_option_$option' on the retrieved/default value
* and passes the filter function(s) the $default value as well.
*
* @param string $option The option to retrieve the value of.
* @param mixed $default The default value to return if the $option being requested
* doesn't exist/hasn't been set. Default is (bool)false.
* @return mixed Either the option value if it's set or the value of $default.
* @since 0.0.1
* @access public
*/
public function get_option( $option, $default=false )
{
// If the option isn't set, we'll try setting them just to make sure they've been loaded
if( !is_array($this->_options) || !isset($this->_options[$option]) )
$this->_set_options();
// Allows filter hooks to short-cut option(s).
if( ($pre = apply_filters( $this->slug .'_pre_option_'. $option, false )) !== false )
return $pre;
return apply_filters( $this->slug .'_option_'. $option,
(isset($this->_options[$option]) ? $this->_options[$option] : $default), $default );
}
/**
* Get Multisite Option
*
* This is used to access the theme/plugin network/site-wide options, which retrieves
* them from the {@link $_site_options} property. This immitates the functionality of
* {@link http://codex.wordpress.org/Function_Reference/get_site_option}, but is only for
* the plugin/theme's options.
*
* If this is called on a non-multisite install, it will just return the value from
* calling the {@link get_option()} method.
*
* If the value doesn't exist, then the value of the $default parameter will be returned.
*
* @uses apply_filters() Calls '$this->slug_pre_site_option_$option' before checking the option.
* Any value other than false will "short-cut" the retrieval of the option and
* return the returned filter value instead.
* @uses apply_filters() Calls '$this->slug_site_option_$option' after retrieving the value
* and also passes the $default value to the filter function.
*
* @param string $option The site option to retrieve the value of.
* @param mixed $default The default value to return if the $option being requested
* doesn't exist/hasn't been set. Default is (bool)false.
* @return mixed Either the option value if it's set or the value of $default.
* @since 0.0.1
* @access public
*/
public function get_site_option( $option, $default=false )
{
// Allows filter hooks to short-cut site option(s).
if( ($pre = apply_filters( $this->slug .'_pre_site_option_'. $option, false )) !== false)
return $pre;
if( !is_multisite() )
return apply_filters( $this->slug .'_site_option_'. $option,
$this->get_option($option, $default), $default );
if( !is_array($this->_site_options) || (!isset($this->_site_options[$option]) &&
!in_array($option, $this->_deleted_site_options)) )
$this->_set_site_options();
return apply_filters( $this->slug .'_site_option_'. $option,
isset($this->_site_options[$option]) ? $this->_site_options[$option] : $default, $default );
}
/**
* Add Option
*
* This adds a new theme/plugin option, which will be added to the {@link $_options} property.
* Theme/Plugin options aren't stored as individual WordPress options, so therefore
* this function is used to keep them all grouped as one WP option.
*
* @uses do_action() Calls '$this->slug_add_option' before adding the option and
* passes the hooked functions the option name being added and the value.
* @uses apply_fiters() Calls '$this->slug_add_option' before adding the option and
* passes the function(s) the option value and option name.
* @uses do_action() Calls '$this->slug_add_option_$option' after the option has
* been successfully added. The function(s) are passed the set value.
* If adding the option fails, this isn't called.
* @uses do_action() Calls '$this->slug_added_option' after the option has been
* successfully added. The function(s) are passed the option name and the
* set value. If adding the option fails, this isn't called.
*
* @param string $option The option name we're adding.
* @param mixed $value The value for the option we're adding
* @return bool true if added successfully, false otherwise
* @since 0.0.1
* @access public
*/
public function add_option( $option, $value )
{
if( strlen( ($option = trim($option))) < 1 )
return false;
// If the option already exists, user should use the update_option class method instead.
if( $this->get_option($option) !== false )
return;
do_action( $this->slug .'_add_option', $option, $value );
// Remove it from the deleted_options array if it is in it
if( ($key = array_search($option, $this->_deleted_options)) !== false )
unset($this->_deleted_options[$key]);
$this->_options[$option] = apply_filters( $this->slug .'_add_option', $value, $option );
if( $this->_update_wp_options(true) )
{
do_action( $this->slug .'_add_optiion_'. $option, $value );
do_action( $this->slug .'_added_option', $option, $value );
return true;
}
return false;
}
/**
* Add Site Option
*
* This adds a new theme/plugin multisite option, which will be added to the
* {@link $_site_options} property. Theme/Plugin options aren't stored as individual
* WordPress options, so therefore this function is used to keep them all grouped
* as one WP option.
*
* @uses do_action() Calls '$this->slug_add_site_option' before adding the site option and
* passes the hooked functions the site option name being added and the value.
* @uses apply_fiters() Calls '$this->slug_add_site_option' before adding the option and
* passes the function(s) the option value and option name.
* @uses do_action() Calls '$this->slug_add_site_option_$option' after the site option has
* been successfully added. The function(s) are passed the set value.
* If adding the site option fails, this isn't called.
* @uses do_action() Calls '$this->slug_added_site_option' after the site option has been
* successfully added. The function(s) are passed the option name and the
* set value. If adding the site option fails, this isn't called.
*
* @param string $option The site option name we're adding.
* @param mixed $value The value for the site option we're adding
* @return bool true if added successfully, false otherwise
* @since 0.0.1
* @access public
*/
public function add_site_option( $option, $value )
{
if( strlen(($option = trim($option))) < 1 )
return false;
// If the option already exists, user should use the update_option class method instead.
if( $this->get_site_option($option) !== false )
return;
if( !is_multisite() )
return $this->add_option( $option, $value );
do_action($this->slug .'_add_site_option', $option, $value);
// Remove it from the deleted_site_options array if it is in it
if( ($key = array_search($option, $this->_deleted_site_options)) !== false )
unset($this->_deleted_site_options[$key]);
$this->_site_options[$option] = apply_filters( $this->slug .'_add_site_option', $value, $option );
if( $this->_update_wp_options(false, true) )
{
do_action( $this->slug .'_add_site_optiion_'. $option, $option, $value );
do_action( $this->slug .'_added_site_option', $option, $value );
return true;
}
return false;
}
/**
* Set Option Defaults
*
* The child class should define this method and it should set the default option
* values to the {@link $_default_options} property and if this plugin/theme supports
* multisite configurations, it should also set the {@link $_default_site_options}
* property as well.
*
* It can be hooked to an activation hook if desired, otherwise it will be called
* when any of these methods are called if the option(s) aren't set in the database yet:
* {@link get_option()}, {@link set_option()}, {@link update_option()} and if running
* on a multisite install, {@link get_site_option()}, {@link set_site_option()}, or
* {@link update_site_option()}.
*
* @abstract
*/
abstract protected function _set_default_options();
/**
* Set Options
*
* This method is used to set the plugin/theme options ({@link $_options} property)
* if they aren't already set or if the values have been updated and need refreshing.
*
* @param bool $refresh If set to true, it will retrieve the values from the
* database and set the {@link $_options} property with
* the retrieved values.
* @return void
* @since 0.0.1
* @access protected
*/
protected function _set_options( $refresh=false )
{
// First validate the class settings
if( !$this->_validate_settings() ) {
wp_die( implode("\n", $this->errors) );
}
do_action( $this->slug .'_pre_set_options', &$refresh );
// Return if there's nothing to do...
if( is_array($this->_options) && !$refresh ) return;
// See if the options already exist as a WordPress option
if( ($opts = get_option($this->slug .'_options')) === false )
{
// If not, call the _set_default_options() method to add them
$this->_set_default_options();
$defaults = $this->_default_options;
// Add deleted options value to the stored options data
if(!isset($defaults['_deleted_options']))
$defaults['_deleted_options'] = array();
// Add the option since it doesn't exist yet
add_option( $this->slug .'_options',
apply_filters($this->slug .'_add_default_options', $defaults) );
$opts = get_option($this->slug .'_options');
}
// Set deleted options
$this->_deleted_options = $opts['_deleted_options'];
// Allows options to be overidden or added via filters
// NOTE: If the _update_wp_option() function is called after this filter is applied,
// the filtered value will not be temporary and will become the new set value
// for the option. This could be problematic....
$this->_options = apply_filters($this->slug .'_set_options', $opts['options']);
}
/**
* Set Multisite/Network Options
*
* This method is used to set the plugin/theme network/site-wide options ({@link $_site_options} property)
* if they aren't already set or if the values have been updated and need refreshing.
*
* @uses do_action() Calls '$this->slug_pre_set_multisite_options' and passes the
* $refresh parameter by reference before the options are setup for multisite options.
* @uses apply_filters() Calls '$this->slug_add_default_multisite_options' and passes
* the {@link $_default_multisite_options} property values to the filter function
* just before adding the new site option for the first time. This only runs once!
* @uses apply_filters() Calls '$this->slug_set_multisite_options' and passes the retrieved
* site options before setting the {@link $_site_options} property.
*
* @param bool $refresh If set to true, it will retrieve the values from the
* database and set the {@link $_site_options} property with
* the retrieved values.
* @return void
* @since 0.0.1
* @access protected
*/
protected function _set_multisite_options( $refresh=false )
{
// First validate the class settings
if( !$this->_validate_settings() ) {
wp_die( implode("\n", $this->errors) );
}
if( !is_multisite() ) return;
do_action( $this->slug .'_pre_set_multisite_options', &$refresh );
// Return if there's nothing to do...
if( is_array($this->_site_options) && !$refresh ) return;
// See if the site options already exist as a WordPress option
if( ($opts = get_site_option($this->slug .'_multisite_options')) === false )
{
// If not, call the _set_default_options() method to add them
$this->_set_default_options();
$defaults = $this->_default_site_options;
// Add deleted site options value to the stored site options data
if(!isset($defaults['_deleted_options']))
$defaults['_deleted_options'] = array();
// Add the site option since it doesn't exist yet
add_site_option( $this->slug .'_multisite_options',
apply_filters($this->slug .'_add_default_multisite_options', $defaults)
);
$opts = get_site_option($this->slug .'_multisite_options');
}
// Set deleted site options
$this->_deleted_site_options = $opts['_deleted_options'];
// Allows options to be overidden or added via filters
$this->_site_options = apply_filters($this->slug .'_set_multisite_options', $opts['options']);
}
/**
* Update Option
*
* Updates the theme/plugin option and mimicks the behavior of WordPress's
* {@link http://codex.wordpress.org/Function_Reference/update_option} function.
*
* @uses apply_filters() Calls '{$this->slug}_sanitize_option_{$option}' and passes
* the function(s) the new value so it can be sanitized before being updated.
* @uses apply_filters() Calls '{$this->slug}_pre_update_option_{$option}' and passes
* the function(s) the new value and the old value before updating the option.
* @uses do_action() Calls '{$this->slug}_update_option' and passes the
* function(s) the option name, the new value, and the old value before
* updating the option. If the option doesn't already exist, this won't be called.
* @uses do_action() Calls '{$this->slug}_update_option_{$option}' and passes the function(s)
* the old value and the new value if the option was successfully updated.
* @uses do_action() Calls '{$this->slug}_updated_option' and passes the function(s)
* the option name, the old value, and the new value if the option was
* successfully updated.
*
* @param string $option The option name to update.
* @param mixed $value The updated value to assign to the option.
* @return bool true if it was updated, false if updated failed.
* @since 0.0.1
* @access public
*/
public function update_option( $option, $value )
{
if( strlen( ($option = trim($option))) < 1 )
return false;
// Allow sanitization filters to be added on a per-option basis
$value = apply_filters($this->slug .'_sanitize_option_'. $option, $value);
$oldvalue = $this->get_option($option);
$value = apply_filters($this->slug .'_pre_update_option_'. $option, $value, $oldvalue);
// No need to update the option if the values match
if( $value === $oldvalue )
return false;
// If the option doesn't already exist, we'll add it now ...
if( $oldvalue === false && !isset($this->_options[$option]) )
return $this->add_option($option, $value);
do_action($this->slug .'_update_option', $option, $value, $oldvalue);
$this->_options[$option] = $value;
if( $this->_update_wp_options(true) )
{
do_action($this->slug .'_update_option_'. $option, $oldvalue, $newvalue);
do_action($this->slug .'_updated_option', $option, $oldvalue, $newvalue);
return true;
}
return false;
}
/**
* Update Site Option
*
* Updates the theme/plugin's multisite option and mimicks the behavior of WordPress's
* {@link http://codex.wordpress.org/Function_Reference/update_site_option} function.
*
* @uses apply_filters() Calls '{$this->slug}_sanitize_site_option_{$option}' and passes
* the function(s) the new value so it can be sanitized before being updated.
* @uses apply_filters() Calls '{$this->slug}_pre_update_site_option_{$option}' and passes
* the function(s) the new value and the old value before updating the option.
* @uses do_action() Calls '{$this->slug}_update_site_option' and passes the
* function(s) the option name, the new value, and the old value before
* updating the option. If the option doesn't already exist, this won't be called.
* @uses do_action() Calls '{$this->slug}_update_site_option_{$option}' and passes the function(s)
* the old value and the new value if the option was successfully updated.
* @uses do_action() Calls '{$this->slug}_site_updated_option' and passes the function(s)
* the option name, the old value, and the new value if the option was
* successfully updated.
*
* @param string $option The site option name to update.
* @param mixed $value The updated value to assign to the option.
* @return bool true if it was updated, false if updated failed.
* @since 0.0.1
* @access public
*/
public function update_site_option( $option, $value )
{
if( strlen( ($option = trim($option))) < 1 )
return false;
// Allow sanitization filters to be added on a per-option basis
$value = apply_filters($this->slug .'_sanitize_site_option_'. $option, $value);
$oldvalue = $this->get_site_option($option);
$value = apply_filters($this->slug .'_pre_update_site_option_'. $option, $value, $oldvalue);
// No need to update the option if the values match
if( $value === $oldvalue )
return false;
if( !is_multisite() )
{
$result = $this->update_option( $option, $value );
}
else
{
// If the option doesn't already exist, we'll add it now ...
if( $oldvalue === false && !isset($this->_site_options[$option]) )
return $this->add_site_option($option, $value);
$this->_site_options[$option] = $value;
$result = $this->_update_wp_options(false, true);
}
do_action($this->slug .'_update_site_option', $option, $value, $oldvalue);
if( $result )
{
do_action($this->slug .'_update_site_option_'. $option, $oldvalue, $newvalue);
do_action($this->slug .'_updated_site_option', $option, $oldvalue, $newvalue);
return true;
}
return false;
}
/**
* Delete Option
*
* This is used to "delete" options, although this differs a bit from WordPress's
* delete_option() function since any unset options that have default values specified
* in the {@link $_default_options} will be set again.
* Therefore any options with defaults are added to the {@link $_deleted_options} array
* to prevent this after being deleted.
*
* @uses do_action() Calls '{$this->slug}_delete_option_{$option}' and passes the
* function(s) the value of the {@link $_options} property. This is called
* BEFORE the value is removed from the {@link $_options} property.
* @uses do_action() Calls '{$this->slug}_delete_option' and passes the function(s)
* the name of the option being deleted and the value of the {@link $_options} property.
* This is called AFTER the option has been removed from the {@link $_options} property.
* @uses do_action() Calls '{$this->slug}_deleted_option' and passes the function(s)
* the deleted option name if the option was successfully deleted.
*
* @param string $option The option to delete
* @return bool true if it was deleted, false if not or if it doesn't exist
* @since 0.0.1
* @access public
*/
public function delete_option( $option )
{
if( !isset($this->_options[$option]) )
return false;
if( is_array($this->_default_options) && isset($this->_default_options[$option]) )
$this->_deleted_options[] = $option;
do_action( $this->slug .'_delete_option_'. $option, $this->_options );
unset($this->_options[$option]);
do_action( $this->slug .'_delete_option', $option, $this->_options );
$result = $this->_update_wp_options(true);
if( $result )
{
do_action( $this->slug .'_deleted_option', $option );
return true;
}
return false;
}
/**
* Delete Site Option
*
* This is used to "delete" options, although this differs a bit from WordPress's
* delete_site_option() function since any unset options that have default values specified
* in the {@link $_default_site_options} will be set again.
* Therefore any site options with defaults are added to the {@link $_deleted_site_options} array
* to prevent this after being deleted.
*
* @uses do_action() Calls '{$this->slug}_delete_site_option_{$option}' and passes the
* function(s) the value of the {@link $_options} property. This is called
* BEFORE the value is removed from the {@link $_options} property.
* @uses do_action() Calls '{$this->slug}_delete_site_option' and passes the function(s)
* the name of the option being deleted and the value of the {@link $_options} property.
* This is called AFTER the option has been removed from the {@link $_options} property.
* @uses do_action() Calls '{$this->slug}_deleted_site_option' and passes the function(s)
* the deleted option name if the option was successfully deleted.
*
* @param string $option The option to delete
* @return bool true if it was deleted, false if not or if it doesn't exist
* @since 0.0.1
* @access public
*/
public function delete_site_option( $option )
{
if( !isset($this->_site_options[$option]) )
return false;
if( !is_multisite() )
return $this->delete_option($option);
if( is_array($this->_default_site_options) && isset($this->_default_site_options[$option]) )
$this->_deleted_site_options[] = $option;
do_action( $this->slug .'_delete_site_option_'. $option, &$this->_site_options );
unset($this->_site_options[$option]);
do_action( $this->slug .'_delete_site_option', $option, &$this->_site_options );
$result = $this->_update_wp_options(false, true);
if( $result )
{
do_action( $this->slug .'_deleted_site_option', $option );
return true;
}
return false;
}
/**
* Update ALL Plugin/Theme Options
*
* This stores the current values for {@link $_options}, {@link $_site_options},
* {@link $_deleted_options}, and {@link $_deleted_site_options} properties to the
* single WordPress option for options and another single option for site options for
* the Theme/Plugin.
*
* Since this class stores/retrieves all option values from only two WordPress options,
* all of the options must be updated together and this does just that.
*
* @param bool $local If the local/normal options need to be updated.
* @param bool $site If the site/multisite options need to be updated.
* @return bool true on success, false if update failed
* @since 0.0.1
* @access protected
*/
protected function _update_wp_option( $local=true, $site=false )
{
if( ($local && !is_array($this->_options)) || ($site && !is_array($this->_site_options)) )
{
wp_die('The options couldn\'t be updated because the `$_options` and/or `$_site_options` '.
'properties aren\'t arrays!');
}
// Update local options
if( $local )
{
$options = array('options' => $this->_options, '_deleted_options' => $this->_deleted_options);
$result = update_option( $this->slug .'_options', $options );
if( !is_multisite() )
return $result;
}
// Update multisite options
if( $site )
{
$site_options = array('options' => $this->_site_options, '_deleted_options' => $this->_deleted_site_options);
return update_option( $this->slug .'_multisite_options', $site_options );
}
// If we're here, something went wrong!
trigger_error('Nothing to do! Check how `_update_wp_option()` is being called.');
return false;
}
/**
* Validate Class Settings
*
* This is used to verify various required portions of this class have been correctly
* defined/setup.
*
* @param void
* @return bool true if they are valid, false if not
* @since 0.0.1
* @access private
*/
private function _validate_settings()
{
try
{
if( strlen($this->slug) < 1 )
throw new Exception('A valid slug must be defined for the $slug property!');
}
catch(Exception $e) {
$this->errors[] = $e->getMessage();
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment