This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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 can declared (as protected) in implementations to perform main actions: * - install: (Protected) Additional actions to run when activating the theme (Settings are already created). * - update: (Protected) Actions to update the theme to a new version. (Updating version on DB is done after this). * Takes old theme version as a parameter. Settings are already updated from defaults. * - defaults: (Protected) Returns the default module settings. Used to install, update and fill. * - registerSidebars: The place where to register all theme sidebars by using register_sidebar() function. * - init: (Protected) Actions to run when plugins initialization is performed (on init hook). * - widgetsInit: (Protected) Actions to init theme widgets (In widgets_init). * - startUp: (Protected) Actions to run at system startup (before plugins are loaded). * - _adminMenus: (Hook, must be public) Set the menus in WordPress Dashboard. * * @author Jordi Canals * @package Alkivia * @subpackage Framework * @link http://alkivia.org * @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; /** * 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; /** * Module data. Readed from the main plugin file header and the readme file. * Filled in loadModuleData(). Called in constructor. * From the filename: * - 'ID' - Plugin internal short name. Taken from main plugin'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 plugins 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). * Fom the Component file header: * - 'Component' - The component internal ID or Short Name. * - 'Name' - Name or title of the component. * - 'Description' - Description of what the component does and/or notes from the author. * * @see akModuleAbstract::mod_data * @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 = '' ) { switch ( strtolower($type) ) { case 'plugin' : $this->mod_type = self::PLUGIN; break; case 'component' : $this->mod_type = self::COMPONENT; break; case 'theme' : $this->mod_type = self::THEME; break; default: $this->mod_type = 0; // Unknown. } if ( $this->isTheme() ) { $this->mod_file = STYLESHEETPATH . '/style.css'; $this->ID = ( empty($ID) ) ? strtolower(basename(TEMPLATEPATH)) : trim($ID) ; } else { $this->mod_file = trim($file); $this->ID = ( empty($ID) ) ? strtolower(basename($this->mod_file, '.php')) : trim($ID) ; } $this->loadModuleData(); if ( $this->isCompatible() ) { add_action('init', array($this, 'systemInit')); add_action('widgets_init', array($this, 'widgetsInit')); 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 */ abstract protected function moduleLoad(); /** * Prepares and returns default module options. * @return array Options array */ abstract protected function defaultOptions(); /** * Fires at 'widgets_init' action hook * @return void */ abstract public function widgetsInit (); /** * Fires at 'init' action hook. * @return void */ abstract public function wpInit (); /** * Fires at 'admin_menus' action hook- * @return void */ abstract 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 */ protected function isCompatible () { return true; } /** * Functions to execute at system Init. * * @hook action 'init' * @access private * @return void */ final function systemInit() { $this->loadTranslations(); $this->wpInit(); } /** * Load module translations. * Load translations for plugins, themes and components. * * @return void */ final private function loadTranslations() { 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; case self::CHILD_THEME : load_theme_textdomain('akchild', STYLESHEETPATH . '/lang'); case self::THEME : load_theme_textdomain('aktheme', TEMPLATEPATH . '/lang'); break; } } /** * Enqueues additional administration styles. * * @hook action 'admin_print_styles' * @uses apply_filters() Calls the 'ak__style_admin' filter on the style url. * @access private * @return void */ final function adminStyles() { $url = ''; 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 = dirname($this->mod_file) . '/admin.css'; } $url = apply_filters('ak_' . $this->ID . '_style_admin', $url); if ( ! empty($url) ) { wp_register_style($this->ID, $url, false, $this->mod_data['Version']); wp_enqueue_style($this->ID); } } /** * Enqueues additional styles for plugins and components. * * @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() { $url = ''; if ( $this->isTheme() || $this->getOption('disable-module-styles') ) { return; } if ( file_exists(dirname($this->mod_file) . '/style.css') ) { $url = dirname($this->mod_file) . '/style.css'; } $url = apply_filters('ak_' . $this->ID . '_style_url', $url); if ( ! empty($url) ) { wp_register_style($this->ID, $url, false, $this->mod_data['Version']); wp_enqueue_style($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 ); } /** * 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 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 akTheme::$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 $option Option name. * @param boolean $show_notice Show a notice if disabled. * @return boolean If administration is allowed or not. */ final public function allowAdmin( $option, $show_notice = true ) { if ( $this->cfg->isForced($this->ID, $option) ) { if ( $show_notice ) { echo '' . __('Option blocked by administrator.', 'aktheme') . ''; } return false; } else { return true; } } /** * 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 () { $this->cfg = ak_settings_object(); if ( $this->isPlugin() ) { $this->loadPluginData(); } elseif ( $this->isComponent() ) { $this->loadComponentData(); } else { $this->loadThemeData(); } $this->cfg->setDefaults($this->ID, $this->defaultOptions()); $ver = get_option($this->ID . '_version'); if ( false === $ver ) { $this->installing = true; } elseif ( version_compare($ver, $this->mod_data['Version'], 'ne') ) { $this->needs_update = true; } } /** * Loads plugins data. * @return void */ final private function loadPluginData() { if ( empty($this->mod_data) ) { if ( ! function_exists('get_plugin_data') ) { require_once ( ABSPATH . 'wp-admin/includes/plugin.php' ); } $plugin_data = get_plugin_data($this->mod_file); $readme_data = ak_plugin_readme_data($this->mod_file); $this->mod_data = array_merge($readme_data, $plugin_data); } } /** * Loads theme (and child) data. * @return void */ final private function loadThemeData() { if ( empty($this->mod_data) ) { $this->mod_data = get_theme_data(TEMPLATEPATH . '/style.css'); } if ( TEMPLATEPATH !== STYLESHEETPATH && empty($this->child_data) ) { $this->mod_type = self::CHILD_THEME; $this->child_data = get_theme_data(STYLESHEETPATH . '/style.css'); } } /** * Loads component data. * TODO: This method needs some revision as it does not work. * @return void */ final private function loadComponentData() { if ( empty($this->mod_data) ) { $this->mod_data = ak_component_data($this->mod_file, true); } $this->ID = $this->c_data['Component']; $this->option_name = $this->plugin->ID . '_' . $this->ID; $this->settings = get_option($this->option_name); if ( ! empty($this->defaults) && is_array($this->defaults) ) { if ( is_array($this->settings) ) { $this->settings = array_merge($this->defaults, $this->settings); } else { $this->settings = $this->defaults; } } if ( ! isset($this->settings['version']) ) { $this->installing = true; } elseif ( version_compare($this->settings['version'], $this->plugin->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() { switch ( $this->mod_type ) { case self::PLUGIN : case self::COMPONENT : $search = str_replace('\\', '/', WP_PLUGIN_DIR); $target = str_replace('\\', '/', dirname($this->mod_file)); $url = str_replace($search, WP_PLUGIN_URL, $target) . '/'; break; case self::THEME : $url = get_template_directory_uri(); break; case self::CHILD_THEME : $url = get_stylesheet_directory_uri(); break; default : $url = ''; break; } return $url; } }