PageRenderTime 64ms CodeModel.GetById 14ms app.highlight 27ms RepoModel.GetById 15ms app.codeStats 0ms

/lib/class.plugin.php

https://github.com/jeffrydegrande/sideposts
PHP | 542 lines | 226 code | 57 blank | 259 comment | 40 complexity | 01e469c6b4b53fe4485d64480d4a0929 MD5 | raw file
  1<?php
  2/**
  3 * Plugins related functions and classes.
  4 *
  5 * @version		$Rev: 139 $
  6 * @author		Jordi Canals
  7 * @package		AOC
  8 * @subpackage	Library
  9 * @link 		http://alkivia.org
 10 * @license 	http://www.gnu.org/licenses/gpl.html GNU General Public License v3
 11
 12	Copyright 2009 Jordi Canals <alkivia@jcanals.net>
 13
 14    This program is free software: you can redistribute it and/or modify
 15    it under the terms of the GNU General Public License as published by
 16    the Free Software Foundation, either version 3 of the License, or
 17    (at your option) any later version.
 18
 19    This program is distributed in the hope that it will be useful,
 20    but WITHOUT ANY WARRANTY; without even the implied warranty of
 21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22    GNU General Public License for more details.
 23
 24    You should have received a copy of the GNU General Public License
 25    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 26*/
 27
 28require_once ( SPOSTS_LIB . '/plugins.php' );
 29
 30/**
 31 * Abtract class to be used as a plugin template.
 32 * Must be implemented before using this class and it's recommended to prefix the class to prevent collissions.
 33 * There are some special functions thay can declared (as protected) in implementations to perform main actions:
 34 * 		- activate: (Protected) Actions to run when activating the plugin.
 35 * 		- _deactivate: (Hook, must be public) Actions to run when deactivating the plugin.
 36 * 		- update: (Protected) Actions to update the plugin to a new version. (Updating version on DB is done after this).
 37 * 						Takes plugin running version as a parameter.
 38 * 		- setDefaults: (Protected) Fills the $defaults class var with the default settings.
 39 * 		- init: (Protected) Actions to run when plugins initialization is performed (In plugins loaded).
 40 * 		- widgetsInit: (Protected) Actions to init plugin widgets (In widgets_init).
 41 * 		- startUp: (Protected) Actions to run at system startup (before plugins are loaded).
 42 * 		- _adminMenus: (Hook, must be public) Set the menus in WordPress Dashboard.
 43 *
 44 * @uses		plugins.php
 45 * @author		Jordi Canals
 46 * @package		AOC
 47 * @subpackage	Library
 48 * @link		http://alkivia.org
 49 */
 50abstract class spostsPlugin
 51{
 52	/**
 53	 * Plugin ID. Is the plugin short name.
 54	 * Filled in constructor (as a constructor param).
 55	 * @var string
 56	 */
 57	protected $ID;
 58
 59	/**
 60	 * Plugin main file.
 61	 * Filled in constructor (as a constructor param).
 62	 * Cointains the full path to the main plugin's file. The one cointaining plugin's data header.
 63	 * @var string
 64	 */
 65	protected $p_file;
 66
 67	/**
 68	 * Plugin data. Readed from the main plugin file header and the readme file.
 69	 * Filled in loadPluginData(). Called in constructor.
 70	 * From the filename:
 71	 * 		- 'ID' - Plugin internal short name. Taken from main plugin's file name.
 72	 * Fom the file header:
 73	 *		- 'Name' - Name of the plugin, must be unique.
 74	 *		- 'Title' - Title of the plugin and the link to the plugin's web site.
 75	 *		- 'Description' - Description of what the plugin does and/or notes from the author.
 76	 *		- 'Author' - The author's name
 77	 *		- 'AuthorURI' - The author's web site address.
 78	 *		- 'Version' - The plugin's version number.
 79	 *		- 'PluginURI' - Plugin's web site address.
 80	 *		- 'TextDomain' - Plugin's text domain for localization.
 81	 *		- 'DomainPath' - Plugin's relative directory path to .mo files.
 82	 * From readme.txt file :
 83	 * 		- 'Contributors' - An array with all contributors nicknames.
 84	 * 		- 'Tags' - An array with all plugin tags.
 85	 * 		- 'DonateURI' - The donations page address.
 86	 *      - 'Requires' - Minimum required WordPress version.
 87	 *      - 'Tested' - Higher WordPress version this plugin has been tested.
 88	 *      - 'Stable' - Last stable tag when this was released.
 89	 * @var array
 90	 */
 91	protected $p_data;
 92
 93	/**
 94	 * Plugin paths: folder name, absolute path to plugin's folder and folder url.
 95	 * Filled in loadPaths(). Called in constructor.
 96	 *		- 'subdir' - The base plugin subdirectory.
 97	 *		- 'path' - The full path to plugin's folder.
 98	 *		- 'url' - The full URL to plugin's folder.
 99	 * @var array
100	 */
101	protected $p_dirs;
102
103	/**
104	 * Plugin saved data.
105	 *		- 'post' - Saves the current post.
106	 *		- 'more' - Saves the read more status.
107	 * @var array
108	 */
109	protected $saved;
110
111	/**
112	 * Plugin settings (from DB)
113	 * @var array
114	 */
115	protected $settings;
116
117	/**
118	 * Plugin default settings.
119	 * This settings can difer from install defaults and are used to fill settings loaded from DB
120	 * @var array
121	 */
122	protected $defaults = array();
123
124	/**
125	 * Flag to see if we are installing (activating for first time) or reactivating the plugin.
126	 * @var boolean
127	 */
128	protected $installing = false;
129
130	/**
131	 * Flag to see if plugin needs to be updated.
132	 * @var boolean
133	 */
134	protected $needs_update = false;
135
136	/**
137	 * Class constructor.
138	 * Calls the implementated method 'startUp' if it exists. This is done at plugins loading time.
139	 * Prepares admin menus by seting an action for the implemented method '_adminMenus' if it exists.
140	 *
141	 * @param string $plugin_file	Full main plugin's filename (absolute to root).
142	 * @param string $ID  Plugin short name (known as plugin ID).
143	 * @return spostsPlugin|false	The plugin object or false if not compatible.
144	 */
145	final function __construct( $plugin_file, $ID = '' ) {
146
147		$this->p_file = trim($plugin_file);
148		$this->ID = ( empty($ID) ) ? strtolower(basename($this->p_file, '.php')) : trim($ID) ;
149
150		// Load component data and settings.
151		if ( method_exists($this, 'setDefaults') ) {
152			$this->setDefaults();
153		}
154		$this->loadPluginData();
155		$this->loadPaths();
156
157		if ( $this->isCompatible() ) {
158			// Activation and deactivation hooks.
159			register_activation_hook($this->p_file, array($this, '_activatePlugin'));
160			if ( method_exists($this, '_deactivate') ) {
161				register_deactivation_hook($this->p_file, array($this, '_deactivate'));
162			}
163
164			// Load style files.
165			if ( is_admin() ) {
166				add_action('admin_print_styles', array($this, '_enqueueStyles'));	// For Compatibility with WP 2.8
167			} else {
168				add_action('wp_print_styles', array($this, '_enqueueStyles'));
169			}
170
171			// Init plugins at plugins and widgets
172			add_action('plugins_loaded', array($this, '_initPlugin'));
173			add_action('widgets_init', array($this, '_initWidgets'));
174
175			// Add administration menus.
176			if ( method_exists($this, '_adminMenus') ) {
177				add_action('admin_menu', array($this, '_adminMenus'));		// Add Panel menus.
178			}
179
180			// Startup the plugin.
181			if ( method_exists($this, 'startUp') ) {
182				$this->startUp();
183			}
184		}
185	}
186
187	/**
188	 * Activates the plugin. Only runs on first activation.
189	 * Saves the plugin version in DB, and calls the 'activate' method.
190	 *
191	 * @hook register_activation_hook
192	 * @access private
193	 * @return void
194	 */
195	final function _activatePlugin() {
196
197		if ( method_exists($this, 'setDefaults') ) {
198			$this->setDefaults();
199		}
200
201		// If there is an additional function to perform on activate.
202		if ( method_exists($this, 'activate') ) {
203			$this->activate();
204		}
205
206		$this->settings = $this->defaults;
207		add_option($this->ID . '_settings', $this->settings);
208		add_option($this->ID . '_version', $this->p_data['Version']);
209	}
210
211	/**
212	 * Init the plugin (In action 'plugins_loaded')
213	 * Here whe call the 'update' and 'init' functions. This is done after the plugins are loaded.
214	 * Also the plugin version and settings are updated here.
215	 *
216	 * @hook action plugins_loaded
217	 * @access private
218	 * @return void
219	 */
220	final function _initPlugin() {
221		$this->loadTranslations();
222
223		// First, check if the plugin needs to be updated.
224		if ( $this->needs_update ) {
225			if ( method_exists($this, 'update') ) {
226				$version = get_option($this->ID . '_version');
227				$this->update($version);
228			}
229			update_option($this->ID . '_version', $this->p_data['Version']);
230			update_option($this->ID . '_settings', $this->settings);
231		}
232
233		// Call the custom init for the plugin.
234		if ( method_exists($this, 'init') ) {
235			$this->init();
236		}
237	}
238
239	/**
240	 * Inits the widgets (In action 'widgets_init')
241	 * Before loading the widgets, we check that standard sidebar is present.
242	 *
243	 * @hook action 'widgets_init'
244	 * @return void
245	 */
246	final function _initWidgets() {
247		if ( method_exists($this, 'widgetsInit') && $this->isStandardSidebar() ) {
248			$this->widgetsInit();
249		}
250	}
251
252	/**
253	 * Loads translations file, located on the plugin's lang subdir.
254	 *
255	 * @return void
256	 */
257	final protected function loadTranslations() {
258		load_plugin_textdomain($this->ID, false, $this->p_dirs['subdir'] . '/lang');
259	}
260
261	/**
262	 * Prepares and enqueues plugin styles.
263	 * Filters used:
264	 * 		- 'pluginID_style_admin' - For the admin style URL.
265	 * 		- 'pluginID_style_url' - For the public style URL.
266	 *
267	 * @uses apply_filters() Calls the 'ID_style_url' and 'ID_style_admin' on the style file URL.
268	 * @hook action wp_print_styles and admin_print_styles
269	 * @access private
270	 * @return void
271	 */
272	final function _enqueueStyles() {
273		$url = '';
274		if ( is_admin() ) {
275			if ( file_exists($this->p_dirs['path'] . 'admin.css') ) {
276				$url = $this->p_dirs['url'] . 'admin.css';
277			}
278			$url = apply_filters($this->ID . '_style_admin', $url);
279		} else {
280			if ( file_exists($this->p_dirs['path'] . 'style.css') ) {
281				$url = $this->p_dirs['url'] . 'style.css';
282			}
283			$url = apply_filters($this->ID . '_style_url', $url);
284		}
285
286		if ( ! empty($url) ) {
287   			wp_register_style($this->ID, $url, false, $this->p_data['Version']);
288   			wp_enqueue_style($this->ID);
289    	}
290   	}
291
292	/**
293	 * Returns the plguin Folder basename.
294	 *
295	 * @return string
296	 */
297	final public function getFolder() {
298		if ( empty($p_dirs) ) {
299			$this->loadPaths();
300		}
301		return $this->p_dirs['subdir'];
302	}
303
304	/**
305	 * Returns the URL to the plugin folder (with trailing slash).
306	 *
307	 * @return string
308	 */
309	final public function getURL() {
310		if ( empty($p_dirs) ) {
311			$this->loadPaths();
312		}
313		return $this->p_dirs['url'];
314	}
315
316	/**
317	 * Returns the Absolute path to plugin folder (with trailing slash).
318	 *
319	 * @return string
320	 */
321	final public function getPath() {
322		if ( empty($p_dirs) ) {
323			$this->loadPaths();
324		}
325		return $this->p_dirs['path'];
326	}
327
328   	/**
329   	 * Returns private or protected values.
330   	 * @since 0.6
331   	 *
332   	 * @param $name	Name of the value.
333   	 * @return mixed Requested value.
334   	 */
335   	public function __get( $name ) {
336
337   		if ( empty($this->p_data) ) {
338			$this->loadPluginData();
339   		}
340
341   		$name = strtolower($name);
342   		switch ( $name ) {
343   			case 'id':
344   				return $this->ID;
345   				break;
346   			case 'file':
347   				return $this->p_file;
348   				break;
349   			case 'version':
350   				return $this->p_data['Version'];
351   				break;
352   			default:
353				return false;
354   		}
355
356   	}
357
358   	/**
359   	 * Returns a plugin setting.
360   	 * If no specific settings is requested, returns all settings.
361   	 * If requested a non existent settings, returns $default.
362   	 *
363   	 * @param $name	Name for the settings to return.
364   	 * @param $default Default value to use if setting does not exists.
365   	 * @return mixed	The settings value or an array with all settings.
366   	 */
367   	public function getOption( $name = '', $default = false ) {
368   		if ( empty($name) ) {
369   			return $this->settings;
370   		} elseif ( isset($this->settings[$name]) ) {
371   			return $this->settings[$name];
372   		} else {
373   			return $default;
374   		}
375
376   	}
377
378	/**
379	 * Returns plugin data.
380	 * This data is loaded from the main plugin's file.
381	 *
382	 * @see $p_data
383	 * @return mixed The parameter requested or an array wil all data.
384	 */
385	final public function getPluginData( $name = '' ) {
386		if ( empty($name) ) {
387			return $this->p_data;
388		} elseif ( isset( $this->p_data[$name]) ) {
389			return $this->p_data['name'];
390		} else {
391			return false;
392		}
393	}
394
395	/**
396	 * Loads plugin data and settings.
397	 * Data is loaded from plugin and readme file headers. Settings from Database.
398	 *
399	 * @return void
400	 */
401	final private function loadPluginData() {
402		if ( empty($this->p_data) ) {
403			if ( ! function_exists('get_plugin_data') ) {
404				require_once ( ABSPATH . 'wp-admin/includes/plugin.php' );
405			}
406
407			$p_data = get_plugin_data($this->p_file);
408			$r_data = sposts_plugin_readme_data($this->p_file);
409			$this->p_data = array_merge($r_data, $p_data);
410		}
411
412		$this->settings = get_option($this->ID . '_settings');
413		if ( ! empty($this->defaults) && is_array($this->defaults) ) {
414			if ( is_array($this->settings) ) {
415				$this->settings = array_merge($this->defaults, $this->settings);
416			} else {
417				$this->settings = $this->defaults;
418			}
419		}
420
421		$ver = get_option($this->ID . '_version');
422		if ( false === $ver ) {
423			$this->installing = true;
424		} elseif ( version_compare($ver, $this->p_data['Version'], 'ne') ) {
425			$this->needs_update = true;
426		}
427	}
428
429	/**
430	 * Saves the current post state.
431	 *
432	 * @return void
433	 */
434	final public function savePost() {
435		global $post, $more;
436
437		$this->saved['post'] = $post;
438		$this->saved['more'] = $more;
439	}
440
441	/**
442	 * Restores the current post state.
443	 * Saved in savePost()
444	 *
445	 * @return void
446	 */
447	final public function restorePost() {
448		global $post, $more;
449
450		$more = $this->saved['more'];
451		$post = $this->saved['post'];
452		if ( $post ) {
453		    setup_postdata($post);
454		}
455	}
456
457	/**
458	 * Checks if the plugin is compatible with the current WordPress version.
459	 * If it's not compatible, sets an admin warning.
460	 *
461	 * @return boolean	Plugin is compatible with this WordPress version or not.
462	 */
463	final private function isCompatible() {
464		global $wp_version;
465
466		if ( version_compare($wp_version, $this->p_data['Requires'] , '>=') ) {
467			return true;
468		} else {
469			add_action('admin_notices', array($this, '_compatibleWarning'));
470			return false;
471		}
472	}
473
474	/**
475	 * Shows a warning message when the plugin is not compatible with current WordPress version.
476	 * This is used by calling the action 'admin_notices' in isCompatible()
477	 *
478	 * @hook action admin_notices
479	 * @access private
480	 * @return void
481	 */
482	final function _compatibleWarning() {
483		$this->loadTranslations(); // We have not loaded translations yet.
484
485		echo '<div class="error"><p><strong>' . __('Warning:', $this->ID) . '</strong> '
486			. sprintf(__('The active plugin %s is not compatible with your WordPress version.', $this->ID),
487				'&laquo;' . $this->p_data['Name'] . ' ' . $this->p_data['Version'] . '&raquo;')
488			. '</p><p>' . sprintf(__('WordPress %s is required to run this plugin.', $this->ID), $this->p_data['Requires'])
489			. '</p></div>';
490	}
491
492	/**
493	 * Checks if standard functions for Widgets are present.
494	 * If them are not present, we are not using the standard sidebar: an admin warning is set.
495	 *
496	 * @return boolean	Standard widget functions were found ot not.
497	 */
498	final private function isStandardSidebar() {
499
500		if (    class_exists('WP_Widget') &&
501		        function_exists('register_widget') &&
502				function_exists('unregister_widget') )
503		{
504			return true;
505		} else {
506			add_action('admin_notices', array($this, '_standardSidebarWarning'));
507			return false;
508		}
509	}
510
511	/**
512	 * Shows an admin warning when not using the WordPress standard sidebar.
513	 * This is done by calling the action 'admin_notices' in isStandardSidebar()
514	 *
515	 * @hook action admin_notices
516	 * @access private
517	 * @return void
518	 */
519	final function _standardSidebarWarning() {
520		$this->loadTranslations(); // We have not loaded translations yet.
521
522		echo '<div class="error"><p><strong>' . __('Warning:', $this->ID) . '</strong> '
523			. __('Standard sidebar functions are not present.', $this->ID) . '</p><p>'
524			. sprintf(__('It is required to use the standard sidebar to run %s', $this->ID),
525				'&laquo;' . $this->p_data['Name'] . ' ' . $this->p_data['Version'] . '&raquo;')
526			. '</p></div>';
527	}
528
529	/**
530	 * Loads the plugin paths based on the plugin main file.
531	 * Paths are set as $this->p_dirs.
532	 *
533	 * @see spostsPlugin::p_dirs
534	 * @return void
535	 */
536	final private function loadPaths() {
537
538		$this->p_dirs['path']	= dirname($this->p_file) .'/';
539		$this->p_dirs['subdir']	= basename($this->p_dirs['path']);
540		$this->p_dirs['url']	= WP_PLUGIN_URL . '/' . $this->p_dirs['subdir'] .'/';
541	}
542}