Skip to:
Content

BuddyPress.org

Changeset 6997


Ignore:
Timestamp:
05/05/2013 07:08:19 PM (11 years ago)
Author:
boonebgorges
Message:

Refactor and reorganization of BP_Group_Extension

The shiny new BP_Group_Extension class boasts the following features:

  • The *_screen* methods (edit_screen(), edit_screen_save(), etc) now share identical requirements for markup and logic. You no longer need to provide a Submit button for edit_screen() but not for create_screen(); BuddyPress provides one for you in each context. (For backward compatibility, we verify that your edit_screen() method does not already have a Submit button before auto-adding our own.) Nonces are now created and checked automatically for all form contexts. And it is no longer necessary to check whether you are on the correct group creation or admin step before outputting your markup - BP_Group_Extension does it for you.
  • Introduces support for fallback methods settings_screen() and settings_screen_save(). When you define these methods in your extension, they will provide the markup and form-saving logic for your Create, Edit, and Admin panels. If you provide specific methods for a given context (say, edit_screen() and create_screen_save()), BP_Group_Extension detects it, and uses the more specific ones instead. This should make it much easier to write DRY code in your BP_Group_Extension classes, while maintaining maximum flexibility.
  • Configuration should now be set using a config array, which is then passed to parent::init() at the end of your class constructor. This technique more closely mirrors the way that BuddyPress and WordPress handle configuration elsewhere. BP_Group_Extension parses your config array to arbitrary depth, so that you only need to pass those values that you wish to change from the defaults.
  • Complete backward compatibility for legacy BP_Group_Extension plugins.
  • Improved organization, documentation, and unit tests.

Props johnjamesjacoby for detailed feedback.

See #4955

