PageRenderTime 61ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/capsman/framework/plugins.php

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