Ticket #4955: 4955.02.patch
| File 4955.02.patch, 55.5 KB (added by , 13 years ago) |
|---|
-
bp-groups/bp-groups-classes.php
1367 1367 * API for creating group extensions without having to hardcode the content into 1368 1368 * the theme. 1369 1369 * 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 1371 1392 * 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. 1375 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. 1437 * 1376 1438 * @package BuddyPress 1377 1439 * @subpackage Groups 1378 1440 * @since BuddyPress (1.1) 1379 1441 */ 1380 1442 class BP_Group_Extension { 1381 var $name = false;1382 var $slug = false;1383 1443 1384 // The name/slug of the Group Admin tab for this extension 1385 var $admin_name = ''; 1386 var $admin_slug = ''; 1444 /** Public ****************************************************************/ 1387 1445 1388 // The name/slug of the Group Creation tab for this extension 1389 var $create_name = ''; 1390 var $create_slug = ''; 1446 /** 1447 * @var array Information about this extension's screens 1448 * @since BuddyPress (1.8) 1449 */ 1450 public $screens = array(); 1391 1451 1392 // Will this extension be visible to non-members of a group? Options: public/private 1393 var $visibility = 'public'; 1452 /** 1453 * @var string The name of the extending class 1454 * @since BuddyPress (1.8) 1455 */ 1456 public $class_name = ''; 1394 1457 1395 var $create_step_position = 81; 1396 var $nav_item_position = 81; 1458 /** 1459 * @var object A ReflectionClass object of the current extension 1460 * @since BuddyPress (1.8) 1461 */ 1462 public $class_reflection = null; 1397 1463 1398 1464 /** 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) 1465 * @var array Parsed configuration paramaters for the extension 1466 * @since BuddyPress (1.8) 1403 1467 */ 1404 var $admin_metabox_context = 'normal';1468 public $params = array(); 1405 1469 1406 1470 /** 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) 1471 * @var int The id of the current group 1472 * @since BuddyPress (1.8) 1411 1473 */ 1412 var $admin_metabox_priority = 'core';1474 public $group_id = 0; 1413 1475 1414 var $enable_create_step = true;1415 var $enable_nav_item = true;1416 var $enable_edit_item = true;1417 var $enable_admin_item = true;1476 /** 1477 * @var string The slug of the current extension 1478 */ 1479 public $slug = ''; 1418 1480 1419 var $nav_item_name = false; 1481 /** 1482 * @var string The translatable name of the current extension 1483 */ 1484 public $name = ''; 1420 1485 1421 var $display_hook = 'groups_custom_group_boxes'; 1422 var $template_file = 'groups/single/plugins'; 1486 /** 1487 * @var string Whether the extension tab is visible. 'public' 1488 * or 'private' 1489 */ 1490 public $visibility = 'public'; 1423 1491 1424 // Methods you should override 1492 /** 1493 * @var int The numeric position of the main nav item 1494 */ 1495 public $nav_item_position = 81; 1425 1496 1426 function display() {} 1497 /** 1498 * @var bool Whether to show the nav item 1499 */ 1500 public $enable_nav_item = false; 1427 1501 1428 function widget_display() {} 1502 /** 1503 * @var string The text of the nav item. Defaults to self::name 1504 */ 1505 public $nav_item_name = ''; 1429 1506 1430 function edit_screen( $group_id = null ) {} 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'; 1431 1512 1432 function edit_screen_save( $group_id = null ) {} 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'; 1433 1518 1434 function create_screen( $group_id = null ) {}1519 /** Protected *************************************************************/ 1435 1520 1436 function create_screen_save( $group_id = null ) {} 1521 /** 1522 * @var bool Has the extension been initialized? 1523 * @since BuddyPress (1.8) 1524 */ 1525 protected $initialized = false; 1437 1526 1438 // Private Methods 1527 /** 1528 * @var array Extension properties as set by legacy extensions 1529 * @since BuddyPress (1.8) 1530 */ 1531 protected $legacy_properties = array(); 1439 1532 1440 function _register() { 1441 global $bp; 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(); 1442 1539 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; 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' => $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(); 1447 1644 } 1448 1645 1449 if ( ! $this->admin_slug ) { 1450 $this->admin_slug = $this->slug; 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 ( is_null( $this->class_name ) ) { 1681 $this->class_name = get_class( $this ); 1451 1682 } 1452 1683 1453 if ( ! $this->create_name) {1454 $this->c reate_name = $this->name;1684 if ( is_null( $this->class_reflection ) ) { 1685 $this->class_reflection = new ReflectionClass( $this->class_name ); 1455 1686 } 1687 } 1456 1688 1457 if ( ! $this->create_slug ) { 1458 $this->create_slug = $this->slug; 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']; 1459 1707 } 1460 1708 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 ); 1709 // This fallback will only be hit when the create step is very early 1710 if ( empty( $group_id ) && bp_get_new_group_id() ) { 1711 $group_id = bp_get_new_group_id(); 1712 } 1468 1713 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' ) ); 1714 // On some setups, the group id has to be fetched out of the $_POST 1715 // array 1716 // @todo Figure out why this is happening during group creation 1717 if ( empty( $group_id ) && isset( $_POST['group_id'] ) ) { 1718 $group_id = (int) $_POST['group_id']; 1476 1719 } 1477 1720 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 ) ); 1721 return $group_id; 1722 } 1492 1723 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 } 1724 /** 1725 * Gather configuration data about your screens 1726 * 1727 * @since BuddyPress (1.8) 1728 */ 1729 protected function get_default_screens() { 1730 $this->setup_class_info(); 1499 1731 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 } 1504 } 1505 } 1732 $screens = array( 1733 'create' => array(), 1734 'edit' => array(), 1735 'admin' => array( 1736 'metabox_context' => 'normal', 1737 'metabox_priority' => 'core', 1738 ), 1739 ); 1506 1740 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 ); 1741 foreach ( $screens as $context => &$screen ) { 1742 $screen['enabled'] = true; 1743 $screen['name'] = ''; 1744 $screen['slug'] = ''; 1745 $screen['position'] = 81; 1746 $screen['submit_text'] = __( 'Save Changes', 'buddypress' ); 1515 1747 1516 // Catch the edit screen and forward it to the plugin template1517 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() );1748 $screen['screen_callback'] = $this->get_screen_callback( $context, 'screen' ); 1749 $screen['screen_save_callback'] = $this->get_screen_callback( $context, 'screen_save' ); 1750 } 1519 1751 1520 add_action( 'groups_custom_edit_steps', array( &$this, 'call_edit_screen' ) ); 1752 return $screens; 1753 } 1521 1754 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 } 1755 /** 1756 * Set up screens array based on params 1757 * 1758 * @since BuddyPress (1.8) 1759 */ 1760 protected function setup_screens() { 1761 foreach ( (array) $this->params['screens'] as $context => $screen ) { 1762 if ( empty( $screen['slug'] ) ) { 1763 $screen['slug'] = $this->slug; 1529 1764 } 1765 1766 if ( empty( $screen['name'] ) ) { 1767 $screen['name'] = $this->name; 1768 } 1769 1770 $this->screens[ $context ] = $screen; 1530 1771 } 1772 } 1531 1773 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' ) ); 1774 /** Display ***************************************************************/ 1538 1775 1539 // Initialize the metabox 1540 add_action( 'bp_groups_admin_meta_boxes', array( $this, '_meta_box_display_callback' ) ); 1776 /** 1777 * Hook this extension's group tab into BuddyPress, if necessary 1778 * 1779 * @since BuddyPress (1.8) 1780 */ 1781 protected function setup_display_hooks() { 1541 1782 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 ); 1783 // Bail if not a group 1784 if ( ! bp_is_group() ) { 1785 return; 1786 } 1787 1788 // Bail if the current user doesn't have access 1789 if ( ( 'public' !== $this->visibility ) && ! buddypress()->groups->current_group->user_has_access ) { 1790 return; 1791 } 1792 1793 if ( true === $this->enable_nav_item ) { 1794 bp_core_new_subnav_item( array( 1795 'name' => ! $this->nav_item_name ? $this->name : $this->nav_item_name, 1796 'slug' => $this->slug, 1797 'parent_slug' => bp_get_current_group_slug(), 1798 'parent_url' => bp_get_group_permalink( groups_get_current_group() ), 1799 'position' => $this->nav_item_position, 1800 'item_css_id' => 'nav-' . $this->slug, 1801 'screen_function' => array( &$this, '_display_hook' ), 1802 'user_has_access' => $this->enable_nav_item 1803 ) ); 1804 1805 // When we are viewing the extension display page, set the title and options title 1806 if ( bp_is_current_action( $this->slug ) ) { 1807 add_action( 'bp_template_content_header', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) ); 1808 add_action( 'bp_template_title', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) ); 1545 1809 } 1546 1810 } 1811 1812 // Hook the group home widget 1813 if ( ! bp_current_action() && bp_is_current_action( 'home' ) ) { 1814 add_action( $this->display_hook, array( &$this, 'widget_display' ) ); 1815 } 1547 1816 } 1548 1817 1549 function _display_hook() { 1818 /** 1819 * Hooks the main display method, and loads the template file 1820 */ 1821 public function _display_hook() { 1550 1822 add_action( 'bp_template_content', array( &$this, 'display' ) ); 1551 1823 bp_core_load_template( apply_filters( 'bp_core_template_plugin', $this->template_file ) ); 1552 1824 } 1553 1825 1826 /** Create ****************************************************************/ 1827 1554 1828 /** 1829 * Hook this extension's Create step into BuddyPress, if necessary 1830 * 1831 * @since BuddyPress (1.8) 1832 */ 1833 protected function setup_create_hooks() { 1834 if ( ! $this->is_screen_enabled( 'create' ) ) { 1835 return; 1836 } 1837 1838 $screen = $this->screens['create']; 1839 1840 // Insert the group creation step for the new group extension 1841 buddypress()->groups->group_creation_steps[ $screen['slug'] ] = array( 1842 'name' => $screen['name'], 1843 'slug' => $screen['slug'], 1844 'position' => $screen['position'], 1845 ); 1846 1847 // The maybe_ methods check to see whether the create_* 1848 // callbacks should be invoked (ie, are we on the 1849 // correct group creation step). Hooked in separate 1850 // methods because current creation step info not yet 1851 // available at this point 1852 add_action( 'groups_custom_create_steps', array( $this, 'maybe_create_screen' ) ); 1853 add_action( 'groups_create_group_step_save_' . $screen['slug'], array( $this, 'maybe_create_screen_save' ) ); 1854 } 1855 1856 /** 1857 * Call the create_screen() method, if we're on the right page 1858 * 1859 * @since 1.8 1860 */ 1861 public function maybe_create_screen() { 1862 if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) { 1863 return; 1864 } 1865 1866 call_user_func( $this->screens['create']['screen_callback'], $this->group_id ); 1867 $this->nonce_field( 'create' ); 1868 1869 // The create screen requires an additional nonce field 1870 // due to a quirk in the way the templates are built 1871 wp_nonce_field( 'groups_create_save_' . bp_get_groups_current_create_step() ); 1872 } 1873 1874 /** 1875 * Call the create_screen_save() method, if we're on the right page 1876 * 1877 * @since 1.8 1878 */ 1879 public function maybe_create_screen_save() { 1880 if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) { 1881 return; 1882 } 1883 1884 $this->check_nonce( 'create' ); 1885 call_user_func( $this->screens['create']['screen_save_callback'], $this->group_id ); 1886 } 1887 1888 /** Edit ******************************************************************/ 1889 1890 /** 1891 * Hook this extension's Edit panel into BuddyPress, if necessary 1892 * 1893 * @since BuddyPress (1.8) 1894 */ 1895 protected function setup_edit_hooks() { 1896 1897 // Bail if not an edit screen 1898 if ( ! $this->is_screen_enabled( 'edit' ) || ! bp_is_item_admin() ) { 1899 return; 1900 } 1901 1902 $screen = $this->screens['edit']; 1903 1904 // Add the tab 1905 // @todo BP should be using bp_core_new_subnav_item() 1906 add_action( 'groups_admin_tabs', create_function( '$current, $group_slug', 1907 '$selected = ""; 1908 if ( "' . esc_attr( $screen['slug'] ) . '" == $current ) 1909 $selected = " class=\"current\""; 1910 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>";' 1911 ), 10, 2 ); 1912 1913 // Catch the edit screen and forward it to the plugin template 1914 if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) && bp_is_action_variable( $screen['slug'], 0 ) ) { 1915 $this->call_edit_screen_save( $this->group_id ); 1916 1917 add_action( 'groups_custom_edit_steps', array( &$this, 'call_edit_screen' ) ); 1918 1919 if ( '' !== bp_locate_template( array( 'groups/single/home.php' ), false ) ) { 1920 bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) ); 1921 } else { 1922 add_action( 'bp_template_content_header', create_function( '', 'echo "<ul class=\"content-header-nav\">"; bp_group_admin_tabs(); echo "</ul>";' ) ); 1923 add_action( 'bp_template_content', array( &$this, 'call_edit_screen' ) ); 1924 bp_core_load_template( apply_filters( 'bp_core_template_plugin', '/groups/single/plugins' ) ); 1925 } 1926 } 1927 } 1928 1929 /** 1930 * Call the edit_screen() method 1931 * 1932 * Previous versions of BP_Group_Extension required plugins to provide 1933 * their own Submit button and nonce fields when building markup. In 1934 * BP 1.8, this requirement was lifted - BP_Group_Extension now handles 1935 * all required submit buttons and nonces. 1936 * 1937 * We put the edit screen markup into an output buffer before echoing. 1938 * This is so that we can check for the presence of a hardcoded submit 1939 * button, as would be present in legacy plugins; if one is found, we 1940 * do not auto-add our own button. 1941 * 1942 * @since BuddyPress (1.8) 1943 */ 1944 public function call_edit_screen() { 1945 ob_start(); 1946 call_user_func( $this->screens['edit']['screen_callback'], $this->group_id ); 1947 $screen = ob_get_contents(); 1948 ob_end_clean(); 1949 1950 echo $this->maybe_add_submit_button( $screen ); 1951 1952 $this->nonce_field( 'edit' ); 1953 } 1954 1955 /** 1956 * Check the nonce, and call the edit_screen_save() method 1957 * 1958 * @since BuddyPress (1.8) 1959 */ 1960 public function call_edit_screen_save() { 1961 if ( empty( $_POST ) ) { 1962 return; 1963 } 1964 1965 $this->check_nonce( 'edit' ); 1966 call_user_func( $this->screens['edit']['screen_save_callback'], $this->group_id ); 1967 } 1968 1969 /** 1970 * Add a submit button to the edit form, if it needs one 1971 * 1972 * There's an inconsistency in the way that the group Edit and Create 1973 * screens are rendered: the Create screen has a submit button built 1974 * in, but the Edit screen does not. This function allows plugin 1975 * authors to write markup that does not contain the submit button for 1976 * use on both the Create and Edit screens - BP will provide the button 1977 * if one is not found. 1978 * 1979 * @since BuddyPress (1.8) 1980 * @param string $screen The screen markup, captured in the output buffer 1981 * @param string $screen The same markup, with a submit button added 1982 */ 1983 protected function maybe_add_submit_button( $screen = '' ) { 1984 if ( $this->has_submit_button( $screen ) ) { 1985 return; 1986 } 1987 1988 return $screen . sprintf( 1989 '<div id="%s"><input type="submit" name="save" value="%s" id="%s"></div>', 1990 'bp-group-edit-' . $this->slug . '-submit-wrapper', 1991 $this->screens['edit']['submit_text'], 1992 'bp-group-edit-' . $this->slug . '-submit' 1993 ); 1994 } 1995 1996 /** 1997 * Does the given markup have a submit button? 1998 * 1999 * @since BuddyPress (1.8) 2000 * @param $screen The markup to check 2001 * @return bool 2002 */ 2003 public static function has_submit_button( $screen = '' ) { 2004 $pattern = "/<input[^>]+type=[\'\"]submit[\'\"]/"; 2005 preg_match( $pattern, $screen, $matches ); 2006 return ! empty( $matches[0] ); 2007 } 2008 2009 /** Admin *****************************************************************/ 2010 2011 /** 2012 * Hook this extension's Admin metabox into BuddyPress, if necessary 2013 * 2014 * @since BuddyPress (1.8) 2015 */ 2016 protected function setup_admin_hooks() { 2017 if ( ! $this->is_screen_enabled( 'admin' ) || ! is_admin() ) { 2018 return; 2019 } 2020 2021 // Hook the admin screen markup function to the content hook 2022 add_action( 'bp_groups_admin_meta_box_content_' . $this->slug, array( $this, 'admin_screen' ) ); 2023 2024 // Initialize the metabox 2025 add_action( 'bp_groups_admin_meta_boxes', array( $this, '_meta_box_display_callback' ) ); 2026 2027 // Catch the metabox save 2028 add_action( 'bp_group_admin_edit_after', array( $this, 'call_admin_screen_save' ), 10 ); 2029 } 2030 2031 /** 2032 * Call the admin_screen() method, and add a nonce field 2033 * 2034 * @since BuddyPress (1.8) 2035 */ 2036 public function call_admin_screen() { 2037 call_user_func( $this->screens['admin']['screen_callback'], $this->group_id ); 2038 $this->nonce_field( 'admin' ); 2039 } 2040 2041 /** 2042 * Check the nonce, and call the admin_screen_save() method 2043 * 2044 * @since BuddyPress (1.8) 2045 */ 2046 public function call_admin_screen_save() { 2047 $this->check_nonce( 'admin' ); 2048 call_user_func( $this->screens['admin']['screen_save_callback'], $this->group_id ); 2049 } 2050 2051 /** 1555 2052 * Create the Dashboard meta box for this extension 1556 2053 * 1557 2054 * @since BuddyPress (1.7) 1558 2055 */ 1559 function _meta_box_display_callback() {2056 public function _meta_box_display_callback() { 1560 2057 $group_id = isset( $_GET['gid'] ) ? (int) $_GET['gid'] : 0; 2058 $screen = $this->screens['admin']; 1561 2059 1562 2060 add_meta_box( 1563 $ this->slug,1564 $ this->name,2061 $screen['slug'], 2062 $screen['name'], 1565 2063 create_function( '', 'do_action( "bp_groups_admin_meta_box_content_' . $this->slug . '", ' . $group_id . ' );' ), 1566 2064 get_current_screen()->id, 1567 $ this->admin_metabox_context,1568 $ this->admin_metabox_priority2065 $screen['metabox_context'], 2066 $screen['metabox_priority'] 1569 2067 ); 1570 2068 } 1571 2069 2070 2071 /** Utilities *************************************************************/ 2072 1572 2073 /** 1573 * Call the edit_screen() method2074 * Generate the nonce fields for a settings form 1574 2075 * 1575 * Broken into a standalone method so we can pass the current group id 1576 * to edit_screen() 2076 * The nonce field name (the second param passed to wp_nonce_field) 2077 * contains this extension's slug and is thus unique to this extension. 2078 * This is necessary because in some cases (namely, the Dashboard), 2079 * more than one extension may generate nonces on the same page, and we 2080 * must avoid name clashes. 1577 2081 * 1578 * @since 1.8 2082 * @since BuddyPress (1.8) 2083 * @uses wp_nonce_field() 2084 * @param string $context 'create', 'edit', 'admin' 1579 2085 */ 1580 public function call_edit_screen() {1581 $this->edit_screen( bp_get_current_group_id());2086 public function nonce_field( $context = '' ) { 2087 wp_nonce_field( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug ); 1582 2088 } 1583 2089 1584 2090 /** 1585 * C all the create_screen() method, if we're on the right page2091 * Check the nonce on a submitted settings form 1586 2092 * 1587 * @since 1.8 2093 * @since BuddyPress (1.8) 2094 * @uses check_admin_referer() 2095 * @param string $context 'create', 'edit', 'admin' 1588 2096 */ 1589 public function maybe_create_screen() { 1590 if ( bp_is_group_creation_step( $this->slug ) ) { 1591 $this->create_screen( bp_get_new_group_id() ); 2097 public function check_nonce( $context = '' ) { 2098 check_admin_referer( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug ); 2099 } 2100 2101 /** 2102 * Is the specified screen enabled? 2103 * 2104 * To be enabled, a screen must both have the 'enabled' key set to true 2105 * (legacy: $this->enable_create_step, etc), and its screen_callback 2106 * must also exist and be callable. 2107 * 2108 * @since BuddyPress (1.8) 2109 * @param string $context 'create', 'edit', 'admin' 2110 * @return bool 2111 */ 2112 public function is_screen_enabled( $context = '' ) { 2113 $enabled = false; 2114 2115 if ( isset( $this->screens[ $context ] ) ) { 2116 $enabled = $this->screens[ $context ]['enabled'] && is_callable( $this->screens[ $context ]['screen_callback'] ); 1592 2117 } 2118 2119 return (bool) $enabled; 1593 2120 } 1594 2121 1595 2122 /** 1596 * Call the create_screen_save() method, if we're on the right page2123 * Get the appropriate screen callback for the specified context/type 1597 2124 * 1598 * @since 1.8 2125 * BP Group Extensions have three special "screen contexts": create, 2126 * admin, and edit. Each of these contexts has a corresponding 2127 * _screen() and _screen_save() method, which allow group extension 2128 * plugins to define different markup and logic for each context. 2129 * 2130 * BP also supports fallback settings_screen() and 2131 * settings_screen_save() methods, which can be used to define markup 2132 * and logic that is shared between context. For each context, you may 2133 * either provide context-specific methods, or you can let BP fall back 2134 * on the shared settings_* callbacks. 2135 * 2136 * For example, consider a BP_Group_Extension implementation that looks 2137 * like this: 2138 * 2139 * // ... 2140 * function create_screen( $group_id ) { ... } 2141 * function create_screen_save( $group_id ) { ... } 2142 * function settings_screen( $group_id ) { ... } 2143 * function settings_screen_save( $group_id ) { ... } 2144 * // ... 2145 * 2146 * BP_Group_Extension will use your create_* methods for the Create 2147 * steps, and will use your generic settings_* methods for the Edit 2148 * and Admin contexts. This schema allows plugin authors maximum 2149 * flexibility without having to repeat themselves. 2150 * 2151 * The get_screen_callback() method uses a ReflectionClass object to 2152 * determine whether your extension has provided a given callback. 2153 * 2154 * @since BuddyPress (1.8) 2155 * @param string $context 'create', 'edit', 'admin' 2156 * @param string $type 'screen', 'screen_save' 2157 * @return mixed A callable function handle 1599 2158 */ 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() ); 2159 public function get_screen_callback( $context = '', $type = 'screen' ) { 2160 $callback = ''; 2161 2162 // Try the context-specific callback first 2163 $method = $context . '_' . $type; 2164 $rmethod = $this->class_reflection->getMethod( $method ); 2165 if ( isset( $rmethod->class ) && $this->class_name === $rmethod->class ) { 2166 $callback = array( $this->class_name, $method ); 1603 2167 } 2168 2169 if ( empty( $callback ) ) { 2170 $fallback_method = 'settings_' . $type; 2171 $rfallback_method = $this->class_reflection->getMethod( $fallback_method ); 2172 if ( isset( $rfallback_method->class ) && $this->class_name === $rfallback_method->class ) { 2173 $callback = array( $this->class_name, $fallback_method ); 2174 } 2175 } 2176 2177 return $callback; 1604 2178 } 1605 2179 2180 /** 2181 * Recursive argument parsing 2182 * 2183 * This acts like a multi-dimensional version of wp_parse_args() (minus 2184 * the querystring parsing - you must pass arrays). 2185 * 2186 * Values from $a override those from $b; keys in $b that don't exist 2187 * in $a are passed through. 2188 * 2189 * This is different from array_merge_recursive(), both because of the 2190 * order of preference ($a overrides $b) and because of the fact that 2191 * array_merge_recursive() combines arrays deep in the tree, rather 2192 * than overwriting the b array with the a array. 2193 * 2194 * The implementation of this function is specific to the needs of 2195 * BP_Group_Extension, where we know that arrays will always be 2196 * associative, and that an argument under a given key in one array 2197 * will be matched by a value of identical depth in the other one. The 2198 * function is NOT designed for general use, and will probably result 2199 * in unexpected results when used with data in the wild. See, eg, 2200 * http://core.trac.wordpress.org/ticket/19888 2201 * 2202 * @since BuddyPress (1.8) 2203 * @arg array $a 2204 * @arg array $b 2205 * @return array 2206 */ 2207 public static function parse_args_r( &$a, $b ) { 2208 $a = (array) $a; 2209 $b = (array) $b; 2210 $r = $b; 2211 2212 foreach ( $a as $k => &$v ) { 2213 if ( is_array( $v ) && isset( $r[ $k ] ) ) { 2214 $r[ $k ] = self::parse_args_r( $v, $r[ $k ] ); 2215 } else { 2216 $r[ $k ] = $v; 2217 } 2218 } 2219 2220 return $r; 2221 } 2222 2223 /** Legacy Support ********************************************************/ 2224 2225 /** 2226 * In BuddyPress 1.8, the recommended technique for configuring 2227 * extensions changed from directly setting various object properties 2228 * in the class constructor, to passing a configuration array to 2229 * parent::init(). The following methods ensure that extensions created 2230 * in the old way continue to work, by converting legacy configuration 2231 * data to the new format. 2232 */ 2233 2234 /** 2235 * Provide access to otherwise unavailable object properties 2236 * 2237 * This magic method is here for backward compatibility with plugins 2238 * that refer to config properties that have moved to a different 2239 * location (such as enable_create_step, which is now at 2240 * $this->screens['create']['enabled'] 2241 * 2242 * The legacy_properties array is set up in 2243 * self::setup_legacy_properties(). 2244 * 2245 * @since BuddyPress (1.8) 2246 * @param string $key 2247 * @return mixed 2248 */ 2249 public function __get( $key ) { 2250 if ( isset( $this->legacy_properties[ $key ] ) ) { 2251 return $this->legacy_properties[ $key ]; 2252 } elseif ( isset( $this->data[ $key ] ) ) { 2253 return $this->data[ $key ]; 2254 } else { 2255 return null; 2256 } 2257 } 2258 2259 /** 2260 * Allow plugins to set otherwise unavailable object properties 2261 * 2262 * This magic method is here for backward compatibility with plugins 2263 * that may attempt to modify the group extension by manually assigning 2264 * a value to an object property that no longer exists, such as 2265 * $this->enable_create_step. 2266 * 2267 * @since BuddyPress (1.8) 2268 * @param string $key 2269 * @param mixed $value 2270 */ 2271 public function __set( $key, $value ) { 2272 2273 if ( empty( $this->initialized ) ) { 2274 $this->data[ $key ] = $value; 2275 } 2276 2277 switch ( $key ) { 2278 case 'enable_create_step' : 2279 $this->screens['create']['enabled'] = $value; 2280 break; 2281 2282 case 'enable_edit_item' : 2283 $this->screens['edit']['enabled'] = $value; 2284 break; 2285 2286 case 'enable_admin_item' : 2287 $this->screens['admin']['enabled'] = $value; 2288 break; 2289 2290 case 'create_step_position' : 2291 $this->screens['create']['position'] = $value; 2292 break; 2293 2294 // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin' 2295 case 'admin_name' : 2296 $this->screens['edit']['name'] = $value; 2297 break; 2298 2299 case 'admin_slug' : 2300 $this->screens['edit']['slug'] = $value; 2301 break; 2302 2303 case 'create_name' : 2304 $this->screens['create']['name'] = $value; 2305 break; 2306 2307 case 'create_slug' : 2308 $this->screens['create']['slug'] = $value; 2309 break; 2310 2311 case 'admin_metabox_context' : 2312 $this->screens['admin']['metabox_context'] = $value; 2313 break; 2314 2315 case 'admin_metabox_priority' : 2316 $this->screens['admin']['metabox_priority'] = $value; 2317 break; 2318 2319 default : 2320 $this->data[ $key ] = $value; 2321 break; 2322 } 2323 } 2324 2325 /** 2326 * Returns a list of legacy properties 2327 * 2328 * The legacy implementation of BP_Group_Extension used all of these 2329 * object properties for configuration. Some have been moved. 2330 * 2331 * @since BuddyPress (1.8) 2332 * @return array 2333 */ 2334 protected function get_legacy_property_list() { 2335 return array( 2336 'name', 2337 'slug', 2338 'admin_name', 2339 'admin_slug', 2340 'create_name', 2341 'create_slug', 2342 'visibility', 2343 'create_step_position', 2344 'nav_item_position', 2345 'admin_metabox_context', 2346 'admin_metabox_priority', 2347 'enable_create_step', 2348 'enable_nav_item', 2349 'enable_edit_item', 2350 'enable_admin_item', 2351 'nav_item_name', 2352 'display_hook', 2353 'template_file', 2354 ); 2355 } 2356 2357 /** 2358 * Parse legacy properties 2359 * 2360 * The old standard for BP_Group_Extension was for plugins to register 2361 * their settings as properties in their constructor. The new method is 2362 * to pass a config array to the init() method. In order to support 2363 * legacy plugins, we slurp up legacy properties, and later on we'll 2364 * parse them into the new init() array. 2365 * 2366 * @since BuddyPress (1.8) 2367 */ 2368 protected function parse_legacy_properties() { 2369 2370 // Only run this one time 2371 if ( ! empty( $this->legacy_properties_converted ) ) { 2372 return; 2373 } 2374 2375 $properties = $this->get_legacy_property_list(); 2376 2377 // By-reference variable for convenience 2378 $lpc =& $this->legacy_properties_converted; 2379 2380 foreach ( $properties as $property ) { 2381 2382 // No legacy config exists for this key 2383 if ( ! isset( $this->{$property} ) ) { 2384 continue; 2385 } 2386 2387 // Grab the value and record it as appropriate 2388 $value = $this->{$property}; 2389 2390 switch ( $property ) { 2391 case 'enable_create_step' : 2392 $lpc['screens']['create']['enabled'] = (bool) $value; 2393 break; 2394 2395 case 'enable_edit_item' : 2396 $lpc['screens']['edit']['enabled'] = (bool) $value; 2397 break; 2398 2399 case 'enable_admin_item' : 2400 $lpc['screens']['admin']['enabled'] = (bool) $value; 2401 break; 2402 2403 case 'create_step_position' : 2404 $lpc['screens']['create']['position'] = $value; 2405 break; 2406 2407 // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin' 2408 case 'admin_name' : 2409 $lpc['screens']['edit']['name'] = $value; 2410 break; 2411 2412 case 'admin_slug' : 2413 $lpc['screens']['edit']['slug'] = $value; 2414 break; 2415 2416 case 'create_name' : 2417 $lpc['screens']['create']['name'] = $value; 2418 break; 2419 2420 case 'create_slug' : 2421 $lpc['screens']['create']['slug'] = $value; 2422 break; 2423 2424 case 'admin_metabox_context' : 2425 $lpc['screens']['admin']['metabox_context'] = $value; 2426 break; 2427 2428 case 'admin_metabox_priority' : 2429 $lpc['screens']['admin']['metabox_priority'] = $value; 2430 break; 2431 2432 default : 2433 $lpc[ $property ] = $value; 2434 break; 2435 } 2436 } 2437 } 2438 2439 /** 2440 * Set up legacy properties 2441 * 2442 * This method is responsible for ensuring that all legacy config 2443 * properties are stored in an array $this->legacy_properties, so that 2444 * they remain available to plugins that reference the variables at 2445 * their old locations. 2446 * 2447 * @see self::__get() 2448 * 2449 * @since BuddyPress (1.8) 2450 */ 2451 protected function setup_legacy_properties() { 2452 2453 // Only run this one time 2454 if ( ! empty( $this->legacy_properties ) ) { 2455 return; 2456 } 2457 2458 $properties = $this->get_legacy_property_list(); 2459 $params = $this->params; 2460 $lp =& $this->legacy_properties; 2461 2462 foreach ( $properties as $property ) { 2463 switch ( $property ) { 2464 case 'enable_create_step' : 2465 $lp['enable_create_step'] = $params['screens']['create']['enabled']; 2466 break; 2467 2468 case 'enable_edit_item' : 2469 $lp['enable_edit_item'] = $params['screens']['edit']['enabled']; 2470 break; 2471 2472 case 'enable_admin_item' : 2473 $lp['enable_admin_item'] = $params['screens']['admin']['enabled']; 2474 break; 2475 2476 case 'create_step_position' : 2477 $lp['create_step_position'] = $params['screens']['create']['position']; 2478 break; 2479 2480 // Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin' 2481 case 'admin_name' : 2482 $lp['admin_name'] = $params['screens']['edit']['name']; 2483 break; 2484 2485 case 'admin_slug' : 2486 $lp['admin_slug'] = $params['screens']['edit']['slug']; 2487 break; 2488 2489 case 'create_name' : 2490 $lp['create_name'] = $params['screens']['create']['name']; 2491 break; 2492 2493 case 'create_slug' : 2494 $lp['create_slug'] = $params['screens']['create']['slug']; 2495 break; 2496 2497 case 'admin_metabox_context' : 2498 $lp['admin_metabox_context'] = $params['screens']['admin']['metabox_context']; 2499 break; 2500 2501 case 'admin_metabox_priority' : 2502 $lp['admin_metabox_priority'] = $params['screens']['admin']['metabox_priority']; 2503 break; 2504 2505 default : 2506 // All other items get moved over 2507 $lp[ $property ] = $params[ $property ]; 2508 2509 // Also reapply to the object, for backpat 2510 $this->{$property} = $params[ $property ]; 2511 2512 break; 2513 } 2514 } 2515 } 1606 2516 } 1607 2517 1608 function bp_register_group_extension( $group_extension_class ) {2518 function bp_register_group_extension( $group_extension_class = '' ) { 1609 2519 1610 if ( ! class_exists( $group_extension_class ) )2520 if ( ! class_exists( $group_extension_class ) ) { 1611 2521 return false; 2522 } 1612 2523 1613 2524 // Register the group extension on the bp_init action so we have access 1614 2525 // to all plugins. -
tests/assets/group-extensions.php
1 <?php 2 3 /** 4 * The following implementations of BP_Group_Extension act as dummy plugins 5 * for our unit tests 6 */ 7 8 class BPTest_Group_Extension_Parse_Legacy_Properties extends BP_Group_Extension { 9 function __construct() { 10 $class_name = get_class( $this ); 11 $this->name = $class_name; 12 $this->slug = sanitize_title( $class_name ); 13 $this->admin_name = $this->name . ' Edit'; 14 $this->admin_slug = $this->slug . '-edit'; 15 $this->create_name = $this->name . ' Create'; 16 $this->create_slug = $this->slug . '-create'; 17 $this->visibility = 'private'; 18 $this->create_step_position = 58; 19 $this->nav_item_position = 63; 20 $this->admin_metabox_context = 'high'; 21 $this->admin_metabox_priority = 'side'; 22 $this->enable_create_step = false; 23 $this->enable_nav_item = true; 24 $this->enable_edit_item = false; 25 $this->enable_admin_item = true; 26 $this->nav_item_name = $this->name . ' Nav'; 27 $this->display_hook = 'foo_hook'; 28 $this->template_file = 'foo_template'; 29 } 30 31 /** 32 * Provides access to protected method unneeded in BP 33 */ 34 function _parse_legacy_properties() { 35 return $this->parse_legacy_properties(); 36 } 37 38 /** 39 * Provides access to protected property unneeded in BP 40 */ 41 function _get_legacy_properties_converted() { 42 return $this->legacy_properties_converted; 43 } 44 } 45 46 class BPTest_Group_Extension_Setup_Screens_Use_Global_Fallbacks extends BP_Group_Extension { 47 function __construct() { 48 $class_name = get_class( $this ); 49 $this->slug = sanitize_title( $class_name ); 50 $this->name = $class_name; 51 } 52 53 /** 54 * Provides access to protected method unneeded in BP 55 */ 56 function _get_default_screens() { 57 return $this->get_default_screens(); 58 } 59 60 /** 61 * Provides access to protected method unneeded in BP 62 */ 63 function _setup_class_info() { 64 return $this->setup_class_info(); 65 } 66 67 } 68 69 class BPTest_Group_Extension_Setup_Screens_Define_Edit_Screens_Locally extends BP_Group_Extension { 70 function __construct() { 71 $class_name = get_class( $this ); 72 $this->slug = sanitize_title( $class_name ); 73 $this->name = $class_name; 74 } 75 76 function edit_screen() {} 77 function edit_screen_save() {} 78 79 /** 80 * Provides access to protected method unneeded in BP 81 */ 82 function _get_default_screens() { 83 return $this->get_default_screens(); 84 } 85 86 /** 87 * Provides access to protected method unneeded in BP 88 */ 89 function _setup_class_info() { 90 return $this->setup_class_info(); 91 } 92 93 } 94 95 class BPTest_Group_Extension_Access_Root_Property extends BP_Group_Extension { 96 function __construct() { 97 $class_name = get_class( $this ); 98 99 $args = array( 100 'slug' => sanitize_title( $class_name ), 101 'name' => $class_name, 102 'nav_item_position' => 39, 103 ); 104 105 parent::init( $args ); 106 } 107 } 108 109 class BPTest_Group_Extension_Access_Init_Property_Using_Legacy_Location extends BP_Group_Extension { 110 function __construct() { 111 $class_name = get_class( $this ); 112 113 $args = array( 114 'slug' => sanitize_title( $class_name ), 115 'name' => $class_name, 116 'screens' => array( 117 'create' => array( 118 'position' => 18, 119 ), 120 ), 121 ); 122 123 parent::init( $args ); 124 } 125 } 126 127 class BPTest_Group_Extension_Get_Screen_Callback_Fallbacks extends BP_Group_Extension { 128 function __construct() { 129 $class_name = get_class( $this ); 130 131 $args = array( 132 'slug' => sanitize_title( $class_name ), 133 'name' => $class_name, 134 ); 135 136 parent::init( $args ); 137 } 138 139 function settings_screen() {} 140 function settings_screen_save() {} 141 142 function edit_screen() {} 143 function edit_screen_save() {} 144 } -
tests/bootstrap.php
2 2 3 3 define( 'BP_PLUGIN_DIR', dirname( dirname( __FILE__ ) ) . '/' ); 4 4 5 if ( ! defined( 'BP_TESTS_DIR' ) ) { 6 define( 'BP_TESTS_DIR', dirname( __FILE__ ) . '/' ); 7 } 8 5 9 require_once getenv( 'WP_TESTS_DIR' ) . '/includes/functions.php'; 6 10 7 11 function _install_and_load_buddypress() { 8 require dirname( __FILE__ ). '/includes/loader.php';12 require BP_TESTS_DIR . '/includes/loader.php'; 9 13 } 10 14 tests_add_filter( 'muplugins_loaded', '_install_and_load_buddypress' ); 11 15 12 16 require getenv( 'WP_TESTS_DIR' ) . '/includes/bootstrap.php'; 13 17 14 18 // Load the BP-specific testing tools 15 require dirname( __FILE__ ). '/includes/testcase.php';19 require BP_TESTS_DIR . '/includes/testcase.php'; -
tests/testcases/groups/class-bp-group-extension.php
1 <?php 2 3 include_once BP_TESTS_DIR . '/assets/group-extensions.php'; 4 5 /** 6 * @group groups 7 */ 8 class BP_Tests_Group_Extension_TestCases extends BP_UnitTestCase { 9 public function setUp() { 10 parent::setUp(); 11 } 12 13 public function tearDown() { 14 parent::tearDown(); 15 } 16 17 public function test_parse_legacy_properties() { 18 $class_name = 'BPTest_Group_Extension_Parse_Legacy_Properties'; 19 $class_slug = sanitize_title( $class_name ); 20 $e = new $class_name(); 21 $e->_register(); 22 23 // Test most items separately so we can ignore irrelevant props 24 $l = $e->_get_legacy_properties_converted(); 25 $this->assertEquals( $l['name'], $class_name ); 26 $this->assertEquals( $l['slug'], $class_slug ); 27 $this->assertEquals( $l['visibility'], 'private' ); 28 $this->assertEquals( $l['nav_item_position'], 63 ); 29 $this->assertEquals( $l['enable_nav_item'], true ); 30 $this->assertEquals( $l['nav_item_name'], $class_name . ' Nav' ); 31 $this->assertEquals( $l['display_hook'], 'foo_hook' ); 32 $this->assertEquals( $l['template_file'], 'foo_template' ); 33 34 // Build the screens array manually 35 $expected = array( 36 'create' => array( 37 'name' => $class_name . ' Create', 38 'slug' => $class_slug . '-create', 39 'position' => 58, 40 'enabled' => false, 41 ), 42 'edit' => array( 43 'name' => $class_name . ' Edit', 44 'slug' => $class_slug . '-edit', 45 'enabled' => false, 46 ), 47 'admin' => array( 48 'enabled' => true, 49 'metabox_context' => 'high', 50 'metabox_priority' => 'side', 51 ), 52 ); 53 54 $this->assertEquals( $expected, $l['screens'] ); 55 } 56 57 public function test_setup_screens_use_global_fallbacks() { 58 $class_name = 'BPTest_Group_Extension_Setup_Screens_Use_Global_Fallbacks'; 59 $e = new $class_name(); 60 $e->_setup_class_info(); 61 $screens = $e->_get_default_screens(); 62 63 $fallback = array( 64 'screen_callback' => array( $class_name, 'settings_screen' ), 65 'screen_save_callback' => array( $class_name, 'settings_screen_save' ), 66 ); 67 $fallbacks = array( 68 'create' => $fallback, 69 'edit' => $fallback, 70 'admin' => $fallback, 71 ); 72 73 // strip everything from the screens array but what we we're 74 // testing 75 foreach ( $screens as &$screen ) { 76 foreach ( $screen as $k => $v ) { 77 if ( ! in_array( $k, array( 'screen_callback', 'screen_save_callback' ) ) ) { 78 unset( $screen[ $k ] ); 79 } 80 } 81 } 82 83 $this->assertEquals( $screens, $fallbacks ); 84 } 85 86 public function test_setup_screens_define_edit_screens_locally() { 87 $class_name = 'BPTest_Group_Extension_Setup_Screens_Define_Edit_Screens_Locally'; 88 $e = new $class_name(); 89 $e->_setup_class_info(); 90 $screens = $e->_get_default_screens(); 91 92 $fallback = array( 93 'screen_callback' => array( $class_name, 'settings_screen' ), 94 'screen_save_callback' => array( $class_name, 'settings_screen_save' ), 95 ); 96 $expected = array( 97 'create' => $fallback, 98 'edit' => array( 99 'screen_callback' => array( $class_name, 'edit_screen' ), 100 'screen_save_callback' => array( $class_name, 'edit_screen_save' ), 101 ), 102 'admin' => $fallback, 103 ); 104 105 // strip everything from the screens array but what we we're 106 // testing 107 foreach ( $screens as &$screen ) { 108 foreach ( $screen as $k => $v ) { 109 if ( ! in_array( $k, array( 'screen_callback', 'screen_save_callback' ) ) ) { 110 unset( $screen[ $k ] ); 111 } 112 } 113 } 114 115 $this->assertEquals( $screens, $expected ); 116 } 117 118 public function test_parse_args_r() { 119 $a = array( 120 'veggies' => 'yes', 121 'ice_cream' => 'dope', 122 'fruit' => array( 123 'apple' => 'gross', 124 'berries' => array( 125 'blueberries' => array( 126 'in_season' => 'never', 127 'oh' => 'boy', 128 ), 129 'cherries' => 'sometimes', 130 ), 131 ), 132 ); 133 134 $b = array( 135 'veggies' => 'no', 136 'cheese' => array( 137 'cheddar' => 'good', 138 ), 139 'fruit' => array( 140 'apple' => 'yum', 141 'berries' => array( 142 'strawberries' => 'awesome', 143 'blueberries' => array( 144 'in_season' => 'yes', 145 'out_of_season' => 'no', 146 ), 147 ), 148 ), 149 ); 150 151 $expected = array( 152 'veggies' => 'yes', 153 'ice_cream' => 'dope', 154 'cheese' => array( 155 'cheddar' => 'good', 156 ), 157 'fruit' => array( 158 'apple' => 'gross', 159 'berries' => array( 160 'strawberries' => 'awesome', 161 'blueberries' => array( 162 'in_season' => 'never', 163 'out_of_season' => 'no', 164 'oh' => 'boy', 165 ), 166 'cherries' => 'sometimes', 167 ), 168 ), 169 ); 170 171 $this->assertEquals( $expected, BP_Group_Extension::parse_args_r( $a, $b ) ); 172 } 173 174 /** 175 * Config that gets intentionally stored as a direct property of object 176 */ 177 public function test_access_root_property() { 178 $class_name = 'BPTest_Group_Extension_Access_Root_Property'; 179 $e = new $class_name(); 180 $e->_register(); 181 182 $this->assertEquals( 39, $e->nav_item_position ); 183 } 184 185 /** 186 * Config that gets registered using init(), but is then accessed via 187 * the legacy location 188 */ 189 public function test_access_init_property_using_legacy_location() { 190 $class_name = 'BPTest_Group_Extension_Access_Init_Property_Using_Legacy_Location'; 191 $e = new $class_name(); 192 $e->_register(); 193 194 $this->assertEquals( 18, $e->create_step_position ); 195 } 196 197 /** 198 * Provides settings_screen* and edit_screen* 199 */ 200 public function test_get_screen_callback_fallbacks() { 201 $class_name = 'BPTest_Group_Extension_Get_Screen_Callback_Fallbacks'; 202 $e = new $class_name(); 203 $e->_register(); 204 205 $this->assertEquals( array( $class_name, 'settings_screen' ), $e->screens['create']['screen_callback'] ); 206 $this->assertEquals( array( $class_name, 'settings_screen_save' ), $e->screens['create']['screen_save_callback'] ); 207 $this->assertEquals( array( $class_name, 'settings_screen' ), $e->screens['admin']['screen_callback'] ); 208 $this->assertEquals( array( $class_name, 'settings_screen_save' ), $e->screens['admin']['screen_save_callback'] ); 209 $this->assertEquals( array( $class_name, 'edit_screen' ), $e->screens['edit']['screen_callback'] ); 210 $this->assertEquals( array( $class_name, 'edit_screen_save' ), $e->screens['edit']['screen_save_callback'] ); 211 } 212 213 public function test_has_submit_button() { 214 $a = '<p>Foo bar</p><input type="text" name="awesome" /><input name="save" type="submit" id="saverrrr" />sweet'; 215 $this->assertTrue( BP_Group_Extension::has_submit_button( $a ) ); 216 217 $b = '<p>Foo bar</p><input type="text" name="awesome" />sweet'; 218 $this->assertFalse( BP_Group_Extension::has_submit_button( $b ) ); 219 220 // switch the quotation marks 221 $c = "<p>Foo bar</p><input type='text' name='awesome' /><input name='save' type='submit' id='saverrrr' />sweet"; 222 $this->assertTrue( BP_Group_Extension::has_submit_button( $c ) ); 223 } 224 }