Ticket #7226: 7226.ray.04.patch
File 7226.ray.04.patch, 20.3 KB (added by , 8 years ago) |
---|
-
src/bp-core/classes/class-bp-button.php
14 14 * API to create BuddyPress buttons. 15 15 * 16 16 * @since 1.2.6 17 * @since 2.7.0 Introduced $parent_element, $parent_attr, $button_element, $button_attr as 18 * $args parameters. Deprecated $wrapper, $wrapper_id, $wrapper_class, 19 * $link_href, $link_class, $link_id, $link_rel, $link_title as $args params. 17 20 * 18 21 * @param array $args { 19 22 * Array of arguments. 20 23 * 21 24 * @type string $id String describing the button type. 22 * @type string $component The name of the component the button belongs to. 23 * Default: 'core'. 24 * @type bool $must_be_logged_in Optional. Does the user need to be logged 25 * in to see this button? Default: true. 26 * @type bool $block_self Optional. True if the button should be hidden 27 * when a user is viewing his own profile. 28 * Default: true. 29 * @type string|bool $wrapper Optional. HTML element type that should wrap 30 * the button: 'div', 'span', 'p', or 'li'. 31 * False for no wrapper at all. Default: 'div'. 32 * @type string $wrapper_id Optional. DOM ID of the button wrapper element. 33 * Default: ''. 34 * @type string $wrapper_class Optional. DOM class of the button wrapper 35 * element. Default: ''. 36 * @type string $link_href Optional. Destination link of the button. 37 * Default: ''. 38 * @type string $link_class Optional. DOM class of the button. Default: ''. 39 * @type string $link_id Optional. DOM ID of the button. Default: ''. 40 * @type string $link_rel Optional. DOM 'rel' attribute of the button. 41 * Default: ''. 42 * @type string $link_title Optional. Title attribute of the button. 43 * Default: ''. 44 * @type string $link_text Optional. Text to appear on the button. 45 * Default: ''. 25 * @type string $component The name of the component the button belongs to. Default: 'core'. 26 * @type bool $must_be_logged_in Optional. Does the user need to be logged in to see this button? Default: 27 * true. 28 * @type bool $block_self Optional. True if the button should be hidden when a user is viewing his 29 * own profile. Default: true. 30 * @type string $parent_element Optional. Parent element to wrap button around. Default: 'div'. 31 * @type array $parent_attr Optional. Element attributes for parent element. Set whatever attributes 32 * like 'id', 'class' as array keys. 33 * @type string $button_element Optional. Button element. Default: 'a'. 34 * @type array $button_attr Optional. Button attributes. Set whatever attributes like 'id', 'class' as 35 * array keys. 36 * @type string $link_text Optional. Text to appear on the button. Default: ''. 37 * @type string|bool $wrapper Deprecated. Use $parent_element instead. 38 * @type string $wrapper_id Deprecated. Use $parent_attr and set 'id' as array key. 39 * @type string $wrapper_class Deprecated. Use $parent_attr and set 'class' as array key. 40 * @type string $link_href Deprecated. Use $button_attr and set 'href' as array key. 41 * @type string $link_class Deprecated. Use $button_attr and set 'class' as array key. 42 * @type string $link_id Deprecated. Use $button_attr and set 'id' as array key. 43 * @type string $link_rel Deprecated. Use $button_attr and set 'rel' as array key. 44 * @type string $link_title Deprecated. Use $button_attr and set 'title' as array key. 46 45 * } 47 46 */ 48 47 class BP_Button { … … 80 79 /** Wrapper ***************************************************************/ 81 80 82 81 /** 82 * Parent element to wrap button around. 83 * 84 * @since 2.7.0 85 * 86 * @var string Default: 'div'. 87 */ 88 public $parent_element = 'div'; 89 90 /** 91 * Element attributes for parent element. 92 * 93 * @since 2.7.0 94 * 95 * @var array Set whatever attributes like 'id', 'class' as array key. 96 */ 97 public $parent_attr = array(); 98 99 /** Button ****************************************************************/ 100 101 /** 102 * Button element. 103 * 104 * @since 2.7.0 105 * 106 * @var string Default: 'a'. 107 */ 108 public $button_element = 'a'; 109 110 /** 111 * Button attributes. 112 * 113 * @since 2.7.0 114 * 115 * @var array Set whatever attributes like 'id', 'href' as array key. 116 */ 117 public $button_attr = array(); 118 119 /** 120 * The contents of the button link. 121 * 122 * @var string 123 */ 124 public $link_text = ''; 125 126 /** HTML result 127 * 128 * @var string 129 */ 130 public $contents = ''; 131 132 /** Deprecated ***********************************************************/ 133 134 /** 83 135 * The type of DOM element to use for a wrapper. 84 136 * 85 * @var string|bool 'div', 'span', 'p', 'li', or false for no wrapper. 137 * @deprecated 2.7.0 Use $parent_element instead. 138 * 139 * @var string|bool 86 140 */ 87 public $wrapper = ' div';141 public $wrapper = ''; 88 142 89 143 /** 90 144 * The DOM class of the button wrapper. 91 145 * 146 * @deprecated 2.7.0 Set 'class' key in $parent_attr instead. 147 * 92 148 * @var string 93 149 */ 94 150 public $wrapper_class = ''; … … 96 152 /** 97 153 * The DOM ID of the button wrapper. 98 154 * 155 * @deprecated 2.7.0 Set 'id' key in $parent_attr instead. 156 * 99 157 * @var string 100 158 */ 101 159 public $wrapper_id = ''; 102 160 103 /** Button ****************************************************************/104 105 161 /** 106 162 * The destination link of the button. 107 163 * 164 * @deprecated 2.7.0 Set 'href' key in $button_attr instead. 165 * 108 166 * @var string 109 167 */ 110 168 public $link_href = ''; … … 112 170 /** 113 171 * The DOM class of the button link. 114 172 * 173 * @deprecated 2.7.0 Set 'class' key in $button_attr instead. 174 * 115 175 * @var string 116 176 */ 117 177 public $link_class = ''; … … 119 179 /** 120 180 * The DOM ID of the button link. 121 181 * 182 * @deprecated 2.7.0 Set 'id' key in $button_attr instead. 183 * 122 184 * @var string 123 185 */ 124 186 public $link_id = ''; … … 126 188 /** 127 189 * The DOM rel value of the button link. 128 190 * 191 * @deprecated 2.7.0 Set 'rel' key in $button_attr instead. 192 * 129 193 * @var string 130 194 */ 131 195 public $link_rel = ''; … … 133 197 /** 134 198 * Title of the button link. 135 199 * 136 * @var string 137 */ 138 public $link_title = ''; 139 140 /** 141 * The contents of the button link. 142 * 143 * @var string 144 */ 145 public $link_text = ''; 146 147 /** HTML result 200 * @deprecated 2.7.0 Set 'title' key in $button_attr instead. 148 201 * 149 202 * @var string 150 203 */ 151 public $ contents= '';204 public $link_title = ''; 152 205 153 206 /** Methods ***************************************************************/ 154 207 … … 163 216 164 217 $r = wp_parse_args( $args, get_class_vars( __CLASS__ ) ); 165 218 219 // Backward compatibility with deprecated parameters. 220 $r = $this->backward_compatibility_args( $r ); 221 222 // Deprecated. Subject to removal in a future release. 223 $this->wrapper = $r['wrapper']; 224 if ( !empty( $r['link_id'] ) ) $this->link_id = ' id="' . $r['link_id'] . '"'; 225 if ( !empty( $r['link_href'] ) ) $this->link_href = ' href="' . $r['link_href'] . '"'; 226 if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"'; 227 if ( !empty( $r['link_rel'] ) ) $this->link_rel = ' rel="' . $r['link_rel'] . '"'; 228 if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"'; 229 if ( !empty( $r['link_text'] ) ) $this->link_text = $r['link_text']; 230 166 231 // Required button properties. 167 232 $this->id = $r['id']; 168 233 $this->component = $r['component']; 169 234 $this->must_be_logged_in = (bool) $r['must_be_logged_in']; 170 235 $this->block_self = (bool) $r['block_self']; 171 $this->wrapper = $r['wrapper'];172 173 // $id and $component are required174 if ( empty( $r['id'] ) || empty( $r['component'] ) )175 return false;176 236 177 // No button if component is notactive.178 if ( ! bp_is_active( $this->component ) )237 // $id and $component are required and component must be active. 238 if ( empty( $r['id'] ) || empty( $r['component'] ) || ! bp_is_active( $this->component ) ) { 179 239 return false; 240 } 180 241 181 242 // No button for guests if must be logged in. 182 if ( true == $this->must_be_logged_in && ! is_user_logged_in() ) 243 if ( true == $this->must_be_logged_in && ! is_user_logged_in() ) { 183 244 return false; 245 } 184 246 185 247 // The block_self property. 186 248 if ( true == $this->block_self ) { 187 // No button if you are the current user in a members loop 188 // This condition takes precedence, because members loops 189 // can be found on user profiles. 249 /* 250 * No button if you are the current user in a members loop. 251 * 252 * This condition takes precedence, because members loops can be found on user 253 * profiles. 254 */ 190 255 if ( bp_get_member_user_id() ) { 191 256 if ( is_user_logged_in() && bp_loggedin_user_id() == bp_get_member_user_id() ) { 192 257 return false; 193 258 } 194 259 195 // No button if viewing your own profile (and not in 196 // a members loop). 260 // No button if viewing your own profile (and not in a members loop). 197 261 } elseif ( bp_is_my_profile() ) { 198 262 return false; 199 263 } 200 264 } 201 265 202 // Wrapper properties. 203 if ( false !== $this->wrapper ) { 204 205 // Wrapper ID. 206 if ( !empty( $r['wrapper_id'] ) ) { 207 $this->wrapper_id = ' id="' . $r['wrapper_id'] . '"'; 266 // Should we use a parent element? 267 if ( ! empty( $r['parent_element'] ) ) { 268 if ( ! isset( $r['parent_attr']['class'] ) ) { 269 $r['parent_attr']['class'] = ''; 208 270 } 209 271 210 // Wrapper class. 211 if ( !empty( $r['wrapper_class'] ) ) { 212 $this->wrapper_class = ' class="generic-button ' . $r['wrapper_class'] . '"'; 213 } else { 214 $this->wrapper_class = ' class="generic-button"'; 272 // Always add 'generic-button' class. 273 if ( false === strpos( $r['parent_attr']['class'], 'generic-button' ) ) { 274 if ( ! empty( $r['parent_attr']['class'] ) ) { 275 $r['parent_attr']['class'] .= ' '; 276 } 277 $r['parent_attr']['class'] .= 'generic-button'; 215 278 } 216 279 280 // Render parent element attributes. 281 $parent_elem = new BP_Core_HTML_Element( array( 282 'element' => $r['parent_element'], 283 'attr' => $r['parent_attr'] 284 ) ); 285 217 286 // Set before and after. 218 $before = '<' . $r['wrapper'] . $this->wrapper_class . $this->wrapper_id . '>';219 $after = '</' . $r['wrapper'] . '>';287 $before = $parent_elem->get( 'open_tag' ); 288 $after = $parent_elem->get( 'close_tag' ); 220 289 221 // No wrapper.290 // No parent element. 222 291 } else { 223 292 $before = $after = ''; 224 293 } 225 294 226 // Link properties. 227 if ( !empty( $r['link_id'] ) ) $this->link_id = ' id="' . $r['link_id'] . '"'; 228 if ( !empty( $r['link_href'] ) ) $this->link_href = ' href="' . $r['link_href'] . '"'; 229 if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"'; 230 if ( !empty( $r['link_rel'] ) ) $this->link_rel = ' rel="' . $r['link_rel'] . '"'; 231 if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"'; 232 if ( !empty( $r['link_text'] ) ) $this->link_text = $r['link_text']; 295 // Button properties. 296 $button = ''; 297 if ( ! empty( $r['button_element'] ) ) { 298 $button = new BP_Core_HTML_Element( array( 299 'element' => $r['button_element'], 300 'attr' => $r['button_attr'], 301 'inner_html' => ! empty( $r['link_text'] ) ? $r['link_text'] : '' 302 ) ); 303 $button = $button->contents(); 304 } 233 305 234 306 // Build the button. 235 $this->contents = $before . '<a'. $this->link_href . $this->link_title . $this->link_id . $this->link_rel . $this->link_class . '>' . $this->link_text . '</a>'. $after;307 $this->contents = $before . $button . $after; 236 308 237 309 /** 238 310 * Filters the button based on class parameters. … … 241 313 * allows button to be manipulated externally. 242 314 * 243 315 * @since 1.2.6 316 * @since 2.7.0 Added $r as a parameter. 244 317 * 245 318 * @param string $contents HTML being used for the button. 246 319 * @param BP_Button $this Current BP_Button instance. 247 320 * @param string $before HTML appended before the actual button. 248 321 * @param string $after HTML appended after the actual button. 322 * @param array $r Parsed button arguments. 249 323 */ 250 $this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after ); 324 $this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after, $r ); 325 } 326 327 /** 328 * Provide backward compatibility for deprecated button arguments. 329 * 330 * @since 2.7.0. 331 * 332 * @param array $r See {@link BP_Button} class for full documentation. 333 * @return array 334 */ 335 protected function backward_compatibility_args( $r = array() ) { 336 // Array of deprecated arguments. 337 $backpat_args = array( 338 'wrapper', 'wrapper_class', 'wrapper_id', 339 'link_href', 'link_class', 'link_id', 'link_rel', 'link_title' 340 ); 341 342 foreach ( $backpat_args as $prop ) { 343 if ( empty( $r[ $prop ] ) ) { 344 continue; 345 } 346 347 $parent = $child = false; 348 $sep = strpos( $prop, '_' ); 349 350 // Check if this is an attribute. 351 if ( false !== $sep ) { 352 $child = true; 353 $parent = substr( $prop, 0, $sep ); 354 } else { 355 $parent = $prop; 356 } 357 358 if ( 'wrapper' === $parent ) { 359 $parent = 'parent'; 360 } else { 361 $parent = 'button'; 362 } 363 364 // Set element. 365 if ( false === $child ) { 366 $r[ "{$parent}_element" ] = $r[ $prop ]; 367 368 // Set attributes. 369 } elseif ( true === $child ) { 370 $new_prop = substr( $prop, strpos( $prop, '_' ) +1 ); 371 if ( empty( $r[ "{$parent}_attr" ] ) ) { 372 $r[ "{$parent}_attr" ] = array(); 373 } 374 375 if ( empty( $r[ "{$parent}_attr" ][ $new_prop ] ) ) { 376 $r[ "{$parent}_attr" ][ $new_prop ] = $r[ $prop ]; 377 } 378 } 379 } 380 381 return $r; 251 382 } 252 383 253 384 /** -
new file src/bp-core/classes/class-bp-core-html-element.php
new file mode 100644
- + 1 <?php 2 /** 3 * Core component classes. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 2.7.0 8 */ 9 10 /** 11 * Generate markup for an HTML element. 12 * 13 * @since 2.7.0 14 */ 15 class BP_Core_HTML_Element { 16 /** 17 * Open tag for an element. 18 * 19 * This would include attributes if applicable. eg. '<a href="" class="">' 20 * 21 * @since 2.7.0 22 * 23 * @var string 24 */ 25 public $open_tag = ''; 26 27 /** 28 * Inner HTML for an element. 29 * 30 * For example, this could be anchor text within an <a> element. 31 * 32 * @since 2.7.0 33 * 34 * @var string 35 */ 36 public $inner_html = ''; 37 38 /** 39 * Closing tag for an element. 40 * 41 * For example, "</a>". 42 * 43 * @since 2.7.0 44 * 45 * @var string 46 */ 47 public $close_tag = ''; 48 49 /** 50 * Constructor. 51 * 52 * @since 2.7.0 53 * 54 * @param array $r { 55 * An array of arguments. 56 * @type string $element The element to render. eg. 'a' for the anchor element. 57 * @type array $attr Optional. The element's attributes set as key/value pairs. eg. 58 * array( 'href' => 'http://example.com', 'class' => 'my-class' ) 59 * @type string $inner_html Optional. The inner HTML for the element if applicable. 60 * } 61 */ 62 public function __construct( $r = array() ) { 63 $elem = sanitize_html_class( $r['element'] ); 64 if ( empty( $elem ) ) { 65 return; 66 } 67 68 // Render attributes. 69 $attributes = ''; 70 foreach( (array) $r['attr'] as $attr => $val ) { 71 if ( 'href' === $attr || 'formaction' === $attr || 'src' === $attr ) { 72 $val = esc_url( $val ); 73 } else { 74 $val = esc_attr( $val ); 75 } 76 77 $attributes .= sprintf( '%s="%s" ', sanitize_html_class( $attr ), $val ); 78 } 79 80 // <input> / <img> is self-closing. 81 if ( 'input' === $elem || 'img' === $elem ) { 82 $this->open_tag = sprintf( '<%1$s %2$s />', $elem, $attributes ); 83 84 // All other elements. 85 } else { 86 $this->open_tag = sprintf( '<%1$s %2$s>', $elem, $attributes ); 87 $this->inner_html = ! empty( $r['inner_html'] ) ? $r['inner_html'] : ''; 88 $this->close_tag = sprintf( '</%1$s>', $elem ); 89 } 90 } 91 92 /** 93 * Returns a property from this class. 94 * 95 * @since 2.7.0 96 * 97 * @param string $prop Property name. Either 'open_tag', 'inner_html', 'close_tag'. 98 * @return string 99 */ 100 public function get( $prop = '' ) { 101 if ( ! isset( $this->{$prop} ) ) { 102 return ''; 103 } 104 105 return $this->{$prop}; 106 } 107 108 /** 109 * Returns full contents of HTML element. 110 * 111 * @since 2.7.0 112 * 113 * @return string 114 */ 115 public function contents() { 116 return $this->open_tag . $this->inner_html . $this->close_tag; 117 } 118 } 119 No newline at end of file -
tests/phpunit/testcases/core/class-bp-button.php
162 162 // clean up 163 163 $GLOBALS['members_template'] = null; 164 164 } 165 166 /** 167 * @ticket BP7226 168 */ 169 public function test_bp_button_new_args() { 170 $b = new BP_Button( array( 171 'id' => 'foo', 172 'component' => 'members', 173 'block_self' => false, 174 'must_be_logged_in' => false, 175 'parent_element' => 'section', 176 'parent_attr' => array( 177 'class' => 'section-class', 178 'id' => 'section-id', 179 'data-parent' => 'foo', 180 ), 181 'button_element' => 'button', 182 'button_attr' => array( 183 'autofocus' => 'autofocus', 184 'type' => 'submit', 185 'name' => 'my-button' 186 ) 187 ) ); 188 189 $this->assertNotFalse( strpos( $b->contents, '<section ' ) ); 190 $this->assertNotFalse( strpos( $b->contents, 'class="section-class ' ) ); 191 $this->assertNotFalse( strpos( $b->contents, 'id="section-id"' ) ); 192 $this->assertNotFalse( strpos( $b->contents, 'data-parent="foo"' ) ); 193 $this->assertNotFalse( strpos( $b->contents, '<button ' ) ); 194 $this->assertNotFalse( strpos( $b->contents, 'autofocus="autofocus"' ) ); 195 $this->assertNotFalse( strpos( $b->contents, 'type="submit"' ) ); 196 $this->assertNotFalse( strpos( $b->contents, 'name="my-button"' ) ); 197 } 198 199 /** 200 * @ticket BP7226 201 */ 202 public function test_bp_button_deprecated_args_should_still_render() { 203 $b = new BP_Button( array( 204 'id' => 'foo', 205 'component' => 'members', 206 'block_self' => false, 207 'must_be_logged_in' => false, 208 'wrapper' => 'section', 209 'wrapper_class' => 'section-class', 210 'wrapper_id' => 'section-id', 211 'link_href' => 'http://example.com', 212 'link_class' => 'link-class', 213 'link_id' => 'link-id', 214 'link_rel' => 'nofollow', 215 'link_title' => 'link-title' 216 ) ); 217 218 $this->assertNotFalse( strpos( $b->contents, '<section ' ) ); 219 $this->assertNotFalse( strpos( $b->contents, 'class="section-class ' ) ); 220 $this->assertNotFalse( strpos( $b->contents, 'id="section-id"' ) ); 221 $this->assertNotFalse( strpos( $b->contents, 'href="http://example.com"' ) ); 222 $this->assertNotFalse( strpos( $b->contents, 'class="link-class"' ) ); 223 $this->assertNotFalse( strpos( $b->contents, 'id="link-id"' ) ); 224 $this->assertNotFalse( strpos( $b->contents, 'rel="nofollow"' ) ); 225 $this->assertNotFalse( strpos( $b->contents, 'title="link-title"' ) ); 226 } 227 228 /** 229 * @ticket BP7226 230 */ 231 public function test_bp_button_new_element_attrs_have_precedence_over_deprecated_element_attrs() { 232 $b = new BP_Button( array( 233 'id' => 'foo', 234 'component' => 'members', 235 'block_self' => false, 236 'must_be_logged_in' => false, 237 'button_element' => 'button', 238 'button_attr' => array( 239 'class' => 'new-class', 240 ), 241 'link_class' => 'old-class' 242 ) ); 243 244 $this->assertNotFalse( strpos( $b->contents, '<button class="new-class"' ) ); 245 } 165 246 }