/app/class-ms-plugin.php

  1. <?php 
  2. /** 
  3. * Primary Membership plugin class. 
  4. * 
  5. * Control of plugin is passed to the MVC implementation found 
  6. * inside the /app and /premium folders. 
  7. * 
  8. * Note: Even all properties are marked private, they are made public via the 
  9. * magic __get() function. 
  10. * 
  11. * @since 1.0.0 
  12. * 
  13. * @return object Plugin instance. 
  14. */ 
  15. class MS_Plugin { 
  16.  
  17. /** 
  18. * Singletone instance of the plugin. 
  19. * 
  20. * @since 1.0.0 
  21. * 
  22. * @var MS_Plugin 
  23. */ 
  24. private static $instance = null; 
  25.  
  26. /** 
  27. * Modifier values. Modifiers are similar to wp-config constants, but can be 
  28. * also changed via code. 
  29. * 
  30. * @since 1.0.0 
  31. * 
  32. * @var array 
  33. */ 
  34. private static $modifiers = array(); 
  35.  
  36. /** 
  37. * The WordPress internal plugin identifier. 
  38. * 
  39. * @since 1.0.0 
  40. * @var string 
  41. */ 
  42. private $id; 
  43.  
  44. /** 
  45. * The plugin name. 
  46. * 
  47. * @since 1.0.0 
  48. * @var string 
  49. */ 
  50. private $name; 
  51.  
  52. /** 
  53. * The plugin version. 
  54. * 
  55. * @since 1.0.0 
  56. * @var string 
  57. */ 
  58. private $version; 
  59.  
  60. /** 
  61. * The plugin file. 
  62. * 
  63. * @since 1.0.0 
  64. * @var string 
  65. */ 
  66. private $file; 
  67.  
  68. /** 
  69. * The plugin path. 
  70. * 
  71. * @since 1.0.0 
  72. * @var string 
  73. */ 
  74. private $dir; 
  75.  
  76. /** 
  77. * The plugin URL. 
  78. * 
  79. * @since 1.0.0 
  80. * @var string 
  81. */ 
  82. private $url; 
  83.  
  84. /** 
  85. * The plugin settings. 
  86. * 
  87. * @since 1.0.0 
  88. * @var MS_Model_Settings 
  89. */ 
  90. private $settings; 
  91.  
  92. /** 
  93. * The plugin add-on settings. 
  94. * 
  95. * @since 1.0.0 
  96. * @var MS_Model_Addon 
  97. */ 
  98. private $addon; 
  99.  
  100. /** 
  101. * The main controller of the plugin. 
  102. * 
  103. * @since 1.0.0 
  104. * @var MS_Controller_Plugin 
  105. */ 
  106. private $controller; 
  107.  
  108. /** 
  109. * The API controller (for convenience) 
  110. * 
  111. * @since 1.0.0 
  112. * @var MS_Controller_Api 
  113. */ 
  114. public static $api = null; 
  115.  
  116. /** 
  117. * Plugin constructor. 
  118. * 
  119. * Set properties, registers hooks and loads the plugin. 
  120. * 
  121. * @since 1.0.0 
  122. */ 
  123. public function __construct() { 
  124.  
  125. /** 
  126. * Actions to execute before the plugin construction starts. 
  127. * 
  128. * @since 1.0.0 
  129. * @param object $this The MS_Plugin object. 
  130. */ 
  131. do_action( 'ms_plugin_init', $this ); 
  132.  
  133. /** 
  134. * Deprecated action. 
  135. * 
  136. * @since 1.0.0 
  137. * @deprecated since 2.0.0 
  138. */ 
  139. do_action( 'ms_plugin_construct_start', $this ); 
  140.  
  141. /** Setup plugin properties */ 
  142. $this->id = MS_PLUGIN; 
  143. $this->name = MS_PLUGIN_NAME; 
  144. $this->version = MS_PLUGIN_VERSION; 
  145. $this->file = MS_PLUGIN_FILE; 
  146. $this->dir = plugin_dir_path( MS_PLUGIN_FILE ); 
  147. $this->url = plugin_dir_url( MS_PLUGIN_FILE ); 
  148.  
  149. // Might refresh the Rewrite-Rules and reloads the page. 
  150. add_action( 
  151. 'wp_loaded',  
  152. array( $this, 'maybe_flush_rewrite_rules' ),  
  153. ); 
  154.  
  155. // Hooks init to register custom post types. 
  156. add_action( 
  157. 'init',  
  158. array( $this, 'register_custom_post_types' ),  
  159. ); 
  160.  
  161. // Hooks init to add rewrite rules and tags (both work in conjunction). 
  162. add_action( 'init', array( $this, 'add_rewrite_rules' ), 1 ); 
  163. add_action( 'init', array( $this, 'add_rewrite_tags' ), 1 ); 
  164.  
  165. // Plugin activation Hook. 
  166. register_activation_hook( 
  167. MS_PLUGIN_FILE,  
  168. array( $this, 'plugin_activation' ) 
  169. ); 
  170.  
  171. /** 
  172. * Hooks init to create the primary plugin controller. 
  173. * 
  174. * We use the setup_theme hook because plugins_loaded is too early: 
  175. * wp_redirect (used by the update model) is initialized after 
  176. * plugins_loaded but before setup_theme. 
  177. */ 
  178. add_action( 
  179. 'setup_theme',  
  180. array( $this, 'ms_plugin_constructing' ) 
  181. ); 
  182.  
  183. /** 
  184. * Creates and Filters the Settings Model. 
  185. * 
  186. * @since 1.0.0 
  187. * @param object $this The MS_Plugin object. 
  188. */ 
  189. $this->settings = MS_Factory::load( 'MS_Model_Settings' ); 
  190.  
  191. /** 
  192. * Creates and Filters the Addon Model. 
  193. * 
  194. * @since 1.0.0 
  195. * @param object $this The MS_Plugin object. 
  196. */ 
  197. $this->addon = MS_Factory::load( 'MS_Model_Addon' ); 
  198.  
  199. add_filter( 
  200. 'plugin_action_links_' . MS_PLUGIN,  
  201. array( $this, 'plugin_settings_link' ) 
  202. ); 
  203.  
  204. add_filter( 
  205. 'network_admin_plugin_action_links_' . MS_PLUGIN,  
  206. array( $this, 'plugin_settings_link' ) 
  207. ); 
  208.  
  209. // Grab instance of self. 
  210. self::$instance = $this; 
  211.  
  212. /** 
  213. * Actions to execute when the Plugin object has successfully constructed. 
  214. * 
  215. * @since 1.0.0 
  216. * @param object $this The MS_Plugin object. 
  217. */ 
  218. do_action( 'ms_plugin_construct_end', $this ); 
  219.  
  220. /** 
  221. * Loads primary plugin controllers. 
  222. * 
  223. * Related Action Hooks: 
  224. * - setup_theme 
  225. * 
  226. * @since 1.0.0 
  227. */ 
  228. public function ms_plugin_constructing() { 
  229. /** 
  230. * Creates and Filters the Plugin Controller. 
  231. * 
  232. * ---> MAIN ENTRY POINT CONTROLLER FOR PLUGIN <--- 
  233. * 
  234. * @uses MS_Controller_Plugin 
  235. * @since 1.0.0 
  236. */ 
  237. $this->controller = MS_Factory::create( 'MS_Controller_Plugin' ); 
  238.  
  239. /** 
  240. * Register plugin custom post types. 
  241. * 
  242. * @since 1.0.0 
  243. */ 
  244. public function register_custom_post_types() { 
  245. do_action( 'ms_plugin_register_custom_post_types_before', $this ); 
  246.  
  247. $cpts = apply_filters( 
  248. 'ms_plugin_register_custom_post_types',  
  249. array( 
  250. MS_Model_Membership::get_post_type() => MS_Model_Membership::get_register_post_type_args(),  
  251. MS_Model_Relationship::get_post_type() => MS_Model_Relationship::get_register_post_type_args(),  
  252. MS_Model_Invoice::get_post_type() => MS_Model_Invoice::get_register_post_type_args(),  
  253. MS_Model_Communication::get_post_type() => MS_Model_Communication::get_register_post_type_args(),  
  254. MS_Model_Event::get_post_type() => MS_Model_Event::get_register_post_type_args(),  
  255. ); 
  256.  
  257. foreach ( $cpts as $cpt => $args ) { 
  258. MS_Helper_Utility::register_post_type( $cpt, $args ); 
  259.  
  260. /** 
  261. * Add rewrite rules. 
  262. * 
  263. * @since 1.0.0 
  264. */ 
  265. public function add_rewrite_rules() { 
  266. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  267.  
  268. // Gateway return - IPN. 
  269. add_rewrite_rule( 
  270. 'ms-payment-return/(.+)/?',  
  271. 'index.php?paymentgateway=$matches[1]',  
  272. 'top' 
  273. ); 
  274.  
  275. // Alternative payment return URL: Old Membership plugin. 
  276. $use_old_ipn = apply_filters( 'ms_legacy_paymentreturn_url', true ); 
  277. if ( $use_old_ipn && ! class_exists( 'M_Membership' ) ) { 
  278. add_rewrite_rule( 
  279. 'paymentreturn/(.+)/?',  
  280. 'index.php?paymentgateway=$matches[1]',  
  281. 'top' 
  282. ); 
  283.  
  284. /** Media / download ----- */ 
  285. $mmask = $settings->downloads['masked_url']; 
  286. $mtype = $settings->downloads['protection_type']; 
  287.  
  288. if ( MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MEDIA ) && $mmask ) { 
  289. if ( MS_Rule_Media_Model::PROTECTION_TYPE_HYBRID == $mtype ) { 
  290. add_rewrite_rule( 
  291. sprintf( '^%1$s/?$', $mmask ),  
  292. 'index.php?protectedfile=0',  
  293. 'top' 
  294. ); 
  295. } else { 
  296. add_rewrite_rule( 
  297. sprintf( '^%1$s/([^/]+)', $mmask ),  
  298. 'index.php?protectedfile=$matches[1]',  
  299. 'top' 
  300. ); 
  301. /** End: Media / download ----- */ 
  302.  
  303. do_action( 'ms_plugin_add_rewrite_rules', $this ); 
  304.  
  305. /** 
  306. * Add rewrite tags. 
  307. * 
  308. * @since 1.0.0 
  309. */ 
  310. public function add_rewrite_tags() { 
  311. // Membership site pages. 
  312. add_rewrite_tag( '%ms_page%', '(.+)' ); 
  313.  
  314. // Gateway return - IPN. 
  315. add_rewrite_tag( '%paymentgateway%', '(.+)' ); 
  316.  
  317. // Media / download. 
  318. add_rewrite_tag( '%protectedfile%', '(.+)' ); 
  319.  
  320. do_action( 'ms_plugin_add_rewrite_tags', $this ); 
  321.  
  322. /** 
  323. * Actions executed in plugin activation. 
  324. * 
  325. * @since 1.0.0 
  326. */ 
  327. public function plugin_activation() { 
  328. // Prevent recursion during plugin activation. 
  329. $refresh = lib3()->session->get( 'refresh_url_rules' ); 
  330. if ( $refresh ) { return; } 
  331.  
  332. // Update the Membership2 database entries after activation. 
  333. MS_Model_Upgrade::update( true ); 
  334.  
  335. do_action( 'ms_plugin_activation', $this ); 
  336.  
  337. /** 
  338. * Redirect page and request plugin to flush the WordPress rewrite rules 
  339. * on next request. 
  340. * 
  341. * @since 1.0.0 
  342. * @param string $url The URL to load after flushing the rewrite rules. 
  343. */ 
  344. static public function flush_rewrite_rules( $url = false ) { 
  345. if ( isset( $_GET['ms_flushed'] ) && 'yes' == $_GET['ms_flushed'] ) { 
  346. $refresh = true; 
  347. } else { 
  348. $refresh = lib3()->session->get( 'refresh_url_rules' ); 
  349.  
  350. if ( $refresh ) { return; } 
  351.  
  352. lib3()->session->add( 'refresh_url_rules', true ); 
  353.  
  354. // The URL param is only to avoid cache. 
  355. $url = esc_url_raw( 
  356. add_query_arg( 'ms_ts', time(), $url ) 
  357. ); 
  358. wp_safe_redirect( $url ); 
  359. exit; 
  360.  
  361. /** 
  362. * Flush the WordPress rewrite rules. 
  363. * 
  364. * @since 1.0.0 
  365. */ 
  366. public function maybe_flush_rewrite_rules() { 
  367. $refresh = lib3()->session->get_clear( 'refresh_url_rules' ); 
  368. if ( ! $refresh ) { return; } 
  369.  
  370. // Set up the plugin specific rewrite rules again. 
  371. $this->add_rewrite_rules(); 
  372. $this->add_rewrite_tags(); 
  373.  
  374. do_action( 'ms_plugin_flush_rewrite_rules', $this ); 
  375.  
  376. $url = remove_query_arg( 'ms_ts' ); 
  377. $url = esc_url_raw( add_query_arg( 'ms_flushed', 'yes', $url ) ); 
  378. wp_safe_redirect( $url ); 
  379. exit; 
  380.  
  381. /** 
  382. * Add link to settings page in plugins page. 
  383. * 
  384. * @since 1.0.0 
  385. * 
  386. * @param array $links WordPress default array of links. 
  387. * @return array Array of links with settings page links added. 
  388. */ 
  389. public function plugin_settings_link( $links ) { 
  390. if ( ! is_network_admin() ) { 
  391. $text = __( 'Settings', 'membership2' ); 
  392. $url = MS_Controller_Plugin::get_admin_url( 'settings' ); 
  393.  
  394. if ( $this->settings->initial_setup ) { 
  395. $url = MS_Controller_Plugin::get_admin_url(); 
  396.  
  397. /** 
  398. * Filter the plugin settings link. 
  399. * 
  400. * @since 1.0.0 
  401. * @param object $this The MS_Plugin object. 
  402. */ 
  403. $settings_link = apply_filters( 
  404. 'ms_plugin_settings_link',  
  405. sprintf( '<a href="%s">%s</a>', $url, $text ),  
  406. $this 
  407. ); 
  408. array_unshift( $links, $settings_link ); 
  409.  
  410. return $links; 
  411.  
  412. /** 
  413. * Returns singleton instance of the plugin. 
  414. * 
  415. * @since 1.0.0 
  416. * 
  417. * @static 
  418. * @access public 
  419. * 
  420. * @return MS_Plugin 
  421. */ 
  422. public static function instance() { 
  423. if ( ! self::$instance ) { 
  424. self::$instance = new MS_Plugin(); 
  425.  
  426. self::$instance = apply_filters( 
  427. 'ms_plugin_instance',  
  428. self::$instance 
  429. ); 
  430.  
  431. return self::$instance; 
  432.  
  433. /** 
  434. * Returns plugin enabled status. 
  435. * 
  436. * @since 1.0.0 
  437. * @access public 
  438. * 
  439. * @static 
  440. * 
  441. * @return bool The status. 
  442. */ 
  443. public static function is_enabled() { 
  444. return self::instance()->settings->plugin_enabled; 
  445.  
  446. /** 
  447. * Returns plugin wizard status. 
  448. * 
  449. * @since 1.0.0 
  450. * @access public 
  451. * 
  452. * @static 
  453. * 
  454. * @return bool The status. 
  455. */ 
  456. public static function is_wizard() { 
  457. return ! ! self::instance()->settings->initial_setup; 
  458.  
  459. /** 
  460. * Returns the network-wide protection status. 
  461. * 
  462. * This flag can be changed by setting the MS_PROTECT_NETWORK flag to true 
  463. * in wp-config.php 
  464. * 
  465. * @since 1.0.0 
  466. * @return bool False means that only the current site is protected. 
  467. * True means that memberships are shared among all network sites. 
  468. */ 
  469. public static function is_network_wide() { 
  470.  
  471.  
  472. // Free plugin always returns false (this is a pro feature). 
  473. return false; 
  474.  
  475. /** 
  476. * Returns a modifier option. 
  477. * This is similar to a setting but more "advanced" in a way that there is 
  478. * no UI for it. A modifier can be set by the plugin (e.g. during Import 
  479. * the "no_messages" modifier is enabled) or via a const in wp-config.php 
  480. * 
  481. * A modifier is never saved in the database. 
  482. * It can be defined ONLY via MS_Plugin::set_modifier() or via wp-config.php 
  483. * The set_modifier() value will always take precedence over wp-config.php 
  484. * definitions. 
  485. * 
  486. * @since 1.0.0 
  487. * @api 
  488. * 
  489. * @param string $key Name of the modifier. 
  490. * @return mixed The modifier value or null. 
  491. */ 
  492. public static function get_modifier( $key ) { 
  493. $res = null; 
  494.  
  495. if ( isset( self::$modifiers[ $key ] ) ) { 
  496. $res = self::$modifiers[ $key ]; 
  497. } elseif ( defined( $key ) ) { 
  498. $res = constant( $key ); 
  499.  
  500. return $res; 
  501.  
  502. /** 
  503. * Changes a modifier option. 
  504. * 
  505. * @see get_modifier() for more details. 
  506. * @since 1.0.0 
  507. * @api 
  508. * 
  509. * @param string $key Name of the modifier. 
  510. * @param mixed $value Value of the modifier. `null` unsets the modifier. 
  511. */ 
  512. public static function set_modifier( $key, $value = null ) { 
  513. if ( null === $value ) { 
  514. unset( self::$modifiers[ $key ] ); 
  515. } else { 
  516. self::$modifiers[ $key ] = $value; 
  517.  
  518. /** 
  519. * This funciton initializes the api property for easy access to the plugin 
  520. * API. This function is *only* called by MS_Controller_Api::__construct()! 
  521. * 
  522. * @since 1.0.0 
  523. * @internal 
  524. * @param MS_Controller_Api $controller The initialized API controller. 
  525. */ 
  526. public static function set_api( $controller ) { 
  527. self::$api = $controller; 
  528.  
  529. /** 
  530. * Returns property associated with the plugin. 
  531. * 
  532. * @since 1.0.0 
  533. * 
  534. * @access public 
  535. * @param string $property The name of a property. 
  536. * @return mixed Returns mixed value of a property or NULL if a property doesn't exist. 
  537. */ 
  538. public function __get( $property ) { 
  539. if ( property_exists( $this, $property ) ) { 
  540. return $this->$property; 
  541.  
  542. /** 
  543. * Check if property isset. 
  544. * 
  545. * @since 1.0.0 
  546. * @internal 
  547. * 
  548. * @param string $property The name of a property. 
  549. * @return mixed Returns true/false. 
  550. */ 
  551. public function __isset( $property ) { 
  552. return isset($this->$property); 
  553. }  
  554. }; 
.