Index: src/bp-core/classes/class-bp-button.php
===================================================================
--- src/bp-core/classes/class-bp-button.php
+++ src/bp-core/classes/class-bp-button.php
@@ -14,35 +14,34 @@
  * API to create BuddyPress buttons.
  *
  * @since 1.2.6
+ * @since 2.7.0 Introduced $parent_element, $parent_attr, $button_element, $button_attr as
+ *              $args parameters. Deprecated $wrapper, $wrapper_id, $wrapper_class,
+ *              $link_href, $link_class, $link_id, $link_rel, $link_title as $args params.
  *
  * @param array $args {
  *     Array of arguments.
  *
  *     @type string      $id                String describing the button type.
- *     @type string      $component         The name of the component the button belongs to.
- *                                          Default: 'core'.
- *     @type bool        $must_be_logged_in Optional. Does the user need to be logged
- *                                          in to see this button? Default: true.
- *     @type bool        $block_self        Optional. True if the button should be hidden
- *                                          when a user is viewing his own profile.
- *                                          Default: true.
- *     @type string|bool $wrapper           Optional. HTML element type that should wrap
- *                                          the button: 'div', 'span', 'p', or 'li'.
- *                                          False for no wrapper at all. Default: 'div'.
- *     @type string      $wrapper_id        Optional. DOM ID of the button wrapper element.
- *                                          Default: ''.
- *     @type string      $wrapper_class     Optional. DOM class of the button wrapper
- *                                          element. Default: ''.
- *     @type string      $link_href         Optional. Destination link of the button.
- *                                          Default: ''.
- *     @type string      $link_class        Optional. DOM class of the button. Default: ''.
- *     @type string      $link_id           Optional. DOM ID of the button. Default: ''.
- *     @type string      $link_rel          Optional. DOM 'rel' attribute of the button.
- *                                          Default: ''.
- *     @type string      $link_title        Optional. Title attribute of the button.
- *                                          Default: ''.
- *     @type string      $link_text         Optional. Text to appear on the button.
- *                                          Default: ''.
+ *     @type string      $component         The name of the component the button belongs to. Default: 'core'.
+ *     @type bool        $must_be_logged_in Optional. Does the user need to be logged in to see this button? Default:
+ *                                          true.
+ *     @type bool        $block_self        Optional. True if the button should be hidden when a user is viewing his
+ *                                          own profile. Default: true.
+ *     @type string      $parent_element    Optional. Parent element to wrap button around. Default: 'div'.
+ *     @type array       $parent_attr       Optional. Element attributes for parent element. Set whatever attributes
+ *                                          like 'id', 'class' as array keys.
+ *     @type string      $button_element    Optional. Button element. Default: 'a'.
+ *     @type array       $button_attr       Optional. Button attributes. Set whatever attributes like 'id', 'class' as
+ *                                          array keys.
+ *     @type string      $link_text         Optional. Text to appear on the button. Default: ''.
+ *     @type string|bool $wrapper           Deprecated. Use $parent_element instead.
+ *     @type string      $wrapper_id        Deprecated. Use $parent_attr and set 'id' as array key.
+ *     @type string      $wrapper_class     Deprecated. Use $parent_attr and set 'class' as array key.
+ *     @type string      $link_href         Deprecated. Use $button_attr and set 'href' as array key.
+ *     @type string      $link_class        Deprecated. Use $button_attr and set 'class' as array key.
+ *     @type string      $link_id           Deprecated. Use $button_attr and set 'id' as array key.
+ *     @type string      $link_rel          Deprecated. Use $button_attr and set 'rel' as array key.
+ *     @type string      $link_title        Deprecated. Use $button_attr and set 'title' as array key.
  * }
  */
 class BP_Button {
@@ -80,15 +79,72 @@
 	/** Wrapper ***************************************************************/
 
 	/**
+	 * Parent element to wrap button around.
+	 *
+	 * @since 2.7.0
+	 *
+	 * @var string Default: 'div'.
+	 */
+	public $parent_element = 'div';
+
+	/**
+	 * Element attributes for parent element.
+	 *
+	 * @since 2.7.0
+	 *
+	 * @var array Set whatever attributes like 'id', 'class' as array key.
+	 */
+	public $parent_attr = array();
+
+	/** Button ****************************************************************/
+
+	/**
+	 * Button element.
+	 *
+	 * @since 2.7.0
+	 *
+	 * @var string Default: 'a'.
+	 */
+	public $button_element = 'a';
+
+	/**
+	 * Button attributes.
+	 *
+	 * @since 2.7.0
+	 *
+	 * @var array Set whatever attributes like 'id', 'href' as array key.
+	 */
+	public $button_attr = array();
+
+	/**
+	 * The contents of the button link.
+	 *
+	 * @var string
+	 */
+	public $link_text = '';
+
+	/** HTML result
+	 *
+	 * @var string
+	 */
+	public $contents = '';
+
+	/** Deprecated ***********************************************************/
+
+	/**
 	 * The type of DOM element to use for a wrapper.
 	 *
-	 * @var string|bool 'div', 'span', 'p', 'li', or false for no wrapper.
+	 * @deprecated 2.7.0 Use $parent_element instead.
+	 *
+	 * @var string|bool
 	 */
-	public $wrapper = 'div';
+	public $wrapper = '';
 
 	/**
 	 * The DOM class of the button wrapper.
 	 *
+	 * @deprecated 2.7.0 Set 'class' key in $parent_attr instead.
+	 *
 	 * @var string
 	 */
 	public $wrapper_class = '';
@@ -96,15 +152,17 @@
 	/**
 	 * The DOM ID of the button wrapper.
 	 *
+	 * @deprecated 2.7.0 Set 'id' key in $parent_attr instead.
+	 *
 	 * @var string
 	 */
 	public $wrapper_id = '';
 
-	/** Button ****************************************************************/
-
 	/**
 	 * The destination link of the button.
 	 *
+	 * @deprecated 2.7.0 Set 'href' key in $button_attr instead.
+	 *
 	 * @var string
 	 */
 	public $link_href = '';
@@ -112,6 +170,8 @@
 	/**
 	 * The DOM class of the button link.
 	 *
+	 * @deprecated 2.7.0 Set 'class' key in $button_attr instead.
+	 *
 	 * @var string
 	 */
 	public $link_class = '';
@@ -119,6 +179,8 @@
 	/**
 	 * The DOM ID of the button link.
 	 *
+	 * @deprecated 2.7.0 Set 'id' key in $button_attr instead.
+	 *
 	 * @var string
 	 */
 	public $link_id = '';
@@ -126,6 +188,8 @@
 	/**
 	 * The DOM rel value of the button link.
 	 *
+	 * @deprecated 2.7.0 Set 'rel' key in $button_attr instead.
+	 *
 	 * @var string
 	 */
 	public $link_rel = '';
@@ -133,22 +197,11 @@
 	/**
 	 * Title of the button link.
 	 *
-	 * @var string
-	 */
-	public $link_title = '';
-
-	/**
-	 * The contents of the button link.
-	 *
-	 * @var string
-	 */
-	public $link_text = '';
-
-	/** HTML result
+	 * @deprecated 2.7.0 Set 'title' key in $button_attr instead.
 	 *
 	 * @var string
 	 */
-	public $contents = '';
+	public $link_title = '';
 
 	/** Methods ***************************************************************/
 
@@ -163,76 +216,118 @@
 
 		$r = wp_parse_args( $args, get_class_vars( __CLASS__ ) );
 
+		// Backward compatibility with deprecated parameters.
+		$r = $this->backward_compatibility_args( $r );
+
+		// Deprecated. Subject to removal in a future release.
+		$this->wrapper = $r['wrapper'];
+		if ( !empty( $r['link_id']    ) ) $this->link_id    = ' id="' .    $r['link_id']    . '"';
+		if ( !empty( $r['link_href']  ) ) $this->link_href  = ' href="' .  $r['link_href']  . '"';
+		if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"';
+		if ( !empty( $r['link_rel']   ) ) $this->link_rel   = ' rel="' .   $r['link_rel']   . '"';
+		if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"';
+		if ( !empty( $r['link_text']  ) ) $this->link_text  =              $r['link_text'];
+
 		// Required button properties.
 		$this->id                = $r['id'];
 		$this->component         = $r['component'];
 		$this->must_be_logged_in = (bool) $r['must_be_logged_in'];
 		$this->block_self        = (bool) $r['block_self'];
-		$this->wrapper           = $r['wrapper'];
-
-		// $id and $component are required
-		if ( empty( $r['id'] ) || empty( $r['component'] ) )
-			return false;
 
-		// No button if component is not active.
-		if ( ! bp_is_active( $this->component ) )
+		// $id and $component are required and component must be active.
+		if ( empty( $r['id'] ) || empty( $r['component'] ) || ! bp_is_active( $this->component ) ) {
 			return false;
+		}
 
 		// No button for guests if must be logged in.
-		if ( true == $this->must_be_logged_in && ! is_user_logged_in() )
+		if ( true == $this->must_be_logged_in && ! is_user_logged_in() ) {
 			return false;
+		}
 
 		// The block_self property.
 		if ( true == $this->block_self ) {
-			// No button if you are the current user in a members loop
-			// This condition takes precedence, because members loops
-			// can be found on user profiles.
+			/*
+			 * No button if you are the current user in a members loop.
+			 *
+			 * This condition takes precedence, because members loops can be found on user
+			 * profiles.
+			 */
 			if ( bp_get_member_user_id() ) {
 				if ( is_user_logged_in() && bp_loggedin_user_id() == bp_get_member_user_id() ) {
 					return false;
 				}
 
-			// No button if viewing your own profile (and not in
-			// a members loop).
+			// No button if viewing your own profile (and not in a members loop).
 			} elseif ( bp_is_my_profile() ) {
 				return false;
 			}
 		}
 
-		// Wrapper properties.
-		if ( false !== $this->wrapper ) {
+		// Should we use a parent element?
+		$parent_elem = sanitize_html_class( $r['parent_element'] );
+		if ( ! empty( $parent_elem ) ) {
+			if ( ! isset( $r['parent_attr']['class'] ) ) {
+				$r['parent_attr']['class'] = '';
+			}
 
-			// Wrapper ID.
-			if ( !empty( $r['wrapper_id'] ) ) {
-				$this->wrapper_id    = ' id="' . $r['wrapper_id'] . '"';
+			// Always add 'generic-button' class.
+			if ( false === strpos( $r['parent_attr']['class'], 'generic-button' ) ) {
+				if ( ! empty( $r['parent_attr']['class'] ) ) {
+					$r['parent_attr']['class'] .= ' ';
+				}
+				$r['parent_attr']['class'] .= 'generic-button';
 			}
 
-			// Wrapper class.
-			if ( !empty( $r['wrapper_class'] ) ) {
-				$this->wrapper_class = ' class="generic-button ' . $r['wrapper_class'] . '"';
-			} else {
-				$this->wrapper_class = ' class="generic-button"';
+			// Render parent element attributes.
+			$parent_attr = '';
+			foreach( $r['parent_attr'] as $attr => $val ) {
+				$parent_attr .= sprintf( '%s="%s" ', sanitize_html_class( $attr ), esc_attr( $val ) );
 			}
 
 			// Set before and after.
-			$before = '<' . $r['wrapper'] . $this->wrapper_class . $this->wrapper_id . '>';
-			$after  = '</' . $r['wrapper'] . '>';
+			$before = sprintf( '<%1$s %2$s>', $parent_elem, $parent_attr );
+			$after  = sprintf( '</%s>', $parent_elem );
 
-		// No wrapper.
+		// No parent element.
 		} else {
 			$before = $after = '';
 		}
 
-		// Link properties.
-		if ( !empty( $r['link_id']    ) ) $this->link_id    = ' id="' .    $r['link_id']    . '"';
-		if ( !empty( $r['link_href']  ) ) $this->link_href  = ' href="' .  $r['link_href']  . '"';
-		if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"';
-		if ( !empty( $r['link_rel']   ) ) $this->link_rel   = ' rel="' .   $r['link_rel']   . '"';
-		if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"';
-		if ( !empty( $r['link_text']  ) ) $this->link_text  =              $r['link_text'];
+		// Button properties.
+		$button = '';
+		$button_elem = sanitize_html_class( $r['button_element'] );
+		if ( ! empty( $button_elem ) ) {
+			// Render button attributes.
+			$button_attr = '';
+			foreach( $r['button_attr'] as $attr => $val ) {
+				if ( 'href' === $attr || 'formaction' === $attr || 'src' === $attr ) {
+					$val = esc_url( $val );
+				} else {
+					$val = esc_attr( $val );
+				}
+
+				$button_attr .= sprintf( '%s="%s" ', sanitize_html_class( $attr ), $val );
+			}
+
+			// <input> / <img> is self-closing.
+			if ( 'input' === $button_elem || 'img' === $button_elem ) {
+				$button = sprintf( '<%1$s %2$s />',
+					$button_elem,
+					$button_attr
+				);
+
+			// All other elements.
+			} else {
+				$button = sprintf( '<%1$s %2$s>%3$s</%1$s>',
+					$button_elem,
+					$button_attr,
+					! empty( $r['link_text'] ) ? $r['link_text'] : ''
+				);
+			}
+		}
 
 		// Build the button.
-		$this->contents = $before . '<a'. $this->link_href . $this->link_title . $this->link_id . $this->link_rel . $this->link_class . '>' . $this->link_text . '</a>' . $after;
+		$this->contents = $before . $button . $after;
 
 		/**
 		 * Filters the button based on class parameters.
@@ -241,13 +336,72 @@
 		 * allows button to be manipulated externally.
 		 *
 		 * @since 1.2.6
+		 * @since 2.7.0 Added $r as a parameter.
 		 *
 		 * @param string    $contents HTML being used for the button.
 		 * @param BP_Button $this     Current BP_Button instance.
 		 * @param string    $before   HTML appended before the actual button.
 		 * @param string    $after    HTML appended after the actual button.
+		 * @param array     $r        Parsed button arguments.
 		 */
-		$this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after );
+		$this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after, $r );
+	}
+
+	/**
+	 * Provide backward compatibility for deprecated button arguments.
+	 *
+	 * @since 2.7.0.
+	 *
+	 * @param  array $r See {@link BP_Button} class for full documentation.
+	 * @return array
+	 */
+	protected function backward_compatibility_args( $r = array() ) {
+		// Array of deprecated arguments.
+		$backpat_args = array(
+			'wrapper', 'wrapper_class', 'wrapper_id',
+			'link_href', 'link_class', 'link_id', 'link_rel', 'link_title'
+		);
+
+		foreach ( $backpat_args as $prop ) {
+			if ( empty( $r[ $prop ] ) ) {
+				continue;
+			}
+
+			$parent = $child = false;
+			$sep    = strpos( $prop, '_' );
+
+			// Check if this is an attribute.
+			if ( false !== $sep ) {
+				$child  = true;
+				$parent = substr( $prop, 0, $sep );
+			} else {
+				$parent = $prop;
+			}
+
+			if ( 'wrapper' === $parent ) {
+				$parent = 'parent';
+			} else {
+				$parent = 'button';
+			}
+
+			// Set element.
+			if ( false === $child ) {
+				$r[ "{$parent}_element" ] = $r[ $prop ];
+
+			// Set attributes.
+			} elseif ( true === $child ) {
+				$new_prop = substr( $prop, strpos( $prop, '_' ) +1 );
+				if ( empty( $r[ "{$parent}_attr" ] ) ) {
+					$r[ "{$parent}_attr" ] = array();
+				}
+
+				if ( empty( $r[ "{$parent}_attr" ][ $new_prop ] ) ) {
+					$r[ "{$parent}_attr" ][ $new_prop ] = $r[ $prop ];
+				}
+			}
+		}
+
+		return $r;
 	}
 
 	/**
Index: tests/phpunit/testcases/core/class-bp-button.php
===================================================================
--- tests/phpunit/testcases/core/class-bp-button.php
+++ tests/phpunit/testcases/core/class-bp-button.php
@@ -162,4 +162,85 @@
 		// clean up
 		$GLOBALS['members_template'] = null;
 	}
+
+	/**
+	 * @ticket BP7226
+	 */
+	public function test_bp_button_new_args() {
+		$b = new BP_Button( array(
+			'id' => 'foo',
+			'component' => 'members',
+			'block_self' => false,
+			'must_be_logged_in' => false,
+			'parent_element' => 'section',
+			'parent_attr' => array(
+				'class' => 'section-class',
+				'id' => 'section-id',
+				'data-parent' => 'foo',
+			),
+			'button_element' => 'button',
+			'button_attr' => array(
+				'autofocus' => 'autofocus',
+				'type' => 'submit',
+				'name' => 'my-button'
+			)
+		) );
+
+		$this->assertNotFalse( strpos( $b->contents, '<section ' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'class="section-class ' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'id="section-id"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'data-parent="foo"' ) );
+		$this->assertNotFalse( strpos( $b->contents, '<button ' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'autofocus="autofocus"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'type="submit"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'name="my-button"' ) );
+	}
+
+	/**
+	 * @ticket BP7226
+	 */
+	public function test_bp_button_deprecated_args_should_still_render() {
+		$b = new BP_Button( array(
+			'id' => 'foo',
+			'component' => 'members',
+			'block_self' => false,
+			'must_be_logged_in' => false,
+			'wrapper' => 'section',
+			'wrapper_class' => 'section-class',
+			'wrapper_id' => 'section-id',
+			'link_href' => 'http://example.com',
+			'link_class' => 'link-class',
+			'link_id' => 'link-id',
+			'link_rel' => 'nofollow',
+			'link_title' => 'link-title'
+		) );
+
+		$this->assertNotFalse( strpos( $b->contents, '<section ' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'class="section-class ' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'id="section-id"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'href="http://example.com"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'class="link-class"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'id="link-id"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'rel="nofollow"' ) );
+		$this->assertNotFalse( strpos( $b->contents, 'title="link-title"' ) );
+	}
+
+	/**
+	 * @ticket BP7226
+	 */
+	public function test_bp_button_new_element_attrs_have_precedence_over_deprecated_element_attrs() {
+		$b = new BP_Button( array(
+			'id' => 'foo',
+			'component' => 'members',
+			'block_self' => false,
+			'must_be_logged_in' => false,
+			'button_element' => 'button',
+			'button_attr' => array(
+				'class' => 'new-class',
+			),
+			'link_class' => 'old-class'
+		) );
+
+		$this->assertNotFalse( strpos( $b->contents, '<button class="new-class"' ) );
+	}
 }
