BP_Group_Extension

API for creating group extensions without having to hardcode the content into the theme.

Defined (1)

The class is defined in the following location(s).

/bp-groups/classes/class-bp-group-extension.php  
  1. class BP_Group_Extension { 
  2.  
  3. /** Public ************************************************************/ 
  4.  
  5. /** 
  6. * Information about this extension's screens. 
  7. * @since 1.8.0 
  8. * @var array 
  9. */ 
  10. public $screens = array(); 
  11.  
  12. /** 
  13. * The name of the extending class. 
  14. * @since 1.8.0 
  15. * @var string 
  16. */ 
  17. public $class_name = ''; 
  18.  
  19. /** 
  20. * A ReflectionClass object of the current extension. 
  21. * @since 1.8.0 
  22. * @var ReflectionClass 
  23. */ 
  24. public $class_reflection = null; 
  25.  
  26. /** 
  27. * Parsed configuration parameters for the extension. 
  28. * @since 1.8.0 
  29. * @var array 
  30. */ 
  31. public $params = array(); 
  32.  
  33. /** 
  34. * Raw config params, as passed by the extending class. 
  35. * @since 2.1.0 
  36. * @var array 
  37. */ 
  38. public $params_raw = array(); 
  39.  
  40. /** 
  41. * The ID of the current group. 
  42. * @since 1.8.0 
  43. * @var int 
  44. */ 
  45. public $group_id = 0; 
  46.  
  47. /** 
  48. * The slug of the current extension. 
  49. * @since 1.1.0 
  50. * @var string 
  51. */ 
  52. public $slug = ''; 
  53.  
  54. /** 
  55. * The translatable name of the current extension. 
  56. * @since 1.1.0 
  57. * @var string 
  58. */ 
  59. public $name = ''; 
  60.  
  61. /** 
  62. * The visibility of the extension tab. 'public' or 'private'. 
  63. * @since 1.1.0 
  64. * @var string 
  65. */ 
  66. public $visibility = 'public'; 
  67.  
  68. /** 
  69. * The numeric position of the main nav item. 
  70. * @since 1.1.0 
  71. * @var int 
  72. */ 
  73. public $nav_item_position = 81; 
  74.  
  75. /** 
  76. * Whether to show the nav item. 
  77. * @since 1.1.0 
  78. * @var bool 
  79. */ 
  80. public $enable_nav_item = true; 
  81.  
  82. /** 
  83. * Whether the current user should see the navigation item. 
  84. * @since 2.1.0 
  85. * @var bool 
  86. */ 
  87. public $user_can_see_nav_item; 
  88.  
  89. /** 
  90. * Whether the current user can visit the tab. 
  91. * @since 2.1.0 
  92. * @var bool 
  93. */ 
  94. public $user_can_visit; 
  95.  
  96. /** 
  97. * The text of the nav item. Defaults to self::name. 
  98. * @since 1.1.0 
  99. * @var string 
  100. */ 
  101. public $nav_item_name = ''; 
  102.  
  103. /** 
  104. * The WP action that self::widget_display() is attached to. 
  105. * Default: 'groups_custom_group_boxes'. 
  106. * @since 1.1.0 
  107. * @var string 
  108. */ 
  109. public $display_hook = 'groups_custom_group_boxes'; 
  110.  
  111. /** 
  112. * The template file used to load the plugin content. 
  113. * Default: 'groups/single/plugins'. 
  114. * @since 1.1.0 
  115. * @var string 
  116. */ 
  117. public $template_file = 'groups/single/plugins'; 
  118.  
  119. /** Protected *********************************************************/ 
  120.  
  121. /** 
  122. * Has the extension been initialized? 
  123. * @since 1.8.0 
  124. * @var bool 
  125. */ 
  126. protected $initialized = false; 
  127.  
  128. /** 
  129. * Extension properties as set by legacy extensions. 
  130. * @since 1.8.0 
  131. * @var array 
  132. */ 
  133. protected $legacy_properties = array(); 
  134.  
  135. /** 
  136. * Converted legacy parameters. 
  137. * These are the extension properties as set by legacy extensions, but 
  138. * then converted to match the new format for params. 
  139. * @since 1.8.0 
  140. * @var array 
  141. */ 
  142. protected $legacy_properties_converted = array(); 
  143.  
  144. /** 
  145. * Redirect location as defined by post-edit save callback. 
  146. * @since 2.1.0 
  147. * @var string 
  148. */ 
  149. protected $post_save_redirect; 
  150.  
  151. /** 
  152. * Miscellaneous data as set by the __set() magic method. 
  153. * @since 1.8.0 
  154. * @var array 
  155. */ 
  156. protected $data = array(); 
  157.  
  158. /** Screen Overrides **************************************************/ 
  159.  
  160. /** 
  161. * Screen override methods are how your extension will display content 
  162. * and handle form submits. Your extension should only override those 
  163. * methods that it needs for its purposes. 
  164. */ 
  165.  
  166. /** 
  167. * The content of the group tab. 
  168. * @since 1.1.0 
  169. * @param int|null $group_id ID of the group to display. 
  170. */ 
  171. public function display( $group_id = null ) {} 
  172.  
  173. /** 
  174. * Content displayed in a widget sidebar, if applicable. 
  175. * @since 1.1.0 
  176. */ 
  177. public function widget_display() {} 
  178.  
  179. /** 
  180. * *_screen() displays the settings form for the given context 
  181. * *_screen_save() processes data submitted via the settings form 
  182. * The settings_* methods are generic fallbacks, which can optionally 
  183. * be overridden by the more specific edit_*, create_*, and admin_* 
  184. * versions. 
  185. */ 
  186. public function settings_screen( $group_id = null ) {} 
  187. public function settings_screen_save( $group_id = null ) {} 
  188. public function edit_screen( $group_id = null ) {} 
  189. public function edit_screen_save( $group_id = null ) {} 
  190. public function create_screen( $group_id = null ) {} 
  191. public function create_screen_save( $group_id = null ) {} 
  192. public function admin_screen( $group_id = null ) {} 
  193. public function admin_screen_save( $group_id = null ) {} 
  194.  
  195. /** Setup *************************************************************/ 
  196.  
  197. /** 
  198. * Initialize the extension, using your config settings. 
  199. * Your plugin should call this method at the very end of its 
  200. * constructor, like so: 
  201. * public function __construct() { 
  202. * $args = array( 
  203. * 'slug' => 'my-group-extension',  
  204. * 'name' => 'My Group Extension',  
  205. * // ... 
  206. * ); 
  207. * parent::init( $args ); 
  208. * } 
  209. * @since 1.8.0 
  210. * @since 2.1.0 Added 'access' and 'show_tab' arguments to `$args`. 
  211. * @param array $args { 
  212. * Array of initialization arguments. 
  213. * @type string $slug Unique, URL-safe identifier for your extension. 
  214. * @type string $name Translatable name for your extension. Used to populate 
  215. * navigation items. 
  216. * @type string $visibility Optional. Set to 'public' for your extension (the main tab as well 
  217. * as the widget) to be available to anyone who can access the group; 
  218. * set to 'private' otherwise. Default: 'public'. 
  219. * @type int $nav_item_position Optional. Location of the nav item in the tab list. 
  220. * Default: 81. 
  221. * @type bool $enable_nav_item Optional. Whether the extension's tab should be accessible to 
  222. * anyone who can view the group. Default: true. 
  223. * @type string $nav_item_name Optional. The translatable text you want to appear in the nav tab. 
  224. * Default: the value of `$name`. 
  225. * @type string $display_hook Optional. The WordPress action that the widget_display() method is 
  226. * hooked to. Default: 'groups_custom_group_boxes'. 
  227. * @type string $template_file Optional. Theme-relative path to the template file BP should use 
  228. * to load the content of your main extension tab. 
  229. * Default: 'groups/single/plugins.php'. 
  230. * @type array $screens A multi-dimensional array of configuration information for the 
  231. * extension screens. See docblock of {@link BP_Group_Extension} 
  232. * for more details. 
  233. * @type string|array $access Which users can visit the plugin's tab. Possible values: 'anyone',  
  234. * 'loggedin', 'member', 'mod', 'admin' or 'noone'. ('member', 'mod',  
  235. * 'admin' refer to user's role in group.) Note that 'mod' targets 
  236. * only group moderators. If you want to allow access to group moderators 
  237. * and admins, specify `array( 'mod', 'admin' )`. Defaults to 'anyone' 
  238. * for public groups and 'member' for private groups. 
  239. * @type string|array $show_tab Which users can see the plugin's navigation tab. Possible values: 
  240. * 'anyone', 'loggedin', 'member', 'mod', 'admin' or 'noone'. 
  241. * ('member', 'mod', 'admin' refer to user's role in group.) Note 
  242. * that 'mod' targets only group moderators. If you want to show the 
  243. * tab to group moderators and admins, specify 
  244. * `array( 'mod', 'admin' )`. Defaults to 'anyone' for public groups 
  245. * and 'member' for private groups. 
  246. * } 
  247. */ 
  248. public function init( $args = array() ) { 
  249. // Store the raw arguments. 
  250. $this->params_raw = $args; 
  251.  
  252. // Before this init() method was introduced, plugins were 
  253. // encouraged to set their config directly. For backward 
  254. // compatibility with these plugins, we detect whether this is 
  255. // one of those legacy plugins, and parse any legacy arguments 
  256. // with those passed to init(). 
  257. $this->parse_legacy_properties(); 
  258. $args = $this->parse_args_r( $args, $this->legacy_properties_converted ); 
  259.  
  260. // Parse with defaults. 
  261. $this->params = $this->parse_args_r( $args, array( 
  262. 'slug' => $this->slug,  
  263. 'name' => $this->name,  
  264. 'visibility' => $this->visibility,  
  265. 'nav_item_position' => $this->nav_item_position,  
  266. 'enable_nav_item' => (bool) $this->enable_nav_item,  
  267. 'nav_item_name' => $this->nav_item_name,  
  268. 'display_hook' => $this->display_hook,  
  269. 'template_file' => $this->template_file,  
  270. 'screens' => $this->get_default_screens(),  
  271. 'access' => null,  
  272. 'show_tab' => null,  
  273. ) ); 
  274.  
  275. $this->initialized = true; 
  276.  
  277. /** 
  278. * The main setup routine for the extension. 
  279. * This method contains the primary logic for setting up an extension's 
  280. * configuration, setting up backward compatibility for legacy plugins,  
  281. * and hooking the extension's screen functions into WP and BP. 
  282. * Marked 'public' because it must be accessible to add_action(). 
  283. * However, you should never need to invoke this method yourself - it 
  284. * is called automatically at the right point in the load order by 
  285. * bp_register_group_extension(). 
  286. * @since 1.1.0 
  287. */ 
  288. public function _register() { 
  289.  
  290. // Detect and parse properties set by legacy extensions. 
  291. $this->parse_legacy_properties(); 
  292.  
  293. // Initialize, if necessary. This should only happen for 
  294. // legacy extensions that don't call parent::init() themselves. 
  295. if ( true !== $this->initialized ) { 
  296. $this->init(); 
  297.  
  298. // Set some config values, based on the parsed params. 
  299. $this->group_id = $this->get_group_id(); 
  300. $this->slug = $this->params['slug']; 
  301. $this->name = $this->params['name']; 
  302. $this->visibility = $this->params['visibility']; 
  303. $this->nav_item_position = $this->params['nav_item_position']; 
  304. $this->nav_item_name = $this->params['nav_item_name']; 
  305. $this->display_hook = $this->params['display_hook']; 
  306. $this->template_file = $this->params['template_file']; 
  307.  
  308. // Configure 'screens': create, admin, and edit contexts. 
  309. $this->setup_screens(); 
  310.  
  311. // Configure access-related settings. 
  312. $this->setup_access_settings(); 
  313.  
  314. // Mirror configuration data so it's accessible to plugins 
  315. // that look for it in its old locations. 
  316. $this->setup_legacy_properties(); 
  317.  
  318. // Hook the extension into BuddyPress. 
  319. $this->setup_display_hooks(); 
  320. $this->setup_create_hooks(); 
  321. $this->setup_edit_hooks(); 
  322. $this->setup_admin_hooks(); 
  323.  
  324. /** 
  325. * Set up some basic info about the Extension. 
  326. * Here we collect the name of the extending class, as well as a 
  327. * ReflectionClass that is used in get_screen_callback() to determine 
  328. * whether your extension overrides certain callback methods. 
  329. * @since 1.8.0 
  330. */ 
  331. protected function setup_class_info() { 
  332. if ( empty( $this->class_name ) ) { 
  333. $this->class_name = get_class( $this ); 
  334.  
  335. if ( is_null( $this->class_reflection ) ) { 
  336. $this->class_reflection = new ReflectionClass( $this->class_name ); 
  337.  
  338. /** 
  339. * Get the current group ID. 
  340. * Check for: 
  341. * - current group 
  342. * - new group 
  343. * - group admin 
  344. * @since 1.8.0 
  345. * @return int 
  346. */ 
  347. public static function get_group_id() { 
  348.  
  349. // Usually this will work. 
  350. $group_id = bp_get_current_group_id(); 
  351.  
  352. // On the admin, get the group id out of the $_GET params. 
  353. if ( empty( $group_id ) && is_admin() && ( isset( $_GET['page'] ) && ( 'bp-groups' === $_GET['page'] ) ) && ! empty( $_GET['gid'] ) ) { 
  354. $group_id = (int) $_GET['gid']; 
  355.  
  356. // This fallback will only be hit when the create step is very 
  357. // early. 
  358. if ( empty( $group_id ) && bp_get_new_group_id() ) { 
  359. $group_id = bp_get_new_group_id(); 
  360.  
  361. // On some setups, the group id has to be fetched out of the 
  362. // $_POST array 
  363. // @todo Figure out why this is happening during group creation. 
  364. if ( empty( $group_id ) && isset( $_POST['group_id'] ) ) { 
  365. $group_id = (int) $_POST['group_id']; 
  366.  
  367. return $group_id; 
  368.  
  369. /** 
  370. * Gather configuration data about your screens. 
  371. * @since 1.8.0 
  372. * @return array 
  373. */ 
  374. protected function get_default_screens() { 
  375. $this->setup_class_info(); 
  376.  
  377. $screens = array( 
  378. 'create' => array( 
  379. 'position' => 81,  
  380. ),  
  381. 'edit' => array( 
  382. 'submit_text' => __( 'Save Changes', 'buddypress' ),  
  383. ),  
  384. 'admin' => array( 
  385. 'metabox_context' => 'normal',  
  386. 'metabox_priority' => 'core',  
  387. ),  
  388. ); 
  389.  
  390. foreach ( $screens as $context => &$screen ) { 
  391. $screen['enabled'] = true; 
  392. $screen['name'] = $this->name; 
  393. $screen['slug'] = $this->slug; 
  394.  
  395. $screen['screen_callback'] = $this->get_screen_callback( $context, 'screen' ); 
  396. $screen['screen_save_callback'] = $this->get_screen_callback( $context, 'screen_save' ); 
  397.  
  398. return $screens; 
  399.  
  400. /** 
  401. * Set up screens array based on params. 
  402. * @since 1.8.0 
  403. */ 
  404. protected function setup_screens() { 
  405. foreach ( (array) $this->params['screens'] as $context => $screen ) { 
  406. if ( empty( $screen['slug'] ) ) { 
  407. $screen['slug'] = $this->slug; 
  408.  
  409. if ( empty( $screen['name'] ) ) { 
  410. $screen['name'] = $this->name; 
  411.  
  412. $this->screens[ $context ] = $screen; 
  413.  
  414. /** 
  415. * Set up access-related settings for this extension. 
  416. * @since 2.1.0 
  417. */ 
  418. protected function setup_access_settings() { 
  419. // Bail if no group ID is available. 
  420. if ( empty( $this->group_id ) ) { 
  421. return; 
  422.  
  423. // Backward compatibility. 
  424. if ( isset( $this->params['enable_nav_item'] ) ) { 
  425. $this->enable_nav_item = (bool) $this->params['enable_nav_item']; 
  426.  
  427. // Tab Access. 
  428. $this->user_can_visit = false; 
  429.  
  430. // Backward compatibility for components that do not provide 
  431. // explicit 'access' parameter. 
  432. if ( empty( $this->params['access'] ) ) { 
  433. if ( false === $this->enable_nav_item ) { 
  434. $this->params['access'] = 'noone'; 
  435. } else { 
  436. $group = groups_get_group( $this->group_id ); 
  437.  
  438. if ( ! empty( $group->status ) && 'public' === $group->status ) { 
  439. // Tabs in public groups are accessible to anyone by default. 
  440. $this->params['access'] = 'anyone'; 
  441. } else { 
  442. // All other groups have members-only as the default. 
  443. $this->params['access'] = 'member'; 
  444.  
  445. // Parse multiple access conditions into an array. 
  446. $access_conditions = $this->params['access']; 
  447. if ( ! is_array( $access_conditions ) ) { 
  448. $access_conditions = explode( ', ', $access_conditions ); 
  449.  
  450. // If the current user meets at least one condition, the 
  451. // get access. 
  452. foreach ( $access_conditions as $access_condition ) { 
  453. if ( $this->user_meets_access_condition( $access_condition ) ) { 
  454. $this->user_can_visit = true; 
  455. break; 
  456.  
  457. // Tab Visibility. 
  458. $this->user_can_see_nav_item = false; 
  459.  
  460. // Backward compatibility for components that do not provide 
  461. // explicit 'show_tab' parameter. 
  462. if ( empty( $this->params['show_tab'] ) ) { 
  463. if ( false === $this->params['enable_nav_item'] ) { 
  464. // The enable_nav_item index is only false if it's been 
  465. // defined explicitly as such in the 
  466. // constructor. So we always trust this value. 
  467. $this->params['show_tab'] = 'noone'; 
  468.  
  469. } elseif ( isset( $this->params_raw['enable_nav_item'] ) || isset( $this->params_raw['visibility'] ) ) { 
  470. // If enable_nav_item or visibility is passed,  
  471. // we assume this is a legacy extension. 
  472. // Legacy behavior is that enable_nav_item=true + 
  473. // visibility=private implies members-only. 
  474. if ( 'public' !== $this->visibility ) { 
  475. $this->params['show_tab'] = 'member'; 
  476. } else { 
  477. $this->params['show_tab'] = 'anyone'; 
  478.  
  479. } else { 
  480. // No show_tab or enable_nav_item value is 
  481. // available, so match the value of 'access'. 
  482. $this->params['show_tab'] = $this->params['access']; 
  483.  
  484. // Parse multiple access conditions into an array. 
  485. $access_conditions = $this->params['show_tab']; 
  486. if ( ! is_array( $access_conditions ) ) { 
  487. $access_conditions = explode( ', ', $access_conditions ); 
  488.  
  489. // If the current user meets at least one condition, the 
  490. // get access. 
  491. foreach ( $access_conditions as $access_condition ) { 
  492. if ( $this->user_meets_access_condition( $access_condition ) ) { 
  493. $this->user_can_see_nav_item = true; 
  494. break; 
  495.  
  496. /** 
  497. * Check whether the current user meets an access condition. 
  498. * @since 2.1.0 
  499. * @param string $access_condition 'anyone', 'loggedin', 'member',  
  500. * 'mod', 'admin' or 'noone'. 
  501. * @return bool 
  502. */ 
  503. protected function user_meets_access_condition( $access_condition ) { 
  504. $group = groups_get_group( $this->group_id ); 
  505.  
  506. switch ( $access_condition ) { 
  507. case 'admin' : 
  508. $meets_condition = groups_is_user_admin( bp_loggedin_user_id(), $this->group_id ); 
  509. break; 
  510.  
  511. case 'mod' : 
  512. $meets_condition = groups_is_user_mod( bp_loggedin_user_id(), $this->group_id ); 
  513. break; 
  514.  
  515. case 'member' : 
  516. $meets_condition = groups_is_user_member( bp_loggedin_user_id(), $this->group_id ); 
  517. break; 
  518.  
  519. case 'loggedin' : 
  520. $meets_condition = is_user_logged_in(); 
  521. break; 
  522.  
  523. case 'noone' : 
  524. $meets_condition = false; 
  525. break; 
  526.  
  527. case 'anyone' : 
  528. default : 
  529. $meets_condition = true; 
  530. break; 
  531.  
  532. return $meets_condition; 
  533.  
  534. /** Display ***********************************************************/ 
  535.  
  536. /** 
  537. * Hook this extension's group tab into BuddyPress, if necessary. 
  538. * @since 1.8.0 
  539. */ 
  540. protected function setup_display_hooks() { 
  541.  
  542. // Bail if not a group. 
  543. if ( ! bp_is_group() ) { 
  544. return; 
  545.  
  546. // Backward compatibility only. 
  547. if ( ( 'public' !== $this->visibility ) && ! buddypress()->groups->current_group->user_has_access ) { 
  548. return; 
  549.  
  550. // If the user can see the nav item, we create it. 
  551. $user_can_see_nav_item = $this->user_can_see_nav_item(); 
  552.  
  553. if ( $user_can_see_nav_item ) { 
  554. $group_permalink = bp_get_group_permalink( groups_get_current_group() ); 
  555.  
  556. bp_core_create_subnav_link( array( 
  557. 'name' => ! $this->nav_item_name ? $this->name : $this->nav_item_name,  
  558. 'slug' => $this->slug,  
  559. 'parent_slug' => bp_get_current_group_slug(),  
  560. 'parent_url' => $group_permalink,  
  561. 'position' => $this->nav_item_position,  
  562. 'item_css_id' => 'nav-' . $this->slug,  
  563. 'screen_function' => array( &$this, '_display_hook' ),  
  564. 'user_has_access' => $user_can_see_nav_item,  
  565. 'no_access_url' => $group_permalink,  
  566. ), 'groups' ); 
  567.  
  568. // If the user can visit the screen, we register it. 
  569. $user_can_visit = $this->user_can_visit(); 
  570.  
  571. if ( $user_can_visit ) { 
  572. $group_permalink = bp_get_group_permalink( groups_get_current_group() ); 
  573.  
  574. bp_core_register_subnav_screen_function( array( 
  575. 'slug' => $this->slug,  
  576. 'parent_slug' => bp_get_current_group_slug(),  
  577. 'screen_function' => array( &$this, '_display_hook' ),  
  578. 'user_has_access' => $user_can_visit,  
  579. 'no_access_url' => $group_permalink,  
  580. ), 'groups' ); 
  581.  
  582. // When we are viewing the extension display page, set the title and options title. 
  583. if ( bp_is_current_action( $this->slug ) ) { 
  584. add_filter( 'bp_group_user_has_access', array( $this, 'group_access_protection' ), 10, 2 ); 
  585. add_action( 'bp_template_content_header', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) ); 
  586. add_action( 'bp_template_title', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) ); 
  587.  
  588. // Hook the group home widget. 
  589. if ( bp_is_group_home() ) { 
  590. add_action( $this->display_hook, array( &$this, 'widget_display' ) ); 
  591.  
  592. /** 
  593. * Hook the main display method, and loads the template file. 
  594. * @since 1.1.0 
  595. */ 
  596. public function _display_hook() { 
  597. add_action( 'bp_template_content', array( &$this, 'call_display' ) ); 
  598.  
  599. /** 
  600. * Filters the template to load for the main display method. 
  601. * @since 1.0.0 
  602. * @param string $template_file Path to the template to load. 
  603. */ 
  604. bp_core_load_template( apply_filters( 'bp_core_template_plugin', $this->template_file ) ); 
  605.  
  606. /** 
  607. * Call the display() method. 
  608. * We use this wrapper so that we can pass the group_id to the 
  609. * display() callback. 
  610. * @since 2.1.1 
  611. */ 
  612. public function call_display() { 
  613. $this->display( $this->group_id ); 
  614.  
  615. /** 
  616. * Determine whether the current user should see this nav tab. 
  617. * Note that this controls only the display of the navigation item. 
  618. * Access to the tab is controlled by the user_can_visit() check. 
  619. * @since 2.1.0 
  620. * @param bool $user_can_see_nav_item Whether or not the user can see the nav item. 
  621. * @return bool 
  622. */ 
  623. public function user_can_see_nav_item( $user_can_see_nav_item = false ) { 
  624. if ( 'noone' !== $this->params['show_tab'] && current_user_can( 'bp_moderate' ) ) { 
  625. return true; 
  626.  
  627. return $this->user_can_see_nav_item; 
  628.  
  629. /** 
  630. * Determine whether the current user has access to visit this tab. 
  631. * @since 2.1.0 
  632. * @param bool $user_can_visit Whether or not the user can visit the tab. 
  633. * @return bool 
  634. */ 
  635. public function user_can_visit( $user_can_visit = false ) { 
  636. if ( 'noone' !== $this->params['access'] && current_user_can( 'bp_moderate' ) ) { 
  637. return true; 
  638.  
  639. return $this->user_can_visit; 
  640.  
  641. /** 
  642. * Filter the access check in bp_groups_group_access_protection() for this extension. 
  643. * Note that $no_access_args is passed by reference, as there are some 
  644. * circumstances where the bp_core_no_access() arguments need to be 
  645. * modified before the redirect takes place. 
  646. * @since 2.1.0 
  647. * @param bool $user_can_visit Whether or not the user can visit the tab. 
  648. * @param array $no_access_args Array of args to help determine access. 
  649. * @return bool 
  650. */ 
  651. public function group_access_protection( $user_can_visit, &$no_access_args ) { 
  652. $user_can_visit = $this->user_can_visit(); 
  653.  
  654. if ( ! $user_can_visit && is_user_logged_in() ) { 
  655. $current_group = groups_get_group( $this->group_id ); 
  656.  
  657. $no_access_args['message'] = __( 'You do not have access to this content.', 'buddypress' ); 
  658. $no_access_args['root'] = bp_get_group_permalink( $current_group ) . 'home/'; 
  659. $no_access_args['redirect'] = false; 
  660.  
  661. return $user_can_visit; 
  662.  
  663.  
  664. /** Create ************************************************************/ 
  665.  
  666. /** 
  667. * Hook this extension's Create step into BuddyPress, if necessary. 
  668. * @since 1.8.0 
  669. */ 
  670. protected function setup_create_hooks() { 
  671. if ( ! $this->is_screen_enabled( 'create' ) ) { 
  672. return; 
  673.  
  674. $screen = $this->screens['create']; 
  675.  
  676. // Insert the group creation step for the new group extension. 
  677. buddypress()->groups->group_creation_steps[ $screen['slug'] ] = array( 
  678. 'name' => $screen['name'],  
  679. 'slug' => $screen['slug'],  
  680. 'position' => $screen['position'],  
  681. ); 
  682.  
  683. // The maybe_ methods check to see whether the create_* 
  684. // callbacks should be invoked (ie, are we on the 
  685. // correct group creation step). Hooked in separate 
  686. // methods because current creation step info not yet 
  687. // available at this point. 
  688. add_action( 'groups_custom_create_steps', array( $this, 'maybe_create_screen' ) ); 
  689. add_action( 'groups_create_group_step_save_' . $screen['slug'], array( $this, 'maybe_create_screen_save' ) ); 
  690.  
  691. /** 
  692. * Call the create_screen() method, if we're on the right page. 
  693. * @since 1.8.0 
  694. */ 
  695. public function maybe_create_screen() { 
  696. if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) { 
  697. return; 
  698.  
  699. call_user_func( $this->screens['create']['screen_callback'], $this->group_id ); 
  700. $this->nonce_field( 'create' ); 
  701.  
  702. // The create screen requires an additional nonce field 
  703. // due to a quirk in the way the templates are built. 
  704. wp_nonce_field( 'groups_create_save_' . bp_get_groups_current_create_step(), '_wpnonce', false ); 
  705.  
  706. /** 
  707. * Call the create_screen_save() method, if we're on the right page. 
  708. * @since 1.8.0 
  709. */ 
  710. public function maybe_create_screen_save() { 
  711. if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) { 
  712. return; 
  713.  
  714. $this->check_nonce( 'create' ); 
  715. call_user_func( $this->screens['create']['screen_save_callback'], $this->group_id ); 
  716.  
  717. /** Edit **************************************************************/ 
  718.  
  719. /** 
  720. * Hook this extension's Edit panel into BuddyPress, if necessary. 
  721. * @since 1.8.0 
  722. */ 
  723. protected function setup_edit_hooks() { 
  724. // Bail if not in a group. 
  725. if ( ! bp_is_group() ) { 
  726. return; 
  727.  
  728. // Bail if not an edit screen. 
  729. if ( ! $this->is_screen_enabled( 'edit' ) || ! bp_is_item_admin() ) { 
  730. return; 
  731.  
  732. $screen = $this->screens['edit']; 
  733.  
  734. $position = isset( $screen['position'] ) ? (int) $screen['position'] : 10; 
  735. $position += 40; 
  736.  
  737. $current_group = groups_get_current_group(); 
  738. $admin_link = trailingslashit( bp_get_group_permalink( $current_group ) . 'admin' ); 
  739.  
  740. $subnav_args = array( 
  741. 'name' => $screen['name'],  
  742. 'slug' => $screen['slug'],  
  743. 'parent_slug' => $current_group->slug . '_manage',  
  744. 'parent_url' => trailingslashit( bp_get_group_permalink( $current_group ) . 'admin' ),  
  745. 'user_has_access' => bp_is_item_admin(),  
  746. 'position' => $position,  
  747. 'screen_function' => 'groups_screen_group_admin',  
  748. ); 
  749.  
  750. // Should we add a menu to the Group's WP Admin Bar. 
  751. if ( ! empty( $screen['show_in_admin_bar'] ) ) { 
  752. $subnav_args['show_in_admin_bar'] = true; 
  753.  
  754. // Add the tab to the manage navigation. 
  755. bp_core_new_subnav_item( $subnav_args, 'groups' ); 
  756.  
  757. // Catch the edit screen and forward it to the plugin template. 
  758. if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) && bp_is_action_variable( $screen['slug'], 0 ) ) { 
  759. $this->call_edit_screen_save( $this->group_id ); 
  760.  
  761. add_action( 'groups_custom_edit_steps', array( &$this, 'call_edit_screen' ) ); 
  762.  
  763. // Determine the proper template and save for later 
  764. // loading. 
  765. if ( '' !== bp_locate_template( array( 'groups/single/home.php' ), false ) ) { 
  766. $this->edit_screen_template = '/groups/single/home'; 
  767. } else { 
  768. add_action( 'bp_template_content_header', function() { 
  769. echo '<ul class="content-header-nav">'; 
  770. bp_group_admin_tabs(); 
  771. echo '</ul>'; 
  772. } ); 
  773. add_action( 'bp_template_content', array( &$this, 'call_edit_screen' ) ); 
  774. $this->edit_screen_template = '/groups/single/plugins'; 
  775.  
  776. // We load the template at bp_screens, to give all 
  777. // extensions a chance to load. 
  778. add_action( 'bp_screens', array( $this, 'call_edit_screen_template_loader' ) ); 
  779.  
  780. /** 
  781. * Call the edit_screen() method. 
  782. * Previous versions of BP_Group_Extension required plugins to provide 
  783. * their own Submit button and nonce fields when building markup. In 
  784. * BP 1.8, this requirement was lifted - BP_Group_Extension now handles 
  785. * all required submit buttons and nonces. 
  786. * We put the edit screen markup into an output buffer before echoing. 
  787. * This is so that we can check for the presence of a hardcoded submit 
  788. * button, as would be present in legacy plugins; if one is found, we 
  789. * do not auto-add our own button. 
  790. * @since 1.8.0 
  791. */ 
  792. public function call_edit_screen() { 
  793. ob_start(); 
  794. call_user_func( $this->screens['edit']['screen_callback'], $this->group_id ); 
  795. $screen = ob_get_contents(); 
  796. ob_end_clean(); 
  797.  
  798. echo $this->maybe_add_submit_button( $screen ); 
  799.  
  800. $this->nonce_field( 'edit' ); 
  801.  
  802. /** 
  803. * Check the nonce, and call the edit_screen_save() method. 
  804. * @since 1.8.0 
  805. */ 
  806. public function call_edit_screen_save() { 
  807. if ( empty( $_POST ) ) { 
  808. return; 
  809.  
  810. // When DOING_AJAX, the POST global will be populated, but we 
  811. // should assume it's a save. 
  812. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { 
  813. return; 
  814.  
  815. $this->check_nonce( 'edit' ); 
  816.  
  817. // Detect whether the screen_save_callback is performing a 
  818. // redirect, so that we don't do one of our own. 
  819. add_filter( 'wp_redirect', array( $this, 'detect_post_save_redirect' ) ); 
  820.  
  821. // Call the extension's save routine. 
  822. call_user_func( $this->screens['edit']['screen_save_callback'], $this->group_id ); 
  823.  
  824. // Clean up detection filters. 
  825. remove_filter( 'wp_redirect', array( $this, 'detect_post_save_redirect' ) ); 
  826.  
  827. // Perform a redirect only if one has not already taken place. 
  828. if ( empty( $this->post_save_redirect ) ) { 
  829.  
  830. /** 
  831. * Filters the URL to redirect to after group edit screen save. 
  832. * Only runs if a redirect has not already occurred. 
  833. * @since 2.1.0 
  834. * @param string $value URL to redirect to. 
  835. */ 
  836. $redirect_to = apply_filters( 'bp_group_extension_edit_screen_save_redirect', bp_get_requested_url( ) ); 
  837.  
  838. bp_core_redirect( $redirect_to ); 
  839. die(); 
  840.  
  841. /** 
  842. * Load the template that houses the Edit screen. 
  843. * Separated out into a callback so that it can run after all other 
  844. * Group Extensions have had a chance to register their navigation, to 
  845. * avoid missing tabs. 
  846. * Hooked to 'bp_screens'. 
  847. * @since 1.8.0 
  848. * @see BP_Group_Extension::setup_edit_hooks() 
  849. */ 
  850. public function call_edit_screen_template_loader() { 
  851. bp_core_load_template( $this->edit_screen_template ); 
  852.  
  853. /** 
  854. * Add a submit button to the edit form, if it needs one. 
  855. * There's an inconsistency in the way that the group Edit and Create 
  856. * screens are rendered: the Create screen has a submit button built 
  857. * in, but the Edit screen does not. This function allows plugin 
  858. * authors to write markup that does not contain the submit button for 
  859. * use on both the Create and Edit screens - BP will provide the button 
  860. * if one is not found. 
  861. * @since 1.8.0 
  862. * @param string $screen The screen markup, captured in the output 
  863. * buffer. 
  864. * @return string $screen The same markup, with a submit button added. 
  865. */ 
  866. protected function maybe_add_submit_button( $screen = '' ) { 
  867. if ( $this->has_submit_button( $screen ) ) { 
  868. return $screen; 
  869.  
  870. return $screen . sprintf( 
  871. '<div id="%s"><input type="submit" name="save" value="%s" id="%s"></div>',  
  872. 'bp-group-edit-' . $this->slug . '-submit-wrapper',  
  873. $this->screens['edit']['submit_text'],  
  874. 'bp-group-edit-' . $this->slug . '-submit' 
  875. ); 
  876.  
  877. /** 
  878. * Does the given markup have a submit button? 
  879. * @since 1.8.0 
  880. * @param string $screen The markup to check. 
  881. * @return bool True if a Submit button is found, otherwise false. 
  882. */ 
  883. public static function has_submit_button( $screen = '' ) { 
  884. $pattern = "/<input[^>]+type=[\'\"]submit[\'\"]/"; 
  885. preg_match( $pattern, $screen, $matches ); 
  886. return ! empty( $matches[0] ); 
  887.  
  888. /** 
  889. * Detect redirects hardcoded into edit_screen_save() callbacks. 
  890. * @since 2.1.0 
  891. * @param string $redirect Redirect string. 
  892. * @return string 
  893. */ 
  894. public function detect_post_save_redirect( $redirect = '' ) { 
  895. if ( ! empty( $redirect ) ) { 
  896. $this->post_save_redirect = $redirect; 
  897.  
  898. return $redirect; 
  899.  
  900. /** Admin *************************************************************/ 
  901.  
  902. /** 
  903. * Hook this extension's Admin metabox into BuddyPress, if necessary. 
  904. * @since 1.8.0 
  905. */ 
  906. protected function setup_admin_hooks() { 
  907. if ( ! $this->is_screen_enabled( 'admin' ) || ! is_admin() ) { 
  908. return; 
  909.  
  910. // Hook the admin screen markup function to the content hook. 
  911. add_action( 'bp_groups_admin_meta_box_content_' . $this->slug, array( $this, 'call_admin_screen' ) ); 
  912.  
  913. // Initialize the metabox. 
  914. add_action( 'bp_groups_admin_meta_boxes', array( $this, '_meta_box_display_callback' ) ); 
  915.  
  916. // Catch the metabox save. 
  917. add_action( 'bp_group_admin_edit_after', array( $this, 'call_admin_screen_save' ), 10 ); 
  918.  
  919. /** 
  920. * Call the admin_screen() method, and add a nonce field. 
  921. * @since 1.8.0 
  922. */ 
  923. public function call_admin_screen() { 
  924. call_user_func( $this->screens['admin']['screen_callback'], $this->group_id ); 
  925. $this->nonce_field( 'admin' ); 
  926.  
  927. /** 
  928. * Check the nonce, and call the admin_screen_save() method. 
  929. * @since 1.8.0 
  930. */ 
  931. public function call_admin_screen_save() { 
  932. $this->check_nonce( 'admin' ); 
  933. call_user_func( $this->screens['admin']['screen_save_callback'], $this->group_id ); 
  934.  
  935. /** 
  936. * Create the Dashboard meta box for this extension. 
  937. * @since 1.7.0 
  938. */ 
  939. public function _meta_box_display_callback() { 
  940. $group_id = isset( $_GET['gid'] ) ? (int) $_GET['gid'] : 0; 
  941. $screen = $this->screens['admin']; 
  942.  
  943. add_meta_box( 
  944. $screen['slug'],  
  945. $screen['name'],  
  946. create_function( '', 'do_action( "bp_groups_admin_meta_box_content_' . $this->slug . '", ' . $group_id . ' );' ),  
  947. get_current_screen()->id,  
  948. $screen['metabox_context'],  
  949. $screen['metabox_priority'] 
  950. ); 
  951.  
  952.  
  953. /** Utilities *********************************************************/ 
  954.  
  955. /** 
  956. * Generate the nonce fields for a settings form. 
  957. * The nonce field name (the second param passed to wp_nonce_field) 
  958. * contains this extension's slug and is thus unique to this extension. 
  959. * This is necessary because in some cases (namely, the Dashboard),  
  960. * more than one extension may generate nonces on the same page, and we 
  961. * must avoid name clashes. 
  962. * @since 1.8.0 
  963. * @param string $context Screen context. 'create', 'edit', or 'admin'. 
  964. */ 
  965. public function nonce_field( $context = '' ) { 
  966. wp_nonce_field( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug ); 
  967.  
  968. /** 
  969. * Check the nonce on a submitted settings form. 
  970. * @since 1.8.0 
  971. * @param string $context Screen context. 'create', 'edit', or 'admin'. 
  972. */ 
  973. public function check_nonce( $context = '' ) { 
  974. check_admin_referer( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug ); 
  975.  
  976. /** 
  977. * Is the specified screen enabled? 
  978. * To be enabled, a screen must both have the 'enabled' key set to true 
  979. * (legacy: $this->enable_create_step, etc), and its screen_callback 
  980. * must also exist and be callable. 
  981. * @since 1.8.0 
  982. * @param string $context Screen context. 'create', 'edit', or 'admin'. 
  983. * @return bool True if the screen is enabled, otherwise false. 
  984. */ 
  985. public function is_screen_enabled( $context = '' ) { 
  986. $enabled = false; 
  987.  
  988. if ( isset( $this->screens[ $context ] ) ) { 
  989. $enabled = $this->screens[ $context ]['enabled'] && is_callable( $this->screens[ $context ]['screen_callback'] ); 
  990.  
  991. return (bool) $enabled; 
  992.  
  993. /** 
  994. * Get the appropriate screen callback for the specified context/type. 
  995. * BP Group Extensions have three special "screen contexts": create,  
  996. * admin, and edit. Each of these contexts has a corresponding 
  997. * _screen() and _screen_save() method, which allow group extension 
  998. * plugins to define different markup and logic for each context. 
  999. * BP also supports fallback settings_screen() and 
  1000. * settings_screen_save() methods, which can be used to define markup 
  1001. * and logic that is shared between context. For each context, you may 
  1002. * either provide context-specific methods, or you can let BP fall back 
  1003. * on the shared settings_* callbacks. 
  1004. * For example, consider a BP_Group_Extension implementation that looks 
  1005. * like this: 
  1006. * // ... 
  1007. * function create_screen( $group_id ) { ... } 
  1008. * function create_screen_save( $group_id ) { ... } 
  1009. * function settings_screen( $group_id ) { ... } 
  1010. * function settings_screen_save( $group_id ) { ... } 
  1011. * // ... 
  1012. * BP_Group_Extension will use your create_* methods for the Create 
  1013. * steps, and will use your generic settings_* methods for the Edit 
  1014. * and Admin contexts. This schema allows plugin authors maximum 
  1015. * flexibility without having to repeat themselves. 
  1016. * The get_screen_callback() method uses a ReflectionClass object to 
  1017. * determine whether your extension has provided a given callback. 
  1018. * @since 1.8.0 
  1019. * @param string $context Screen context. 'create', 'edit', or 'admin'. 
  1020. * @param string $type Screen type. 'screen' or 'screen_save'. Default: 
  1021. * 'screen'. 
  1022. * @return callable A callable function handle. 
  1023. */ 
  1024. public function get_screen_callback( $context = '', $type = 'screen' ) { 
  1025. $callback = ''; 
  1026.  
  1027. // Try the context-specific callback first. 
  1028. $method = $context . '_' . $type; 
  1029. $rmethod = $this->class_reflection->getMethod( $method ); 
  1030. if ( isset( $rmethod->class ) && $this->class_name === $rmethod->class ) { 
  1031. $callback = array( $this, $method ); 
  1032.  
  1033. if ( empty( $callback ) ) { 
  1034. $fallback_method = 'settings_' . $type; 
  1035. $rfallback_method = $this->class_reflection->getMethod( $fallback_method ); 
  1036. if ( isset( $rfallback_method->class ) && $this->class_name === $rfallback_method->class ) { 
  1037. $callback = array( $this, $fallback_method ); 
  1038.  
  1039. return $callback; 
  1040.  
  1041. /** 
  1042. * Recursive argument parsing. 
  1043. * This acts like a multi-dimensional version of wp_parse_args() (minus 
  1044. * the querystring parsing - you must pass arrays). 
  1045. * Values from $a override those from $b; keys in $b that don't exist 
  1046. * in $a are passed through. 
  1047. * This is different from array_merge_recursive(), both because of the 
  1048. * order of preference ($a overrides $b) and because of the fact that 
  1049. * array_merge_recursive() combines arrays deep in the tree, rather 
  1050. * than overwriting the b array with the a array. 
  1051. * The implementation of this function is specific to the needs of 
  1052. * BP_Group_Extension, where we know that arrays will always be 
  1053. * associative, and that an argument under a given key in one array 
  1054. * will be matched by a value of identical depth in the other one. The 
  1055. * function is NOT designed for general use, and will probably result 
  1056. * in unexpected results when used with data in the wild. See, eg,  
  1057. * https://core.trac.wordpress.org/ticket/19888 
  1058. * @since 1.8.0 
  1059. * @param array $a First set of arguments. 
  1060. * @param array $b Second set of arguments. 
  1061. * @return array Parsed arguments. 
  1062. */ 
  1063. public static function parse_args_r( &$a, $b ) { 
  1064. $a = (array) $a; 
  1065. $b = (array) $b; 
  1066. $r = $b; 
  1067.  
  1068. foreach ( $a as $k => &$v ) { 
  1069. if ( is_array( $v ) && isset( $r[ $k ] ) ) { 
  1070. $r[ $k ] = self::parse_args_r( $v, $r[ $k ] ); 
  1071. } else { 
  1072. $r[ $k ] = $v; 
  1073.  
  1074. return $r; 
  1075.  
  1076. /** Legacy Support ********************************************************/ 
  1077.  
  1078. /** 
  1079. * In BuddyPress 1.8, the recommended technique for configuring 
  1080. * extensions changed from directly setting various object properties 
  1081. * in the class constructor, to passing a configuration array to 
  1082. * parent::init(). The following methods ensure that extensions created 
  1083. * in the old way continue to work, by converting legacy configuration 
  1084. * data to the new format. 
  1085. */ 
  1086.  
  1087. /** 
  1088. * Provide access to otherwise unavailable object properties. 
  1089. * This magic method is here for backward compatibility with plugins 
  1090. * that refer to config properties that have moved to a different 
  1091. * location (such as enable_create_step, which is now at 
  1092. * $this->screens['create']['enabled'] 
  1093. * The legacy_properties array is set up in 
  1094. * self::setup_legacy_properties(). 
  1095. * @since 1.8.0 
  1096. * @param string $key Property name. 
  1097. * @return mixed The value if found, otherwise null. 
  1098. */ 
  1099. public function __get( $key ) { 
  1100. if ( isset( $this->legacy_properties[ $key ] ) ) { 
  1101. return $this->legacy_properties[ $key ]; 
  1102. } elseif ( isset( $this->data[ $key ] ) ) { 
  1103. return $this->data[ $key ]; 
  1104. } else { 
  1105. return null; 
  1106.  
  1107. /** 
  1108. * Provide a fallback for isset( $this->foo ) when foo is unavailable. 
  1109. * This magic method is here for backward compatibility with plugins 
  1110. * that have set their class config options directly in the class 
  1111. * constructor. The parse_legacy_properties() method of the current 
  1112. * class needs to check whether any legacy keys have been put into the 
  1113. * $this->data array. 
  1114. * @since 1.8.0 
  1115. * @param string $key Property name. 
  1116. * @return bool True if the value is set, otherwise false. 
  1117. */ 
  1118. public function __isset( $key ) { 
  1119. if ( isset( $this->legacy_properties[ $key ] ) ) { 
  1120. return true; 
  1121. } elseif ( isset( $this->data[ $key ] ) ) { 
  1122. return true; 
  1123. } else { 
  1124. return false; 
  1125.  
  1126. /** 
  1127. * Allow plugins to set otherwise unavailable object properties. 
  1128. * This magic method is here for backward compatibility with plugins 
  1129. * that may attempt to modify the group extension by manually assigning 
  1130. * a value to an object property that no longer exists, such as 
  1131. * $this->enable_create_step. 
  1132. * @since 1.8.0 
  1133. * @param string $key Property name. 
  1134. * @param mixed $value Property value. 
  1135. */ 
  1136. public function __set( $key, $value ) { 
  1137.  
  1138. if ( empty( $this->initialized ) ) { 
  1139. $this->data[ $key ] = $value; 
  1140.  
  1141. switch ( $key ) { 
  1142. case 'enable_create_step' : 
  1143. $this->screens['create']['enabled'] = $value; 
  1144. break; 
  1145.  
  1146. case 'enable_edit_item' : 
  1147. $this->screens['edit']['enabled'] = $value; 
  1148. break; 
  1149.  
  1150. case 'enable_admin_item' : 
  1151. $this->screens['admin']['enabled'] = $value; 
  1152. break; 
  1153.  
  1154. case 'create_step_position' : 
  1155. $this->screens['create']['position'] = $value; 
  1156. break; 
  1157.  
  1158. // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'. 
  1159. case 'admin_name' : 
  1160. $this->screens['edit']['name'] = $value; 
  1161. break; 
  1162.  
  1163. case 'admin_slug' : 
  1164. $this->screens['edit']['slug'] = $value; 
  1165. break; 
  1166.  
  1167. case 'create_name' : 
  1168. $this->screens['create']['name'] = $value; 
  1169. break; 
  1170.  
  1171. case 'create_slug' : 
  1172. $this->screens['create']['slug'] = $value; 
  1173. break; 
  1174.  
  1175. case 'admin_metabox_context' : 
  1176. $this->screens['admin']['metabox_context'] = $value; 
  1177. break; 
  1178.  
  1179. case 'admin_metabox_priority' : 
  1180. $this->screens['admin']['metabox_priority'] = $value; 
  1181. break; 
  1182.  
  1183. default : 
  1184. $this->data[ $key ] = $value; 
  1185. break; 
  1186.  
  1187. /** 
  1188. * Return a list of legacy properties. 
  1189. * The legacy implementation of BP_Group_Extension used all of these 
  1190. * object properties for configuration. Some have been moved. 
  1191. * @since 1.8.0 
  1192. * @return array List of legacy property keys. 
  1193. */ 
  1194. protected function get_legacy_property_list() { 
  1195. return array( 
  1196. 'name',  
  1197. 'slug',  
  1198. 'admin_name',  
  1199. 'admin_slug',  
  1200. 'create_name',  
  1201. 'create_slug',  
  1202. 'visibility',  
  1203. 'create_step_position',  
  1204. 'nav_item_position',  
  1205. 'admin_metabox_context',  
  1206. 'admin_metabox_priority',  
  1207. 'enable_create_step',  
  1208. 'enable_nav_item',  
  1209. 'enable_edit_item',  
  1210. 'enable_admin_item',  
  1211. 'nav_item_name',  
  1212. 'display_hook',  
  1213. 'template_file',  
  1214. ); 
  1215.  
  1216. /** 
  1217. * Parse legacy properties. 
  1218. * The old standard for BP_Group_Extension was for plugins to register 
  1219. * their settings as properties in their constructor. The new method is 
  1220. * to pass a config array to the init() method. In order to support 
  1221. * legacy plugins, we slurp up legacy properties, and later on we'll 
  1222. * parse them into the new init() array. 
  1223. * @since 1.8.0 
  1224. */ 
  1225. protected function parse_legacy_properties() { 
  1226.  
  1227. // Only run this one time. 
  1228. if ( ! empty( $this->legacy_properties_converted ) ) { 
  1229. return; 
  1230.  
  1231. $properties = $this->get_legacy_property_list(); 
  1232.  
  1233. // By-reference variable for convenience. 
  1234. $lpc =& $this->legacy_properties_converted; 
  1235.  
  1236. foreach ( $properties as $property ) { 
  1237.  
  1238. // No legacy config exists for this key. 
  1239. if ( ! isset( $this->{$property} ) ) { 
  1240. continue; 
  1241.  
  1242. // Grab the value and record it as appropriate. 
  1243. $value = $this->{$property}; 
  1244.  
  1245. switch ( $property ) { 
  1246. case 'enable_create_step' : 
  1247. $lpc['screens']['create']['enabled'] = (bool) $value; 
  1248. break; 
  1249.  
  1250. case 'enable_edit_item' : 
  1251. $lpc['screens']['edit']['enabled'] = (bool) $value; 
  1252. break; 
  1253.  
  1254. case 'enable_admin_item' : 
  1255. $lpc['screens']['admin']['enabled'] = (bool) $value; 
  1256. break; 
  1257.  
  1258. case 'create_step_position' : 
  1259. $lpc['screens']['create']['position'] = $value; 
  1260. break; 
  1261.  
  1262. // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'. 
  1263. case 'admin_name' : 
  1264. $lpc['screens']['edit']['name'] = $value; 
  1265. break; 
  1266.  
  1267. case 'admin_slug' : 
  1268. $lpc['screens']['edit']['slug'] = $value; 
  1269. break; 
  1270.  
  1271. case 'create_name' : 
  1272. $lpc['screens']['create']['name'] = $value; 
  1273. break; 
  1274.  
  1275. case 'create_slug' : 
  1276. $lpc['screens']['create']['slug'] = $value; 
  1277. break; 
  1278.  
  1279. case 'admin_metabox_context' : 
  1280. $lpc['screens']['admin']['metabox_context'] = $value; 
  1281. break; 
  1282.  
  1283. case 'admin_metabox_priority' : 
  1284. $lpc['screens']['admin']['metabox_priority'] = $value; 
  1285. break; 
  1286.  
  1287. default : 
  1288. $lpc[ $property ] = $value; 
  1289. break; 
  1290.  
  1291. /** 
  1292. * Set up legacy properties. 
  1293. * This method is responsible for ensuring that all legacy config 
  1294. * properties are stored in an array $this->legacy_properties, so that 
  1295. * they remain available to plugins that reference the variables at 
  1296. * their old locations. 
  1297. * @since 1.8.0 
  1298. * @see BP_Group_Extension::__get() 
  1299. */ 
  1300. protected function setup_legacy_properties() { 
  1301.  
  1302. // Only run this one time. 
  1303. if ( ! empty( $this->legacy_properties ) ) { 
  1304. return; 
  1305.  
  1306. $properties = $this->get_legacy_property_list(); 
  1307. $params = $this->params; 
  1308. $lp =& $this->legacy_properties; 
  1309.  
  1310. foreach ( $properties as $property ) { 
  1311. switch ( $property ) { 
  1312. case 'enable_create_step' : 
  1313. $lp['enable_create_step'] = $params['screens']['create']['enabled']; 
  1314. break; 
  1315.  
  1316. case 'enable_edit_item' : 
  1317. $lp['enable_edit_item'] = $params['screens']['edit']['enabled']; 
  1318. break; 
  1319.  
  1320. case 'enable_admin_item' : 
  1321. $lp['enable_admin_item'] = $params['screens']['admin']['enabled']; 
  1322. break; 
  1323.  
  1324. case 'create_step_position' : 
  1325. $lp['create_step_position'] = $params['screens']['create']['position']; 
  1326. break; 
  1327.  
  1328. // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'. 
  1329. case 'admin_name' : 
  1330. $lp['admin_name'] = $params['screens']['edit']['name']; 
  1331. break; 
  1332.  
  1333. case 'admin_slug' : 
  1334. $lp['admin_slug'] = $params['screens']['edit']['slug']; 
  1335. break; 
  1336.  
  1337. case 'create_name' : 
  1338. $lp['create_name'] = $params['screens']['create']['name']; 
  1339. break; 
  1340.  
  1341. case 'create_slug' : 
  1342. $lp['create_slug'] = $params['screens']['create']['slug']; 
  1343. break; 
  1344.  
  1345. case 'admin_metabox_context' : 
  1346. $lp['admin_metabox_context'] = $params['screens']['admin']['metabox_context']; 
  1347. break; 
  1348.  
  1349. case 'admin_metabox_priority' : 
  1350. $lp['admin_metabox_priority'] = $params['screens']['admin']['metabox_priority']; 
  1351. break; 
  1352.  
  1353. default : 
  1354. // All other items get moved over. 
  1355. $lp[ $property ] = $params[ $property ]; 
  1356.  
  1357. // Also reapply to the object, for backpat. 
  1358. $this->{$property} = $params[ $property ]; 
  1359.  
  1360. break;