Location:
trunk
Files:
3 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-groups/bp-groups-classes.php

    r6992 r6997  
    13681368 * the theme.
    13691369 *
    1370  * This class must be extended for each group extension and the following methods overridden:
     1370 * To implement, extend this class. In your constructor, pass an optional array
     1371 * of arguments to parent::init() to configure your widget. The config array
     1372 * supports the following values:
     1373 *   - 'slug' A unique identifier for your extension. This value will be used
     1374 *     to build URLs, so make it URL-safe
     1375 *   - 'name' A translatable name for your extension. This value is used to
     1376       populate the navigation tab, as well as the default titles for admin/
     1377       edit/create tabs.
     1378 *   - 'visibility' Set to 'public' (default) for your extension (the main tab
     1379 *     as well as the widget) to be available to anyone who can access the
     1380 *     group, 'private' otherwise.
     1381 *   - 'nav_item_position' An integer explaining where the nav item should
     1382 *     appear in the tab list
     1383 *   - 'enable_nav_item' Set to true for your extension's main tab to be
     1384 *     available to anyone who can access the group.
     1385 *   - 'nav_item_name' The translatable text you want to appear in the nav tab.
     1386 *     Defaults to the value of 'name'.
     1387 *   - 'display_hook' The WordPress action that the widget_display() method is
     1388 *     hooked to
     1389 *   - 'template_file' The template file that will be used to load the content
     1390 *     of your main extension tab. Defaults to 'groups/single/plugins.php'.
     1391 *   - 'screens' A multi-dimensional array, described below
    13711392 *
    1372  * BP_Group_Extension::widget_display(), BP_Group_Extension::display(),
    1373  * BP_Group_Extension::edit_screen_save(), BP_Group_Extension::edit_screen(),
    1374  * BP_Group_Extension::create_screen_save(), BP_Group_Extension::create_screen()
     1393 * BP_Group_Extension uses the concept of "settings screens". There are three
     1394 * contexts for settings screens:
     1395 *   - 'create', which inserts a new step into the group creation process
     1396 *   - 'edit', which adds a tab for your extension into the Admin section of
     1397 *     a group
     1398 *   - 'admin', which adds a metabox to the Groups administration panel in the
     1399 *     WordPress Dashboard
     1400 * Each of these settings screens is populated by a pair of methods: one that
     1401 * creates the markup for the screen, and one that processes form data
     1402 * submitted from the screen. If your plugin needs screens in all three
     1403 * contexts, and if the markup and form processing logic will be the same in
     1404 * each case, you can define two methods to handle all of the screens:
     1405 *   function settings_screen() {}
     1406 *   function settings_screen_save() {}
     1407 * If one or more of your settings screen needs separate logic, you may define
     1408 * context-specific methods, for example:
     1409 *   function edit_screen() {}
     1410 *   function edit_screen_save() {}
     1411 * BP_Group_Extension will use the more specific methods if they are available.
     1412 *
     1413 * You can further customize the settings screens (tab names, etc) by passing
     1414 * an optional 'screens' parameter to the init array. The format is as follows:
     1415 *   'screens' => array(
     1416 *       'create' => array(
     1417 *       'slug' => 'foo',
     1418 *       'name' => 'Foo',
     1419 *       'position' => 55,
     1420 *       'screen_callback' => 'my_create_screen_callback',
     1421 *       'screen_save_callback' => 'my_create_screen_save_callback',
     1422 *   ),
     1423 *   'edit' => array( // ...
     1424 *   ),
     1425 * Only provide those arguments that you actually want to change from the
     1426 * default configuration. BP_Group_Extension will do the rest.
     1427 *
     1428 * Note that the 'edit' screen accepts an additional parameter: 'submit_text',
     1429 * which defines the text of the Submit button automatically added to the Edit
     1430 * screen of the extension (defaults to 'Save Changes'). Also, the 'admin'
     1431 * screen accepts two additional parameters: 'metabox_priority' and
     1432 * 'metabox_context'. See the docs for add_meta_box() for more details on these
     1433 * arguments.
     1434 *
     1435 * Prior to BuddyPress 1.7, group extension configurations were set slightly
     1436 * differently. The legacy method is still supported, though deprecated.
    13751437 *
    13761438 * @package BuddyPress
     
    13791441 */
    13801442class BP_Group_Extension {
    1381     var $name = false;
    1382     var $slug = false;
    1383 
    1384     // The name/slug of the Group Admin tab for this extension
    1385     var $admin_name = '';
    1386     var $admin_slug = '';
    1387 
    1388     // The name/slug of the Group Creation tab for this extension
    1389     var $create_name = '';
    1390     var $create_slug = '';
    1391 
    1392     // Will this extension be visible to non-members of a group? Options: public/private
    1393     var $visibility = 'public';
    1394 
    1395     var $create_step_position = 81;
    1396     var $nav_item_position = 81;
    1397 
    1398     /**
    1399      * @var string Context for the optional admin metabox
    1400      * @see https://codex.wordpress.org/Function_Reference/add_meta_box for
    1401      *      possible values
    1402      * @since BuddyPress (1.7)
    1403      */
    1404     var $admin_metabox_context = 'normal';
    1405 
    1406     /**
    1407      * @var string Priority for the optional admin menabox
    1408      * @see https://codex.wordpress.org/Function_Reference/add_meta_box for
    1409      *      possible values
    1410      * @since BuddyPress (1.7)
    1411      */
    1412     var $admin_metabox_priority = 'core';
    1413 
    1414     var $enable_create_step = true;
    1415     var $enable_nav_item = true;
    1416     var $enable_edit_item = true;
    1417     var $enable_admin_item = true;
    1418 
    1419     var $nav_item_name = false;
    1420 
    1421     var $display_hook = 'groups_custom_group_boxes';
    1422     var $template_file = 'groups/single/plugins';
    1423 
    1424     // Methods you should override
    1425 
    1426     function display() {}
    1427 
    1428     function widget_display() {}
    1429 
    1430     function edit_screen( $group_id = null ) {}
    1431 
    1432     function edit_screen_save( $group_id = null ) {}
    1433 
    1434     function create_screen( $group_id = null ) {}
    1435 
    1436     function create_screen_save( $group_id = null ) {}
    1437 
    1438     // Private Methods
    1439 
    1440     function _register() {
    1441         global $bp;
    1442 
    1443         // If admin/create names and slugs are not provided, they fall back on the main
    1444         // name and slug for the extension
    1445         if ( ! $this->admin_name ) {
    1446             $this->admin_name = $this->name;
    1447         }
    1448 
    1449         if ( ! $this->admin_slug ) {
    1450             $this->admin_slug = $this->slug;
    1451         }
    1452 
    1453         if ( ! $this->create_name ) {
    1454             $this->create_name = $this->name;
    1455         }
    1456 
    1457         if ( ! $this->create_slug ) {
    1458             $this->create_slug = $this->slug;
    1459         }
    1460 
    1461         if ( ! empty( $this->enable_create_step ) ) {
    1462             // Insert the group creation step for the new group extension
    1463             $bp->groups->group_creation_steps[ $this->create_slug ] = array(
    1464                 'name'     => $this->create_name,
    1465                 'slug'     => $this->create_slug,
    1466                 'position' => $this->create_step_position,
    1467             );
    1468 
    1469             // The maybe_ methods check to see whether the create_*
    1470             // callbacks should be invoked (ie, are we on the
    1471             // correct group creation step). Hooked in separate
    1472             // methods because current creation step info not yet
    1473             // available at this point
    1474             add_action( 'groups_custom_create_steps', array( $this, 'maybe_create_screen' ) );
    1475             add_action( 'groups_create_group_step_save_' . $this->create_slug, array( $this, 'maybe_create_screen_save' ) );
    1476         }
    1477 
    1478         // When we are viewing a single group, add the group extension nav item
    1479         if ( bp_is_group() ) {
    1480             if ( $this->visibility == 'public' || ( $this->visibility != 'public' && $bp->groups->current_group->user_has_access ) ) {
    1481                 if ( $this->enable_nav_item ) {
    1482                     bp_core_new_subnav_item( array(
    1483                         'name' => !$this->nav_item_name ? $this->name : $this->nav_item_name,
    1484                         'slug' => $this->slug,
    1485                         'parent_slug' => $bp->groups->current_group->slug,
    1486                         'parent_url' => bp_get_group_permalink( $bp->groups->current_group ),
    1487                         'position' => $this->nav_item_position,
    1488                         'item_css_id' => 'nav-' . $this->slug,
    1489                         'screen_function' => array( &$this, '_display_hook' ),
    1490                         'user_has_access' => $this->enable_nav_item
    1491                     ) );
    1492 
    1493                     // When we are viewing the extension display page, set the title and options title
    1494                     if ( bp_is_current_action( $this->slug ) ) {
    1495                         add_action( 'bp_template_content_header', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
    1496                         add_action( 'bp_template_title', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
    1497                     }
    1498                 }
    1499 
    1500                 // Hook the group home widget
    1501                 if ( ! bp_current_action() && bp_is_current_action( 'home' ) ) {
    1502                     add_action( $this->display_hook, array( &$this, 'widget_display' ) );
    1503                 }
     1443
     1444    /** Public ****************************************************************/
     1445
     1446    /**
     1447     * @var array Information about this extension's screens
     1448     * @since BuddyPress (1.8)
     1449     */
     1450    public $screens = array();
     1451
     1452    /**
     1453     * @var string The name of the extending class
     1454     * @since BuddyPress (1.8)
     1455     */
     1456    public $class_name = '';
     1457
     1458    /**
     1459     * @var object A ReflectionClass object of the current extension
     1460     * @since BuddyPress (1.8)
     1461     */
     1462    public $class_reflection = null;
     1463
     1464    /**
     1465     * @var array Parsed configuration paramaters for the extension
     1466     * @since BuddyPress (1.8)
     1467     */
     1468    public $params = array();
     1469
     1470    /**
     1471     * @var int The id of the current group
     1472     * @since BuddyPress (1.8)
     1473     */
     1474    public $group_id = 0;
     1475
     1476    /**
     1477     * @var string The slug of the current extension
     1478     */
     1479    public $slug = '';
     1480
     1481    /**
     1482     * @var string The translatable name of the current extension
     1483     */
     1484    public $name = '';
     1485
     1486    /**
     1487     * @var string Whether the extension tab is visible. 'public'
     1488     *   or 'private'
     1489     */
     1490    public $visibility = 'public';
     1491
     1492    /**
     1493     * @var int The numeric position of the main nav item
     1494     */
     1495    public $nav_item_position = 81;
     1496
     1497    /**
     1498     * @var bool Whether to show the nav item
     1499     */
     1500    public $enable_nav_item = false;
     1501
     1502    /**
     1503     * @var string The text of the nav item. Defaults to self::name
     1504     */
     1505    public $nav_item_name = '';
     1506
     1507    /**
     1508     * @var string The WP action that self::widget_display() is attached to.
     1509     *   Defaults to 'groups_custom_group_boxes'
     1510     */
     1511    public $display_hook = 'groups_custom_group_boxes';
     1512
     1513    /**
     1514     * @var string The template file used to load the plugin content.
     1515     *   Defaults to 'groups/single/plugins'
     1516     */
     1517    public $template_file = 'groups/single/plugins';
     1518
     1519    /** Protected *************************************************************/
     1520
     1521    /**
     1522     * @var bool Has the extension been initialized?
     1523     * @since BuddyPress (1.8)
     1524     */
     1525    protected $initialized = false;
     1526
     1527    /**
     1528     * @var array Extension properties as set by legacy extensions
     1529     * @since BuddyPress (1.8)
     1530     */
     1531    protected $legacy_properties = array();
     1532
     1533    /**
     1534     * @var array Extension properties as set by legacy extensions, but
     1535     *   converted to match the new format for params
     1536     * @since BuddyPress (1.8)
     1537     */
     1538    protected $legacy_properties_converted = array();
     1539
     1540    /**
     1541     * @var array Miscellaneous data as set by the __set() magic method
     1542     * @since BuddyPress (1.8)
     1543     */
     1544    protected $data = array();
     1545
     1546    /** Screen Overrides ******************************************************/
     1547
     1548    /**
     1549     * Screen override methods are how your extension will display content
     1550     * and handle form submits. Your extension should only override those
     1551     * methods that it needs for its purposes.
     1552     */
     1553
     1554    // The content of the group tab
     1555    public function display() {}
     1556
     1557    // Content displayed in a widget sidebar, if applicable
     1558    public function widget_display() {}
     1559
     1560    // *_screen() displays the settings form for the given context
     1561    // *_screen_save() processes data submitted via the settings form
     1562    // The settings_* methods are generic fallbacks, which can optionally
     1563    // be overridden by the more specific edit_*, create_*, and admin_*
     1564    // versions.
     1565    public function settings_screen( $group_id = null ) {}
     1566    public function settings_screen_save( $group_id = null ) {}
     1567    public function edit_screen( $group_id = null ) {}
     1568    public function edit_screen_save( $group_id = null ) {}
     1569    public function create_screen( $group_id = null ) {}
     1570    public function create_screen_save( $group_id = null ) {}
     1571    public function admin_screen( $group_id = null ) {}
     1572    public function admin_screen_save( $group_id = null ) {}
     1573
     1574    /** Setup *************************************************************/
     1575
     1576    /**
     1577     * Initialize the extension, using your config settings
     1578     *
     1579     * Your plugin should call this method at the very end of its
     1580     * constructor, like so:
     1581     *
     1582     *   public function __construct() {
     1583     *       $args = array(
     1584     *           'slug' => 'my-group-extension',
     1585     *           'name' => 'My Group Extension',
     1586     *           // ...
     1587     *       );
     1588     *
     1589     *       parent::init( $args );
     1590     *   }
     1591     *
     1592     * @since BuddyPress (1.8)
     1593     * @param array $args See inline definition below for arguments
     1594     */
     1595    public function init( $args = array() ) {
     1596
     1597        // Before this init() method was introduced, plugins were
     1598        // encouraged to set their config directly. For backward
     1599        // compatibility with these plugins, we detect whether this is
     1600        // one of those legacy plugins, and parse any legacy arguments
     1601        // with those passed to init()
     1602        $this->parse_legacy_properties();
     1603        $args = $this->parse_args_r( $args, $this->legacy_properties_converted );
     1604
     1605        // Parse with defaults
     1606        $this->params = $this->parse_args_r( $args, array(
     1607            'slug'              => $this->slug,
     1608            'name'              => $this->name,
     1609            'visibility'        => $this->visibility,
     1610            'nav_item_position' => $this->nav_item_position,
     1611            'enable_nav_item'   => (bool) $this->enable_nav_item,
     1612            'nav_item_name'     => $this->nav_item_name,
     1613            'display_hook'      => $this->display_hook,
     1614            'template_file'     => $this->template_file,
     1615            'screens'           => $this->get_default_screens(),
     1616        ) );
     1617
     1618        $this->initialized = true;
     1619    }
     1620
     1621    /**
     1622     * The main setup routine for the extension
     1623     *
     1624     * This method contains the primary logic for setting up an extension's
     1625     * configuration, setting up backward compatibility for legacy plugins,
     1626     * and hooking the extension's screen functions into WP and BP.
     1627     *
     1628     * Marked 'public' because it must be accessible to add_action().
     1629     * However, you should never need to invoke this method yourself - it
     1630     * is called automatically at the right point in the load order by
     1631     * bp_register_group_extension().
     1632     *
     1633     * @since BuddyPress (1.1)
     1634     */
     1635    public function _register() {
     1636
     1637        // Detect and parse properties set by legacy extensions
     1638        $this->parse_legacy_properties();
     1639
     1640        // Initialize, if necessary. This should only happen for
     1641        // legacy extensions that don't call parent::init() themselves
     1642        if ( true !== $this->initialized ) {
     1643            $this->init();
     1644        }
     1645
     1646        // Set some config values, based on the parsed params
     1647        $this->group_id          = $this->get_group_id();
     1648        $this->slug              = $this->params['slug'];
     1649        $this->name              = $this->params['name'];
     1650        $this->visibility        = $this->params['visibility'];
     1651        $this->nav_item_position = $this->params['nav_item_position'];
     1652        $this->nav_item_name     = $this->params['nav_item_name'];
     1653        $this->display_hook      = $this->params['display_hook'];
     1654        $this->template_file     = $this->params['template_file'];
     1655
     1656        // Configure 'screens': create, admin, and edit contexts
     1657        $this->setup_screens();
     1658
     1659        // Mirror configuration data so it's accessible to plugins
     1660        // that look for it in its old locations
     1661        $this->setup_legacy_properties();
     1662
     1663        // Hook the extension into BuddyPress
     1664        $this->setup_display_hooks();
     1665        $this->setup_create_hooks();
     1666        $this->setup_edit_hooks();
     1667        $this->setup_admin_hooks();
     1668    }
     1669
     1670    /**
     1671     * Set up some basic info about the Extension
     1672     *
     1673     * Here we collect the name of the extending class, as well as a
     1674     * ReflectionClass that is used in get_screen_callback() to determine
     1675     * whether your extension overrides certain callback methods.
     1676     *
     1677     * @since BuddyPress (1.8)
     1678     */
     1679    protected function setup_class_info() {
     1680        if ( empty( $this->class_name ) ) {
     1681            $this->class_name = get_class( $this );
     1682        }
     1683
     1684        if ( is_null( $this->class_reflection ) ) {
     1685            $this->class_reflection = new ReflectionClass( $this->class_name );
     1686        }
     1687    }
     1688
     1689    /**
     1690     * Get the current group id
     1691     *
     1692     * Check for:
     1693     *   - current group
     1694     *   - new group
     1695     *   - group admin
     1696     *
     1697     * @since BuddyPress (1.8)
     1698     */
     1699    public static function get_group_id() {
     1700
     1701        // Usually this will work
     1702        $group_id = bp_get_current_group_id();
     1703
     1704        // On the admin, get the group id out of the $_GET params
     1705        if ( empty( $group_id ) && is_admin() && ( isset( $_GET['page'] ) && ( 'bp-groups' === $_GET['page'] ) ) && ! empty( $_GET['gid'] ) ) {
     1706            $group_id = (int) $_GET['gid'];
     1707        }
     1708
     1709        // This fallback will only be hit when the create step is very
     1710        // early
     1711        if ( empty( $group_id ) && bp_get_new_group_id() ) {
     1712            $group_id = bp_get_new_group_id();
     1713        }
     1714
     1715        // On some setups, the group id has to be fetched out of the
     1716        // $_POST array
     1717        // @todo Figure out why this is happening during group creation
     1718        if ( empty( $group_id ) && isset( $_POST['group_id'] ) ) {
     1719            $group_id = (int) $_POST['group_id'];
     1720        }
     1721
     1722        return $group_id;
     1723    }
     1724
     1725    /**
     1726     * Gather configuration data about your screens
     1727     *
     1728     * @since BuddyPress (1.8)
     1729     */
     1730    protected function get_default_screens() {
     1731        $this->setup_class_info();
     1732
     1733        $screens = array(
     1734            'create' => array(
     1735                'position' => 81,
     1736            ),
     1737            'edit'   => array(
     1738                'submit_text' => __( 'Save Changes', 'buddypress' ),
     1739            ),
     1740            'admin'  => array(
     1741                'metabox_context'  => 'normal',
     1742                'metabox_priority' => 'core',
     1743            ),
     1744        );
     1745
     1746        foreach ( $screens as $context => &$screen ) {
     1747            $screen['enabled']     = true;
     1748            $screen['name']        = $this->name;
     1749            $screen['slug']        = $this->slug;
     1750
     1751            $screen['screen_callback']      = $this->get_screen_callback( $context, 'screen'      );
     1752            $screen['screen_save_callback'] = $this->get_screen_callback( $context, 'screen_save' );
     1753        }
     1754
     1755        return $screens;
     1756    }
     1757
     1758    /**
     1759     * Set up screens array based on params
     1760     *
     1761     * @since BuddyPress (1.8)
     1762     */
     1763    protected function setup_screens() {
     1764        foreach ( (array) $this->params['screens'] as $context => $screen ) {
     1765            if ( empty( $screen['slug'] ) ) {
     1766                $screen['slug'] = $this->slug;
    15041767            }
    1505         }
    1506 
    1507         // Construct the admin edit tab for the new group extension
    1508         if ( ! empty( $this->enable_edit_item ) && bp_is_item_admin() ) {
    1509             add_action( 'groups_admin_tabs', create_function( '$current, $group_slug',
    1510                 '$selected = "";
    1511                 if ( "' . esc_attr( $this->admin_slug ) . '" == $current )
    1512                     $selected = " class=\"current\"";
    1513                 echo "<li{$selected}><a href=\"' . trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/{$group_slug}/admin/' . esc_attr( $this->admin_slug ) ) . '\">' . esc_attr( $this->admin_name ) . '</a></li>";'
    1514             ), 10, 2 );
    1515 
    1516             // Catch the edit screen and forward it to the plugin template
    1517             if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) && bp_is_action_variable( $this->admin_slug, 0 ) ) {
    1518                 $this->edit_screen_save( bp_get_current_group_id() );
    1519 
    1520                 add_action( 'groups_custom_edit_steps', array( &$this, 'call_edit_screen' ) );
    1521 
    1522                 if ( '' != bp_locate_template( array( 'groups/single/home.php' ), false ) ) {
    1523                     bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
    1524                 } else {
    1525                     add_action( 'bp_template_content_header', create_function( '', 'echo "<ul class=\"content-header-nav\">"; bp_group_admin_tabs(); echo "</ul>";' ) );
    1526                     add_action( 'bp_template_content', array( &$this, 'call_edit_screen' ) );
    1527                     bp_core_load_template( apply_filters( 'bp_core_template_plugin', '/groups/single/plugins' ) );
    1528                 }
     1768
     1769            if ( empty( $screen['name'] ) ) {
     1770                $screen['name'] = $this->name;
    15291771            }
    1530         }
    1531 
    1532         // Construct the admin metabox
    1533         // Plugin authors: Note that $this->enable_admin_item must be
    1534         // set to true, and self::admin_screen() must be defined
    1535         if ( ! empty( $this->enable_admin_item ) && is_admin() && method_exists( get_class( $this ), 'admin_screen' ) ) {
    1536             // Hook the admin screen markup function to the content hook
    1537             add_action( 'bp_groups_admin_meta_box_content_' . $this->slug, array( $this, 'admin_screen' ) );
    1538 
    1539             // Initialize the metabox
    1540             add_action( 'bp_groups_admin_meta_boxes', array( $this, '_meta_box_display_callback' ) );
    1541 
    1542             // Catch the metabox save
    1543             if ( method_exists( get_class( $this ), 'admin_screen_save' ) ) {
    1544                 add_action( 'bp_group_admin_edit_after', array( $this, 'admin_screen_save' ), 10 );
     1772
     1773            $this->screens[ $context ] = $screen;
     1774        }
     1775    }
     1776
     1777    /** Display ***************************************************************/
     1778
     1779    /**
     1780     * Hook this extension's group tab into BuddyPress, if necessary
     1781     *
     1782     * @since BuddyPress (1.8)
     1783     */
     1784    protected function setup_display_hooks() {
     1785
     1786        // Bail if not a group
     1787        if ( ! bp_is_group() ) {
     1788            return;
     1789        }
     1790
     1791        // Bail if the current user doesn't have access
     1792        if ( ( 'public' !== $this->visibility ) && ! buddypress()->groups->current_group->user_has_access ) {
     1793            return;
     1794        }
     1795
     1796        if ( true === $this->enable_nav_item ) {
     1797            bp_core_new_subnav_item( array(
     1798                'name'            => ! $this->nav_item_name ? $this->name : $this->nav_item_name,
     1799                'slug'            => $this->slug,
     1800                'parent_slug'     => bp_get_current_group_slug(),
     1801                'parent_url'      => bp_get_group_permalink( groups_get_current_group() ),
     1802                'position'        => $this->nav_item_position,
     1803                'item_css_id'     => 'nav-' . $this->slug,
     1804                'screen_function' => array( &$this, '_display_hook' ),
     1805                'user_has_access' => $this->enable_nav_item
     1806            ) );
     1807
     1808            // When we are viewing the extension display page, set the title and options title
     1809            if ( bp_is_current_action( $this->slug ) ) {
     1810                add_action( 'bp_template_content_header', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
     1811                add_action( 'bp_template_title',          create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
    15451812            }
    15461813        }
    1547     }
    1548 
    1549     function _display_hook() {
     1814
     1815        // Hook the group home widget
     1816        if ( ! bp_current_action() && bp_is_current_action( 'home' ) ) {
     1817            add_action( $this->display_hook, array( &$this, 'widget_display' ) );
     1818        }
     1819    }
     1820
     1821    /**
     1822     * Hooks the main display method, and loads the template file
     1823     */
     1824    public function _display_hook() {
    15501825        add_action( 'bp_template_content', array( &$this, 'display' ) );
    15511826        bp_core_load_template( apply_filters( 'bp_core_template_plugin', $this->template_file ) );
    15521827    }
    15531828
     1829    /** Create ****************************************************************/
     1830
     1831    /**
     1832     * Hook this extension's Create step into BuddyPress, if necessary
     1833     *
     1834     * @since BuddyPress (1.8)
     1835     */
     1836    protected function setup_create_hooks() {
     1837        if ( ! $this->is_screen_enabled( 'create' ) ) {
     1838            return;
     1839        }
     1840
     1841        $screen = $this->screens['create'];
     1842
     1843        // Insert the group creation step for the new group extension
     1844        buddypress()->groups->group_creation_steps[ $screen['slug'] ] = array(
     1845            'name'     => $screen['name'],
     1846            'slug'     => $screen['slug'],
     1847            'position' => $screen['position'],
     1848        );
     1849
     1850        // The maybe_ methods check to see whether the create_*
     1851        // callbacks should be invoked (ie, are we on the
     1852        // correct group creation step). Hooked in separate
     1853        // methods because current creation step info not yet
     1854        // available at this point
     1855        add_action( 'groups_custom_create_steps', array( $this, 'maybe_create_screen' ) );
     1856        add_action( 'groups_create_group_step_save_' . $screen['slug'], array( $this, 'maybe_create_screen_save' ) );
     1857    }
     1858
     1859    /**
     1860     * Call the create_screen() method, if we're on the right page
     1861     *
     1862     * @since 1.8
     1863     */
     1864    public function maybe_create_screen() {
     1865        if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) {
     1866            return;
     1867        }
     1868
     1869        call_user_func( $this->screens['create']['screen_callback'], $this->group_id );
     1870        $this->nonce_field( 'create' );
     1871
     1872        // The create screen requires an additional nonce field
     1873        // due to a quirk in the way the templates are built
     1874        wp_nonce_field( 'groups_create_save_' . bp_get_groups_current_create_step() );
     1875    }
     1876
     1877    /**
     1878     * Call the create_screen_save() method, if we're on the right page
     1879     *
     1880     * @since 1.8
     1881     */
     1882    public function maybe_create_screen_save() {
     1883        if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) {
     1884            return;
     1885        }
     1886
     1887        $this->check_nonce( 'create' );
     1888        call_user_func( $this->screens['create']['screen_save_callback'], $this->group_id );
     1889    }
     1890
     1891    /** Edit ******************************************************************/
     1892
     1893    /**
     1894     * Hook this extension's Edit panel into BuddyPress, if necessary
     1895     *
     1896     * @since BuddyPress (1.8)
     1897     */
     1898    protected function setup_edit_hooks() {
     1899
     1900        // Bail if not an edit screen
     1901        if ( ! $this->is_screen_enabled( 'edit' ) || ! bp_is_item_admin() ) {
     1902            return;
     1903        }
     1904
     1905        $screen = $this->screens['edit'];
     1906
     1907        // Add the tab
     1908        // @todo BP should be using bp_core_new_subnav_item()
     1909        add_action( 'groups_admin_tabs', create_function( '$current, $group_slug',
     1910            '$selected = "";
     1911            if ( "' . esc_attr( $screen['slug'] ) . '" == $current )
     1912                $selected = " class=\"current\"";
     1913            echo "<li{$selected}><a href=\"' . trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/{$group_slug}/admin/' . esc_attr( $screen['slug'] ) ) . '\">' . esc_attr( $screen['name'] ) . '</a></li>";'
     1914        ), 10, 2 );
     1915
     1916        // Catch the edit screen and forward it to the plugin template
     1917        if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) && bp_is_action_variable( $screen['slug'], 0 ) ) {
     1918            $this->call_edit_screen_save( $this->group_id );
     1919
     1920            add_action( 'groups_custom_edit_steps', array( &$this, 'call_edit_screen' ) );
     1921
     1922            if ( '' !== bp_locate_template( array( 'groups/single/home.php' ), false ) ) {
     1923                bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
     1924            } else {
     1925                add_action( 'bp_template_content_header', create_function( '', 'echo "<ul class=\"content-header-nav\">"; bp_group_admin_tabs(); echo "</ul>";' ) );
     1926                add_action( 'bp_template_content', array( &$this, 'call_edit_screen' ) );
     1927                bp_core_load_template( apply_filters( 'bp_core_template_plugin', '/groups/single/plugins' ) );
     1928            }
     1929        }
     1930    }
     1931
     1932    /**
     1933     * Call the edit_screen() method
     1934     *
     1935     * Previous versions of BP_Group_Extension required plugins to provide
     1936     * their own Submit button and nonce fields when building markup. In
     1937     * BP 1.8, this requirement was lifted - BP_Group_Extension now handles
     1938     * all required submit buttons and nonces.
     1939     *
     1940     * We put the edit screen markup into an output buffer before echoing.
     1941     * This is so that we can check for the presence of a hardcoded submit
     1942     * button, as would be present in legacy plugins; if one is found, we
     1943     * do not auto-add our own button.
     1944     *
     1945     * @since BuddyPress (1.8)
     1946     */
     1947    public function call_edit_screen() {
     1948        ob_start();
     1949        call_user_func( $this->screens['edit']['screen_callback'], $this->group_id );
     1950        $screen = ob_get_contents();
     1951        ob_end_clean();
     1952
     1953        echo $this->maybe_add_submit_button( $screen );
     1954
     1955        $this->nonce_field( 'edit' );
     1956    }
     1957
     1958    /**
     1959     * Check the nonce, and call the edit_screen_save() method
     1960     *
     1961     * @since BuddyPress (1.8)
     1962     */
     1963    public function call_edit_screen_save() {
     1964        if ( empty( $_POST ) ) {
     1965            return;
     1966        }
     1967
     1968        $this->check_nonce( 'edit' );
     1969        call_user_func( $this->screens['edit']['screen_save_callback'], $this->group_id );
     1970    }
     1971
     1972    /**
     1973     * Add a submit button to the edit form, if it needs one
     1974     *
     1975     * There's an inconsistency in the way that the group Edit and Create
     1976     * screens are rendered: the Create screen has a submit button built
     1977     * in, but the Edit screen does not. This function allows plugin
     1978     * authors to write markup that does not contain the submit button for
     1979     * use on both the Create and Edit screens - BP will provide the button
     1980     * if one is not found.
     1981     *
     1982     * @since BuddyPress (1.8)
     1983     * @param string $screen The screen markup, captured in the output buffer
     1984     * @param string $screen The same markup, with a submit button added
     1985     */
     1986    protected function maybe_add_submit_button( $screen = '' ) {
     1987        if ( $this->has_submit_button( $screen ) ) {
     1988            return $screen;
     1989        }
     1990
     1991        return $screen . sprintf(
     1992            '<div id="%s"><input type="submit" name="save" value="%s" id="%s"></div>',
     1993            'bp-group-edit-' . $this->slug . '-submit-wrapper',
     1994            $this->screens['edit']['submit_text'],
     1995            'bp-group-edit-' . $this->slug . '-submit'
     1996        );
     1997    }
     1998
     1999    /**
     2000     * Does the given markup have a submit button?
     2001     *
     2002     * @since BuddyPress (1.8)
     2003     * @param $screen The markup to check
     2004     * @return bool
     2005     */
     2006    public static function has_submit_button( $screen = '' ) {
     2007        $pattern = "/<input[^>]+type=[\'\"]submit[\'\"]/";
     2008        preg_match( $pattern, $screen, $matches );
     2009        return ! empty( $matches[0] );
     2010    }
     2011
     2012    /** Admin *****************************************************************/
     2013
     2014    /**
     2015     * Hook this extension's Admin metabox into BuddyPress, if necessary
     2016     *
     2017     * @since BuddyPress (1.8)
     2018     */
     2019    protected function setup_admin_hooks() {
     2020        if ( ! $this->is_screen_enabled( 'admin' ) || ! is_admin() ) {
     2021            return;
     2022        }
     2023
     2024        // Hook the admin screen markup function to the content hook
     2025        add_action( 'bp_groups_admin_meta_box_content_' . $this->slug, array( $this, 'call_admin_screen' ) );
     2026
     2027        // Initialize the metabox
     2028        add_action( 'bp_groups_admin_meta_boxes', array( $this, '_meta_box_display_callback' ) );
     2029
     2030        // Catch the metabox save
     2031        add_action( 'bp_group_admin_edit_after', array( $this, 'call_admin_screen_save' ), 10 );
     2032    }
     2033
     2034    /**
     2035     * Call the admin_screen() method, and add a nonce field
     2036     *
     2037     * @since BuddyPress (1.8)
     2038     */
     2039    public function call_admin_screen() {
     2040        call_user_func( $this->screens['admin']['screen_callback'], $this->group_id );
     2041        $this->nonce_field( 'admin' );
     2042    }
     2043
     2044    /**
     2045     * Check the nonce, and call the admin_screen_save() method
     2046     *
     2047     * @since BuddyPress (1.8)
     2048     */
     2049    public function call_admin_screen_save() {
     2050        $this->check_nonce( 'admin' );
     2051        call_user_func( $this->screens['admin']['screen_save_callback'], $this->group_id );
     2052    }
     2053
    15542054    /**
    15552055     * Create the Dashboard meta box for this extension
     
    15572057     * @since BuddyPress (1.7)
    15582058     */
    1559     function _meta_box_display_callback() {
     2059    public function _meta_box_display_callback() {
    15602060        $group_id = isset( $_GET['gid'] ) ? (int) $_GET['gid'] : 0;
     2061        $screen   = $this->screens['admin'];
    15612062
    15622063        add_meta_box(
    1563             $this->slug,
    1564             $this->name,
     2064            $screen['slug'],
     2065            $screen['name'],
    15652066            create_function( '', 'do_action( "bp_groups_admin_meta_box_content_' . $this->slug . '", ' . $group_id . ' );' ),
    15662067            get_current_screen()->id,
    1567             $this->admin_metabox_context,
    1568             $this->admin_metabox_priority
     2068            $screen['metabox_context'],
     2069            $screen['metabox_priority']
    15692070        );
    15702071    }
    15712072
    1572     /**
    1573      * Call the edit_screen() method
    1574      *
    1575      * Broken into a standalone method so we can pass the current group id
    1576      * to edit_screen()
    1577      *
    1578      * @since 1.8
    1579      */
    1580     public function call_edit_screen() {
    1581         $this->edit_screen( bp_get_current_group_id() );
    1582     }
    1583 
    1584     /**
    1585      * Call the create_screen() method, if we're on the right page
    1586      *
    1587      * @since 1.8
    1588      */
    1589     public function maybe_create_screen() {
    1590         if ( bp_is_group_creation_step( $this->slug ) ) {
    1591             $this->create_screen( bp_get_new_group_id() );
    1592         }
    1593     }
    1594 
    1595     /**
    1596      * Call the create_screen_save() method, if we're on the right page
    1597      *
    1598      * @since 1.8
    1599      */
    1600     public function maybe_create_screen_save() {
    1601         if ( bp_is_group_creation_step( $this->slug ) ) {
    1602             $this->create_screen_save( bp_get_new_group_id() );
    1603         }
    1604     }
    1605 
     2073
     2074    /** Utilities *************************************************************/
     2075
     2076    /**
     2077     * Generate the nonce fields for a settings form
     2078     *
     2079     * The nonce field name (the second param passed to wp_nonce_field)
     2080     * contains this extension's slug and is thus unique to this extension.
     2081     * This is necessary because in some cases (namely, the Dashboard),
     2082     * more than one extension may generate nonces on the same page, and we
     2083     * must avoid name clashes.
     2084     *
     2085     * @since BuddyPress (1.8)
     2086     * @uses wp_nonce_field()
     2087     * @param string $context 'create', 'edit', 'admin'
     2088     */
     2089    public function nonce_field( $context = '' ) {
     2090        wp_nonce_field( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug );
     2091    }
     2092
     2093    /**
     2094     * Check the nonce on a submitted settings form
     2095     *
     2096     * @since BuddyPress (1.8)
     2097     * @uses check_admin_referer()
     2098     * @param string $context 'create', 'edit', 'admin'
     2099     */
     2100    public function check_nonce( $context = '' ) {
     2101        check_admin_referer( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug );
     2102    }
     2103
     2104    /**
     2105     * Is the specified screen enabled?
     2106     *
     2107     * To be enabled, a screen must both have the 'enabled' key set to true
     2108     * (legacy: $this->enable_create_step, etc), and its screen_callback
     2109     * must also exist and be callable.
     2110     *
     2111     * @since BuddyPress (1.8)
     2112     * @param string $context 'create', 'edit', 'admin'
     2113     * @return bool
     2114     */
     2115    public function is_screen_enabled( $context = '' ) {
     2116        $enabled = false;
     2117
     2118        if ( isset( $this->screens[ $context ] ) ) {
     2119            $enabled = $this->screens[ $context ]['enabled'] && is_callable( $this->screens[ $context ]['screen_callback'] );
     2120        }
     2121
     2122        return (bool) $enabled;
     2123    }
     2124
     2125    /**
     2126     * Get the appropriate screen callback for the specified context/type
     2127     *
     2128     * BP Group Extensions have three special "screen contexts": create,
     2129     * admin, and edit. Each of these contexts has a corresponding
     2130     * _screen() and _screen_save() method, which allow group extension
     2131     * plugins to define different markup and logic for each context.
     2132     *
     2133     * BP also supports fallback settings_screen() and
     2134     * settings_screen_save() methods, which can be used to define markup
     2135     * and logic that is shared between context. For each context, you may
     2136     * either provide context-specific methods, or you can let BP fall back
     2137     * on the shared settings_* callbacks.
     2138     *
     2139     * For example, consider a BP_Group_Extension implementation that looks
     2140     * like this:
     2141     *
     2142     *   // ...
     2143     *   function create_screen( $group_id ) { ... }
     2144     *   function create_screen_save( $group_id ) { ... }
     2145     *   function settings_screen( $group_id ) { ... }
     2146     *   function settings_screen_save( $group_id ) { ... }
     2147     *   // ...
     2148     *
     2149     * BP_Group_Extension will use your create_* methods for the Create
     2150     * steps, and will use your generic settings_* methods for the Edit
     2151     * and Admin contexts. This schema allows plugin authors maximum
     2152     * flexibility without having to repeat themselves.
     2153     *
     2154     * The get_screen_callback() method uses a ReflectionClass object to
     2155     * determine whether your extension has provided a given callback.
     2156     *
     2157     * @since BuddyPress (1.8)
     2158     * @param string $context 'create', 'edit', 'admin'
     2159     * @param string $type 'screen', 'screen_save'
     2160     * @return mixed A callable function handle
     2161     */
     2162    public function get_screen_callback( $context = '', $type = 'screen' ) {
     2163        $callback = '';
     2164
     2165        // Try the context-specific callback first
     2166        $method  = $context . '_' . $type;
     2167        $rmethod = $this->class_reflection->getMethod( $method );
     2168        if ( isset( $rmethod->class ) && $this->class_name === $rmethod->class ) {
     2169            $callback = array( $this->class_name, $method );
     2170        }
     2171
     2172        if ( empty( $callback ) ) {
     2173            $fallback_method  = 'settings_' . $type;
     2174            $rfallback_method = $this->class_reflection->getMethod( $fallback_method );
     2175            if ( isset( $rfallback_method->class ) && $this->class_name === $rfallback_method->class ) {
     2176                $callback = array( $this->class_name, $fallback_method );
     2177            }
     2178        }
     2179
     2180        return $callback;
     2181    }
     2182
     2183    /**
     2184     * Recursive argument parsing
     2185     *
     2186     * This acts like a multi-dimensional version of wp_parse_args() (minus
     2187     * the querystring parsing - you must pass arrays).
     2188     *
     2189     * Values from $a override those from $b; keys in $b that don't exist
     2190     * in $a are passed through.
     2191     *
     2192     * This is different from array_merge_recursive(), both because of the
     2193     * order of preference ($a overrides $b) and because of the fact that
     2194     * array_merge_recursive() combines arrays deep in the tree, rather
     2195     * than overwriting the b array with the a array.
     2196     *
     2197     * The implementation of this function is specific to the needs of
     2198     * BP_Group_Extension, where we know that arrays will always be
     2199     * associative, and that an argument under a given key in one array
     2200     * will be matched by a value of identical depth in the other one. The
     2201     * function is NOT designed for general use, and will probably result
     2202     * in unexpected results when used with data in the wild. See, eg,
     2203     * http://core.trac.wordpress.org/ticket/19888
     2204     *
     2205     * @since BuddyPress (1.8)
     2206     * @arg array $a
     2207     * @arg array $b
     2208     * @return array
     2209     */
     2210    public static function parse_args_r( &$a, $b ) {
     2211        $a = (array) $a;
     2212        $b = (array) $b;
     2213        $r = $b;
     2214
     2215        foreach ( $a as $k => &$v ) {
     2216            if ( is_array( $v ) && isset( $r[ $k ] ) ) {
     2217                $r[ $k ] = self::parse_args_r( $v, $r[ $k ] );
     2218            } else {
     2219                $r[ $k ] = $v;
     2220            }
     2221        }
     2222
     2223        return $r;
     2224    }
     2225
     2226    /** Legacy Support ********************************************************/
     2227
     2228    /**
     2229     * In BuddyPress 1.8, the recommended technique for configuring
     2230     * extensions changed from directly setting various object properties
     2231     * in the class constructor, to passing a configuration array to
     2232     * parent::init(). The following methods ensure that extensions created
     2233     * in the old way continue to work, by converting legacy configuration
     2234     * data to the new format.
     2235     */
     2236
     2237    /**
     2238     * Provide access to otherwise unavailable object properties
     2239     *
     2240     * This magic method is here for backward compatibility with plugins
     2241     * that refer to config properties that have moved to a different
     2242     * location (such as enable_create_step, which is now at
     2243     * $this->screens['create']['enabled']
     2244     *
     2245     * The legacy_properties array is set up in
     2246     * self::setup_legacy_properties().
     2247     *
     2248     * @since BuddyPress (1.8)
     2249     * @param string $key
     2250     * @return mixed
     2251     */
     2252    public function __get( $key ) {
     2253        if ( isset( $this->legacy_properties[ $key ] ) ) {
     2254            return $this->legacy_properties[ $key ];
     2255        } elseif ( isset( $this->data[ $key ] ) ) {
     2256            return $this->data[ $key ];
     2257        } else {
     2258            return null;
     2259        }
     2260    }
     2261
     2262    /**
     2263     * Provide a fallback for isset( $this->foo ) when foo is unavailable
     2264     *
     2265     * This magit method is here for backward compatibility with plugins
     2266     * that have set their class config options directly in the class
     2267     * constructor. The parse_legacy_properties() method of the current
     2268     * class needs to check whether any legacy keys have been put into the
     2269     * $this->data array.
     2270     *
     2271     * @since BuddyPress (1.8)
     2272     * @param string $key
     2273     * @return bool
     2274     */
     2275    public function __isset( $key ) {
     2276        if ( isset( $this->legacy_properties[ $key ] ) ) {
     2277            return true;
     2278        } elseif ( isset( $this->data[ $key ] ) ) {
     2279            return true;
     2280        } else {
     2281            return false;
     2282        }
     2283    }
     2284
     2285    /**
     2286     * Allow plugins to set otherwise unavailable object properties
     2287     *
     2288     * This magic method is here for backward compatibility with plugins
     2289     * that may attempt to modify the group extension by manually assigning
     2290     * a value to an object property that no longer exists, such as
     2291     * $this->enable_create_step.
     2292     *
     2293     * @since BuddyPress (1.8)
     2294     * @param string $key
     2295     * @param mixed $value
     2296     */
     2297    public function __set( $key, $value ) {
     2298
     2299        if ( empty( $this->initialized ) ) {
     2300            $this->data[ $key ] = $value;
     2301        }
     2302
     2303        switch ( $key ) {
     2304            case 'enable_create_step' :
     2305                $this->screens['create']['enabled'] = $value;
     2306                break;
     2307
     2308            case 'enable_edit_item' :
     2309                $this->screens['edit']['enabled'] = $value;
     2310                break;
     2311
     2312            case 'enable_admin_item' :
     2313                $this->screens['admin']['enabled'] = $value;
     2314                break;
     2315
     2316            case 'create_step_position' :
     2317                $this->screens['create']['position'] = $value;
     2318                break;
     2319
     2320            // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'
     2321            case 'admin_name' :
     2322                $this->screens['edit']['name'] = $value;
     2323                break;
     2324
     2325            case 'admin_slug' :
     2326                $this->screens['edit']['slug'] = $value;
     2327                break;
     2328
     2329            case 'create_name' :
     2330                $this->screens['create']['name'] = $value;
     2331                break;
     2332
     2333            case 'create_slug' :
     2334                $this->screens['create']['slug'] = $value;
     2335                break;
     2336
     2337            case 'admin_metabox_context' :
     2338                $this->screens['admin']['metabox_context'] = $value;
     2339                break;
     2340
     2341            case 'admin_metabox_priority' :
     2342                $this->screens['admin']['metabox_priority'] = $value;
     2343                break;
     2344
     2345            default :
     2346                $this->data[ $key ] = $value;
     2347                break;
     2348        }
     2349    }
     2350
     2351    /**
     2352     * Returns a list of legacy properties
     2353     *
     2354     * The legacy implementation of BP_Group_Extension used all of these
     2355     * object properties for configuration. Some have been moved.
     2356     *
     2357     * @since BuddyPress (1.8)
     2358     * @return array
     2359     */
     2360    protected function get_legacy_property_list() {
     2361        return array(
     2362            'name',
     2363            'slug',
     2364            'admin_name',
     2365            'admin_slug',
     2366            'create_name',
     2367            'create_slug',
     2368            'visibility',
     2369            'create_step_position',
     2370            'nav_item_position',
     2371            'admin_metabox_context',
     2372            'admin_metabox_priority',
     2373            'enable_create_step',
     2374            'enable_nav_item',
     2375            'enable_edit_item',
     2376            'enable_admin_item',
     2377            'nav_item_name',
     2378            'display_hook',
     2379            'template_file',
     2380        );
     2381    }
     2382
     2383    /**
     2384     * Parse legacy properties
     2385     *
     2386     * The old standard for BP_Group_Extension was for plugins to register
     2387     * their settings as properties in their constructor. The new method is
     2388     * to pass a config array to the init() method. In order to support
     2389     * legacy plugins, we slurp up legacy properties, and later on we'll
     2390     * parse them into the new init() array.
     2391     *
     2392     * @since BuddyPress (1.8)
     2393     */
     2394    protected function parse_legacy_properties() {
     2395
     2396        // Only run this one time
     2397        if ( ! empty( $this->legacy_properties_converted ) ) {
     2398            return;
     2399        }
     2400
     2401        $properties = $this->get_legacy_property_list();
     2402
     2403        // By-reference variable for convenience
     2404        $lpc =& $this->legacy_properties_converted;
     2405
     2406        foreach ( $properties as $property ) {
     2407
     2408            // No legacy config exists for this key
     2409            if ( ! isset( $this->{$property} ) ) {
     2410                continue;
     2411            }
     2412
     2413            // Grab the value and record it as appropriate
     2414            $value = $this->{$property};
     2415
     2416            switch ( $property ) {
     2417                case 'enable_create_step' :
     2418                    $lpc['screens']['create']['enabled'] = (bool) $value;
     2419                    break;
     2420
     2421                case 'enable_edit_item' :
     2422                    $lpc['screens']['edit']['enabled'] = (bool) $value;
     2423                    break;
     2424
     2425                case 'enable_admin_item' :
     2426                    $lpc['screens']['admin']['enabled'] = (bool) $value;
     2427                    break;
     2428
     2429                case 'create_step_position' :
     2430                    $lpc['screens']['create']['position'] = $value;
     2431                    break;
     2432
     2433                // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'
     2434                case 'admin_name' :
     2435                    $lpc['screens']['edit']['name'] = $value;
     2436                    break;
     2437
     2438                case 'admin_slug' :
     2439                    $lpc['screens']['edit']['slug'] = $value;
     2440                    break;
     2441
     2442                case 'create_name' :
     2443                    $lpc['screens']['create']['name'] = $value;
     2444                    break;
     2445
     2446                case 'create_slug' :
     2447                    $lpc['screens']['create']['slug'] = $value;
     2448                    break;
     2449
     2450                case 'admin_metabox_context' :
     2451                    $lpc['screens']['admin']['metabox_context'] = $value;
     2452                    break;
     2453
     2454                case 'admin_metabox_priority' :
     2455                    $lpc['screens']['admin']['metabox_priority'] = $value;
     2456                    break;
     2457
     2458                default :
     2459                    $lpc[ $property ] = $value;
     2460                    break;
     2461            }
     2462        }
     2463    }
     2464
     2465    /**
     2466     * Set up legacy properties
     2467     *
     2468     * This method is responsible for ensuring that all legacy config
     2469     * properties are stored in an array $this->legacy_properties, so that
     2470     * they remain available to plugins that reference the variables at
     2471     * their old locations.
     2472     *
     2473     * @see self::__get()
     2474     *
     2475     * @since BuddyPress (1.8)
     2476     */
     2477    protected function setup_legacy_properties() {
     2478
     2479        // Only run this one time
     2480        if ( ! empty( $this->legacy_properties ) ) {
     2481            return;
     2482        }
     2483
     2484        $properties = $this->get_legacy_property_list();
     2485        $params     = $this->params;
     2486        $lp         =& $this->legacy_properties;
     2487
     2488        foreach ( $properties as $property ) {
     2489            switch ( $property ) {
     2490                case 'enable_create_step' :
     2491                    $lp['enable_create_step'] = $params['screens']['create']['enabled'];
     2492                    break;
     2493
     2494                case 'enable_edit_item' :
     2495                    $lp['enable_edit_item'] = $params['screens']['edit']['enabled'];
     2496                    break;
     2497
     2498                case 'enable_admin_item' :
     2499                    $lp['enable_admin_item'] = $params['screens']['admin']['enabled'];
     2500                    break;
     2501
     2502                case 'create_step_position' :
     2503                    $lp['create_step_position'] = $params['screens']['create']['position'];
     2504                    break;
     2505
     2506                // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'
     2507                case 'admin_name' :
     2508                    $lp['admin_name'] = $params['screens']['edit']['name'];
     2509                    break;
     2510
     2511                case 'admin_slug' :
     2512                    $lp['admin_slug'] = $params['screens']['edit']['slug'];
     2513                    break;
     2514
     2515                case 'create_name' :
     2516                    $lp['create_name'] = $params['screens']['create']['name'];
     2517                    break;
     2518
     2519                case 'create_slug' :
     2520                    $lp['create_slug'] = $params['screens']['create']['slug'];
     2521                    break;
     2522
     2523                case 'admin_metabox_context' :
     2524                    $lp['admin_metabox_context'] = $params['screens']['admin']['metabox_context'];
     2525                    break;
     2526
     2527                case 'admin_metabox_priority' :
     2528                    $lp['admin_metabox_priority'] = $params['screens']['admin']['metabox_priority'];
     2529                    break;
     2530
     2531                default :
     2532                    // All other items get moved over
     2533                    $lp[ $property ] = $params[ $property ];
     2534
     2535                    // Also reapply to the object, for backpat
     2536                    $this->{$property} = $params[ $property ];
     2537
     2538                    break;
     2539            }
     2540        }
     2541    }
    16062542}
    16072543
    1608 function bp_register_group_extension( $group_extension_class ) {
    1609 
    1610     if ( !class_exists( $group_extension_class ) )
     2544function bp_register_group_extension( $group_extension_class = '' ) {
     2545
     2546    if ( ! class_exists( $group_extension_class ) ) {
    16112547        return false;
     2548    }
    16122549
    16132550    // Register the group extension on the bp_init action so we have access
  • trunk/tests/bootstrap.php

    r6908 r6997  
    33define( 'BP_PLUGIN_DIR', dirname( dirname( __FILE__ ) ) . '/' );
    44
     5if ( ! defined( 'BP_TESTS_DIR' ) ) {
     6    define( 'BP_TESTS_DIR', dirname( __FILE__ ) . '/' );
     7}
     8
    59require_once getenv( 'WP_TESTS_DIR' ) . '/includes/functions.php';
    610
    711function _install_and_load_buddypress() {
    8     require dirname( __FILE__ ) . '/includes/loader.php';
     12    require BP_TESTS_DIR . '/includes/loader.php';
    913}
    1014tests_add_filter( 'muplugins_loaded', '_install_and_load_buddypress' );
     
    1317
    1418// Load the BP-specific testing tools
    15 require dirname( __FILE__ ) . '/includes/testcase.php';
     19require BP_TESTS_DIR . '/includes/testcase.php';
Note: See TracChangeset for help on using the changeset viewer.