This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/**
* Abtract class to be used as a theme template.
* Must be implemented before using this class.
* There are some special functions that have to be declared in implementations to perform main actions:
* - moduleLoad (Protected) Additional actions to be run at module load time.
* - defaultOptions (Protected) Returns the module default options.
* - widgetsInit (Public) Runs at 'widgets_init' action.
* - wpInit (Public) Runs at 'init' action.
* - adminMenus (Public) Runs at 'admin_menus' option, used to set admin menus and page options.
*
* @author Jordi Canals
* @package Alkivia
* @subpackage Framework
* @link http://wiki.alkivia.org/framework/classes/module
*
* @uses akSettings
*/
abstract class akModuleAbstract
{
/**
* Module ID. Is the module internal short name.
* Filled in constructor (as a constructor param). Used for translations textdomain.
*
* @var string
*/
public $ID;
/**
* Component parent ID.
* Used only for components.
*
* @var string
*/
public $PID = '';
/**
* Module version number.
*
* @since 0.8
*
* @var string
*/
public $version;
/**
* Module Type using a class constant: self::PLUGIN, self::COMPONENT, seelf::THEME, self::CHILD_THEME
* By default is set to 0 (unknown).
*
* @var int
*/
protected $mod_type = 0;
/**
* Full path to module main file.
* Main file is 'style.css' for themes and the php file with data header for plugins and components.
*
* @var string
*/
protected $mod_file;
/**
* URL to the module folder.
*
* @var string
*/
protected $mod_url;
/**
* Module data. Readed from the main plugin file header and the readme file.
* Filled in loadModuleData(). Called in constructor.
* From the filename:
* - 'ID' - Module internal short name. Taken from main module's file name.
* From themes style.css file header:
* - 'Name' - Name of the theme.
* - 'Title' - Long title for the theme. As WP 2.8 is the same as 'Name'.
* - 'URI' - Theme's page URI.
* - 'Description' - Description of theme's features.
* - 'Author' - Author name and link (to author home).
* - 'Version' - Theme Version number.
* - 'Template' - The parent theme (If this is a child theme).
* - 'Tags' - An array of theme tags features.
* From plugins file header:
* - 'Name' - Name of the plugin, must be unique.
* - 'Title' - Title of the plugin and the link to the plugin's web site.
* - 'Description' - Description of what the plugin does and/or notes from the author.
* - 'Author' - The author's name
* - 'AuthorURI' - The author's web site address.
* - 'Version' - The plugin's version number.
* - 'PluginURI' - Plugin's web site address.
* - 'TextDomain' - Plugin's text domain for localization.
* - 'DomainPath' - Plugin's relative directory path to .mo files.
* From readme.txt file :
* - 'Contributors' - An array with all contributors nicknames.
* - 'Tags' - An array with all plugin tags.
* - 'DonateURI' - The donations page address.
* - 'Requires' - Minimum required WordPress version.
* - 'Tested' - Higher WordPress version this plugin has been tested.
* - 'Stable' - Last stable tag when this was released.
*
* @var array
*/
protected $mod_data;
/**
* Same as $mod_data but for child themes and components.
*
* From the Component file:
* - 'File' - FileName of the component (relative to plugin's folder).
* From componets file header:
* - 'File' - The component filename, relative to the plugin folder.
* - 'Component' - The component short name or ID.
* - 'Name' - Descriptive name for the component.
* - 'Description' - A descriptive text about the component.
* - 'Author' - Component author name
* - 'URL' - Author homepage URL.
* - 'Link' - Author anchor to home page.
* - 'Core' - If this is a core compoment or not.
* - 'Version' - Component version number.
* From readme.txt file:
* - Same as seen on akModuleAbstract::mod_data.
* From child themes file header:
* - Same as seen on akModuleAbstract::mod_data for themes.
*
* @var array
*/
protected $child_data = array();
/**
* Theme saved data.
* - 'post' - Saves the current post.
* - 'more' - Saves the read more status.
*
* @var array
*/
protected $saved;
/**
* Holds a reference to the global 'settings' object.
* This object has been created on the framework loader.
*
* @var akSettings
*/
protected $cfg;
/**
* Flag to see if we are installing (activating for first time) or reactivating the module.
*
* @var boolean
*/
protected $installing = false;
/**
* Flag to see if module needs to be updated.
*
* @var boolean
*/
protected $needs_update = false;
/** Constant used to define module as plugin. */
const PLUGIN = 10;
/** Constant used to define module as component. */
const COMPONENT = 15;
/** Constant used to define module as theme. */
const THEME = 20;
/** Constant used to define module as child theme. */
const CHILD_THEME = 25;
/**
* Class constructor.
* Calls the implementated method 'startUp' if it exists. This is done at theme's loading time.
* Prepares admin menus by setting an action for the implemented method '_adminMenus' if it exists.
*
* @param string $type Module type. Must be one of 'plugin', 'component', 'theme'. (child themes are detected).
* @param string $ID Theme internal short name (known as theme ID).
* @param string $file Module file. Only for plugins and components. (For themes style.css is always used).
* @return akTheme
*/
public function __construct ( $type = '', $ID = '', $file = '' )
{
$this->cfg =& ak_settings_object();
switch ( strtolower($type) ) {
case 'plugin' :
$this->mod_type = self::PLUGIN;
$this->mod_file = trim($file);
break;
case 'component' :
$this->mod_type = self::COMPONENT;
$this->mod_file = trim($file);
break;
case 'theme' :
$this->mod_type = self::THEME;
$this->mod_file = STYLESHEETPATH . '/style.css';
break;
default:
$this->mod_type = 0; // Unknown.
}
$this->loadModuleData($ID);
if ( $this->isCompatible() ) {
add_action('init', array($this, 'systemInit'));
add_action('plugins_loaded', array($this, 'pluginsInit'));
add_action('widgets_init', array($this, 'widgetsInit'));
if ( ! apply_filters('ak_' . $this->ID . '_disable_admin', $this->getOption('disable-admin-page')) ) {
add_action('admin_menu', array($this, 'adminMenus'));
}
// Load styles
if ( is_admin() ) {
add_action('admin_print_styles', array($this, 'adminStyles'));
} else {
add_action('wp_print_styles', array($this, 'enqueueStyles'));
}
$this->moduleLoad();
}
}
/**
* Executes as soon as module class is loaded.
*
* @return void
*/
protected function moduleLoad() {}
/**
* Prepares and returns default module options.
*
* @return array Options array
*/
protected function defaultOptions()
{
return array();
}
/**
* Fires at 'widgets_init' action hook
*.
* @return void
*/
public function widgetsInit () {}
/**
* Fires at 'init' action hook.
*
* @return void
*/
protected function wpInit () {}
/**
* Fires at 'admin_menus' action hook.
*
* @return void
*/
public function adminMenus () {}
/**
* Dummy method provided to check additional WP compatibility on inplementations.
* This is mostly used on plugins to check for WordPress required version.
*
* @return boolean
*/
public function isCompatible ()
{
return true;
}
/**
* Loads module data.
* Loads different data for Plugin, Theme or Component.
*
* @return void
*/
abstract protected function loadData ();
/**
* Functions to execute at system Init.
*
* @hook action 'init'
* @access private
*
* @return void
*/
final function systemInit ()
{
switch ( $this->mod_type ) {
case self::CHILD_THEME :
load_theme_textdomain('akchild', STYLESHEETPATH . '/lang');
case self::THEME :
load_theme_textdomain('aktheme', TEMPLATEPATH . '/lang');
break;
}
$this->wpInit();
}
/**
* Functions to execute after loading plugins.
*
* @return void
*/
final function pluginsInit ()
{
switch ( $this->mod_type ) {
case self::PLUGIN :
load_plugin_textdomain($this->ID, false, basename(dirname($this->mod_file)) . '/lang');
break;
case self::COMPONENT :
// TODO: Manage components translations.
break;
}
}
/**
* Enqueues additional administration styles.
* Send the framework admin.css file and additionally any other admin.css file
* found on the module direcotry.
*
* @hook action 'admin_print_styles'
* @uses apply_filters() Calls the 'ak_framework_style_admin' filter on the framework style url.
* @uses apply_filters() Calls the 'ak__style_admin' filter on the style url.
* @access private
*
* @return void
*/
final function adminStyles()
{
// FRAMEWORK admin styles.
$url = apply_filters('ak_framework_style_admin', AK_STYLES_URL . '/admin.css');
if ( ! empty($url) ) {
wp_register_style('ak_framework_admin', $url, false, get_option('ak_framework_version'));
wp_enqueue_style('ak_framework_admin');
}
// MODULE admin styles.
if ( $this->isChildTheme() && file_exists(STYLESHEETPATH . '/admin.css') ) {
$url = get_stylesheet_directory_uri() . '/admin.css';
} elseif ( $this->isTheme() && file_exists(TEMPLATEPATH . '/admin.css') ) {
$url = get_template_directory_uri() . '/admin.css';
} elseif ( file_exists(dirname($this->mod_file) . '/admin.css') ) {
$url = $this->mod_url . '/admin.css';
} else {
$url = '';
}
$url = apply_filters('ak_' . $this->ID . '_style_admin', $url);
if ( ! empty($url) ) {
wp_register_style('ak_' . $this->ID . '_admin', $url, array('ak_framework_admin'), $this->version);
wp_enqueue_style('ak_' . $this->ID . '_admin');
}
}
/**
* Enqueues additional styles for plugins and components.
* For themes no styles are enqueued as them are already sent by WP.
*
* @hook action 'wp_print_styles'
* @uses apply_filters() Calls the 'ak__style_url' filter on the style url.
* @access private
*
* @return void
*/
final function enqueueStyles()
{
if ( $this->isTheme() || $this->getOption('disable-module-styles') ) {
return;
}
$url = $this->getOption('style-url', false);
if ( false === $url ) {
if ( file_exists(dirname($this->mod_file) . '/style.css') ) {
$url = $this->mod_url . '/style.css';
} else {
$url = '';
}
}
$url = apply_filters('ak_' . $this->ID . '_style_url', $url);
if ( ! empty($url) ) {
wp_register_style('ak_' . $this->ID, $url, false, $this->version);
wp_enqueue_style('ak_' . $this->ID);
}
}
/**
* Checks if current module is a Plugin.
* @return boolean
*/
final public function isPlugin()
{
return ( self::PLUGIN == $this->mod_type ) ? true : false;
}
/**
* Checks if current module is a Component.
* @return boolean
*/
final public function isComponent()
{
return ( self::COMPONENT == $this->mod_type ) ? true : false;
}
/**
* Checks if current module is a Theme (or child)
* @return boolean
*/
final public function isTheme()
{
return ( self::THEME == $this->mod_type || self::CHILD_THEME == $this->mod_type ) ? true : false;
}
/**
* Checks if current module is a child theme.
* @return boolean
*/
final public function isChildTheme()
{
return ( self::CHILD_THEME == $this->mod_type ) ? true : false;
}
/**
* Returns a module option.
* If no specific option is requested, returns all options.
* If requested a non existent settings, returns $default.
*
* @param $name Name for the option to return.
* @param $default Default value to use if the option does not exists.
* @return mixed The option's value or an array with all options.
*/
final public function getOption ( $name = '', $default = false )
{
return $this->cfg->getSetting($this->ID, $name, $default);
}
/**
* Updates a module option.
*
* @param string $name Option Name
* @param mixed $value Option value
* @return void
*/
final public function updateOption ( $name, $value )
{
$this->cfg->updateOption($this->ID, $name, $value );
}
/**
* Deletes a module option.
*
* @param string $name Option Name
* @return void
*/
final public function deleteOption( $name )
{
$this->cfg->deleteOption($this->ID, $name);
}
/**
* Merges new options into module settings.
* Replaces exsisting ones and adds new ones.
*
* @since 0.7
*
* @param array $options New options to merge into settings.
* @return void
*/
final protected function mergeOptions ( $options )
{
$current = $this->cfg->getSetting($this->ID);
$new_opt = array_merge($current, $options);
$this->cfg->replaceOptions($this->ID, $new_opt);
}
/**
* Replaces ALL module options by new ones.
*
* @param array $options Array with all options pairs (name=>value)
* @return void
*/
final public function setNewOptions ( $options )
{
$this->cfg->replaceOptions($this->ID, $options);
}
/**
* Returns current module default options.
*
* @since 0.7
*
* @return array Default module options.
*/
final protected function getDefaults ()
{
$this->cfg->getDefaults($this->ID);
}
/**
* Replaces current module defaults by new ones.
*
* @since 0.7
*
* @param array $options New default options-
* @return void
*/
final protected function setDefaults ( $options )
{
$this->cfg->setDefaults($this->ID, $options);
}
/**
* Merges new options into module defaults.
* Replaces exsisting ones and adds new ones.
*
* @since 0.7
*
* @param array $options New options to merge into defaults.
* @return void
*/
final protected function mergeDefaults ( $options )
{
$defaults = $this->cfg->getDefaults($this->ID);
$new_def = array_merge($defaults, $options);
$this->cfg->setDefaults($this->ID, $new_def);
}
/**
* Returns module data.
* This data is loaded from the main module file.
*
* @see akModuleAbstract::$mod_data
* @return mixed The parameter requested or an array wil all data.
*/
final public function getModData ( $name = '' )
{
if ( empty($name) ) {
return $this->mod_data;
} elseif ( isset( $this->mod_data[$name]) ) {
return $this->mod_data[$name];
} else {
return false;
}
}
/**
* Returns child module data.
* This data is loaded from the child module file.
*
* @see akModuleAbstract::$child_data
* @return mixed The parameter requested or an array wil all data.
*/
final public function getChildData ( $name = '' )
{
if ( empty($name) ) {
return $this->child_data;
} elseif ( isset( $this->child_data[$name]) ) {
return $this->child_data[$name];
} else {
return false;
}
}
/**
* Checks if an option can be maneged on settings page.
* Looks at the alkivia.ini file and if set there, the option will be disabled.
*
* @param string|array $options Options names.
* @param boolean $show_notice Show a notice if disabled.
* @return boolean If administration is allowed or not.
*/
final public function allowAdmin( $options, $show_notice = true )
{
foreach ( (array) $options as $option ) {
if ( ! $this->cfg->isForced($this->ID, $option) ) {
return true;
}
}
if ( $show_notice ) {
echo '' . __('Option blocked by administrator.', 'akfw') . '';
}
return false;
}
/**
* Loads module data and settings.
* Data is loaded from the module file headers. Settings from Database and alkivia.ini.
*
* @return void
*/
final private function loadModuleData ( $id )
{
$this->loadData();
switch ( $this->mod_type ) {
case self::PLUGIN :
$this->mod_url = WP_PLUGIN_URL . '/' . basename(dirname($this->mod_file));
$this->ID = ( empty($id) ) ? strtolower(basename($this->mod_file, '.php')) : trim($id) ;
break;
case self::THEME :
case self::CHILD_THEME :
$this->mod_url = get_stylesheet_directory_uri();
$this->ID = ( empty($id) ) ? strtolower(basename(TEMPLATEPATH)) : trim($id) ;
break;
case self::COMPONENT :
$this->mod_url = ak_get_object($this->PID)->getUrl() . 'components/' . basename(dirname($this->mod_file));
$this->ID = $this->PID . '_' . $this->child_data['Component'];
break;
}
$this->cfg->setDefaults($this->ID, $this->defaultOptions());
$old_version = get_option($this->ID . '_version');
if ( false === $old_version ) {
$this->installing = true;
} elseif ( version_compare($old_version, $this->version, 'ne') ) {
$this->needs_update = true;
}
}
/**
* Saves the current post state.
* Used if we are looping a new query to reset previous state.
*
* @return void
*/
final public function savePost()
{
global $post, $more;
$this->saved['post'] = $post;
$this->saved['more'] = $more;
}
/**
* Restores the current post state.
* Saved in savePost()
*
* @return void
*/
final public function restorePost()
{
global $post, $more;
$more = $this->saved['more'];
$post = $this->saved['post'];
if ( $post ) {
setup_postdata($post);
}
}
/**
* Returns the URL to the module folder.
*
* @return string Absolute URL to the module folder.
*/
final public function getURL()
{
return trailingslashit($this->mod_url);
}
/**
* Returns the absolute path to module direcotory.
*
* @since 0.7
*
* @return string Full absolute path to module directory.
*/
final public function getPath()
{
return trailingslashit(dirname($this->mod_file));
}
/**
* Returns the basename for the plugin folder.
*
* @since 0.7
*
* @return string Plugin folder name (Relative to wp-content/plugins or wp-content/themes.
*/
final public function getSlug()
{
$folder = basename(dirname($this->mod_file));
return $folder;
}
}