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

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