/app/model/class-ms-model-addon.php

  1. <?php 
  2. /** 
  3. * @copyright Incsub (http://incsub.com/) 
  4. * 
  5. * @license http://opensource.org/licenses/GPL-2.0 GNU General Public License, version 2 (GPL-2.0) 
  6. * 
  7. * This program is free software; you can redistribute it and/or modify 
  8. * it under the terms of the GNU General Public License, version 2, as 
  9. * published by the Free Software Foundation. 
  10. * 
  11. * This program is distributed in the hope that it will be useful,  
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  14. * GNU General Public License for more details. 
  15. * 
  16. * You should have received a copy of the GNU General Public License 
  17. * along with this program; if not, write to the Free Software 
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  
  19. * MA 02110-1301 USA 
  20. * 
  21. */ 
  22.  
  23. /** 
  24. * Manage Add-ons. 
  25. * 
  26. * Add-ons are stored in the directory /app/addon/<addon_name>/ 
  27. * Each Add-on must provide a file called `addon-<addon_name>.php` 
  28. * This file must define class MS_Addon_<addon_name>. 
  29. * This object is reponsible to initialize the the add-on logic. 
  30. * 
  31. * @since 1.0.0 
  32. * 
  33. * @package Membership2 
  34. * @subpackage Model 
  35. */ 
  36. class MS_Model_Addon extends MS_Model_Option { 
  37.  
  38. /** 
  39. * Add-on name constants. 
  40. * 
  41. * @deprecated Since 1.1.0 the Add-On constants are deprecated. 
  42. * Use the appropriate hooks to register new addons! 
  43. * Example: See the "Taxamo" addon 
  44. * 
  45. * @since 1.0.0 
  46. * 
  47. * @var string 
  48. */ 
  49. const ADDON_MULTI_MEMBERSHIPS = 'multi_memberships'; 
  50. const ADDON_POST_BY_POST = 'post_by_post'; 
  51. const ADDON_URL_GROUPS = 'url_groups'; 
  52. const ADDON_CPT_POST_BY_POST = 'cpt_post_by_post'; 
  53. const ADDON_TRIAL = 'trial'; 
  54. const ADDON_MEDIA = 'media'; 
  55. const ADDON_PRO_RATE = 'pro_rate'; 
  56. const ADDON_SHORTCODE = 'shortcode'; 
  57. const ADDON_AUTO_MSGS_PLUS = 'auto_msgs_plus'; 
  58. const ADDON_SPECIAL_PAGES = 'special_pages'; 
  59. const ADDON_ADV_MENUS = 'adv_menus'; 
  60. const ADDON_ADMINSIDE = 'adminside'; 
  61. const ADDON_MEMBERCAPS = 'membercaps'; 
  62. const ADDON_MEMBERCAPS_ADV = 'membercaps_advanced'; 
  63.  
  64. /** 
  65. * List of all registered Add-ons 
  66. * 
  67. * Related hook: ms_model_addon_register 
  68. * 
  69. * @var array { 
  70. * @key <string> The add-on ID. 
  71. * @value object { 
  72. * The add-on data. 
  73. * 
  74. * $name <string> Display name 
  75. * $parent <string> Empty/The Add-on ID of the parent 
  76. * $description <string> Description 
  77. * $footer <string> For the Add-ons list 
  78. * $icon <string> For the Add-ons list 
  79. * $class <string> For the Add-ons list 
  80. * $details <array of HTML elements> For the Add-ons list 
  81. * } 
  82. * } 
  83. */ 
  84. static private $_registered = array(); 
  85.  
  86. /** 
  87. * Used by function `flush_list` 
  88. * 
  89. * @since 1.1.0 
  90. * 
  91. * @var bool 
  92. */ 
  93. static private $_reload_files = false; 
  94.  
  95. /** 
  96. * List of add-on files to load when plugin is initialized. 
  97. * 
  98. * @since 1.1.0 
  99. * 
  100. * @var array of file-paths 
  101. */ 
  102. protected $addon_files = array(); 
  103.  
  104. /** 
  105. * Add-ons array. 
  106. * 
  107. * @since 1.0.0 
  108. * 
  109. * @var array { 
  110. * @key <string> The add-on ID. 
  111. * @value <boolean> The add-on enbled status (always true). 
  112. * } 
  113. */ 
  114. protected $active = array(); 
  115.  
  116. /** 
  117. * Initalize Object Hooks 
  118. * 
  119. * @since 1.1.0 
  120. */ 
  121. public function __construct() { 
  122. parent::__construct(); 
  123.  
  124. $this->add_action( 'ms_model_addon_flush', 'flush_list' ); 
  125.  
  126. /** 
  127. * Returns a list of all registered Add-Ons 
  128. * 
  129. * @since 1.1.0 
  130. * @return array Add-on lisl 
  131. */ 
  132. static public function get_addons() { 
  133. static $Done = false; 
  134. $res = null; 
  135.  
  136. if ( ! $Done || self::$_reload_files ) { 
  137. self::$_registered = array(); 
  138. $addons = array(); 
  139. $Done = true; 
  140. self::load_core_addons(); 
  141.  
  142. // Register core add-ons 
  143. $addons = self::get_core_list(); 
  144.  
  145. /** 
  146. * Register new addons. 
  147. * 
  148. * @since 1.1.0 
  149. */ 
  150. $addons = apply_filters( 
  151. 'ms_model_addon_register',  
  152. $addons 
  153. ); 
  154.  
  155. // Sanitation and populate default fields. 
  156. foreach ( $addons as $key => $data ) { 
  157. self::$_registered[$key] = $data->name; 
  158.  
  159. $addons[$key]->id = $key; 
  160. $addons[$key]->active = self::is_enabled( $key ); 
  161. $addons[$key]->title = $data->name; 
  162.  
  163. if ( isset( $addons[$key]->icon ) ) { 
  164. $addons[$key]->icon = '<i class="' . $addons[$key]->icon . '"></i>'; 
  165. } else { 
  166. $addons[$key]->icon = '<i class="wpmui-fa wpmui-fa-puzzle-piece"></i>'; 
  167.  
  168. if ( empty( $addons[$key]->action ) ) { 
  169. $addons[$key]->action = array(); 
  170. $addons[$key]->action[] = array( 
  171. 'id' => 'ms-toggle-' . $key,  
  172. 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER,  
  173. 'value' => self::is_enabled( $key ),  
  174. 'class' => 'toggle-plugin',  
  175. 'ajax_data' => array( 
  176. 'action' => MS_Controller_Addon::AJAX_ACTION_TOGGLE_ADDON,  
  177. 'field' => 'active',  
  178. 'addon' => $key,  
  179. ),  
  180. ); 
  181. $addons[$key]->action[] = MS_Helper_Html::save_text( null, false, true ); 
  182.  
  183. /** 
  184. * Add custom Actions or remove default actions 
  185. * 
  186. * @since 1.1.0 
  187. */ 
  188. $addons[$key]->action = apply_filters( 
  189. 'ms_model_addon_action-' . $key,  
  190. $addons[$key]->action,  
  191. $addons[$key] 
  192. ); 
  193.  
  194. natcasesort( self::$_registered ); 
  195. foreach ( self::$_registered as $key => $dummy ) { 
  196. self::$_registered[$key] = $addons[$key]; 
  197.  
  198. /** 
  199. * The Add-on list is prepared. Initialize the addons now. 
  200. * 
  201. * @since 1.1.0 
  202. */ 
  203. do_action( 'ms_model_addon_initialize' ); 
  204.  
  205. return self::$_registered; 
  206.  
  207. /** 
  208. * Force to reload the add-on list 
  209. * 
  210. * Related action hooks: 
  211. * - ms_model_addon_flush 
  212. * 
  213. * @since 1.1.0 
  214. */ 
  215. public function flush_list() { 
  216. self::$_reload_files = true; 
  217. self::get_addons(); 
  218.  
  219. /** 
  220. * Checks the /app/addon directory for a list of all addons and loads these 
  221. * files. 
  222. * 
  223. * @since 1.1.0 
  224. */ 
  225. static protected function load_core_addons() { 
  226. $model = MS_Factory::load( 'MS_Model_Addon' ); 
  227. $root_path = trailingslashit( dirname( dirname( MS_Plugin::instance()->dir ) ) ); 
  228. $plugin_dir = substr( MS_Plugin::instance()->dir, strlen( $root_path ) ); 
  229. $addon_dir = $plugin_dir . 'app/addon/'; 
  230.  
  231. if ( empty( $model->addon_files ) || self::$_reload_files ) { 
  232. // In Admin dashboard we always refresh the addon-list... 
  233. self::$_reload_files = false; 
  234.  
  235. $mask = $root_path . $addon_dir . '*/class-ms-addon-*.php'; 
  236. $addons = glob( $mask ); 
  237.  
  238. $model->addon_files = array(); 
  239. foreach ( $addons as $file ) { 
  240. $model->addon_files[] = substr( $file, strlen( $root_path ) ); 
  241.  
  242. /** 
  243. * Allow other plugins/themes to register custom addons 
  244. * 
  245. * @since 1.1.0 
  246. * 
  247. * @var array 
  248. */ 
  249. $model->addon_files = apply_filters( 
  250. 'ms_model_addon_files',  
  251. $model->addon_files 
  252. ); 
  253.  
  254. $model->save(); 
  255.  
  256. // Loop all recignized Add-ons and initialize them. 
  257. foreach ( $model->addon_files as $file ) { 
  258. $addon = $root_path . $file; 
  259.  
  260. // Get class-name from file-name 
  261. $class = basename( $file ); 
  262. $class = str_replace( '.php', '', $class ); 
  263. $class = implode( '_', array_map( 'ucfirst', explode( '-', $class ) ) ); 
  264. $class = substr( $class, 6 ); // remove 'Class_' prefix 
  265.  
  266. if ( file_exists( $addon ) ) { 
  267. if ( ! class_exists( $class ) ) { 
  268. include_once $addon; 
  269.  
  270. if ( class_exists( $class ) ) { 
  271. MS_Factory::load( $class ); 
  272.  
  273. /** 
  274. * Allow custom addon-initialization code to run 
  275. * 
  276. * @since 1.1.0 
  277. */ 
  278. do_action( 'ms_model_addon_load' ); 
  279.  
  280. /** 
  281. * Verify if an add-on is enabled 
  282. * 
  283. * @since 1.0.0 
  284. * 
  285. * @var string $addon The add-on type. 
  286. * @return boolean True if enabled. 
  287. */ 
  288. static public function is_enabled( $addon ) { 
  289. $model = MS_Factory::load( 'MS_Model_Addon' ); 
  290. $enabled = ! empty( $model->active[ $addon ] ); 
  291.  
  292. if ( $enabled ) { 
  293. // Sub-addons are considered enabled only when the parent add-on is enabled also. 
  294. switch ( $addon ) { 
  295. case self::ADDON_MEMBERCAPS_ADV: 
  296. $enabled = self::is_enabled( self::ADDON_MEMBERCAPS ); 
  297. break; 
  298.  
  299. return apply_filters( 
  300. 'ms_model_addon_is_enabled_' . $addon,  
  301. $enabled 
  302. ); 
  303.  
  304. /** 
  305. * Enable an add-on type in the plugin. 
  306. * 
  307. * @since 1.0.0 
  308. * 
  309. * @var string $addon The add-on type. 
  310. */ 
  311. public function enable( $addon ) { 
  312. $this->refresh(); 
  313. $this->active[ $addon ] = true; 
  314. $this->save(); 
  315.  
  316. do_action( 'ms_model_addon_enable', $addon, $this ); 
  317.  
  318. /** 
  319. * Disable an add-on type in the plugin. 
  320. * 
  321. * @since 1.0.0 
  322. * 
  323. * @var string $addon The add-on type. 
  324. */ 
  325. public function disable( $addon ) { 
  326. $this->refresh(); 
  327. unset( $this->active[ $addon ] ); 
  328. $this->save(); 
  329.  
  330. do_action( 'ms_model_addon_disable', $addon, $this ); 
  331.  
  332. /** 
  333. * Toggle add-on type status in the plugin. 
  334. * 
  335. * @since 1.0.0 
  336. * 
  337. * @var string $addon The add-on type. 
  338. */ 
  339. public function toggle_activation( $addon, $value = null ) { 
  340. if ( null === $value ) { 
  341. $value = self::is_enabled( $addon ); 
  342.  
  343. if ( $value ) { 
  344. $this->disable( $addon ); 
  345. } else { 
  346. $this->enable( $addon ); 
  347.  
  348. do_action( 'ms_model_addon_toggle_activation', $addon, $this ); 
  349.  
  350. /** 
  351. * Enable add-on necessary to membership. 
  352. * 
  353. * @since 1.0.0 
  354. * 
  355. * @var string $addon The add-on type. 
  356. */ 
  357. public function auto_config( $membership ) { 
  358. if ( $membership->trial_period_enabled ) { 
  359. $this->enable( self::ADDON_TRIAL ); 
  360.  
  361. do_action( 'ms_model_addon_auto_config', $membership, $this ); 
  362.  
  363. /** 
  364. * Returns a list of all registered Add-Ons. 
  365. * Alias for the `get_addons()` function. 
  366. * 
  367. * @since 1.0.0 
  368. * @return array List of all registered Add-ons. 
  369. */ 
  370. public function get_addon_list() { 
  371. return self::get_addons(); 
  372.  
  373. /** 
  374. * Returns Add-On details for the core add-ons in legacy format. 
  375. * New Add-ons are stored in the /app/addon folder and use the 
  376. * ms_model_addon_register hook to provide these informations. 
  377. * 
  378. * ** This function should not be extended ** 
  379. * ** Create new Add-ons in the app/addon/ directory ** 
  380. * 
  381. * @since 1.1.0 
  382. * @return array List of Add-ons 
  383. */ 
  384. static private function get_core_list() { 
  385. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  386.  
  387. $options_text = sprintf( 
  388. '<i class="dashicons dashicons dashicons-admin-settings"></i> %s',  
  389. __( 'Options available', MS_TEXT_DOMAIN ) 
  390. ); 
  391.  
  392. $list[self::ADDON_MULTI_MEMBERSHIPS] = (object) array( 
  393. 'name' => __( 'Multiple Memberships', MS_TEXT_DOMAIN ),  
  394. 'description' => __( 'Your members can join more than one membership at the same time.', MS_TEXT_DOMAIN ),  
  395. ); 
  396.  
  397. $list[self::ADDON_TRIAL] = (object) array( 
  398. 'name' => __( 'Trial Period', MS_TEXT_DOMAIN ),  
  399. 'description' => __( 'Allow your members to sign up for a free membership trial. Trial details can be configured separately for each membership.', MS_TEXT_DOMAIN ),  
  400. ); 
  401.  
  402. $list[self::ADDON_POST_BY_POST] = (object) array( 
  403. 'name' => __( 'Individual Posts', MS_TEXT_DOMAIN ),  
  404. 'description' => __( 'Protect individual Posts instead of Categories.', MS_TEXT_DOMAIN ),  
  405. ); 
  406.  
  407. $list[self::ADDON_CPT_POST_BY_POST] = (object) array( 
  408. 'name' => __( 'Individual Custom Posts', MS_TEXT_DOMAIN ),  
  409. 'description' => __( 'Protect individual Posts of a Custom Post Type.', MS_TEXT_DOMAIN ),  
  410. 'action' => array( __( 'Pro Version', MS_TEXT_DOMAIN ) ),  
  411. ); 
  412.  
  413. $list[self::ADDON_MEDIA] = (object) array( 
  414. 'name' => __( 'Media Protection', MS_TEXT_DOMAIN ),  
  415. 'description' => __( 'Protect Images and other Media-Library content.', MS_TEXT_DOMAIN ),  
  416. 'footer' => $options_text,  
  417. 'icon' => 'dashicons dashicons-admin-media',  
  418. 'class' => 'ms-options',  
  419. 'details' => array( 
  420. array( 
  421. 'id' => 'masked_url',  
  422. 'before' => esc_html( trailingslashit( get_option( 'home' ) ) ),  
  423. 'type' => MS_Helper_Html::INPUT_TYPE_TEXT,  
  424. 'title' => __( 'Mask download URL:', MS_TEXT_DOMAIN ),  
  425. 'value' => $settings->downloads['masked_url'],  
  426. 'data_ms' => array( 
  427. 'field' => 'masked_url',  
  428. 'action' => MS_Controller_Settings::AJAX_ACTION_UPDATE_SETTING,  
  429. '_wpnonce' => true, // Nonce will be generated from 'action' 
  430. ),  
  431. ),  
  432. array( 
  433. 'id' => 'protection_type',  
  434. 'type' => MS_Helper_Html::INPUT_TYPE_RADIO,  
  435. 'title' => __( 'Protection method', MS_TEXT_DOMAIN ),  
  436. 'desc' => __( 'You can change the way that Membership2 changes the default URL to your WordPress media library files.<br>This is done for increased protection by hiding the real filename and path.', MS_TEXT_DOMAIN ),  
  437. 'value' => $settings->downloads['protection_type'],  
  438. 'field_options' => MS_Rule_Media_Model::get_protection_types(),  
  439. 'data_ms' => array( 
  440. 'field' => 'protection_type',  
  441. 'action' => MS_Controller_Settings::AJAX_ACTION_UPDATE_SETTING,  
  442. '_wpnonce' => true, // Nonce will be generated from 'action' 
  443. ),  
  444. ),  
  445. array( 
  446. 'id' => 'advanced',  
  447. 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER,  
  448. 'title' => __( 'Protect Individual Media files', MS_TEXT_DOMAIN ) . 
  449. ' - ' . __( 'Pro Version', MS_TEXT_DOMAIN ),  
  450. 'wrapper_class' => 'disabled',  
  451. 'read_only' => true,  
  452. 'desc' => __( 'Enable this to display a new tab in "Membership2" where you can manually modify access to each media library item.<br>Default: When this option is disabled then the parent-post controls the access to the media file.', MS_TEXT_DOMAIN ),  
  453. 'value' => false,  
  454. ),  
  455. ),  
  456. ); 
  457.  
  458. $list[self::ADDON_SHORTCODE] = (object) array( 
  459. 'name' => __( 'Shortcode Protection', MS_TEXT_DOMAIN ),  
  460. 'description' => __( 'Protect Shortcode-Output via Memberships.', MS_TEXT_DOMAIN ),  
  461. 'icon' => 'dashicons dashicons-editor-code',  
  462. ); 
  463.  
  464. $list[self::ADDON_URL_GROUPS] = (object) array( 
  465. 'name' => __( 'URL Protection', MS_TEXT_DOMAIN ),  
  466. 'description' => __( 'URL Protection will protect pages by the URL. This rule overrides all other rules, so use it carefully.', MS_TEXT_DOMAIN ),  
  467. 'icon' => 'dashicons dashicons-admin-links',  
  468. ); 
  469.  
  470. $list[self::ADDON_AUTO_MSGS_PLUS] = (object) array( 
  471. 'name' => __( 'Additional Automated Messages', MS_TEXT_DOMAIN ),  
  472. 'description' => __( 'Send your members automated Email responses for various additional events.', MS_TEXT_DOMAIN ),  
  473. 'icon' => 'dashicons dashicons-email',  
  474. ); 
  475.  
  476. $list[self::ADDON_SPECIAL_PAGES] = (object) array( 
  477. 'name' => __( 'Protect Special Pages', MS_TEXT_DOMAIN ),  
  478. 'description' => __( 'Change protection of special pages such as the search results.', MS_TEXT_DOMAIN ),  
  479. 'icon' => 'dashicons dashicons-admin-home',  
  480. ); 
  481.  
  482. $list[self::ADDON_ADV_MENUS] = (object) array( 
  483. 'name' => __( 'Advanced menu protection', MS_TEXT_DOMAIN ),  
  484. 'description' => __( 'Adds a new option to the General Settings that controls how WordPress menus are protected.<br />Protect individual Menu-Items, replace the contents of WordPress Menu-Locations or replace each Menu individually.', MS_TEXT_DOMAIN ),  
  485. 'footer' => $options_text,  
  486. 'class' => 'ms-options',  
  487. 'details' => array( 
  488. array( 
  489. 'id' => 'menu_protection',  
  490. 'type' => MS_Helper_Html::INPUT_TYPE_SELECT,  
  491. 'title' => __( 'Choose how you want to protect your WordPress menus.', MS_TEXT_DOMAIN ),  
  492. 'value' => $settings->menu_protection,  
  493. 'field_options' => array( 
  494. 'item' => __( 'Protect single Menu Items (Default)', MS_TEXT_DOMAIN ),  
  495. 'menu' => __( 'Replace individual Menus', MS_TEXT_DOMAIN ),  
  496. 'location' => __( 'Overwrite contents of Menu Locations', MS_TEXT_DOMAIN ),  
  497. ),  
  498. 'data_ms' => array( 
  499. 'action' => MS_Controller_Settings::AJAX_ACTION_UPDATE_SETTING,  
  500. 'field' => 'menu_protection',  
  501. ),  
  502. ),  
  503. ),  
  504. ); 
  505.  
  506. // New since 1.1 
  507. $list[self::ADDON_ADMINSIDE] = (object) array( 
  508. 'name' => __( 'Admin Side Protection', MS_TEXT_DOMAIN ),  
  509. 'description' => __( 'Control the pages and even Meta boxes that members can access on the admin side.', MS_TEXT_DOMAIN ),  
  510. 'icon' => 'dashicons dashicons-admin-network',  
  511. 'action' => array( __( 'Pro Version', MS_TEXT_DOMAIN ) ),  
  512. ); 
  513.  
  514. $list[self::ADDON_MEMBERCAPS] = (object) array( 
  515. 'name' => __( 'Member Capabilities', MS_TEXT_DOMAIN ),  
  516. 'description' => __( 'Manage user-capabilities on membership level.', MS_TEXT_DOMAIN ),  
  517. 'footer' => $options_text,  
  518. 'class' => 'ms-options',  
  519. 'icon' => 'dashicons dashicons-admin-users',  
  520. 'details' => array( 
  521. array( 
  522. 'id' => 'ms-toggle-' . self::ADDON_MEMBERCAPS_ADV,  
  523. 'title' => __( 'Advanced Capability protection', MS_TEXT_DOMAIN ),  
  524. 'desc' => __( 'Allows you to protect individual WordPress Capabilities. When activated then the "User Roles" tab is replaced by a "Member Capabilities" tab where you can protect and assign individual WordPress Capabilities instead of roles.', MS_TEXT_DOMAIN ),  
  525. 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER,  
  526. 'value' => self::is_enabled( self::ADDON_MEMBERCAPS_ADV ),  
  527. 'class' => 'toggle-plugin',  
  528. 'ajax_data' => array( 
  529. 'action' => MS_Controller_Addon::AJAX_ACTION_TOGGLE_ADDON,  
  530. 'field' => 'active',  
  531. 'addon' => self::ADDON_MEMBERCAPS_ADV,  
  532. ),  
  533. ),  
  534. ),  
  535. ); 
  536.  
  537. return $list; 
  538.  
.