/app/controller/class-ms-controller-plugin.php

  1. <?php 
  2. /** 
  3. * Primary controller for Membership Plugin. 
  4. * 
  5. * This controller is created during the `setup_theme` hook! 
  6. * 
  7. * Responsible for flow control, navigation and invoking other controllers. 
  8. * 
  9. * @since 1.0.0 
  10. * 
  11. * @package Membership2 
  12. * @subpackage Controller 
  13. */ 
  14. class MS_Controller_Plugin extends MS_Controller { 
  15.  
  16. /** 
  17. * Plugin Menu slug. 
  18. * 
  19. * @since 1.0.0 
  20. * 
  21. * @var string 
  22. */ 
  23. const MENU_SLUG = 'membership2'; 
  24.  
  25. /** 
  26. * The slug of the top-level admin page 
  27. * 
  28. * @since 1.0.0 
  29. * 
  30. * @var string 
  31. */ 
  32. private static $base_slug = ''; 
  33.  
  34. /** 
  35. * Capability required to count as M2 'admin' user. Admin users have full 
  36. * access to all M2 features. 
  37. * 
  38. * @since 1.0.0 
  39. * 
  40. * @var $capability 
  41. */ 
  42. protected $capability = 'manage_options'; 
  43.  
  44. /** 
  45. * Instance of MS_Model_Plugin. 
  46. * 
  47. * @since 1.0.0 
  48. * 
  49. * @var $model 
  50. */ 
  51. private $model; 
  52.  
  53. /** 
  54. * Pointer array for other controllers. 
  55. * 
  56. * @since 1.0.0 
  57. * 
  58. * @var $controllers 
  59. */ 
  60. protected $controllers = array(); 
  61.  
  62. /** 
  63. * Stores the callback handler for the submenu items. 
  64. * It is set by self::route_submenu_request() and is used by 
  65. * self::handle_submenu_request() 
  66. * 
  67. * @since 1.0.0 
  68. * 
  69. * @var array 
  70. */ 
  71. private $menu_handler = null; 
  72.  
  73. /** 
  74. * Constructs the primary Plugin controller. 
  75. * 
  76. * Created by the MS_Plugin object during the setup_theme action. 
  77. * 
  78. * @since 1.0.0 
  79. */ 
  80. public function __construct() { 
  81. parent::__construct(); 
  82.  
  83. /** 
  84. * Fix for IE: This is a privacy policy which states, that we do not 
  85. * collect personal contact information without consent. 
  86. * 
  87. * Note that other plugins that output this header later will overwrite 
  88. * it! So this is a default value if no other file sends the P3P header. 
  89. * 
  90. * @since 1.0.2.2 
  91. */ 
  92. $p3p_done = false; 
  93. foreach ( headers_list() as $header ) { 
  94. if ( false !== stripos( $header, 'P3P:' ) ) { 
  95. $p3p_done = true; 
  96. break; 
  97. if ( ! $p3p_done ) { header( 'P3P:CP="NOI"' ); } 
  98.  
  99. /** 
  100. * Remove the "&msg" attribute from the URL if it was already present in 
  101. * the previous request. 
  102. */ 
  103. if ( empty( $_POST ) ) { 
  104. /** 
  105. * No form was submitted: 
  106. * It's save to redirect the request without losing form-data. 
  107. */ 
  108. if ( isset( $_GET['msg'] ) 
  109. && isset( $_SERVER['HTTP_REFERER'] ) 
  110. && MS_Helper_Utility::is_current_url( $_SERVER['HTTP_REFERER'] ) 
  111. ) { 
  112. // A msg is set AND the referer URL has the same msg flag! 
  113. $url = esc_url_raw( remove_query_arg( array( 'msg' ) ) ); 
  114. wp_safe_redirect( $url ); 
  115. exit; 
  116.  
  117. /** 
  118. * We allow two ways to modify the default Admin-Capability setting: 
  119. * 
  120. * Either by defining the constant in wp-config or by using the filter. 
  121. * The constant takes priority over the filter. 
  122. * 
  123. * @since 1.0.0 
  124. */ 
  125. if ( defined( 'MS_ADMIN_CAPABILITY' ) && MS_ADMIN_CAPABILITY ) { 
  126. $this->capability = MS_ADMIN_CAPABILITY; 
  127. } else { 
  128. $this->capability = apply_filters( 
  129. 'ms_admin_user_capability',  
  130. $this->capability 
  131. ); 
  132.  
  133. // Create core controllers that are available on every page. 
  134. $this->model = MS_Factory::load( 'MS_Model_Plugin' ); 
  135. $this->dialogs = MS_Factory::load( 'MS_Controller_Dialog' ); 
  136. $this->controllers['widget'] = MS_Factory::load( 'MS_Controller_Widget' ); 
  137. $this->controllers['membership'] = MS_Factory::load( 'MS_Controller_Membership' ); 
  138. $this->controllers['protection'] = MS_Factory::load( 'MS_Controller_Protection' ); 
  139. $this->controllers['rule'] = MS_Factory::load( 'MS_Controller_Rule' ); 
  140. $this->controllers['member'] = MS_Factory::load( 'MS_Controller_Member' ); 
  141. $this->controllers['billing'] = MS_Factory::load( 'MS_Controller_Billing' ); 
  142. $this->controllers['addon'] = MS_Factory::load( 'MS_Controller_Addon' ); 
  143. $this->controllers['pages'] = MS_Factory::load( 'MS_Controller_Pages' ); 
  144. $this->controllers['settings'] = MS_Factory::load( 'MS_Controller_Settings' ); 
  145. $this->controllers['communication'] = MS_Factory::load( 'MS_Controller_Communication' ); 
  146. $this->controllers['gateway'] = MS_Factory::load( 'MS_Controller_Gateway' ); 
  147. $this->controllers['admin_bar'] = MS_Factory::load( 'MS_Controller_Adminbar' ); 
  148. $this->controllers['membership_metabox'] = MS_Factory::load( 'MS_Controller_Metabox' ); 
  149. $this->controllers['membership_shortcode'] = MS_Factory::load( 'MS_Controller_Shortcode' ); 
  150. $this->controllers['frontend'] = MS_Factory::load( 'MS_Controller_Frontend' ); 
  151. $this->controllers['import'] = MS_Factory::load( 'MS_Controller_Import' ); 
  152. $this->controllers['help'] = MS_Factory::load( 'MS_Controller_Help' ); 
  153.  
  154. // API should be the last Controller to create. 
  155. $this->controllers['api'] = MS_Controller_Api::instance(); 
  156.  
  157. // Load the template-tags. 
  158. require_once MS_Plugin::instance()->dir . 'app/template/template-tags.php'; 
  159.  
  160. // Register all available styles and scripts. Nothing is enqueued. 
  161. $this->add_action( 'wp_loaded', 'wp_loaded' ); 
  162.  
  163. // Setup plugin admin UI. 
  164. if( ! is_multisite() ) 
  165. $this->add_action( 'admin_menu', 'add_menu_pages' ); 
  166. else 
  167. if ( MS_Plugin::is_network_wide() ) { 
  168. $this->add_action( 'network_admin_menu', 'add_menu_pages' ); 
  169. $this->add_action( 'admin_menu', 'add_menu_pages' ); 
  170.  
  171. // Select the right page to display. 
  172. $this->add_action( 'admin_init', 'route_submenu_request' ); 
  173.  
  174. // This will do the ADMIN-SIDE initialization of the controllers 
  175. $this->add_action( 'ms_plugin_admin_setup', 'run_admin_init' ); 
  176.  
  177. // Changes the current themes "single" template to the invoice form when an invoice is displayed. 
  178. $this->add_filter( 'single_template', 'custom_single_template' ); 
  179. $this->add_filter( 'page_template', 'custom_page_template' ); 
  180.  
  181. // Register styles and javascripts for use in front-end 
  182. $this->add_action( 'ms_register_public_scripts', 'register_public_scripts' ); 
  183. $this->add_action( 'ms_register_public_scripts', 'register_public_styles' ); 
  184. $this->add_action( 'wp_enqueue_scripts', 'enqueue_plugin_styles' ); 
  185. $this->add_action( 'wp_enqueue_scripts', 'enqueue_plugin_scripts' ); 
  186.  
  187. /** 
  188. * Creates all the plugin controllers and initialize stuff. 
  189. * 
  190. * This is done after admin_menu (when in admin site) or 
  191. * after setup_theme (on front-end) 
  192. * 
  193. * @since 1.0.0 
  194. */ 
  195. public function run_admin_init() { 
  196. if ( ! is_admin() && ! is_network_admin() ) { return; } 
  197.  
  198. /** 
  199. * This function is used to redirect the user to special kind of page 
  200. * that is not available via the menu. 
  201. */ 
  202. $this->check_special_view(); 
  203.  
  204. foreach ( $this->controllers as $obj ) { 
  205. $obj->admin_init(); 
  206.  
  207. // Register styles and javascripts for use in admin-side 
  208. $this->run_action( 'ms_register_admin_scripts', 'register_admin_scripts' ); 
  209. $this->run_action( 'ms_register_admin_scripts', 'register_admin_styles' ); 
  210. $this->run_action( 'admin_enqueue_scripts', 'enqueue_plugin_admin_styles' ); 
  211. $this->run_action( 'admin_enqueue_scripts', 'enqueue_plugin_admin_scripts' ); 
  212.  
  213. /** 
  214. * If a special view is active then we ensure that it is displayed now. 
  215. * 
  216. * A special view is not accessible via the normal menu structure, like 
  217. * a Migration assistant or an overview page after updating the plugin. 
  218. * 
  219. * Special views can be set/reset/checked via these functions: 
  220. * MS_Model_Settings::set_special_view( 'name' ); 
  221. * MS_Model_Settings::get_special_view(); 
  222. * MS_Model_Settings::reset_special_view(); 
  223. * 
  224. * @since 1.0.0 
  225. */ 
  226. protected function check_special_view() { 
  227. $view_name = MS_Model_Settings::get_special_view(); 
  228.  
  229. if ( ! $view_name ) { return; } 
  230.  
  231. $view = MS_Factory::load( $view_name ); 
  232. $view->enqueue_scripts(); 
  233.  
  234. // Modify the main menu to handle our special_view for default item. 
  235. add_submenu_page( 
  236. self::$base_slug,  
  237. 'Membership 2',  
  238. 'Membership 2',  
  239. $this->capability,  
  240. self::$base_slug,  
  241. array( $this, 'handle_special_view' ) 
  242. ); 
  243.  
  244. /** 
  245. * Function is only called when a special view is defined. This function 
  246. * will load that view and display it. 
  247. * 
  248. * @since 1.0.0 
  249. */ 
  250. public function handle_special_view() { 
  251. $view_name = MS_Model_Settings::get_special_view(); 
  252. $view = MS_Factory::load( $view_name ); 
  253.  
  254. echo $view->to_html(); 
  255.  
  256. /** 
  257. * Returns the WordPress hook that identifies a Membership2 admin page. 
  258. * 
  259. * Important: In order for this function to work as expected it needs to 
  260. * be called *after* the admin-menu was registered! 
  261. * 
  262. * @since 1.0.0 
  263. * @param string $subpage 
  264. * @return string The internal hook name 
  265. */ 
  266. public static function admin_page_hook( $subpage = '' ) { 
  267. if ( empty( $subpage ) ) { 
  268. $plugin_page = self::MENU_SLUG; 
  269. } else { 
  270. $plugin_page = self::MENU_SLUG . '-' . $subpage; 
  271.  
  272. if ( ! function_exists( 'get_plugin_page_hookname' ) ) { 
  273. require_once ABSPATH . 'wp-admin/includes/plugin.php'; 
  274.  
  275. $the_parent = 'admin.php'; 
  276. $hook = get_plugin_page_hookname( $plugin_page, $the_parent ); 
  277.  
  278. return $hook; 
  279.  
  280. /** 
  281. * Register scripts and styles 
  282. * 
  283. * @since 1.0.0 
  284. */ 
  285. public function wp_loaded() { 
  286. if ( is_admin() || is_network_admin() ) { 
  287. do_action( 'ms_register_admin_scripts' ); 
  288. } else { 
  289. do_action( 'ms_register_public_scripts' ); 
  290.  
  291. /** 
  292. * Adds Dashboard navigation menus. 
  293. * 
  294. * @since 1.0.0 
  295. */ 
  296. public function add_menu_pages() { 
  297. global $submenu; 
  298. $limited_mode = false; 
  299.  
  300. $view = MS_Model_Settings::get_special_view(); 
  301. if ( $view ) { 
  302. // A special view is displayed. Do not display other menu items. 
  303. $pages = array(); 
  304.  
  305. $limited_mode = true; 
  306. } elseif ( MS_Plugin::is_wizard() ) { 
  307. // Submenus definition: Wizard mode 
  308. $pages = $this->get_setup_menu_pages(); 
  309.  
  310. $limited_mode = true; 
  311. } else { 
  312. // Submenus definition: Normal mode 
  313. $pages = $this->get_default_menu_pages(); 
  314.  
  315. if ( MS_Plugin::is_network_wide() && ! is_network_admin() ) { 
  316. $limited_mode = true; 
  317.  
  318. /** 
  319. * Allow Add-ons and other plugins to add menu pages. 
  320. * 
  321. * A menu item is defined by an array containing the following members: 
  322. * 'title' => '...',  
  323. * 'slug' => '...',  
  324. * 'function' => callback 
  325. * 
  326. * @var array 
  327. */ 
  328. $pages = apply_filters( 
  329. 'ms_plugin_menu_pages',  
  330. $pages,  
  331. $limited_mode,  
  332. $this 
  333. ); 
  334.  
  335. $page_keys = array_keys( $pages ); 
  336. $slug = ''; 
  337. if ( isset( $page_keys[0] ) && $pages[ $page_keys[0] ] ) { 
  338. $slug = $pages[ $page_keys[0] ]['slug']; 
  339. if ( empty( $slug ) ) { 
  340. self::$base_slug = self::MENU_SLUG; 
  341. } else { 
  342. self::$base_slug = self::MENU_SLUG . '-' . $slug; 
  343.  
  344. /** 
  345. * Create primary menu item: Membership. 
  346. * 
  347. * The menu title is not translatable because of a bug in WordPress core 
  348. * https://core.trac.wordpress.org/ticket/18857 
  349. * Until this bug is closed the title (2nd argument) can't be translated 
  350. */ 
  351. add_menu_page( 
  352. 'Membership 2', // no i18n! 
  353. 'Membership 2', // no i18n! 
  354. $this->capability,  
  355. self::$base_slug,  
  356. null,  
  357. 'dashicons-lock' 
  358. ); 
  359.  
  360. // Create submenus 
  361. foreach ( $pages as $page ) { 
  362. if ( ! is_array( $page ) ) { continue; } 
  363.  
  364. if ( empty( $page['link'] ) ) { 
  365. $menu_link = false; 
  366. } else { 
  367. $menu_link = $page['link']; 
  368.  
  369. $slug = self::MENU_SLUG; 
  370. if ( ! empty( $page['slug'] ) ) { 
  371. $slug .= '-' . $page['slug']; 
  372.  
  373. $page_title = apply_filters( 'ms_admin_submenu_page_title_' . $slug, $page['title'], $slug, self::$base_slug ); 
  374. $menu_title = apply_filters( 'ms_admin_submenu_menu_title_' . $slug, $page['title'], $slug, self::$base_slug ); 
  375. $capability = apply_filters( 'ms_admin_submenu_capability_' . $slug, $this->capability, $slug, self::$base_slug ); 
  376. $submenu_slug = apply_filters( 'ms_admin_submenu_slug_' . $slug, $slug, self::$base_slug ); 
  377.  
  378. add_submenu_page( 
  379. self::$base_slug,  
  380. strip_tags( $page_title ),  
  381. $menu_title,  
  382. $capability,  
  383. $submenu_slug,  
  384. array( $this, 'handle_submenu_request' ) 
  385. ); 
  386.  
  387. /** 
  388. * WordPress does not support absolute URLs in the admin-menu. 
  389. * So we have to manny modify the menu-link href value if our slug 
  390. * is an absolute URL. 
  391. */ 
  392. if ( $menu_link ) { 
  393. $item = end( $submenu[ self::$base_slug ] ); 
  394. $key = key( $submenu[ self::$base_slug ] ); 
  395. $submenu[ self::$base_slug ][ $key ][2] = $menu_link; 
  396.  
  397. do_action( 'ms_controller_plugin_add_menu_pages', $this ); 
  398.  
  399. // Setup the rest of the plugin after the menu was registered. 
  400. do_action( 'ms_plugin_admin_setup' ); 
  401.  
  402. /** 
  403. * Returns the admin menu items for setting up the plugin. 
  404. * Helper function used by add_menu_pages 
  405. * 
  406. * @since 1.0.0 
  407. * @return array 
  408. */ 
  409. private function get_setup_menu_pages() { 
  410. $pages = array( 
  411. 'setup' => array( 
  412. 'title' => __( 'Set-up', 'membership2' ),  
  413. 'slug' => '',  
  414. ),  
  415. ); 
  416.  
  417. $step = $this->controllers['membership']->get_step(); 
  418. if ( MS_Controller_Membership::STEP_ADD_NEW == $step ) { 
  419. $pages['setup']['slug'] = 'setup'; 
  420.  
  421. $pages[ self::MENU_SLUG ] = array( 
  422. 'title' => __( 'Protection Rules', 'membership2' ),  
  423. 'slug' => '',  
  424. ); 
  425.  
  426. return $pages; 
  427.  
  428. /** 
  429. * Returns the default admin menu items for Membership2. 
  430. * Helper function used by add_menu_pages 
  431. * 
  432. * @since 1.0.0 
  433. * @return array 
  434. */ 
  435. private function get_default_menu_pages() { 
  436. $show_billing = false; 
  437.  
  438. $pages = array( 
  439. 'memberships' => array( 
  440. 'title' => __( 'Memberships', 'membership2' ),  
  441. 'slug' => '',  
  442. ),  
  443. 'protected-content' => array( 
  444. 'title' => __( 'Protection Rules', 'membership2' ),  
  445. 'slug' => 'protection',  
  446. ),  
  447. 'members' => array( 
  448. 'title' => __( 'All Members', 'membership2' ),  
  449. 'slug' => 'members',  
  450. ),  
  451. 'add-member' => array( 
  452. 'title' => __( 'Add Member', 'membership2' ),  
  453. 'slug' => 'add-member',  
  454. ),  
  455. 'billing' => false,  
  456. 'addon' => array( 
  457. 'title' => __( 'Add-ons', 'membership2' ),  
  458. 'slug' => 'addon',  
  459. ),  
  460. 'settings' => array( 
  461. 'title' => __( 'Settings', 'membership2' ),  
  462. 'slug' => 'settings',  
  463. ),  
  464. 'help' => array( 
  465. 'title' => __( 'Help', 'membership2' ),  
  466. 'slug' => 'help',  
  467. ),  
  468. ); 
  469.  
  470. $show_billing = MS_Model_Membership::have_paid_membership(); 
  471.  
  472. if ( $show_billing ) { 
  473. $bill_count = MS_Model_Invoice::get_unpaid_invoice_count( null, true ); 
  474.  
  475. if ( $bill_count > 0 ) { 
  476. $msg = '%1$s <span class="awaiting-mod count-%3$s"><span class="pending-count"><i class="hidden">(</i>%2$s<i class="hidden">)</i></span></span>'; 
  477. } else { 
  478. $msg = '%1$s'; 
  479.  
  480. $pages['billing'] = array( 
  481. 'title' => sprintf( 
  482. $msg,  
  483. __( 'Billing', 'membership2' ),  
  484. $bill_count,  
  485. sanitize_html_class( $bill_count, '0' ) 
  486. ),  
  487. 'slug' => 'billing',  
  488. ); 
  489.  
  490. /** 
  491. * This condition checks if the site has configured some payment 
  492. * gateways - if not then users cannot sign up for a membership. 
  493. * Show a notice if no payment gateway is configured/activated. 
  494. */ 
  495. $gateways = MS_Model_Gateway::get_gateways( true ); 
  496. $payment_possible = false; 
  497. foreach ( $gateways as $key => $gateway ) { 
  498. if ( 'free' == $key ) { continue; } 
  499. $payment_possible = true; 
  500. break; 
  501. if ( ! $payment_possible ) { 
  502. lib3()->ui->admin_message( 
  503. sprintf( 
  504. __( 'Oops, looks like you did not activate a payment gateway yet.<br />You need to set up and activate at least one gateway, otherwise your members cannot sign up to a paid membership.<br />%sFix this now »%s', 'membership2' ),  
  505. '<a href="' . self::get_admin_url( 'settings', array( 'tab' => MS_Controller_Settings::TAB_PAYMENT ) ) . '">',  
  506. '</a>' 
  507. ),  
  508. 'err' 
  509. ); 
  510.  
  511. return $pages; 
  512.  
  513. /** 
  514. * Handles all menu-items and calls the correct callback function. 
  515. * 
  516. * We introduce this routing function to monitor all menu-item calls so we 
  517. * can make sure that network-wide protection loads the correct blog or 
  518. * admin-area before displaing the page. 
  519. * 
  520. * This function will only handle submenu items of the Membership2 menu! 
  521. * 
  522. * @since 1.0.0 
  523. */ 
  524. public function route_submenu_request() { 
  525. global $submenu; 
  526. $handler = null; 
  527. $handle_it = false; 
  528.  
  529. if ( ! isset( $_GET['page'] ) ) { return; } 
  530. if ( $_GET['page'] === self::$base_slug ) { 
  531. $handle_it = true; 
  532. } elseif ( isset( $submenu[ self::$base_slug ] ) ) { 
  533. foreach ( $submenu[ self::$base_slug ] as $item ) { 
  534. if ( $_GET['page'] === $item[2] ) { $handle_it = true; break; } 
  535. if ( ! $handle_it ) { return; } 
  536.  
  537. if ( MS_Plugin::is_wizard() ) { 
  538. $step_add = MS_Controller_Membership::STEP_ADD_NEW == MS_Plugin::instance()->settings->wizard_step; 
  539.  
  540. if ( ! $step_add || self::is_page( 'setup' ) ) { 
  541. $handler = array( 
  542. 'any',  
  543. array( $this->controllers['membership'], 'admin_page_router' ),  
  544. ); 
  545. } else { 
  546. $handler = array( 
  547. 'site',  
  548. array( $this->controllers['protection'], 'admin_page' ),  
  549. ); 
  550. } else { 
  551. if ( self::is_page( '' ) ) { 
  552. $handler = array( 
  553. 'network',  
  554. array( $this->controllers['membership'], 'admin_page_router' ),  
  555. ); 
  556. } elseif ( self::is_page( 'protection' ) ) { 
  557. $handler = array( 
  558. 'site',  
  559. array( $this->controllers['protection'], 'admin_page' ),  
  560. ); 
  561. } elseif ( self::is_page( 'members' ) ) { 
  562. $handler = array( 
  563. 'network',  
  564. array( $this->controllers['member'], 'admin_page' ),  
  565. ); 
  566. } elseif ( self::is_page( 'add-member' ) ) { 
  567. $handler = array( 
  568. 'network',  
  569. array( $this->controllers['member'], 'admin_page_editor' ),  
  570. ); 
  571. } elseif ( self::is_page( 'addon' ) ) { 
  572. $handler = array( 
  573. 'network',  
  574. array( $this->controllers['addon'], 'admin_page' ),  
  575. ); 
  576. } elseif ( self::is_page( 'settings' ) ) { 
  577. $handler = array( 
  578. 'network',  
  579. array( $this->controllers['settings'], 'admin_page' ),  
  580. ); 
  581. } elseif ( self::is_page( 'help' ) ) { 
  582. $handler = array( 
  583. 'any',  
  584. array( $this->controllers['help'], 'admin_page' ),  
  585. ); 
  586. } elseif ( self::is_page( 'billing' ) ) { 
  587. $handler = array( 
  588. 'network',  
  589. array( $this->controllers['billing'], 'admin_page' ),  
  590. ); 
  591.  
  592. /** 
  593. * Filter that allows Add-ons to add their own sub-menu handlers. 
  594. * 
  595. * @since 1.0.0 
  596. */ 
  597. $handler = apply_filters( 
  598. 'ms_route_submenu_request',  
  599. $handler,  
  600. $this 
  601. ); 
  602.  
  603. // Provide a fallback handler in case we could not identify the handler. 
  604. if ( ! $handler ) { 
  605. $handler = array( 
  606. 'network',  
  607. array( $this->controllers['membership'], 'membership_admin_page_router' ),  
  608. ); 
  609.  
  610. // Handle the target attribute specified in $handler[0] 
  611. if ( MS_Plugin::is_network_wide() && 'any' != $handler[0] ) { 
  612. $redirect = false; 
  613. $admin_script = 'admin.php?' . $_SERVER['QUERY_STRING']; 
  614.  
  615. if ( 'network' == $handler[0] && ! is_network_admin() ) { 
  616. $redirect = network_admin_url( $admin_script ); 
  617. } elseif ( 'site' == $handler[0] && is_network_admin() ) { 
  618. $redirect = admin_url( $admin_script ); 
  619.  
  620. if ( $redirect ) { 
  621. if ( headers_sent() ) { 
  622. echo '<script>location.href=' . json_encode( $redirect ) . ';</script>'; 
  623. } else { 
  624. wp_safe_redirect( $redirect ); 
  625.  
  626. exit; 
  627.  
  628. $this->menu_handler = $handler; 
  629.  
  630. /** 
  631. * Simply calls the menu-handler callback function. 
  632. * 
  633. * This function was determined by the previous call to 
  634. * self::route_submenu_request() during the admin_init hook. 
  635. * 
  636. * @since 1.0.0 
  637. */ 
  638. public function handle_submenu_request() { 
  639. if ( ! empty( $this->menu_handler ) ) { 
  640. // This function will actually render the requested page! 
  641. call_user_func( $this->menu_handler[1] ); 
  642.  
  643. /** 
  644. * Checks if the current user is on the specified Membership2 admin page. 
  645. * 
  646. * @since 1.0.0 
  647. * @param string $slug The membership2 slug (without the menu-slug prefix) 
  648. * @return bool 
  649. */ 
  650. public static function is_page( $slug ) { 
  651. $curpage = false; 
  652. if ( isset( $_REQUEST['page'] ) ) { 
  653. $curpage = sanitize_html_class( $_REQUEST['page'] ); 
  654.  
  655. if ( empty( $slug ) ) { 
  656. $slug = self::$base_slug; 
  657. } else { 
  658. $slug = self::MENU_SLUG . '-' . $slug; 
  659.  
  660. return $curpage == $slug; 
  661.  
  662. /** 
  663. * Checks if the current user is on any Membership2 admin page. 
  664. * 
  665. * @since 1.0.0 
  666. * @return bool 
  667. */ 
  668. public static function is_admin_page( ) { 
  669. $curpage = false; 
  670. if ( isset( $_REQUEST['page'] ) ) { 
  671. $curpage = sanitize_html_class( $_REQUEST['page'] ); 
  672.  
  673. $slug = self::$base_slug; 
  674.  
  675. return (strpos($curpage, $slug) !== false); 
  676. }  
  677.  
  678. /** 
  679. * Get admin url. 
  680. * 
  681. * @since 1.0.0 
  682. * @param string $slug Optional. Slug of the admin page, if empty the link 
  683. * points to the main admin page. 
  684. * @return string The full URL to the admin page. 
  685. */ 
  686. public static function get_admin_url( $slug = '', $args = null ) { 
  687. $base_slug = self::$base_slug; 
  688.  
  689. // These slugs are opened in network-admin for network-wide protection. 
  690. $global_slugs = array( 
  691. 'memberships',  
  692. 'addon',  
  693. 'settings',  
  694. ); 
  695.  
  696. // Determine if the slug is opened in network-admin or site admin. 
  697. $network_slug = MS_Plugin::is_network_wide() 
  698. && ( in_array( $slug, $global_slugs ) || is_network_admin() ); 
  699.  
  700. if ( $network_slug ) { 
  701. $base_slug = self::MENU_SLUG; 
  702. if ( 'memberships' === $slug ) { $slug = ''; } 
  703.  
  704. if ( 'MENU_SLUG' == $slug ) { 
  705. $slug = self::MENU_SLUG; 
  706. } elseif ( empty( $slug ) ) { 
  707. $slug = self::$base_slug; 
  708. } else { 
  709. $slug = self::MENU_SLUG . '-' . $slug; 
  710.  
  711. if ( ! $slug ) { 
  712. $slug = self::MENU_SLUG; 
  713.  
  714. if ( $network_slug ) { 
  715. $url = network_admin_url( 'admin.php?page=' . $slug ); 
  716. } else { 
  717. $url = admin_url( 'admin.php?page=' . $slug ); 
  718.  
  719. if ( $args ) { 
  720. $url = esc_url_raw( add_query_arg( $args, $url ) ); 
  721.  
  722. return apply_filters( 
  723. 'ms_controller_plugin_get_admin_url',  
  724. $url 
  725. ); 
  726.  
  727. /** 
  728. * Get admin settings url. 
  729. * 
  730. * @since 1.0.0 
  731. * 
  732. */ 
  733. public static function get_admin_settings_url() { 
  734. return apply_filters( 
  735. 'ms_controller_plugin_get_admin_url',  
  736. admin_url( 'admin.php?page=' . self::MENU_SLUG . '-settings' ) 
  737. ); 
  738.  
  739. /** 
  740. * Use a special template for our custom post types. 
  741. * 
  742. * Invoices: 
  743. * Replaces the themes "Single" template with our invoice template when an 
  744. * invoice is displayed. The theme can override this by defining its own 
  745. * m2-invoice.php / single-ms_invoice.php template. 
  746. * 
  747. * You can even specifiy a membership ID in the page template to create 
  748. * a custom invoice form based on the membership that is billed. 
  749. * Example: 
  750. * m2-invoice-100.php (Invoice form for membership 100) 
  751. * 
  752. * @since 1.0.0 
  753. * @see filter single_template 
  754. * 
  755. * @param string $template The template path to filter. 
  756. * @return string The template path. 
  757. */ 
  758. public function custom_single_template( $default_template ) { 
  759. global $post; 
  760. $template = ''; 
  761.  
  762. // Checks for invoice single template. 
  763. if ( $post->post_type == MS_Model_Invoice::get_post_type() ) { 
  764. $invoice = MS_Factory::load( 'MS_Model_Invoice', $post->ID ); 
  765.  
  766. // First look for themes 'm2-invoice-100.php' template (membership ID). 
  767. $template = get_query_template( 
  768. 'm2',  
  769. 'm2-invoice-' . $invoice->membership_id . '.php' 
  770. ); 
  771.  
  772. // Fallback to themes 'm2-invoice.php' template. 
  773. if ( ! $template ) { 
  774. $template = get_query_template( 
  775. 'm2',  
  776. 'm2-invoice.php' 
  777. ); 
  778.  
  779. // Second look for themes 'single-ms_invoice.php' template. 
  780. if ( ! $template && strpos( $default_template, '/single-ms_invoice.php' ) ) { 
  781. $template = $default_template; 
  782.  
  783. // Last: Use the default M2 invoice template. 
  784. if ( ! $template ) { 
  785. $invoice_template = apply_filters( 
  786. 'ms_controller_plugin_invoice_template',  
  787. MS_Plugin::instance()->dir . 'app/template/single-ms_invoice.php' 
  788. ); 
  789.  
  790. if ( file_exists( $invoice_template ) ) { 
  791. $template = $invoice_template; 
  792.  
  793. if ( ! $template ) { 
  794. $template = $default_template; 
  795.  
  796. return $template; 
  797.  
  798. /** 
  799. * Use a special template for our membership pages. 
  800. * 
  801. * Recognized templates are: 
  802. * m2-memberships.php 
  803. * m2-protected-content.php 
  804. * m2-account.php 
  805. * m2-register.php 
  806. * m2-registration-complete.php 
  807. * 
  808. * Note that certain pages receive a membership-ID when they are loaded 
  809. * (like the m2-registration-complete or m2-register pages). 
  810. * You can even specify special pages for each membership. 
  811. * 
  812. * Example: 
  813. * m2-register-100.php (register form for membership 100) 
  814. * m2-registration-complete-100.php (thank you page for membership 100) 
  815. * 
  816. * @since 1.0.1.0 
  817. * @see filter page_template 
  818. * 
  819. * @param string $template The default template path to filter. 
  820. * @return string The custom template path. 
  821. */ 
  822. public function custom_page_template( $default_template ) { 
  823. $template = ''; 
  824.  
  825. // Checks for invoice single template. 
  826. if ( $type = MS_Model_Pages::is_membership_page() ) { 
  827. $membership_id = apply_filters( 
  828. 'ms_detect_membership_id',  
  829. 0,  
  830. true,  
  831. true 
  832. ); 
  833.  
  834. if ( $membership_id ) { 
  835. $template = get_query_template( 
  836. 'm2',  
  837. 'm2-' . $type . '-' . $membership_id . '.php' 
  838. ); 
  839.  
  840. if ( ! $template ) { 
  841. $template = get_query_template( 
  842. 'm2',  
  843. 'm2-' . $type . '.php' 
  844. ); 
  845.  
  846. if ( ! $template ) { 
  847. $template = $default_template; 
  848.  
  849. return $template; 
  850.  
  851. /** 
  852. * Returns information on current memberships and access to current page. 
  853. * 
  854. * Wrapper for MS_Model_Plugin->get_access_info() 
  855. * 
  856. * @since 1.0.0 
  857. * @return array 
  858. */ 
  859. public function get_access_info() { 
  860. return $this->model->get_access_info(); 
  861.  
  862. /** 
  863. * Returns a list with complete admin menu items. 
  864. * 
  865. * Wrapper for MS_Model_Plugin->get_admin_menu() 
  866. * 
  867. * @since 1.0.0 
  868. * @return array 
  869. */ 
  870. public function get_admin_menu() { 
  871. return $this->model->get_admin_menu(); 
  872.  
  873. /** 
  874. * Register scripts that are used on the dashboard. 
  875. * 
  876. * @since 1.0.0 
  877. */ 
  878. public function register_admin_scripts() { 
  879. $plugin_url = MS_Plugin::instance()->url; 
  880. $version = MS_Plugin::instance()->version; 
  881.  
  882. // The main plugin script. 
  883. // Dont add dependants that hav not already loaded - Paul Kevin 
  884. wp_register_script( 
  885. 'ms-admin',  
  886. $plugin_url . 'app/assets/js/ms-admin.js',  
  887. array( 'jquery' ), $version 
  888. ); 
  889.  
  890. wp_register_script( 
  891. 'm2-jquery-plugins',  
  892. $plugin_url . 'app/assets/js/jquery.m2.plugins.js',  
  893. array( 'jquery' ), $version 
  894. ); 
  895.  
  896. if( self::is_admin_page( ) ) { 
  897. wp_register_script( 
  898. 'jquery-validate',  
  899. $plugin_url . 'app/assets/js/jquery.m2.validate.js',  
  900. array( 'jquery' ), $version 
  901. ); 
  902.  
  903. /** 
  904. * Register styles that are used on the dashboard. 
  905. * 
  906. * @since 1.0.0 
  907. */ 
  908. public function register_admin_styles() { 
  909. $plugin_url = MS_Plugin::instance()->url; 
  910. $version = MS_Plugin::instance()->version; 
  911.  
  912. // The main plugin style. 
  913. wp_register_style( 
  914. 'ms-admin-styles',  
  915. $plugin_url . 'app/assets/css/ms-admin.css',  
  916. null, $version 
  917. ); 
  918.  
  919. /** 
  920. * Register scripts that are used on the front-end. 
  921. * 
  922. * @since 1.0.0 
  923. */ 
  924. public function register_public_scripts() { 
  925. $plugin_url = MS_Plugin::instance()->url; 
  926. $version = MS_Plugin::instance()->version; 
  927.  
  928. // The main plugin script. 
  929. wp_register_script( 
  930. 'ms-admin',  
  931. $plugin_url . 'app/assets/js/ms-admin.js',  
  932. array( 'jquery', 'jquery-validate', 'm2-jquery-plugins' ), $version 
  933. ); 
  934. wp_register_script( 
  935. 'ms-ajax-login',  
  936. $plugin_url . 'app/assets/js/ms-public-ajax.js',  
  937. array( 'jquery' ), $version, true // last param forces script to load in footer 
  938. ); 
  939. wp_register_script( 
  940. 'ms-public',  
  941. $plugin_url . 'app/assets/js/ms-public.js',  
  942. array( 'jquery' ), $version 
  943. ); 
  944.  
  945. wp_register_script( 
  946. 'm2-jquery-plugins',  
  947. $plugin_url . 'app/assets/js/jquery.m2.plugins.js',  
  948. array( 'jquery' ), $version 
  949. ); 
  950. wp_register_script( 
  951. 'jquery-validate',  
  952. $plugin_url . 'app/assets/js/jquery.m2.validate.js',  
  953. array( 'jquery' ), $version 
  954. ); 
  955.  
  956. /** 
  957. * Register styles that are used on the front-end. 
  958. * 
  959. * @since 1.0.0 
  960. */ 
  961. public function register_public_styles() { 
  962. $plugin_url = MS_Plugin::instance()->url; 
  963. $version = MS_Plugin::instance()->version; 
  964.  
  965. // The main plugin style. 
  966. wp_register_style( 
  967. 'ms-styles',  
  968. $plugin_url . 'app/assets/css/ms-public.css',  
  969. array(),  
  970. $version 
  971. ); 
  972.  
  973. /** 
  974. * Adds CSS for Membership settings pages. 
  975. * 
  976. * @since 1.0.0 
  977. */ 
  978. public function enqueue_plugin_admin_styles() { 
  979. lib3()->ui->css( 'ms-admin-styles' ); 
  980. lib3()->ui->add( 'core' ); 
  981. lib3()->ui->add( 'select' ); 
  982. lib3()->ui->add( 'fontawesome' ); 
  983.  
  984. /** 
  985. * Adds CSS for Membership pages used in the front end. 
  986. * 
  987. * @since 1.0.0 
  988. * 
  989. * @return void 
  990. */ 
  991. public function enqueue_plugin_styles() { 
  992. // Front-End styles are enqueued by MS_Controller_Frontend. 
  993.  
  994. /** 
  995. * Register JavasSript for Membership settings pages. 
  996. * 
  997. * @since 1.0.0 
  998. * 
  999. * @return void 
  1000. */ 
  1001. public function enqueue_plugin_admin_scripts() { 
  1002. //Missing scripts needed for the meta box 
  1003. lib3()->ui->js( 'm2-jquery-plugins' ); 
  1004. if( self::is_admin_page( ) ) { 
  1005. lib3()->ui->js( 'jquery-validate' ); 
  1006. lib3()->ui->js( 'ms-admin-scripts' ); 
  1007. lib3()->ui->add( 'select' ); 
  1008.  
  1009. /** 
  1010. * Adds JavasSript for Membership pages used in the front end. 
  1011. * 
  1012. * @since 1.0.0 
  1013. * 
  1014. * @return void 
  1015. */ 
  1016. public function enqueue_plugin_scripts() { 
  1017. // Front-End scripts are enqueued by MS_Controller_Frontend. 
  1018.  
  1019. /** 
  1020. * Adds a javascript to the page that will translate the jQuery validator 
  1021. * messages. 
  1022. * 
  1023. * @since 1.0.0 
  1024. */ 
  1025. static public function translate_jquery_validator() { 
  1026. ob_start(); 
  1027. ?> 
  1028. jQuery.extend( jQuery.validator.messages, { 
  1029. required: "<?php _e( 'This field is required.', 'membership2' ); ?>",  
  1030. remote: "<?php _e( 'Please fix this field.', 'membership2' ); ?>",  
  1031. email: "<?php _e( 'Please enter a valid email address.', 'membership2' ); ?>",  
  1032. url: "<?php _e( 'Please enter a valid URL.', 'membership2' ); ?>",  
  1033. date: "<?php _e( 'Please enter a valid date.', 'membership2' ); ?>",  
  1034. dateISO: "<?php _e( 'Please enter a valid date ( ISO ).', 'membership2' ); ?>",  
  1035. number: "<?php _e( 'Please enter a valid number.', 'membership2' ); ?>",  
  1036. digits: "<?php _e( 'Please enter only digits.', 'membership2' ); ?>",  
  1037. creditcard: "<?php _e( 'Please enter a valid credit card number.', 'membership2' ); ?>",  
  1038. equalTo: "<?php _e( 'Please enter the same value again.', 'membership2' ); ?>",  
  1039. maxlength: jQuery.validator.format( "<?php _e( 'Please enter no more than {0} characters.', 'membership2' ); ?>" ),  
  1040. minlength: jQuery.validator.format( "<?php _e( 'Please enter at least {0} characters.', 'membership2' ); ?>" ),  
  1041. rangelength: jQuery.validator.format( "<?php _e( 'Please enter a value between {0} and {1} characters long.', 'membership2' ); ?>" ),  
  1042. range: jQuery.validator.format( "<?php _e( 'Please enter a value between {0} and {1}.', 'membership2' ); ?>" ),  
  1043. max: jQuery.validator.format( "<?php _e( 'Please enter a value less than or equal to {0}.', 'membership2' ); ?>" ),  
  1044. min: jQuery.validator.format( "<?php _e( 'Please enter a value greater than or equal to {0}.', 'membership2' ); ?>" ) 
  1045. }); 
  1046. <?php 
  1047. $script = ob_get_clean(); 
  1048. lib3()->ui->script( $script ); 
.