Skip to:
Content

BuddyPress.org

Ticket #7226: 7226.ray.04.patch

File 7226.ray.04.patch, 20.3 KB (added by r-a-y, 8 years ago)
  • src/bp-core/classes/class-bp-button.php

     
    1414 * API to create BuddyPress buttons.
    1515 *
    1616 * @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.
    1720 *
    1821 * @param array $args {
    1922 *     Array of arguments.
    2023 *
    2124 *     @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.
    4645 * }
    4746 */
    4847class BP_Button {
     
    8079        /** Wrapper ***************************************************************/
    8180
    8281        /**
     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        /**
    83135         * The type of DOM element to use for a wrapper.
    84136         *
    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
    86140         */
    87         public $wrapper = 'div';
     141        public $wrapper = '';
    88142
    89143        /**
    90144         * The DOM class of the button wrapper.
    91145         *
     146         * @deprecated 2.7.0 Set 'class' key in $parent_attr instead.
     147         *
    92148         * @var string
    93149         */
    94150        public $wrapper_class = '';
     
    96152        /**
    97153         * The DOM ID of the button wrapper.
    98154         *
     155         * @deprecated 2.7.0 Set 'id' key in $parent_attr instead.
     156         *
    99157         * @var string
    100158         */
    101159        public $wrapper_id = '';
    102160
    103         /** Button ****************************************************************/
    104 
    105161        /**
    106162         * The destination link of the button.
    107163         *
     164         * @deprecated 2.7.0 Set 'href' key in $button_attr instead.
     165         *
    108166         * @var string
    109167         */
    110168        public $link_href = '';
     
    112170        /**
    113171         * The DOM class of the button link.
    114172         *
     173         * @deprecated 2.7.0 Set 'class' key in $button_attr instead.
     174         *
    115175         * @var string
    116176         */
    117177        public $link_class = '';
     
    119179        /**
    120180         * The DOM ID of the button link.
    121181         *
     182         * @deprecated 2.7.0 Set 'id' key in $button_attr instead.
     183         *
    122184         * @var string
    123185         */
    124186        public $link_id = '';
     
    126188        /**
    127189         * The DOM rel value of the button link.
    128190         *
     191         * @deprecated 2.7.0 Set 'rel' key in $button_attr instead.
     192         *
    129193         * @var string
    130194         */
    131195        public $link_rel = '';
     
    133197        /**
    134198         * Title of the button link.
    135199         *
    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.
    148201         *
    149202         * @var string
    150203         */
    151         public $contents = '';
     204        public $link_title = '';
    152205
    153206        /** Methods ***************************************************************/
    154207
     
    163216
    164217                $r = wp_parse_args( $args, get_class_vars( __CLASS__ ) );
    165218
     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
    166231                // Required button properties.
    167232                $this->id                = $r['id'];
    168233                $this->component         = $r['component'];
    169234                $this->must_be_logged_in = (bool) $r['must_be_logged_in'];
    170235                $this->block_self        = (bool) $r['block_self'];
    171                 $this->wrapper           = $r['wrapper'];
    172 
    173                 // $id and $component are required
    174                 if ( empty( $r['id'] ) || empty( $r['component'] ) )
    175                         return false;
    176236
    177                 // No button if component is not active.
    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 ) ) {
    179239                        return false;
     240                }
    180241
    181242                // 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() ) {
    183244                        return false;
     245                }
    184246
    185247                // The block_self property.
    186248                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                         */
    190255                        if ( bp_get_member_user_id() ) {
    191256                                if ( is_user_logged_in() && bp_loggedin_user_id() == bp_get_member_user_id() ) {
    192257                                        return false;
    193258                                }
    194259
    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).
    197261                        } elseif ( bp_is_my_profile() ) {
    198262                                return false;
    199263                        }
    200264                }
    201265
    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'] = '';
    208270                        }
    209271
    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';
    215278                        }
    216279
     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
    217286                        // 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' );
    220289
    221                 // No wrapper.
     290                // No parent element.
    222291                } else {
    223292                        $before = $after = '';
    224293                }
    225294
    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                }
    233305
    234306                // 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;
    236308
    237309                /**
    238310                 * Filters the button based on class parameters.
     
    241313                 * allows button to be manipulated externally.
    242314                 *
    243315                 * @since 1.2.6
     316                 * @since 2.7.0 Added $r as a parameter.
    244317                 *
    245318                 * @param string    $contents HTML being used for the button.
    246319                 * @param BP_Button $this     Current BP_Button instance.
    247320                 * @param string    $before   HTML appended before the actual button.
    248321                 * @param string    $after    HTML appended after the actual button.
     322                 * @param array     $r        Parsed button arguments.
    249323                 */
    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;
    251382        }
    252383
    253384        /**
  • 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 */
     15class 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

     
    162162                // clean up
    163163                $GLOBALS['members_template'] = null;
    164164        }
     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        }
    165246}