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