Skip to:
Content

BuddyPress.org

Ticket #6570: 6570.07.patch

File 6570.07.patch, 94.3 KB (added by imath, 5 years ago)
  • src/bp-core/admin/bp-core-admin-settings.php

    diff --git src/bp-core/admin/bp-core-admin-settings.php src/bp-core/admin/bp-core-admin-settings.php
    index 39dd4ea..67119e4 100644
    function bp_admin_setting_callback_avatar_uploads() { 
    159159<?php
    160160}
    161161
     162/**
     163 * Allow members to upload cover images field.
     164 *
     165 * @since 2.4.0
     166 */
     167function bp_admin_setting_callback_cover_image_uploads() {
     168?>
     169        <input id="bp-disable-cover-image-uploads" name="bp-disable-cover-image-uploads" type="checkbox" value="1" <?php checked( ! bp_disable_cover_image_uploads() ); ?> />
     170        <label for="bp-disable-cover-image-uploads"><?php _e( 'Allow registered members to upload cover images', 'buddypress' ); ?></label>
     171<?php
     172}
     173
    162174/** Groups Section ************************************************************/
    163175
    164176/**
    function bp_admin_setting_callback_group_avatar_uploads() { 
    197209<?php
    198210}
    199211
     212/**
     213 * 'Enable group cover images' field markup.
     214 *
     215 * @since 2.4.0
     216 */
     217function bp_admin_setting_callback_group_cover_image_uploads() {
     218?>
     219        <input id="bp-disable-group-cover-image-uploads" name="bp-disable-group-cover-image-uploads" type="checkbox" value="1" <?php checked( ! bp_disable_group_cover_image_uploads() ); ?> />
     220        <label for="bp-disable-group-cover-image-uploads"><?php _e( 'Allow customizable cover images for groups', 'buddypress' ); ?></label>
     221<?php
     222}
     223
    200224/** Forums Section ************************************************************/
    201225
    202226/**
    function bp_core_admin_settings_save() { 
    299323                $legacy_options = array(
    300324                        'bp-disable-account-deletion',
    301325                        'bp-disable-avatar-uploads',
     326                        'bp-disable-cover-image-uploads',
    302327                        'bp-disable-group-avatar-uploads',
     328                        'bp-disable-group-cover-image-uploads',
    303329                        'bp_disable_blogforum_comments',
    304330                        'bp-disable-profile-sync',
    305331                        'bp_restrict_group_creation',
  • src/bp-core/bp-core-actions.php

    diff --git src/bp-core/bp-core-actions.php src/bp-core/bp-core-actions.php
    index 3612378..5778efd 100644
    add_action( 'bp_template_redirect', 'bp_post_request', 10 ); 
    9393add_action( 'bp_template_redirect', 'bp_get_request',        10 );
    9494
    9595/**
    96  * Add the BuddyPress functions file.
     96 * Add the BuddyPress functions file and the Theme Compat Default features.
    9797 */
    98 add_action( 'bp_after_setup_theme', 'bp_load_theme_functions', 1 );
     98add_action( 'bp_after_setup_theme', 'bp_load_theme_functions',                    1 );
     99add_action( 'bp_after_setup_theme', 'bp_register_theme_compat_default_features', 10 );
    99100
    100101// Load the admin.
    101102if ( is_admin() ) {
  • src/bp-core/bp-core-admin.php

    diff --git src/bp-core/bp-core-admin.php src/bp-core/bp-core-admin.php
    index 7457ddd..2b3a770 100644
    class BP_Admin { 
    338338                        // Add the main section
    339339                        add_settings_section( 'bp_xprofile', _x( 'Profile Settings', 'BuddyPress setting tab', 'buddypress' ), 'bp_admin_setting_callback_xprofile_section', 'buddypress' );
    340340
     341                        // Avatars
    341342                        add_settings_field( 'bp-disable-avatar-uploads', __( 'Profile Photo Uploads', 'buddypress' ), 'bp_admin_setting_callback_avatar_uploads', 'buddypress', 'bp_xprofile' );
    342343                        register_setting( 'buddypress', 'bp-disable-avatar-uploads', 'intval' );
    343344
     345                        // Cover images
     346                        if ( bp_is_active( 'xprofile', 'cover_image' ) ) {
     347                                add_settings_field( 'bp-disable-cover-image-uploads', __( 'Cover Image Uploads', 'buddypress' ), 'bp_admin_setting_callback_cover_image_uploads', 'buddypress', 'bp_xprofile' );
     348                                register_setting( 'buddypress', 'bp-disable-cover-image-uploads', 'intval' );
     349                        }
     350
    344351                        // Profile sync setting
    345352                        add_settings_field( 'bp-disable-profile-sync',   __( 'Profile Syncing',  'buddypress' ), 'bp_admin_setting_callback_profile_sync', 'buddypress', 'bp_xprofile' );
    346353                        register_setting  ( 'buddypress', 'bp-disable-profile-sync', 'intval' );
    class BP_Admin { 
    360367                        // Allow group avatars.
    361368                        add_settings_field( 'bp-disable-group-avatar-uploads', __( 'Group Photo Uploads', 'buddypress' ), 'bp_admin_setting_callback_group_avatar_uploads', 'buddypress', 'bp_groups' );
    362369                        register_setting( 'buddypress', 'bp-disable-group-avatar-uploads', 'intval' );
     370
     371                        // Allow group cover images.
     372                        if ( bp_is_active( 'groups', 'cover_image' ) ) {
     373                                add_settings_field( 'bp-disable-group-cover-image-uploads', __( 'Group Cover Image Uploads', 'buddypress' ), 'bp_admin_setting_callback_group_cover_image_uploads', 'buddypress', 'bp_groups' );
     374                                register_setting( 'buddypress', 'bp-disable-group-cover-image-uploads', 'intval' );
     375                        }
    363376                }
    364377
    365378                /** Forums ************************************************************/
  • src/bp-core/bp-core-attachments.php

    diff --git src/bp-core/bp-core-attachments.php src/bp-core/bp-core-attachments.php
    index 785c4f6..0999e0d 100644
    function bp_attachments_is_wp_version_supported() { 
    2525}
    2626
    2727/**
     28 * Get the Attachments Uploads dir data
     29 *
     30 * @since  2.4.0
     31 *
     32 * @param  string        $data The data to get. Possible values are: 'dir', 'basedir' & 'baseurl'
     33 *                       Leave empty to get all datas.
     34 * @return string|array  The needed Upload dir data.
     35 */
     36function bp_attachments_uploads_dir_get( $data = '' ) {
     37        $attachments_dir = 'buddypress';
     38        $retval          = '';
     39
     40        if ( 'dir' === $data ) {
     41                $retval = $attachments_dir;
     42        } else {
     43                $upload_data = bp_upload_dir();
     44
     45                // Build the Upload data array for BuddyPress attachments
     46                foreach ( $upload_data as $key => $value ) {
     47                        if ( 'basedir' === $key || 'baseurl' === $key ) {
     48                                $upload_data[ $key ] = trailingslashit( $value ) . $attachments_dir;
     49                        } else {
     50                                unset( $upload_data[ $key ] );
     51                        }
     52                }
     53
     54                // Add the dir to the array
     55                $upload_data['dir'] = $attachments_dir;
     56
     57                if ( empty( $data ) ) {
     58                        $retval = $upload_data;
     59                } elseif ( isset( $upload_data[ $data ] ) ) {
     60                        $retval = $upload_data[ $data ];
     61                }
     62        }
     63
     64        /**
     65         * Filter here to edit the Attachments upload dir data.
     66         *
     67         * @since  2.4.0
     68         *
     69         * @param  string|array $retval      The needed Upload dir data or the full array of data
     70         * @param  string       $data        The data requested
     71         */
     72        return apply_filters( 'bp_attachments_uploads_dir_get', $retval, $data );
     73}
     74
     75/**
     76 * Get the max upload file size for any attachment
     77 *
     78 * @since  2.4.0
     79 *
     80 * @param  string $type A string to inform about the type of attachment
     81 *                      we wish to get the max upload file size for
     82 * @return int    max upload file size for any attachment
     83 */
     84function bp_attachments_get_max_upload_file_size( $type = '' ) {
     85        $fileupload_maxk = bp_core_get_root_option( 'fileupload_maxk' );
     86
     87        if ( '' === $fileupload_maxk ) {
     88                $fileupload_maxk = 5120000; // 5mb;
     89        } else {
     90                $fileupload_maxk = $fileupload_maxk * 1024;
     91        }
     92
     93        /**
     94         * Filter here to edit the max upload file size.
     95         *
     96         * @since  2.4.0
     97         *
     98         * @param  int    $fileupload_maxk Max upload file size for any attachment
     99         * @param  string $type            The attachment type (eg: 'avatar' or 'cover_image')
     100         */
     101        return apply_filters( 'bp_attachments_get_max_upload_file_size', $fileupload_maxk, $type );
     102}
     103
     104/**
     105 * Get allowed types for any attachment
     106 *
     107 * @since  2.4.0
     108 *
     109 * @param  string $type  The extension types to get.
     110 *                       Default: 'avatar'
     111 * @return array         The list of allowed extensions for attachments
     112 */
     113function bp_attachments_get_allowed_types( $type = 'avatar' ) {
     114        // Defaults to BuddyPress supported image extensions
     115        $exts = array( 'jpeg', 'gif', 'png' );
     116
     117        /**
     118         * It's not a BuddyPress feature, get the allowed extensions
     119         * matching the $type requested
     120         */
     121        if ( 'avatar' !== $type && 'cover_image' !== $type ) {
     122                // Reset the default exts
     123                $exts = array();
     124
     125                switch ( $type ) {
     126                        case 'video' :
     127                                $exts = wp_get_video_extensions();
     128                        break;
     129
     130                        case 'audio' :
     131                                $exts = wp_get_video_extensions();
     132                        break;
     133
     134                        default:
     135                                $allowed_mimes = get_allowed_mime_types();
     136
     137                                /**
     138                                 * Search for allowed mimes matching the type
     139                                 *
     140                                 * eg: using 'application/vnd.oasis' as the $type
     141                                 * parameter will get all OpenOffice extensions supported
     142                                 * by WordPress and allowed for the current user.
     143                                 */
     144                                if ( '' !== $type ) {
     145                                        $allowed_mimes = preg_grep( '/' . addcslashes( $type, '/.+-' ) . '/', $allowed_mimes );
     146                                }
     147
     148                                $allowed_types = array_keys( $allowed_mimes );
     149
     150                                // Loop to explode keys using '|'
     151                                foreach ( $allowed_types as $allowed_type ) {
     152                                        $t = explode( '|', $allowed_type );
     153                                        $exts = array_merge( $exts, (array) $t );
     154                                }
     155                        break;
     156                }
     157        }
     158
     159        /**
     160         * Filter here to edit the allowed extensions by attachment type.
     161         *
     162         * @since  2.4.0
     163         *
     164         * @param  array  $exts List of allowed extensions
     165         * @param  string $type The requested file type
     166         */
     167        return apply_filters( 'bp_attachments_get_allowed_types', $exts, $type );
     168}
     169
     170/**
     171 * Get allowed attachment mime types.
     172 *
     173 * @since 2.4.0
     174 *
     175 * @param  string $type         The extension types to get (Optional).
     176 * @param  array $allowed_types List of allowed extensions
     177 * @return array                List of allowed mime types
     178 */
     179function bp_attachments_get_allowed_mimes( $type = '', $allowed_types = array() ) {
     180        if ( empty( $allowed_types ) ) {
     181                $allowed_types = bp_attachments_get_allowed_types( $type );
     182        }
     183
     184        $validate_mimes = wp_match_mime_types( join( ',', $allowed_types ), wp_get_mime_types() );
     185        $allowed_mimes  = array_map( 'implode', $validate_mimes );
     186
     187        /**
     188         * Include jpg type if jpeg is set
     189         */
     190        if ( isset( $allowed_mimes['jpeg'] ) && ! isset( $allowed_mimes['jpg'] ) ) {
     191                $allowed_mimes['jpg'] = $allowed_mimes['jpeg'];
     192        }
     193
     194        return $allowed_mimes;
     195}
     196
     197/**
     198 * Check the uploaded attachment type is allowed
     199 *
     200 * @since  2.4.0
     201 *
     202 * @param  string $file          Full path to the file.
     203 * @param  string $filename      The name of the file (may differ from $file due to $file being
     204 *                               in a tmp directory).
     205 * @param  array  $allowed_mimes The attachment allowed mimes (Required)
     206 * @return bool                  True if the attachment type is allowed. False otherwise
     207 */
     208function bp_attachments_check_filetype( $file, $filename, $allowed_mimes ) {
     209        $filetype = wp_check_filetype_and_ext( $file, $filename, $allowed_mimes );
     210
     211        if ( ! empty( $filetype['ext'] ) && ! empty( $filetype['type'] ) ) {
     212                return true;
     213        }
     214
     215        return false;
     216}
     217
     218/**
    28219 * Get the BuddyPress Plupload settings.
    29220 *
    30221 * @since  2.3.0
    function bp_attachments_enqueue_scripts( $class = '' ) { 
    257448                 * @param string $object the object the avatar belongs to (eg: user or group)
    258449                 */
    259450                $settings['nav'] = bp_sort_by_key( apply_filters( 'bp_attachments_avatar_nav', $avatar_nav, $object ), 'order', 'num' );
     451
     452        // Specific to BuddyPress cover images
     453        } elseif ( 'bp_cover_image_upload' === $defaults['multipart_params']['action'] ) {
     454
     455                // Cover images only need 1 file and 1 only!
     456                $defaults['multi_selection'] = false;
     457
     458                // Default cover component is xprofile
     459                $cover_component = 'xprofile';
     460
     461                // Get the object we're editing the cover image of
     462                $object = $defaults['multipart_params']['bp_params']['object'];
     463
     464                // Set the cover component according to the object
     465                if ( 'group' === $object ) {
     466                        $cover_component = 'groups';
     467                } elseif ( 'user' !== $object ) {
     468                        $cover_component = apply_filters( 'bp_attachments_cover_image_ui_component', $cover_component );
     469                }
     470                // Get cover image advised dimensions
     471                $cover_dimensions = bp_attachments_get_cover_image_dimensions( $cover_component );
     472
     473                // Set warning messages
     474                $strings['cover_image_warnings'] = apply_filters( 'bp_attachments_cover_image_ui_warnings', array(
     475                        'dimensions'  => sprintf(
     476                                        __( 'For better results, make sure to upload an image that is larger than %1$spx wide, and %2$spx tall.', 'buddypress' ),
     477                                        (int) $cover_dimensions['width'],
     478                                        (int) $cover_dimensions['height']
     479                                ),
     480                ) );
    260481        }
    261482
    262483        // Set Plupload settings
    function bp_attachments_enqueue_scripts( $class = '' ) { 
    317538function bp_attachments_current_user_can( $capability, $args = array() ) {
    318539        $can = false;
    319540
    320         if ( 'edit_avatar' === $capability ) {
     541        if ( 'edit_avatar' === $capability || 'edit_cover_image' === $capability ) {
    321542                /**
    322543                 * Needed avatar arguments are set.
    323544                 */
    function bp_attachments_get_template_part( $slug ) { 
    410631                bp_get_template_part( $attachment_template_part );
    411632        }
    412633}
     634
     635/** Cover Image ***************************************************************/
     636
     637/**
     638 * Get the cover image settings
     639 *
     640 * @since  2.4.0
     641 *
     642 * @param  string $component the component to get the settings for ("xprofile" for user or "groups")
     643 * @return array            the cover image settings
     644 */
     645function bp_attachments_get_cover_image_settings( $component = 'xprofile' ) {
     646        // Default parameters
     647        $args = array();
     648
     649        // First look in BP Theme Compat
     650        $cover_image = bp_get_theme_compat_feature( 'cover_image' );
     651
     652        if ( ! empty( $cover_image ) ) {
     653                $args = (array) $cover_image;
     654        }
     655
     656        /**
     657         * Then let people override/set the feature using this dynamic filter
     658         *
     659         * eg: for the user's profile cover image use :
     660         * add_filter( 'bp_before_xprofile_cover_image_settings_parse_args', 'your_filter', 10, 1 );
     661         *
     662         * @since  2.4.0
     663         *
     664         * @param array $settings the cover image settings
     665         */
     666        $settings = bp_parse_args( $args, array(
     667                'components'    => array(),
     668                'width'         => 1300,
     669                'height'        => 225,
     670                'callback'      => '',
     671                'theme_handle'  => '',
     672                'default_cover' => '',
     673        ), $component . '_cover_image_settings' );
     674
     675        if ( empty( $settings['components'] ) || empty( $settings['callback'] ) || empty( $settings['theme_handle'] ) ) {
     676                return false;
     677        }
     678
     679        // Current component is not supported
     680        if ( ! in_array( $component, $settings['components'] ) ) {
     681                return false;
     682        }
     683
     684        // Finally return the settings
     685        return $settings;
     686}
     687
     688/**
     689 * Get cover image Width and Height
     690 *
     691 * @since  2.4.0
     692 *
     693 * @param  string $component the BuddyPress component concerned ("xprofile" for user or "groups")
     694 * @return array             an associative array containing the advised width and height for the cover image
     695 */
     696function bp_attachments_get_cover_image_dimensions( $component = 'xprofile' ) {
     697        // Let's prevent notices when setting the warning strings
     698        $default = array( 'width' => 0, 'height' => 0 );
     699
     700        $settings = bp_attachments_get_cover_image_settings( $component );
     701
     702        if ( empty( $settings ) ) {
     703                return false;
     704        }
     705
     706        // Get width and height
     707        $wh = array_intersect_key( $settings, $default );
     708
     709        /**
     710         * Filter here to edit the cover image dimensions if needed.
     711         *
     712         * @since  2.4.0
     713         *
     714         * @param  array  $wh        an associative array containing the width and height values
     715         * @param  array  $settings  an associative array containing all the feature settings
     716         * @param  string $compnent  the requested component
     717         */
     718        return apply_filters( 'bp_attachments_get_cover_image_dimensions', $wh, $settings, $component );
     719}
     720
     721/**
     722 * Are we on a page to edit a cover image ?
     723 *
     724 * @since  2.4.0
     725 *
     726 * @return bool True if on a page to edit a cover image, false otherwise
     727 */
     728function bp_attachments_cover_image_is_edit() {
     729        $retval = false;
     730
     731        $current_component = bp_current_component();
     732        if ( 'profile' === $current_component ) {
     733                $current_component = 'xprofile';
     734        }
     735
     736        if ( ! bp_is_active( $current_component, 'cover_image' ) ) {
     737                return $retval;
     738        }
     739
     740        if ( bp_is_user_change_cover_image() ) {
     741                $retval = ! bp_disable_cover_image_uploads();
     742        }
     743
     744        if ( ( bp_is_group_admin_page() && 'group-cover-image' == bp_get_group_current_admin_tab() )
     745                || ( bp_is_group_create() && bp_is_group_creation_step( 'group-cover-image' ) ) ) {
     746                $retval = ! bp_disable_group_cover_image_uploads();
     747        }
     748
     749        return apply_filters( 'bp_attachments_cover_image_is_edit', $retval, $current_component );
     750}
     751
     752/**
     753 * Get the url or the path for a type of attachment
     754 *
     755 * @since  2.4.0
     756 *
     757 * @param  string $data whether to get the url or the path
     758 * @param  array  $args {
     759 *     @type string $object_dir  The object dir (eg: members/groups). Defaults to members.
     760 *     @type int    $item_id     The object id (eg: a user or a group id). Defaults to current user.
     761 *     @type string $type        The type of the attachment which is also the subdir where files are saved.
     762 *                               Defaults to 'cover-image'
     763 *     @type string $file        The name of the file.
     764 * }
     765 * @return string|bool the url or the path to the attachment, false otherwise
     766 */
     767function bp_attachments_get_attachment( $data = 'url', $args = array() ) {
     768        // Default value
     769        $attachment_data = false;
     770
     771        $r = bp_parse_args( $args, array(
     772                'object_dir' => 'members',
     773                'item_id'    => bp_loggedin_user_id(),
     774                'type'       => 'cover-image',
     775                'file'       => '',
     776        ), 'attachments_get_attachment_src' );
     777
     778        // Get BuddyPress Attachments Uploads Dir datas
     779        $bp_attachments_uploads_dir = bp_attachments_uploads_dir_get();
     780
     781        $type_subdir = $r['object_dir'] . '/' . $r['item_id'] . '/' . $r['type'];
     782        $type_dir    = trailingslashit( $bp_attachments_uploads_dir['basedir'] ) . $type_subdir;
     783
     784        if ( ! is_dir( $type_dir ) ) {
     785                return $attachment_data;
     786        }
     787
     788        if ( ! empty( $r['file'] ) ) {
     789                if ( ! file_exists( trailingslashit( $type_dir ) . $r['file'] ) ) {
     790                        return $attachment_data;
     791                }
     792
     793                if ( 'url' === $data ) {
     794                        $attachment_data = trailingslashit( $bp_attachments_uploads_dir['baseurl'] ) . $type_subdir . '/' . $r['file'];
     795                } else {
     796                        $attachment_data = trailingslashit( $type_dir ) . $r['file'];
     797                }
     798
     799        } else {
     800                $file = false;
     801
     802                // Open the directory and get the first file
     803                if ( $att_dir = opendir( $type_dir ) ) {
     804
     805                        while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
     806                                // Look for the first file having the type in its name
     807                                if ( false !== strpos( $attachment_file, $r['type'] ) && empty( $file ) ) {
     808                                        $file = $attachment_file;
     809                                        break;
     810                                }
     811                        }
     812                }
     813
     814                if ( empty( $file ) ) {
     815                        return $attachment_data;
     816                }
     817
     818                if ( 'url' === $data ) {
     819                        $attachment_data = trailingslashit( $bp_attachments_uploads_dir['baseurl'] ) . $type_subdir . '/' . $file;
     820                } else {
     821                        $attachment_data = trailingslashit( $type_dir ) . $file;
     822                }
     823        }
     824
     825        return $attachment_data;
     826}
     827
     828/**
     829 * Does the user has a cover image ?
     830 *
     831 * @since  2.4.0
     832 *
     833 * @param  int $user_id
     834 * @return bool True if the user has a cover image, false otherwise
     835 */
     836function bp_attachments_get_user_has_cover_image( $user_id = 0 ) {
     837        if ( empty( $user_id ) ) {
     838                $user_id = bp_displayed_user_id();
     839        }
     840
     841        $cover_src = bp_attachments_get_attachment( 'url', array(
     842                'item_id'   => $user_id,
     843        ) );
     844
     845        return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $user_id );
     846}
     847
     848/**
     849 * Does the group has a cover image ?
     850 *
     851 * @since  2.4.0
     852 *
     853 * @param  int $group_id
     854 * @return bool True if the group has a cover image, false otherwise
     855 */
     856function bp_attachments_get_group_has_cover_image( $group_id = 0 ) {
     857        if ( empty( $group_id ) ) {
     858                $group_id = bp_get_current_group_id();
     859        }
     860
     861        $cover_src = bp_attachments_get_attachment( 'url', array(
     862                'object_dir' => 'groups',
     863                'item_id'    => $group_id,
     864        ) );
     865
     866        return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $group_id );
     867}
     868
     869/**
     870 * Delete an attachment for the given arguments
     871 *
     872 * @since  2.4.0
     873 *
     874 * @param  array $args
     875 * @see    bp_attachments_get_attachment() For more information on accepted arguments.
     876 * @return bool True if the attachment was deleted, false otherwise
     877 */
     878function bp_attachments_delete_file( $args = array() ) {
     879        $attachment_path = bp_attachments_get_attachment( 'path', $args );
     880
     881        if ( empty( $attachment_path ) ) {
     882                return false;
     883        }
     884
     885        @unlink( $attachment_path );
     886        return true;
     887}
     888
     889/**
     890 * Ajax Upload and set a cover image
     891 *
     892 * @since  2.4.0
     893 *
     894 * @return  string|null A json object containing success data if the upload succeeded
     895 *                      error message otherwise.
     896 */
     897function bp_attachments_cover_image_ajax_upload() {
     898        // Bail if not a POST action
     899        if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
     900                wp_die();
     901        }
     902
     903        /**
     904         * Sending the json response will be different if
     905         * the current Plupload runtime is html4
     906         */
     907        $is_html4 = false;
     908        if ( ! empty( $_POST['html4' ] ) ) {
     909                $is_html4 = true;
     910        }
     911
     912        // Check the nonce
     913        check_admin_referer( 'bp-uploader' );
     914
     915        // Init the BuddyPress parameters
     916        $bp_params = array();
     917
     918        // We need it to carry on
     919        if ( ! empty( $_POST['bp_params' ] ) ) {
     920                $bp_params = bp_parse_args( $_POST['bp_params' ], array(
     921                        'object'  => 'user',
     922                        'item_id' => bp_loggedin_user_id(),
     923                ), 'attachments_cover_image_ajax_upload' );
     924        } else {
     925                bp_attachments_json_response( false, $is_html4 );
     926        }
     927
     928        // We need the object to set the uploads dir filter
     929        if ( empty( $bp_params['object'] ) ) {
     930                bp_attachments_json_response( false, $is_html4 );
     931        }
     932
     933        // Capability check
     934        if ( ! bp_attachments_current_user_can( 'edit_cover_image', $bp_params ) ) {
     935                bp_attachments_json_response( false, $is_html4 );
     936        }
     937
     938        $bp          = buddypress();
     939        $needs_reset = array();
     940
     941        // Default object data
     942        $object_data = array( 'dir' => 'members', 'component' => 'xprofile' );
     943        if ( 'group' === $bp_params['object'] ) {
     944                $object_data = array( 'dir' => 'groups', 'component' => 'groups' );
     945
     946                if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) {
     947                        $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group );
     948                        $bp->groups->current_group = groups_get_group( array(
     949                                'group_id'        => $bp_params['item_id'],
     950                                'populate_extras' => false,
     951                        ) );
     952                }
     953        } elseif ( 'user' !== $bp_params['object'] ) {
     954                $object_data = apply_filters( 'bp_attachments_cover_image_object_dir', $object_data, $bp_params['object'] );
     955
     956                if ( ! bp_displayed_user_id() && ! empty( $bp_params['item_id'] ) ) {
     957                        $needs_reset = array( 'key' => 'displayed_user', 'value' => $bp->displayed_user );
     958                        $bp->displayed_user->id = $bp_params['item_id'];
     959                }
     960        }
     961
     962        $cover_image_attachment = new BP_Attachment_Cover_Image();
     963        $uploaded = $cover_image_attachment->upload( $_FILES );
     964
     965        // Reset objects
     966        if ( ! empty( $needs_reset ) ) {
     967                if ( ! empty( $needs_reset['component'] ) ) {
     968                        $bp->{$needs_reset['component']}->{$needs_reset['key']} = $needs_reset['value'];
     969                } else {
     970                        $bp->{$needs_reset['key']} = $needs_reset['value'];
     971                }
     972        }
     973
     974        if ( ! empty( $uploaded['error'] ) ) {
     975                // Upload error response
     976                bp_attachments_json_response( false, $is_html4, array(
     977                        'type'    => 'upload_error',
     978                        'message' => sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $uploaded['error'] ),
     979                ) );
     980        }
     981
     982        // Get advised dimensions for the cover image
     983        $dimensions = bp_attachments_get_cover_image_dimensions( $object_data['component'] );
     984
     985        // Resize the image so that it fit with the cover image dimensions
     986        $cover_image  = $cover_image_attachment->fit( $uploaded['file'], $dimensions );
     987        $is_too_small = false;
     988
     989        // Image is too small in width and height
     990        if ( empty( $cover_image ) ) {
     991                $cover_file = $cover_image_attachment->generate_filename( $uploaded['file'] );
     992                @rename( $uploaded['file'], $cover_file );
     993
     994                // It's too small!
     995                $is_too_small = true;
     996        } elseif ( ! empty( $cover_image['path'] ) ) {
     997                $cover_file   = $cover_image['path'];
     998
     999                if ( $cover_image['width'] < $dimensions['width'] || $cover_image['height'] < $dimensions['height'] ) {
     1000                        $is_too_small = true;
     1001                }
     1002        }
     1003
     1004        // Default error message
     1005        $error_message = __( 'There was a problem uploading the cover image.', 'buddypress' );
     1006
     1007        if ( empty( $cover_file ) ) {
     1008                // Upload error response
     1009                bp_attachments_json_response( false, $is_html4, array(
     1010                        'type'    => 'upload_error',
     1011                        'message' => $error_message,
     1012                ) );
     1013        }
     1014
     1015        // Set the basename for the cover file
     1016        $cover_basename = wp_basename( $cover_file );
     1017
     1018        // Get BuddyPress Attachments Uploads Dir datas
     1019        $bp_attachments_uploads_dir = bp_attachments_uploads_dir_get();
     1020
     1021        $cover_subdir = $object_data['dir'] . '/' . $bp_params['item_id'] . '/cover-image';
     1022        $cover_dir    = trailingslashit( $bp_attachments_uploads_dir['basedir'] ) . $cover_subdir;
     1023
     1024        if ( ! is_dir( $cover_dir ) ) {
     1025                // Upload error response
     1026                bp_attachments_json_response( false, $is_html4, array(
     1027                        'type'    => 'upload_error',
     1028                        'message' => $error_message,
     1029                ) );
     1030        }
     1031
     1032        // Clean up the cover dir to only keep the uploaded cover image
     1033        if ( $att_dir = opendir( $cover_dir ) ) {
     1034                while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
     1035                        // skip directories and the new cover image
     1036                        if ( 2 < strlen( $attachment_file ) && 0 !== strpos( $attachment_file, '.' ) && $cover_basename !== $attachment_file ) {
     1037                                @unlink( $cover_dir . '/' . $attachment_file );
     1038                        }
     1039                }
     1040        }
     1041
     1042        // Build the url to the file
     1043        $cover_url = trailingslashit( $bp_attachments_uploads_dir['baseurl'] ) . $cover_subdir . '/' . $cover_basename;
     1044
     1045        // Init Feedback code, 1 is success
     1046        $feedback_code = 1;
     1047
     1048        // 0 is the size warning
     1049        if ( $is_too_small ) {
     1050                $feedback_code = 0;
     1051        }
     1052
     1053        // Set the name of the file
     1054        $name = $_FILES['file']['name'];
     1055        $name_parts = pathinfo( $name );
     1056        $name = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) );
     1057
     1058        // Finally return the cover image url to the UI
     1059        bp_attachments_json_response( true, $is_html4, array(
     1060                'name'          => $name,
     1061                'url'           => $cover_url,
     1062                'feedback_code' => $feedback_code,
     1063        ) );
     1064}
     1065add_action( 'wp_ajax_bp_cover_image_upload', 'bp_attachments_cover_image_ajax_upload' );
     1066
     1067/**
     1068 * Ajax delete a cover image for a given object and item id.
     1069 *
     1070 * @since 2.4.0
     1071 *
     1072 * @return string|null A json object containing success data if the cover image was deleted
     1073 *                     error message otherwise.
     1074 */
     1075function bp_attachments_cover_image_ajax_delete() {
     1076        // Bail if not a POST action.
     1077        if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
     1078                wp_send_json_error();
     1079        }
     1080
     1081        $cover_image_data = $_POST;
     1082
     1083        if ( empty( $cover_image_data['object'] ) || empty( $cover_image_data['item_id'] ) ) {
     1084                wp_send_json_error();
     1085        }
     1086
     1087        // Check the nonce
     1088        check_admin_referer( 'bp_delete_cover_image', 'nonce' );
     1089
     1090        // Capability check
     1091        if ( ! bp_attachments_current_user_can( 'edit_cover_image', $cover_image_data ) ) {
     1092                wp_send_json_error();
     1093        }
     1094
     1095        // Set object for the user's case
     1096        if ( 'user' === $cover_image_data['object'] ) {
     1097                $component = 'xprofile';
     1098                $dir       = 'members';
     1099
     1100        // Set it for any other cases
     1101        } else {
     1102                $component = $cover_image_data['object'] . 's';
     1103                $dir       = $component;
     1104        }
     1105
     1106        // Handle delete
     1107        if ( bp_attachments_delete_file( array( 'item_id' => $cover_image_data['item_id'], 'object_dir' => $dir, 'type' => 'cover-image' ) ) ) {
     1108
     1109                // Defaults no cover image
     1110                $response = array(
     1111                        'reset_url'     => '',
     1112                        'feedback_code' => 3 ,
     1113                );
     1114
     1115                // Get cover image settings in case there's a default header
     1116                $cover_params = bp_attachments_get_cover_image_settings( $component );
     1117
     1118                // Check if there's a default cover
     1119                if ( ! empty( $cover_params['default_cover'] ) ) {
     1120                        $response['reset_url'] = $cover_params['default_cover'];
     1121                }
     1122
     1123                // Finally send the reset url
     1124                wp_send_json_success( $response );
     1125
     1126        } else {
     1127                wp_send_json_error( array(
     1128                        'feedback_code' => 2,
     1129                ) );
     1130        }
     1131}
     1132add_action( 'wp_ajax_bp_cover_image_delete', 'bp_attachments_cover_image_ajax_delete' );
  • src/bp-core/bp-core-avatars.php

    diff --git src/bp-core/bp-core-avatars.php src/bp-core/bp-core-avatars.php
    index 4180784..1553725 100644
    function bp_core_set_avatar_constants() { 
    3232                define( 'BP_AVATAR_ORIGINAL_MAX_WIDTH', 450 );
    3333
    3434        if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE' ) ) {
    35 
    36                 $fileupload_maxk = bp_core_get_root_option( 'fileupload_maxk' );
    37                 if ( '' === $fileupload_maxk ) {
    38                         define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', 5120000 ); // 5mb
    39                 } else {
    40                         define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', $fileupload_maxk * 1024 );
    41                 }
     35                define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', bp_attachments_get_max_upload_file_size( 'avatar' ) );
    4236        }
    4337
    4438        if ( ! defined( 'BP_SHOW_AVATARS' ) ) {
    function bp_core_check_avatar_size( $file ) { 
    13701364 * @since 2.3.0
    13711365 */
    13721366function bp_core_get_allowed_avatar_types() {
    1373         $allowed_types = array( 'jpeg', 'gif', 'png' );
     1367        $allowed_types = bp_attachments_get_allowed_types( 'avatar' );
    13741368
    13751369        /**
    13761370         * Filters the list of allowed image types.
    function bp_core_get_allowed_avatar_types() { 
    13971391 */
    13981392function bp_core_get_allowed_avatar_mimes() {
    13991393        $allowed_types  = bp_core_get_allowed_avatar_types();
    1400         $validate_mimes = wp_match_mime_types( join( ',', $allowed_types ), wp_get_mime_types() );
    1401         $allowed_mimes  = array_map( 'implode', $validate_mimes );
    14021394
    1403         /**
    1404          * Include jpg type if needed so that bp_core_check_avatar_type()
    1405          * will check for jpeg and jpg extensions.
    1406          */
    1407         if ( isset( $allowed_mimes['jpeg'] ) ) {
    1408                 $allowed_mimes['jpg'] = $allowed_mimes['jpeg'];
    1409         }
    1410 
    1411         return $allowed_mimes;
     1395        return bp_attachments_get_allowed_mimes( 'avatar', $allowed_types );
    14121396}
    14131397
    14141398/**
    function bp_core_get_allowed_avatar_mimes() { 
    14211405 * @return bool True if the file extension is permitted, otherwise false.
    14221406 */
    14231407function bp_core_check_avatar_type( $file ) {
    1424         $avatar_filetype = wp_check_filetype_and_ext( $file['file']['tmp_name'], $file['file']['name'], bp_core_get_allowed_avatar_mimes() );
    1425 
    1426         if ( ! empty( $avatar_filetype['ext'] ) && ! empty( $avatar_filetype['type'] ) ) {
    1427                 return true;
    1428         }
    1429 
    1430         return false;
     1408        return bp_attachments_check_filetype( $file['file']['tmp_name'], $file['file']['name'], bp_core_get_allowed_avatar_mimes() );
    14311409}
    14321410
    14331411/**
  • src/bp-core/bp-core-classes.php

    diff --git src/bp-core/bp-core-classes.php src/bp-core/bp-core-classes.php
    index 7d1e0be..0da6fbb 100644
    require dirname( __FILE__ ) . '/classes/class-bp-recursive-query.php'; 
    2323require dirname( __FILE__ ) . '/classes/class-bp-media-extractor.php';
    2424require dirname( __FILE__ ) . '/classes/class-bp-attachment.php';
    2525require dirname( __FILE__ ) . '/classes/class-bp-attachment-avatar.php';
     26require dirname( __FILE__ ) . '/classes/class-bp-attachment-cover-image.php';
  • src/bp-core/bp-core-cssjs.php

    diff --git src/bp-core/bp-core-cssjs.php src/bp-core/bp-core-cssjs.php
    index ff5075e..f09f5f2 100644
    function bp_core_register_common_scripts() { 
    4343                'bp-avatar'   => array( 'file' => "{$url}avatar{$min}.js", 'dependencies' => array( 'jcrop' ), 'footer' => true ),
    4444                'bp-webcam'   => array( 'file' => "{$url}webcam{$min}.js", 'dependencies' => array( 'bp-avatar' ), 'footer' => true ),
    4545
     46                // 2.4
     47                'bp-cover-image' => array( 'file' => "{$url}cover-image{$min}.js", 'dependencies' => array(), 'footer' => true ),
     48
    4649        ) );
    4750
    4851        $version = bp_get_version();
    function bp_core_avatar_scripts() { 
    140143add_action( 'bp_enqueue_scripts', 'bp_core_avatar_scripts' );
    141144
    142145/**
     146 * Enqueues the css and js required by the Cover Image UI.
     147 *
     148 * @since  2.4.0
     149 */
     150function bp_core_cover_image_scripts() {
     151        if ( ! bp_attachments_cover_image_is_edit() ) {
     152                return false;
     153        }
     154
     155        // Enqueue the Attachments scripts for the Cover Image UI
     156        bp_attachments_enqueue_scripts( 'BP_Attachment_Cover_Image' );
     157}
     158add_action( 'bp_enqueue_scripts', 'bp_core_cover_image_scripts' );
     159
     160/**
    143161 * Enqueues jCrop library and hooks BP's custom cropper JS.
    144162 */
    145163function bp_core_add_jquery_cropper() {
    function bp_core_get_js_dependencies() { 
    337355                'bp-jquery-scroll-to'
    338356        ) );
    339357}
     358
     359/**
     360 * Add inline css to display the component's single item cover image
     361 *
     362 * @since 2.4.0
     363 *
     364 * @param  bool $return true to get the inline css
     365 * @return string|array the inline css or an associative array containing
     366 *                      the css rules and the style handle
     367 */
     368function bp_add_cover_image_inline_css( $return = false ) {
     369        $bp = buddypress();
     370
     371        // Find the component of the current item
     372        if ( bp_is_user() ) {
     373
     374                // User is not allowed to upload cover images
     375                // no need to carry on
     376                if ( bp_disable_cover_image_uploads() ) {
     377                        return;
     378                }
     379
     380                $cover_image_object = array(
     381                        'component' => 'xprofile',
     382                        'object' => $bp->displayed_user
     383                );
     384        } elseif ( bp_is_group() ) {
     385
     386                // Users are not allowed to upload cover images for their groups
     387                // no need to carry on
     388                if ( bp_disable_group_cover_image_uploads() ) {
     389                        return;
     390                }
     391
     392                $cover_image_object = array(
     393                        'component' =>'groups',
     394                        'object' => $bp->groups->current_group
     395                );
     396        } else {
     397                $cover_image_object = apply_filters( 'bp_current_cover_image_object_inline_css', array() );
     398        }
     399
     400        // Bail if no component were found.
     401        if ( empty( $cover_image_object['component'] ) || empty( $cover_image_object['object'] ) || ! bp_is_active( $cover_image_object['component'], 'cover_image' ) ) {
     402                return;
     403        }
     404
     405        // Get the settings of the cover image feature for the current component
     406        $params = bp_attachments_get_cover_image_settings( $cover_image_object['component'] );
     407
     408        // Bail if no params.
     409        if ( empty( $params ) ) {
     410                return;
     411        }
     412
     413        // Try to call the callback
     414        if ( is_callable( $params['callback'] ) ) {
     415
     416                $object_dir = $cover_image_object['component'];
     417
     418                if ( 'xprofile' === $object_dir ) {
     419                        $object_dir = 'members';
     420                }
     421
     422                $cover_image = bp_attachments_get_attachment( 'url', array(
     423                        'object_dir' => $object_dir,
     424                        'item_id'    => $cover_image_object['object']->id,
     425                ) );
     426
     427                if ( empty( $cover_image ) ) {
     428                        if ( ! empty( $params['default_cover'] ) ) {
     429                                $cover_image = $params['default_cover'];
     430                        }
     431                }
     432
     433                $inline_css = call_user_func_array( $params['callback'], array( array(
     434                        'cover_image' => esc_url( $cover_image ),
     435                        'component'   => sanitize_key( $cover_image_object['component'] ),
     436                        'object_id'   => (int) $cover_image_object['object']->id,
     437                        'width'       => (int) $params['width'],
     438                        'height'      => (int) $params['height'],
     439                ) ) );
     440
     441                // Finally add the inline css to the handle
     442                if ( ! empty( $inline_css ) ) {
     443
     444                        // Used to get the css when Ajax setting the cover image
     445                        if ( true === $return ) {
     446                                return array(
     447                                        'css_rules' => '<style type="text/css">' . "\n" . $inline_css . "\n" . '</style>',
     448                                        'handle'    => $params['theme_handle'],
     449                                );
     450                        }
     451
     452                        wp_add_inline_style( $params['theme_handle'], $inline_css );
     453                } else {
     454                        return false;
     455                }
     456        }
     457}
     458add_action( 'bp_enqueue_scripts', 'bp_add_cover_image_inline_css', 11 );
  • src/bp-core/bp-core-options.php

    diff --git src/bp-core/bp-core-options.php src/bp-core/bp-core-options.php
    index e825316..bb6ca3f 100644
    function bp_get_default_options() { 
    2323
    2424                /** Components ********************************************************/
    2525
    26                 'bp-deactivated-components'       => array(),
     26                'bp-deactivated-components'            => array(),
    2727
    2828                /** bbPress ***********************************************************/
    2929
    3030                // Legacy bbPress config location
    31                 'bb-config-location'              => ABSPATH . 'bb-config.php',
     31                'bb-config-location'                   => ABSPATH . 'bb-config.php',
    3232
    3333                /** XProfile **********************************************************/
    3434
    3535                // Base profile groups name
    36                 'bp-xprofile-base-group-name'     => 'Base',
     36                'bp-xprofile-base-group-name'          => 'Base',
    3737
    3838                // Base fullname field name
    39                 'bp-xprofile-fullname-field-name' => 'Name',
     39                'bp-xprofile-fullname-field-name'      => 'Name',
    4040
    4141                /** Blogs *************************************************************/
    4242
    4343                // Used to decide if blogs need indexing
    44                 'bp-blogs-first-install'          => false,
     44                'bp-blogs-first-install'               => false,
    4545
    4646                /** Settings **********************************************************/
    4747
    4848                // Disable the WP to BP profile sync
    49                 'bp-disable-profile-sync'         => false,
     49                'bp-disable-profile-sync'              => false,
    5050
    5151                // Hide the Toolbar for logged out users
    52                 'hide-loggedout-adminbar'         => false,
     52                'hide-loggedout-adminbar'              => false,
    5353
    5454                // Avatar uploads
    55                 'bp-disable-avatar-uploads'       => false,
     55                'bp-disable-avatar-uploads'            => false,
     56
     57                // Cover image uploads
     58                'bp-disable-cover-image-uploads'       => false,
    5659
    5760                // Group Profile Photos
    58                 'bp-disable-group-avatar-uploads' => false,
     61                'bp-disable-group-avatar-uploads'      => false,
     62
     63                // Group Cover image uploads
     64                'bp-disable-group-cover-image-uploads' => false,
    5965
    6066                // Allow users to delete their own accounts
    61                 'bp-disable-account-deletion'     => false,
     67                'bp-disable-account-deletion'          => false,
    6268
    6369                // Allow comments on blog and forum activity items
    64                 'bp-disable-blogforum-comments'   => true,
     70                'bp-disable-blogforum-comments'        => true,
    6571
    6672                // The ID for the current theme package.
    67                 '_bp_theme_package_id'            => 'legacy',
     73                '_bp_theme_package_id'                 => 'legacy',
    6874
    6975                /** Groups ************************************************************/
    7076
    7177                // @todo Move this into the groups component
    7278
    7379                // Restrict group creation to super admins
    74                 'bp_restrict_group_creation'      => false,
     80                'bp_restrict_group_creation'           => false,
    7581
    7682                /** Akismet ***********************************************************/
    7783
    7884                // Users from all sites can post
    79                 '_bp_enable_akismet'              => true,
     85                '_bp_enable_akismet'                   => true,
    8086
    8187                /** Activity HeartBeat ************************************************/
    8288
    8389                // HeartBeat is on to refresh activities
    84                 '_bp_enable_heartbeat_refresh'    => true,
     90                '_bp_enable_heartbeat_refresh'         => true,
    8591
    8692                /** BuddyBar **********************************************************/
    8793
    8894                // Force the BuddyBar
    89                 '_bp_force_buddybar'              => false,
     95                '_bp_force_buddybar'                   => false,
    9096
    9197                /** Legacy theme *********************************************/
    9298
    9399                // Whether to register the bp-default themes directory
    94                 '_bp_retain_bp_default'           => false,
     100                '_bp_retain_bp_default'                => false,
    95101
    96102                /** Widgets **************************************************/
    97103                'widget_bp_core_login_widget'                => false,
    function bp_disable_avatar_uploads( $default = true ) { 
    596602}
    597603
    598604/**
     605 * Are members able to upload their own cover images?
     606 *
     607 * @since 2.4.0
     608 *
     609 * @uses bp_get_option() To get the cover image uploads option.
     610 *
     611 * @param bool $default Optional. Fallback value if not found in the database.
     612 *                      Default: false.
     613 *
     614 * @return bool True if cover image uploads are disabled, otherwise false.
     615 */
     616function bp_disable_cover_image_uploads( $default = false ) {
     617
     618        /**
     619         * Filters whether or not members are able to upload their own cover images.
     620         *
     621         * @since 2.4.0
     622         *
     623         * @param bool $value Whether or not members are able to upload their own cover images.
     624         */
     625        return (bool) apply_filters( 'bp_disable_cover_image_uploads', (bool) bp_get_option( 'bp-disable-cover-image-uploads', $default ) );
     626}
     627
     628/**
    599629 * Are group avatars disabled?
    600630 *
    601631 * For backward compatibility, this option falls back on the value of 'bp-disable-avatar-uploads' when no value is
    function bp_disable_group_avatar_uploads( $default = null ) { 
    631661}
    632662
    633663/**
     664 * Are group cover images disabled?
     665 *
     666 * @since 2.4.0
     667 *
     668 * @uses bp_get_option() To get the group cover image uploads option.
     669 *
     670 * @param bool $default Optional. Fallback value if not found in the database.
     671 *                      Default: false.
     672 *
     673 * @return bool True if group cover image uploads are disabled, otherwise false.
     674 */
     675function bp_disable_group_cover_image_uploads( $default = false ) {
     676
     677        /**
     678         * Filters whether or not members are able to upload group cover images.
     679         *
     680         * @since 2.4.0
     681         *
     682         * @param bool $value Whether or not members are able to upload thier groups cover images.
     683         */
     684        return (bool) apply_filters( 'bp_disable_group_cover_image_uploads', (bool) bp_get_option( 'bp-disable-group-cover-image-uploads', $default ) );
     685}
     686
     687/**
    634688 * Are members able to delete their own accounts?
    635689 *
    636690 * @since 1.6.0
  • src/bp-core/bp-core-template.php

    diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php
    index a89a0e4..be74901 100644
    function bp_is_active( $component = '', $feature = '' ) { 
    19341934
    19351935                // Is feature active?
    19361936                if ( ! empty( $feature ) ) {
     1937                        // The xProfile component is specific
     1938                        if ( 'xprofile' === $component ) {
     1939                                $component = 'profile';
     1940                        }
     1941
    19371942                        if ( empty( buddypress()->$component->features ) || false === in_array( $feature, buddypress()->$component->features, true ) ) {
    19381943                                $retval = false;
    19391944                        }
    function bp_is_user_change_avatar() { 
    22472252}
    22482253
    22492254/**
     2255 * Is the current page the a user's change cover image profile page?
     2256 *
     2257 * Eg http://example.com/members/joe/profile/change-cover-image/ (or a subpage thereof).
     2258 *
     2259 * @since  2.4.0
     2260 *
     2261 * @return True if the current page is a user's profile edit cover image page.
     2262 */
     2263function bp_is_user_change_cover_image() {
     2264        return (bool) ( bp_is_profile_component() && bp_is_current_action( 'change-cover-image' ) );
     2265}
     2266
     2267/**
    22502268 * Is this a user's forums page?
    22512269 *
    22522270 * Eg http://example.com/members/joe/forums/ (or a subpage thereof).
  • src/bp-core/bp-core-theme-compatibility.php

    diff --git src/bp-core/bp-core-theme-compatibility.php src/bp-core/bp-core-theme-compatibility.php
    index 08a4791..c43d604 100644
    function bp_set_theme_compat_original_template( $template = '' ) { 
    436436}
    437437
    438438/**
     439 * Set a theme compat feature
     440 *
     441 * @since 2.4.0
     442 *
     443 * @param  string $theme_id the theme id (eg: legacy)
     444 * @param  array  $feature  an associative array (eg: array( name => 'feature_name', 'settings' => array() ))
     445 */
     446function bp_set_theme_compat_feature( $theme_id, $feature = array() ) {
     447        if ( empty( $theme_id ) || empty( $feature['name'] ) ) {
     448                return;
     449        }
     450
     451        // Get BuddyPress instance
     452        $bp = buddypress();
     453
     454        // Get current theme compat theme
     455        $theme_compat_theme = $bp->theme_compat->theme;
     456
     457        // Bail if the Theme Compat theme is not in use
     458        if ( $theme_id !== bp_get_theme_compat_id() ) {
     459                return;
     460        }
     461
     462        $features = $theme_compat_theme->__get( 'features' );
     463        if ( empty( $features ) ) {
     464                $features = array();
     465        }
     466
     467        // Bail if the feature is already registered or no settings were provided
     468        if ( isset( $features[ $feature['name'] ] ) || empty( $feature['settings'] ) ) {
     469                return;
     470        }
     471
     472        // Add the feature
     473        $features[ $feature['name'] ] = (object) $feature['settings'];
     474
     475        // The feature is attached to components
     476        if ( isset( $features[ $feature['name'] ]->components ) ) {
     477                // Set the feature for each concerned component
     478                foreach ( (array) $features[ $feature['name'] ]->components as $component ) {
     479                        // The xProfile component is specific
     480                        if ( 'xprofile' === $component ) {
     481                                $component = 'profile';
     482                        }
     483
     484                        if ( isset( $bp->{$component} ) ) {
     485                                if ( isset( $bp->{$component}->features ) ) {
     486                                        $bp->{$component}->features[] = $feature['name'];
     487                                } else {
     488                                        $bp->{$component}->features = array( $feature['name'] );
     489                                }
     490                        }
     491                }
     492        }
     493
     494        // Finally update the theme compat features
     495        $theme_compat_theme->__set( 'features', $features );
     496}
     497
     498/**
     499 * Get a theme compat feature
     500 *
     501 * @since 2.4.0
     502 *
     503 * @param  string $feature the feature (eg: cover_image)
     504 * @return object          the feature settings.
     505 */
     506function bp_get_theme_compat_feature( $feature = '' ) {
     507        // Get current theme compat theme
     508        $theme_compat_theme = buddypress()->theme_compat->theme;
     509
     510        // Get features
     511        $features = $theme_compat_theme->__get( 'features' );
     512
     513        if ( ! isset( $features[ $feature ] ) ) {
     514                return false;
     515        }
     516
     517        return $features[ $feature ];
     518}
     519
     520/**
     521 * Setup the theme's features
     522 *
     523 * Note: BP Legacy's buddypress-functions.php is not loaded in WP Administration
     524 * as it's loaded using bp_locate_template(). That's why this function is here.
     525 *
     526 * @since 2.4.0
     527 *
     528 * @global $content_width the content width of the theme
     529 */
     530function bp_register_theme_compat_default_features() {
     531        global $content_width;
     532
     533        // If the current theme doesn't need theme compat, bail at this point.
     534        if ( ! bp_use_theme_compat_with_current_theme() ) {
     535                return;
     536        }
     537
     538        // Make sure BP Legacy is the Theme Compat in use.
     539        if ( 'legacy' !== bp_get_theme_compat_id() ) {
     540                return;
     541        }
     542
     543        // Get the theme
     544        $current_theme = wp_get_theme();
     545        $theme_handle  = $current_theme->get_stylesheet();
     546        $parent        = $current_theme->parent();
     547
     548        if ( $parent ) {
     549                $theme_handle = $parent->get_stylesheet();
     550        }
     551
     552        /**
     553         * Since Companion stylesheets, the $content_width is smaller
     554         * than the width used by BuddyPress, so we need to manually set the
     555         * content width for the concerned themes.
     556         *
     557         * array( stylesheet => content width used by BuddyPress )
     558         */
     559        $bp_content_widths = array(
     560                'twentyfifteen'  => 1300,
     561                'twentyfourteen' => 955,
     562                'twentythirteen' => 890,
     563        );
     564
     565        // Default values
     566        $bp_content_width = (int) $content_width;
     567        $bp_handle        = 'bp-legacy-css';
     568
     569        // Specific to themes having companion stylesheets
     570        if ( isset( $bp_content_widths[ $theme_handle ] ) ) {
     571                $bp_content_width = $bp_content_widths[ $theme_handle ];
     572                $bp_handle        = 'bp-' . $theme_handle;
     573        }
     574
     575        if ( is_rtl() ) {
     576                $bp_handle .= '-rtl';
     577        }
     578
     579        $top_offset    = 150;
     580        $avatar_height = apply_filters( 'bp_core_avatar_full_height', $top_offset );
     581
     582        if ( $avatar_height > $top_offset ) {
     583                $top_offset = $avatar_height;
     584        }
     585
     586        bp_set_theme_compat_feature( 'legacy', array(
     587                'name'     => 'cover_image',
     588                'settings' => array(
     589                        'components'   => array( 'xprofile', 'groups' ),
     590                        'width'        => $bp_content_width,
     591                        'height'       => $top_offset + round( $avatar_height / 2 ),
     592                        'callback'     => 'bp_legacy_theme_cover_image',
     593                        'theme_handle' => $bp_handle,
     594                ),
     595        ) );
     596}
     597
     598/**
    439599 * Check whether a given template is the one that WP originally selected to display current page.
    440600 *
    441601 * @since 1.7.0
  • src/bp-core/classes/class-bp-attachment-cover-image.php

    diff --git src/bp-core/classes/class-bp-attachment-cover-image.php src/bp-core/classes/class-bp-attachment-cover-image.php
    index e69de29..fc700f9 100644
     
     1<?php
     2/**
     3 * Core Cover Image attachment class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage Core
     7 */
     8
     9// Exit if accessed directly
     10defined( 'ABSPATH' ) || exit;
     11
     12/**
     13 * BP Attachment Cover Image class.
     14 *
     15 * Extends BP Attachment to manage the cover images uploads.
     16 *
     17 * @since 2.4.0
     18 */
     19class BP_Attachment_Cover_Image extends BP_Attachment {
     20        /**
     21         * The constuctor
     22         *
     23         * @since 2.4.0
     24         */
     25        public function __construct() {
     26                // Allowed cover image types & upload size
     27                $allowed_types        = bp_attachments_get_allowed_types( 'cover_image' );
     28                $max_upload_file_size = bp_attachments_get_max_upload_file_size( 'cover_image' );
     29
     30                parent::__construct( array(
     31                        'action'                => 'bp_cover_image_upload',
     32                        'file_input'            => 'file',
     33                        'original_max_filesize' => $max_upload_file_size,
     34                        'base_dir'              => bp_attachments_uploads_dir_get( 'dir' ),
     35                        'required_wp_files'     => array( 'file', 'image' ),
     36
     37                        // Specific errors for cover images
     38                        'upload_error_strings'  => array(
     39                                11  => sprintf( __( 'That image is too big. Please upload one smaller than %s', 'buddypress' ), size_format( $max_upload_file_size ) ),
     40                                12  => sprintf( _n( 'Please upload only this file type: %s.', 'Please upload only these file types: %s.', count( $allowed_types ), 'buddypress' ), self::get_cover_image_types( $allowed_types ) ),
     41                        ),
     42                ) );
     43        }
     44
     45        /**
     46         * Gets the available cover image types.
     47         *
     48         * @since 2.4.0
     49         *
     50         * @param array $allowed_types Array of allowed cover image types.
     51         *
     52         * @return string comma separated list of allowed cover image types.
     53         */
     54        public static function get_cover_image_types( $allowed_types = array() ) {
     55                $types = array_map( 'strtoupper', $allowed_types );
     56                $comma = _x( ',', 'cover image types separator', 'buddypress' );
     57                return join( $comma . ' ', $types );
     58        }
     59
     60        /**
     61         * Cover image specific rules.
     62         *
     63         * Adds an error if the cover image size or type don't match BuddyPress needs.
     64         * The error code is the index of $upload_error_strings.
     65         *
     66         * @since 2.4.0
     67         *
     68         * @param  array $file the temporary file attributes (before it has been moved).
     69         *
     70         * @return array the file with extra errors if needed.
     71         */
     72        public function validate_upload( $file = array() ) {
     73                // Bail if already an error
     74                if ( ! empty( $file['error'] ) ) {
     75                        return $file;
     76                }
     77
     78                // File size is too big
     79                if ( $file['size'] > $this->original_max_filesize ) {
     80                        $file['error'] = 11;
     81
     82                // File is of invalid type
     83                } elseif ( ! bp_attachments_check_filetype( $file['tmp_name'], $file['name'], bp_attachments_get_allowed_mimes( 'cover_image' ) ) ) {
     84                        $file['error'] = 12;
     85                }
     86
     87                // Return with error code attached
     88                return $file;
     89        }
     90
     91        /**
     92         * Set the directory when uploading a file
     93         *
     94         * @since 2.4.0
     95         *
     96         * @return array upload data (path, url, basedir...)
     97         */
     98        public function upload_dir_filter() {
     99                // Default values are for profiles
     100                $object_id = bp_displayed_user_id();
     101
     102                if ( empty( $object_id ) ) {
     103                        $object_id = bp_loggedin_user_id();
     104                }
     105
     106                $object_directory = 'members';
     107
     108                // We're in a group, edit default values
     109                if ( bp_is_group() || bp_is_group_create() ) {
     110                        $object_id        = bp_get_current_group_id();
     111                        $object_directory = 'groups';
     112                }
     113
     114                // Set the subdir
     115                $subdir  = '/' . $object_directory . '/' . $object_id . '/cover-image';
     116
     117                return apply_filters( 'bp_attachments_cover_image_upload_datas', array(
     118                        'path'    => $this->upload_path . $subdir,
     119                        'url'     => $this->url . $subdir,
     120                        'subdir'  => $subdir,
     121                        'basedir' => $this->upload_path,
     122                        'baseurl' => $this->url,
     123                        'error'   => false
     124                ) );
     125        }
     126
     127        /**
     128         * Adjust the cover image to fit with advised width & height.
     129         *
     130         * @since 2.4.0
     131         *
     132         * @param string $file the absolute path to the file.
     133         * @return mixed
     134         */
     135        public function fit( $file = '', $dimensions = array() ) {
     136                if ( empty( $dimensions['width'] ) || empty( $dimensions['height'] ) ) {
     137                        return false;
     138                }
     139
     140                // Get image size
     141                $size   = @getimagesize( $file );
     142                $retval = false;
     143
     144                // Check image size and shrink if too large
     145                if ( $size[0] > $dimensions['width'] || $size[1] > $dimensions['height'] ) {
     146                        $editor = wp_get_image_editor( $file );
     147
     148                        if ( ! is_wp_error( $editor ) ) {
     149                                $editor->set_quality( 100 );
     150
     151                                $resized = $editor->resize( $dimensions['width'], $dimensions['height'], true );
     152                                if ( ! is_wp_error( $resized ) ) {
     153                                        $cover   = $editor->save( $this->generate_filename( $file ) );
     154                                } else {
     155                                        $retval = $resized;
     156                                }
     157
     158                                // Check for cover creation errors
     159                                if ( ( false === $retval ) && is_wp_error( $cover ) ) {
     160                                        $retval = $cover;
     161                                }
     162
     163                                // Cover is good so proceed
     164                                if ( false === $retval ) {
     165                                        $retval = $cover;
     166                                }
     167
     168                        } else {
     169                                $retval = $editor;
     170                        }
     171                }
     172
     173                return $retval;
     174        }
     175
     176        /**
     177         * Generate a filename for the cover image
     178         *
     179         * @since 2.4.0
     180         *
     181         * @param  string $file the absolute path to the file.
     182         * @return string       the absolute path to the new file name
     183         */
     184        public function generate_filename( $file = '' ) {
     185                if ( empty( $file ) || ! file_exists( $file ) ) {
     186                        return false;
     187                }
     188
     189                $info    = pathinfo( $file );
     190                $dir     = $info['dirname'];
     191                $ext     = strtolower( $info['extension'] );
     192                $name    = wp_hash( $file . time() ) . '-bp-cover-image';
     193
     194                return trailingslashit( $dir ) . "{$name}.{$ext}";
     195        }
     196
     197        /**
     198         * Build script datas for the Uploader UI
     199         *
     200         * @since 2.4.0
     201         *
     202         * @return array the javascript localization data
     203         */
     204        public function script_data() {
     205                // Get default script data
     206                $script_data = parent::script_data();
     207
     208                if ( bp_is_user() ) {
     209                        $item_id = bp_displayed_user_id();
     210
     211                        $script_data['bp_params'] = array(
     212                                'object'          => 'user',
     213                                'item_id'         => $item_id,
     214                                'has_cover_image' => bp_attachments_get_user_has_cover_image( $item_id ),
     215                                'nonces'  => array(
     216                                        'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
     217                                ),
     218                        );
     219
     220                        // Set feedback messages
     221                        $script_data['feedback_messages'] = array(
     222                                1 => __( 'Your new cover image was uploaded successfully.', 'buddypress' ),
     223                                2 => __( 'There was a problem deleting your cover image. Please try again.', 'buddypress' ),
     224                                3 => __( 'Your cover image was deleted successfully!', 'buddypress' ),
     225                        );
     226                } elseif ( bp_is_group() ) {
     227                        $item_id = bp_get_current_group_id();
     228
     229                        $script_data['bp_params'] = array(
     230                                'object'          => 'group',
     231                                'item_id'         => bp_get_current_group_id(),
     232                                'has_cover_image' => bp_attachments_get_group_has_cover_image( $item_id ),
     233                                'nonces'  => array(
     234                                        'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
     235                                ),
     236                        );
     237
     238                        // Set feedback messages
     239                        $script_data['feedback_messages'] = array(
     240                                1 => __( 'The group cover image was uploaded successfully.', 'buddypress' ),
     241                                2 => __( 'There was a problem deleting the group cover image. Please try again.', 'buddypress' ),
     242                                3 => __( 'The group cover image was deleted successfully!', 'buddypress' ),
     243                        );
     244                } else {
     245                        /**
     246                         * Use this filter to include specific BuddyPress params for your object.
     247                         * e.g. Cover image for blogs single item.
     248                         *
     249                         * @since 2.4.0
     250                         *
     251                         * @param array $value The cover image specific BuddyPress parameters.
     252                         */
     253                        $script_data['bp_params'] = apply_filters( 'bp_attachment_cover_image_params', array() );
     254                }
     255
     256                // Include our specific js & css
     257                $script_data['extra_js']  = array( 'bp-cover-image' );
     258                $script_data['extra_css'] = array( 'bp-avatar' );
     259
     260                return apply_filters( 'bp_attachments_cover_image_script_data', $script_data );
     261        }
     262}
  • src/bp-core/css/avatar.css

    diff --git src/bp-core/css/avatar.css src/bp-core/css/avatar.css
    index 385852f..2986dff 100644
     
    1 div.bp-avatar-status {
     1div.bp-avatar-status,
     2div.bp-cover-image-status {
    23        clear: both;
    34        margin: 1em 0;
    45}
    56
    6 div.bp-avatar-status p.updated {
     7div.bp-avatar-status p.updated,
     8div.bp-cover-image-status p.updated {
    79        display: block;
    810        padding: 10px 15px;
    911}
    1012
    11 div.bp-avatar-status p.success {
     13div.bp-avatar-status p.success,
     14div.bp-cover-image-status p.success {
    1215        background-color: #efc;
    1316        border: 1px solid #591;
    1417        color: #250;
    1518}
    1619
    17 div.bp-avatar-status p.error {
     20div.bp-avatar-status p.error,
     21div.bp-cover-image-status p.error {
    1822        background-color: #fdc;
    1923        border: 1px solid #a00;
    2024        color: #800;
    2125}
    2226
    23 div.bp-avatar-status .bp-progress {
     27div.bp-avatar-status .bp-progress,
     28div.bp-cover-image-status .bp-progress {
    2429        background: none;
    2530        border: 1px solid #d1d1d1;
    2631        float: right;
    div.bp-avatar-status .bp-progress { 
    3338        width: 200px;
    3439}
    3540
    36 div.bp-avatar-status .bp-bar {
     41div.bp-avatar-status .bp-bar,
     42div.bp-cover-image-status .bp-bar {
    3743        background-color: #c3ff88;
    3844        width: 0;
    3945        height: 100%;
  • src/bp-core/js/cover-image.js

    diff --git src/bp-core/js/cover-image.js src/bp-core/js/cover-image.js
    index e69de29..47db780 100644
     
     1/* global bp, BP_Uploader, _, Backbone */
     2
     3window.bp = window.bp || {};
     4
     5( function( exports, $ ) {
     6
     7        // Bail if not set
     8        if ( typeof BP_Uploader === 'undefined' ) {
     9                return;
     10        }
     11
     12        bp.Models      = bp.Models || {};
     13        bp.Collections = bp.Collections || {};
     14        bp.Views       = bp.Views || {};
     15
     16        bp.CoverImage = {
     17                start: function() {
     18
     19                        // Init some vars
     20                        this.views   = new Backbone.Collection();
     21                        this.warning = null;
     22
     23                        // Set up views
     24                        this.uploaderView();
     25
     26                        // Inform about the needed dimensions
     27                        this.displayWarning( BP_Uploader.strings.cover_image_warnings.dimensions );
     28
     29                        // Set up the delete view if needed
     30                        if ( true === BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image ) {
     31                                this.deleteView();
     32                        }
     33                },
     34
     35                uploaderView: function() {
     36                        // Listen to the Queued uploads
     37                        bp.Uploader.filesQueue.on( 'add', this.uploadProgress, this );
     38
     39                        // Create the BuddyPress Uploader
     40                        var uploader = new bp.Views.Uploader();
     41
     42                        // Add it to views
     43                        this.views.add( { id: 'upload', view: uploader } );
     44
     45                        // Display it
     46                        uploader.inject( '.bp-cover-image' );
     47                },
     48
     49                uploadProgress: function() {
     50                        // Create the Uploader status view
     51                        var coverImageUploadProgress = new bp.Views.coverImageUploadProgress( { collection: bp.Uploader.filesQueue } );
     52
     53                        if ( ! _.isUndefined( this.views.get( 'status' ) ) ) {
     54                                this.views.set( { id: 'status', view: coverImageUploadProgress } );
     55                        } else {
     56                                this.views.add( { id: 'status', view: coverImageUploadProgress } );
     57                        }
     58
     59                        // Display it
     60                        coverImageUploadProgress.inject( '.bp-cover-image-status' );
     61                },
     62
     63                deleteView: function() {
     64                        // Create the delete model
     65                        var delete_model = new Backbone.Model( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params,
     66                                'object',
     67                                'item_id',
     68                                'nonces'
     69                        ) );
     70
     71                        // Do not add it if already there!
     72                        if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
     73                                return;
     74                        }
     75
     76                        // Create the delete view
     77                        var deleteView = new bp.Views.DeleteCoverImage( { model: delete_model } );
     78
     79                        // Add it to views
     80                        this.views.add( { id: 'delete', view: deleteView } );
     81
     82                        // Display it
     83                        deleteView.inject( '.bp-cover-image-manage' );
     84                },
     85
     86                deleteCoverImage: function( model ) {
     87                        var self = this,
     88                                deleteView;
     89
     90                        // Remove the delete view
     91                        if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
     92                                deleteView = this.views.get( 'delete' );
     93                                deleteView.get( 'view' ).remove();
     94                                this.views.remove( { id: 'delete', view: deleteView } );
     95                        }
     96
     97                        // Remove the cover image !
     98                        bp.ajax.post( 'bp_cover_image_delete', {
     99                                json:          true,
     100                                item_id:       model.get( 'item_id' ),
     101                                object:        model.get( 'object' ),
     102                                nonce:         model.get( 'nonces' ).remove
     103                        } ).done( function( response ) {
     104                                var coverImageStatus = new bp.Views.CoverImageStatus( {
     105                                        value : BP_Uploader.strings.feedback_messages[ response.feedback_code ],
     106                                        type : 'success'
     107                                } );
     108
     109                                self.views.add( {
     110                                        id   : 'status',
     111                                        view : coverImageStatus
     112                                } );
     113
     114                                coverImageStatus.inject( '.bp-cover-image-status' );
     115
     116                                // Reset the header of the page
     117                                if ( '' === response.reset_url ) {
     118                                        $( '#header-cover-image' ).css( {
     119                                                'background-image': 'none'
     120                                        } );
     121                                } else {
     122                                        $( '#header-cover-image' ).css( {
     123                                                'background-image': 'url( ' + response.reset_url + ' )'
     124                                        } );
     125                                }
     126
     127                                // Reset the has_cover_image bp_param
     128                                BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image = false;
     129
     130                        } ).fail( function( response ) {
     131                                var feedback = BP_Uploader.strings.default_error;
     132                                if ( ! _.isUndefined( response ) ) {
     133                                        feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ];
     134                                }
     135
     136                                var coverImageStatus = new bp.Views.CoverImageStatus( {
     137                                        value : feedback,
     138                                        type : 'error'
     139                                } );
     140
     141                                self.views.add( {
     142                                        id   : 'status',
     143                                        view : coverImageStatus
     144                                } );
     145
     146                                coverImageStatus.inject( '.bp-cover-image-status' );
     147
     148                                // Put back the delete view
     149                                bp.CoverImage.deleteView();
     150                        } );
     151                },
     152
     153                removeWarning: function() {
     154                        if ( ! _.isNull( this.warning ) ) {
     155                                this.warning.remove();
     156                        }
     157                },
     158
     159                displayWarning: function( message ) {
     160                        this.removeWarning();
     161
     162                        this.warning = new bp.Views.uploaderWarning( {
     163                                value: message
     164                        } );
     165
     166                        this.warning.inject( '.bp-cover-image-status' );
     167                }
     168        };
     169
     170        // Custom Uploader Files view
     171        bp.Views.coverImageUploadProgress = bp.Views.uploaderStatus.extend( {
     172                className: 'files',
     173
     174                initialize: function() {
     175                        bp.Views.uploaderStatus.prototype.initialize.apply( this, arguments );
     176
     177                        this.collection.on( 'change:url', this.uploadResult, this );
     178                },
     179
     180                uploadResult: function( model ) {
     181                        var message, type;
     182
     183                        if ( ! _.isUndefined( model.get( 'url' ) ) ) {
     184
     185                                // Image is too small
     186                                if ( 0 === model.get( 'feedback_code' ) ) {
     187                                        message = BP_Uploader.strings.cover_image_warnings.dimensions;
     188                                        type    = 'warning';
     189
     190                                // Success, Rock n roll!
     191                                } else {
     192                                        message = BP_Uploader.strings.feedback_messages[ model.get( 'feedback_code' ) ];
     193                                        type = 'success';
     194                                }
     195
     196                                this.views.set( '.bp-uploader-progress', new bp.Views.CoverImageStatus( {
     197                                        value : message,
     198                                        type  : type
     199                                } ) );
     200
     201                                // Update the header of the page
     202                                $( '#header-cover-image' ).css( {
     203                                        'background-image': 'url( ' + model.get( 'url' ) + ' )'
     204                                } );
     205
     206                                // Add the delete view
     207                                bp.CoverImage.deleteView();
     208                        }
     209                }
     210        } );
     211
     212        // BuddyPress Cover Image Feedback view
     213        bp.Views.CoverImageStatus = bp.View.extend( {
     214                tagName: 'p',
     215                className: 'updated',
     216                id: 'bp-cover-image-feedback',
     217
     218                initialize: function() {
     219                        this.el.className += ' ' + this.options.type;
     220                        this.value = this.options.value;
     221                },
     222
     223                render: function() {
     224                        this.$el.html( this.value );
     225                        return this;
     226                }
     227        } );
     228
     229        // BuddyPress Cover Image Delete view
     230        bp.Views.DeleteCoverImage = bp.View.extend( {
     231                tagName: 'div',
     232                id: 'bp-delete-cover-image-container',
     233                template: bp.template( 'bp-cover-image-delete' ),
     234
     235                events: {
     236                        'click #bp-delete-cover-image': 'deleteCoverImage'
     237                },
     238
     239                deleteCoverImage: function( event ) {
     240                        event.preventDefault();
     241
     242                        bp.CoverImage.deleteCoverImage( this.model );
     243                }
     244        } );
     245
     246        bp.CoverImage.start();
     247
     248})( bp, jQuery );
  • src/bp-groups/bp-groups-loader.php

    diff --git src/bp-groups/bp-groups-loader.php src/bp-groups/bp-groups-loader.php
    index 0949b8a..3c5653b 100644
    class BP_Groups_Component extends BP_Component { 
    313313                        );
    314314                }
    315315
     316                if ( bp_group_use_cover_image_header() ) {
     317                        $this->group_creation_steps['group-cover-image'] = array(
     318                                'name'     => _x( 'Cover Image', 'Group screen nav', 'buddypress' ),
     319                                'position' => 25
     320                        );
     321                }
     322
    316323                // If friends component is active, add invitations
    317324                if ( bp_is_active( 'friends' ) ) {
    318325                        $this->group_creation_steps['group-invites'] = array(
    class BP_Groups_Component extends BP_Component { 
    591598                                        ), $default_params );
    592599                                }
    593600
     601                                if ( bp_group_use_cover_image_header() ) {
     602                                        $sub_nav[] = array_merge( array(
     603                                                'name'     => __( 'Cover Image', 'buddypress' ),
     604                                                'slug'     => 'group-cover-image',
     605                                                'position' => 25,
     606                                        ), $default_params );
     607                                }
     608
    594609                                $sub_nav[] = array_merge( array(
    595610                                        'name'     => __( 'Members', 'buddypress' ),
    596611                                        'slug'     => 'manage-members',
  • src/bp-groups/bp-groups-screens.php

    diff --git src/bp-groups/bp-groups-screens.php src/bp-groups/bp-groups-screens.php
    index 325c4fb..875527f 100644
    function groups_screen_group_admin_avatar() { 
    989989add_action( 'bp_screens', 'groups_screen_group_admin_avatar' );
    990990
    991991/**
     992 * Handle the display of a group's Change cover image page.
     993 *
     994 * @since 2.4.0
     995 */
     996function groups_screen_group_admin_cover_image() {
     997        if ( 'group-cover-image' != bp_get_group_current_admin_tab() ) {
     998                return false;
     999        }
     1000
     1001        // If the logged-in user doesn't have permission or if cover image uploads are disabled, then stop here
     1002        if ( ! bp_is_item_admin() || ! bp_group_use_cover_image_header() ) {
     1003                return false;
     1004        }
     1005
     1006        /**
     1007         * Fires before the loading of the group Change cover image page template.
     1008         *
     1009         * @since 2.4.0
     1010         *
     1011         * @param int $id ID of the group that is being displayed.
     1012         */
     1013        do_action( 'groups_screen_group_admin_cover_image', bp_get_current_group_id() );
     1014
     1015        /**
     1016         * Filters the template to load for a group's Change cover image page.
     1017         *
     1018         * @since 2.4.0
     1019         *
     1020         * @param string $value Path to a group's Change cover image template.
     1021         */
     1022        bp_core_load_template( apply_filters( 'groups_template_group_admin_cover_image', 'groups/single/home' ) );
     1023}
     1024add_action( 'bp_screens', 'groups_screen_group_admin_cover_image' );
     1025
     1026/**
    9921027 * This function handles actions related to member management on the group admin.
    9931028 */
    9941029function groups_screen_group_admin_manage_members() {
  • src/bp-groups/bp-groups-template.php

    diff --git src/bp-groups/bp-groups-template.php src/bp-groups/bp-groups-template.php
    index 9104ea1..de2d344 100644
    function bp_group_avatar_mini( $group = false ) { 
    10041004                ) );
    10051005        }
    10061006
     1007/** Group cover image *********************************************************/
     1008
     1009/**
     1010 * Should we use the group's cover image header
     1011 *
     1012 * @since 2.4.0
     1013 *
     1014 * @return bool True if the displayed user has a cover image,
     1015 *              False otherwise
     1016 */
     1017function bp_group_use_cover_image_header() {
     1018        return (bool) bp_is_active( 'groups', 'cover_image' ) && ! bp_disable_group_cover_image_uploads() && bp_attachments_is_wp_version_supported();
     1019}
     1020
    10071021/**
    10081022 * Output the 'last active' string for the current group in the loop.
    10091023 *
  • src/bp-members/bp-members-template.php

    diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
    index e3f7477..920d5af 100644
    function bp_get_displayed_user_nav() { 
    14791479        }
    14801480}
    14811481
     1482/** Cover image ***************************************************************/
     1483
     1484/**
     1485 * Should we use the cover image header
     1486 *
     1487 * @since 2.4.0
     1488 *
     1489 * @return bool True if the displayed user has a cover image,
     1490 *              False otherwise
     1491 */
     1492function bp_displayed_user_use_cover_image_header() {
     1493        return (bool) bp_is_active( 'xprofile', 'cover_image' ) && ! bp_disable_cover_image_uploads() && bp_attachments_is_wp_version_supported();
     1494}
     1495
    14821496/** Avatars *******************************************************************/
    14831497
    14841498/**
  • src/bp-templates/bp-legacy/buddypress-functions.php

    diff --git src/bp-templates/bp-legacy/buddypress-functions.php src/bp-templates/bp-legacy/buddypress-functions.php
    index 55dc3d0..65b3fe0 100644
    class BP_Legacy extends BP_Theme_Compat { 
    5858         * @access private
    5959         */
    6060        protected function setup_globals() {
    61                 $bp            = buddypress();
    62                 $this->id      = 'legacy';
    63                 $this->name    = __( 'BuddyPress Legacy', 'buddypress' );
    64                 $this->version = bp_get_version();
    65                 $this->dir     = trailingslashit( $bp->themes_dir . '/bp-legacy' );
    66                 $this->url     = trailingslashit( $bp->themes_url . '/bp-legacy' );
     61                $bp             = buddypress();
     62                $this->id       = 'legacy';
     63                $this->name     = __( 'BuddyPress Legacy', 'buddypress' );
     64                $this->version  = bp_get_version();
     65                $this->dir      = trailingslashit( $bp->themes_dir . '/bp-legacy' );
     66                $this->url      = trailingslashit( $bp->themes_url . '/bp-legacy' );
    6767        }
    6868
    6969        /**
    function bp_legacy_theme_ajax_messages_star_handler() { 
    17171717        echo '-1';
    17181718        die();
    17191719}
     1720
     1721/**
     1722 * BP Legacy's callback for the cover image feature
     1723 *
     1724 * @since  2.4.0
     1725 *
     1726 * @param  array  $params the current component's feature parameters
     1727 * @return array          an array to inform about the css handle to attach the css rules to
     1728 */
     1729function bp_legacy_theme_cover_image( $params = array() ) {
     1730        if ( empty( $params ) ) {
     1731                return;
     1732        }
     1733
     1734        // avatar height - padding - 1/2 avatar height
     1735        $avatar_offset = $params['height'] - 5 - round( (int) bp_core_avatar_full_height() / 2 );
     1736
     1737        // header content offset + spacing
     1738        $top_offset  = bp_core_avatar_full_height() - 10;
     1739        $left_offset = bp_core_avatar_full_width() + 20;
     1740
     1741        $cover_image = isset( $params['cover_image'] ) ? 'background-image: url(' . $params['cover_image'] . ');' : '';
     1742
     1743        $hide_avatar_style = '';
     1744
     1745        // Adjust the cover image header, in case avatars are completely disabled
     1746        if ( ! buddypress()->avatar->show_avatars ) {
     1747                $hide_avatar_style = '
     1748                        #buddypress #item-header-cover-image #item-header-avatar {
     1749                                display:  none;
     1750                        }
     1751                ';
     1752
     1753                if ( bp_is_user() ) {
     1754                        $hide_avatar_style = '
     1755                                #buddypress #item-header-cover-image #item-header-avatar a {
     1756                                        display: block;
     1757                                        height: ' . $top_offset . 'px;
     1758                                        margin: 0 15px 19px 0;
     1759                                }
     1760
     1761                                #buddypress div#item-header #item-header-cover-image #item-header-content {
     1762                                        margin-left:auto;
     1763                                }
     1764                        ';
     1765                }
     1766        }
     1767
     1768        return '
     1769                /* Cover image */
     1770                #buddypress #header-cover-image {
     1771                        height: ' . $params["height"] . 'px;
     1772                        ' . $cover_image . '
     1773                }
     1774
     1775                #buddypress #create-group-form #header-cover-image {
     1776                        position: relative;
     1777                        margin: 1em 0;
     1778                }
     1779
     1780                .bp-user #buddypress #item-header {
     1781                        padding-top: 0;
     1782                }
     1783
     1784                #buddypress #item-header-cover-image #item-header-avatar {
     1785                        margin-top: '. $avatar_offset .'px;
     1786                        float: left;
     1787                        overflow: visible;
     1788                        width:auto;
     1789                }
     1790
     1791                #buddypress div#item-header #item-header-cover-image #item-header-content {
     1792                        clear: both;
     1793                        float: left;
     1794                        margin-left: ' . $left_offset . 'px;
     1795                        margin-top: -' . $top_offset . 'px;
     1796                        width:auto;
     1797                }
     1798
     1799                body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-header-content,
     1800                body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-actions {
     1801                        margin-top: ' . $params["height"] . 'px;
     1802                        margin-left: 0;
     1803                        clear: none;
     1804                        max-width: 50%;
     1805                }
     1806
     1807                body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-actions {
     1808                        padding-top: 20px;
     1809                        max-width: 20%;
     1810                }
     1811
     1812                ' . $hide_avatar_style . '
     1813
     1814                #buddypress div#item-header-cover-image h2 a,
     1815                #buddypress div#item-header-cover-image h2 {
     1816                        color: #FFF;
     1817                        text-rendering: optimizelegibility;
     1818                        text-shadow: 0px 0px 3px rgba( 0, 0, 0, 0.8 );
     1819                        margin: 0;
     1820                        font-size:200%;
     1821                }
     1822
     1823                #buddypress #item-header-cover-image #item-header-avatar img.avatar {
     1824                        border: solid 2px #FFF;
     1825                        background: rgba( 255, 255, 255, 0.8 );
     1826                }
     1827
     1828                #buddypress #item-header-cover-image #item-header-avatar a {
     1829                        border: none;
     1830                        text-decoration: none;
     1831                }
     1832
     1833                #buddypress #item-header-cover-image #item-buttons {
     1834                        overflow:hidden;
     1835                        margin: 20px 0 10px;
     1836                        padding: 0 0 5px;
     1837                }
     1838
     1839                #buddypress #item-header-cover-image #item-buttons:before {
     1840                        content:"\00a0";
     1841                }
     1842
     1843                @media screen and (max-width: 782px) {
     1844                        #buddypress #item-header-cover-image #item-header-avatar,
     1845                        .bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar,
     1846                        #buddypress div#item-header #item-header-cover-image #item-header-content {
     1847                                width:100%;
     1848                                text-align:center;
     1849                        }
     1850
     1851                        #buddypress #item-header-cover-image #item-header-avatar a {
     1852                                display:inline-block;
     1853                        }
     1854
     1855                        #buddypress #item-header-cover-image #item-header-avatar img {
     1856                                margin:0;
     1857                        }
     1858
     1859                        #buddypress div#item-header #item-header-cover-image #item-header-content,
     1860                        body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-header-content,
     1861                        body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-actions {
     1862                                margin:0;
     1863                        }
     1864
     1865                        body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-header-content,
     1866                        body.single-item.groups #buddypress div#item-header #item-header-cover-image #item-actions {
     1867                                max-width: 100%;
     1868                        }
     1869
     1870                        #buddypress div#item-header-cover-image h2 a,
     1871                        #buddypress div#item-header-cover-image h2 {
     1872                                color: inherit;
     1873                                text-shadow: none;
     1874                                margin:25px 0 0;
     1875                                font-size:200%;
     1876                        }
     1877
     1878                        #buddypress #item-header-cover-image #item-buttons div {
     1879                                float:none;
     1880                                display:inline-block;
     1881                        }
     1882
     1883                        #buddypress #item-header-cover-image #item-buttons:before {
     1884                                content:"";
     1885                        }
     1886
     1887                        #buddypress #item-header-cover-image #item-buttons {
     1888                                margin: 5px 0;
     1889                        }
     1890                }
     1891        ';
     1892}
  • src/bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php src/bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php
    index e69de29..03820b8 100644
     
     1<?php
     2/**
     3 * BuddyPress Cover Images main template
     4 *
     5 * This template is used to inject the BuddyPress Backbone views
     6 * dealing with cover images.
     7 * It's also used to create the common Backbone views
     8 *
     9 * @since 2.4.0
     10 *
     11 * @package BuddyPress
     12 * @subpackage bp-attachments
     13 */
     14?>
     15
     16<div class="bp-cover-image"></div>
     17<div class="bp-cover-image-status"></div>
     18<div class="bp-cover-image-manage"></div>
     19
     20<?php bp_attachments_get_template_part( 'uploader' ); ?>
     21
     22<script id="tmpl-bp-cover-image-delete" type="text/html">
     23        <# if ( 'user' === data.object ) { #>
     24                <p><?php _e( "If you'd like to delete your current cover image but not upload a new one, please use the delete Cover Image button.", 'buddypress' ); ?></p>
     25                <p><a class="button edit" id="bp-delete-cover-image" href="#" title="<?php esc_attr_e( 'Delete Cover Image', 'buddypress' ); ?>"><?php esc_html_e( 'Delete My Cover Image', 'buddypress' ); ?></a></p>
     26        <# } else if ( 'group' === data.object ) { #>
     27                <p><?php _e( "If you'd like to remove the existing group cover image but not upload a new one, please use the delete group cover image button.", 'buddypress' ); ?></p>
     28                <p><a class="button edit" id="bp-delete-cover-image" href="#" title="<?php esc_attr_e( 'Delete Cover Image', 'buddypress' ); ?>"><?php esc_html_e( 'Delete Group Cover Image', 'buddypress' ); ?></a></p>
     29        <# } else { #>
     30                <?php do_action( 'bp_attachments_cover_image_delete_template' ); ?>
     31        <# } #>
     32</script>
     33
     34<?php do_action( 'bp_attachments_cover_image_main_template' ); ?>
  • src/bp-templates/bp-legacy/buddypress/groups/create.php

    diff --git src/bp-templates/bp-legacy/buddypress/groups/create.php src/bp-templates/bp-legacy/buddypress/groups/create.php
    index 3e77626..15f6db5 100644
    do_action( 'bp_before_create_group_page' ); ?> 
    252252
    253253                        <?php endif; ?>
    254254
    255                         <?php /* Group creation step 4: Invite friends to group */ ?>
     255                        <?php /* Group creation step 4: Cover image */ ?>
     256                        <?php if ( bp_is_group_creation_step( 'group-cover-image' ) ) : ?>
     257
     258                                <?php
     259
     260                                /**
     261                                 * Fires before the display of the group cover image creation step.
     262                                 *
     263                                 * @since 2.4.0
     264                                 */
     265                                do_action( 'bp_before_group_cover_image_creation_step' ); ?>
     266
     267                                <div id="header-cover-image"></div>
     268
     269                                <p><?php _e( 'The Cover Image will be used to customize the header of your group.', 'buddypress' ); ?></p>
     270
     271                                <?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
     272
     273                                <?php
     274
     275                                /**
     276                                 * Fires after the display of the group cover image creation step.
     277                                 *
     278                                 * @since 2.4.0
     279                                 */
     280                                do_action( 'bp_after_group_cover_image_creation_step' ); ?>
     281
     282                                <?php wp_nonce_field( 'groups_create_save_group-cover-image' ); ?>
     283
     284                        <?php endif; ?>
     285
     286                        <?php /* Group creation step 5: Invite friends to group */ ?>
    256287                        <?php if ( bp_is_group_creation_step( 'group-invites' ) ) : ?>
    257288
    258289                                <?php
  • src/bp-templates/bp-legacy/buddypress/groups/single/admin.php

    diff --git src/bp-templates/bp-legacy/buddypress/groups/single/admin.php src/bp-templates/bp-legacy/buddypress/groups/single/admin.php
    index c7db4a7..1943692 100644
    do_action( 'bp_before_group_admin_content' ); ?> 
    207207
    208208<?php endif; ?>
    209209
     210<?php /* Group Cover image Settings */ ?>
     211<?php if ( bp_is_group_admin_screen( 'group-cover-image' ) ) : ?>
     212
     213        <h4><?php _e( 'Change Cover Image', 'buddypress' ); ?></h4>
     214
     215        <?php
     216
     217        /**
     218         * Fires before the display of profile cover image upload content.
     219         *
     220         * @since 2.4.0
     221         */
     222        do_action( 'bp_before_group_settings_cover_image' ); ?>
     223
     224        <p><?php _e( 'The Cover Image will be used to customize the header of your group.', 'buddypress' ); ?></p>
     225
     226        <?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
     227
     228        <?php
     229
     230        /**
     231         * Fires after the display of group cover image upload content.
     232         *
     233         * @since 2.4.0
     234         */
     235        do_action( 'bp_after_group_settings_cover_image' ); ?>
     236
     237<?php endif; ?>
     238
    210239<?php /* Manage Group Members */ ?>
    211240<?php if ( bp_is_group_admin_screen( 'manage-members' ) ) : ?>
    212241
  • src/bp-templates/bp-legacy/buddypress/groups/single/cover-image-header.php

    diff --git src/bp-templates/bp-legacy/buddypress/groups/single/cover-image-header.php src/bp-templates/bp-legacy/buddypress/groups/single/cover-image-header.php
    index e69de29..a57fc58 100644
     
     1<?php
     2/**
     3 * BuddyPress - Groups Cover Image Header
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 */
     8
     9?>
     10
     11<?php
     12
     13/**
     14 * Fires before the display of a group's header.
     15 *
     16 * @since 1.2.0
     17 */
     18do_action( 'bp_before_group_header' ); ?>
     19
     20<a id="header-cover-image" href="<?php bp_group_permalink(); ?>"></a>
     21
     22<div id="item-header-cover-image">
     23        <?php if ( ! bp_disable_group_avatar_uploads() ) : ?>
     24                <div id="item-header-avatar">
     25                        <a href="<?php bp_group_permalink(); ?>" title="<?php bp_group_name(); ?>">
     26
     27                                <?php bp_group_avatar(); ?>
     28
     29                        </a>
     30                </div><!-- #item-header-avatar -->
     31        <?php endif; ?>
     32
     33        <div id="item-header-content">
     34
     35                <div id="item-buttons">
     36
     37                        <?php
     38
     39                        /**
     40                         * Fires in the group header actions section.
     41                         *
     42                         * @since 1.2.6
     43                         */
     44                        do_action( 'bp_group_header_actions' ); ?>
     45
     46                </div><!-- #item-buttons -->
     47
     48                <?php
     49
     50                /**
     51                 * Fires before the display of the group's header meta.
     52                 *
     53                 * @since 1.2.0
     54                 */
     55                do_action( 'bp_before_group_header_meta' ); ?>
     56
     57                <div id="item-meta">
     58
     59                        <?php
     60
     61                        /**
     62                         * Fires after the group header actions section.
     63                         *
     64                         * @since 1.2.0
     65                         */
     66                        do_action( 'bp_group_header_meta' ); ?>
     67
     68                        <span class="highlight"><?php bp_group_type(); ?></span>
     69                        <span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
     70
     71                        <?php bp_group_description(); ?>
     72
     73                </div>
     74        </div><!-- #item-header-content -->
     75
     76        <div id="item-actions">
     77
     78                <?php if ( bp_group_is_visible() ) : ?>
     79
     80                        <h3><?php _e( 'Group Admins', 'buddypress' ); ?></h3>
     81
     82                        <?php bp_group_list_admins();
     83
     84                        /**
     85                         * Fires after the display of the group's administrators.
     86                         *
     87                         * @since 1.1.0
     88                         */
     89                        do_action( 'bp_after_group_menu_admins' );
     90
     91                        if ( bp_group_has_moderators() ) :
     92
     93                                /**
     94                                 * Fires before the display of the group's moderators, if there are any.
     95                                 *
     96                                 * @since 1.1.0
     97                                 */
     98                                do_action( 'bp_before_group_menu_mods' ); ?>
     99
     100                                <h3><?php _e( 'Group Mods' , 'buddypress' ); ?></h3>
     101
     102                                <?php bp_group_list_mods();
     103
     104                                /**
     105                                 * Fires after the display of the group's moderators, if there are any.
     106                                 *
     107                                 * @since 1.1.0
     108                                 */
     109                                do_action( 'bp_after_group_menu_mods' );
     110
     111                        endif;
     112
     113                endif; ?>
     114
     115        </div><!-- #item-actions -->
     116
     117</div><!-- #item-header-cover-image -->
     118
     119<?php
     120
     121/**
     122 * Fires after the display of a group's header.
     123 *
     124 * @since 1.2.0
     125 */
     126do_action( 'bp_after_group_header' );
     127
     128/** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
     129do_action( 'template_notices' ); ?>
  • src/bp-templates/bp-legacy/buddypress/groups/single/home.php

    diff --git src/bp-templates/bp-legacy/buddypress/groups/single/home.php src/bp-templates/bp-legacy/buddypress/groups/single/home.php
    index c8e62f4..5097547 100644
     
    1313
    1414        <div id="item-header" role="complementary">
    1515
    16                 <?php bp_get_template_part( 'groups/single/group-header' ); ?>
     16                <?php
     17                /**
     18                 * If the cover image feature is enabled, use a specific header
     19                 */
     20                if ( bp_group_use_cover_image_header() ) :
     21                        bp_get_template_part( 'groups/single/cover-image-header' );
     22                else :
     23                        bp_get_template_part( 'groups/single/group-header' );
     24                endif;
     25                ?>
    1726
    1827        </div><!-- #item-header -->
    1928
  • src/bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php src/bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php
    index e69de29..27b3778 100644
     
     1<?php
     2/**
     3 * BuddyPress - Users Cover Image Header
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 */
     8
     9?>
     10
     11<?php
     12
     13/**
     14 * Fires before the display of a member's header.
     15 *
     16 * @since 1.2.0
     17 */
     18do_action( 'bp_before_member_header' ); ?>
     19
     20<a id="header-cover-image" href="<?php bp_displayed_user_link(); ?>"></a>
     21
     22<div id="item-header-cover-image">
     23        <div id="item-header-avatar">
     24                <a href="<?php bp_displayed_user_link(); ?>">
     25
     26                        <?php bp_displayed_user_avatar( 'type=full' ); ?>
     27
     28                </a>
     29        </div><!-- #item-header-avatar -->
     30
     31        <div id="item-header-content">
     32
     33                <?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
     34                        <h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
     35                <?php endif; ?>
     36
     37                <div id="item-buttons">
     38
     39                        <?php
     40
     41                        /**
     42                         * Fires in the member header actions section.
     43                         *
     44                         * @since 1.2.6
     45                         */
     46                        do_action( 'bp_member_header_actions' ); ?>
     47
     48                </div><!-- #item-buttons -->
     49
     50                <span class="activity"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
     51
     52                <?php
     53
     54                /**
     55                 * Fires before the display of the member's header meta.
     56                 *
     57                 * @since 1.2.0
     58                 */
     59                do_action( 'bp_before_member_header_meta' ); ?>
     60
     61                <div id="item-meta">
     62
     63                        <?php if ( bp_is_active( 'activity' ) ) : ?>
     64
     65                                <div id="latest-update">
     66
     67                                        <?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
     68
     69                                </div>
     70
     71                        <?php endif; ?>
     72
     73                        <?php
     74
     75                         /**
     76                          * Fires after the group header actions section.
     77                          *
     78                          * If you'd like to show specific profile fields here use:
     79                          * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
     80                          *
     81                          * @since 1.2.0
     82                          */
     83                         do_action( 'bp_profile_header_meta' );
     84
     85                         ?>
     86
     87                </div><!-- #item-meta -->
     88
     89        </div><!-- #item-header-content -->
     90
     91</div><!-- #item-header-cover-image -->
     92
     93<?php
     94
     95/**
     96 * Fires after the display of a member's header.
     97 *
     98 * @since 1.2.0
     99 */
     100do_action( 'bp_after_member_header' ); ?>
     101
     102<?php
     103
     104/** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
     105do_action( 'template_notices' ); ?>
  • src/bp-templates/bp-legacy/buddypress/members/single/home.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/home.php src/bp-templates/bp-legacy/buddypress/members/single/home.php
    index b11453e..cbbe91e 100644
     
    1111
    1212        <div id="item-header" role="complementary">
    1313
    14                 <?php bp_get_template_part( 'members/single/member-header' ) ?>
     14                <?php
     15                /**
     16                 * If the cover image feature is enabled, use a specific header
     17                 */
     18                if ( bp_displayed_user_use_cover_image_header() ) :
     19                        bp_get_template_part( 'members/single/cover-image-header' );
     20                else :
     21                        bp_get_template_part( 'members/single/member-header' );
     22                endif;
     23                ?>
    1524
    1625        </div><!-- #item-header -->
    1726
  • src/bp-templates/bp-legacy/buddypress/members/single/profile.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/profile.php src/bp-templates/bp-legacy/buddypress/members/single/profile.php
    index 747fa4c..0be4935 100644
    do_action( 'bp_before_profile_content' ); ?> 
    3737                bp_get_template_part( 'members/single/profile/change-avatar' );
    3838                break;
    3939
     40        // Change Cover Image
     41        case 'change-cover-image' :
     42                bp_get_template_part( 'members/single/profile/change-cover-image' );
     43                break;
     44
    4045        // Compose
    4146        case 'public' :
    4247
  • src/bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php src/bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php
    index e69de29..718e750 100644
     
     1<h4><?php _e( 'Change Cover Image', 'buddypress' ); ?></h4>
     2
     3<?php
     4
     5/**
     6 * Fires before the display of profile cover image upload content.
     7 *
     8 * @since 2.4.0
     9 */
     10do_action( 'bp_before_profile_edit_cover_image' ); ?>
     11
     12<p><?php _e( 'Your Cover Image will be used to customize the header of your profile.', 'buddypress' ); ?></p>
     13
     14<?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
     15
     16<?php
     17
     18/**
     19 * Fires after the display of profile cover image upload content.
     20 *
     21 * @since 2.4.0
     22 */
     23do_action( 'bp_after_profile_edit_cover_image' ); ?>
  • src/bp-templates/bp-legacy/css/buddypress.css

    diff --git src/bp-templates/bp-legacy/css/buddypress.css src/bp-templates/bp-legacy/css/buddypress.css
    index 0d78f61..088ee06 100644
    Hello, this is the BuddyPress Legacy stylesheet. 
    1919        3.6 - Ajax Loading
    2020        3.7 - Topics and Tables - Forums and General
    2121        3.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
     22                3.8.1 - Cover Image
    2223        3.9 - Private Messaging Threads
    2324        3.10 - Extended Profiles
    2425        3.11 - Widgets
    a.bp-title-button { 
    845846#buddypress form *[disabled="disabled"]{
    846847        cursor: default;
    847848        opacity: .4;
    848  }
     849}
     850
    849851.bp-screen-reader-text {
    850852        position: absolute;
    851853        margin: -1px;
    a.bp-title-button { 
    11721174}
    11731175#buddypress div#item-header {
    11741176        overflow: hidden;
     1177        position: relative;
    11751178}
    11761179#buddypress div#item-header div#item-header-content {
    11771180        float: left;
    a.bp-title-button { 
    12521255        float: left;
    12531256        margin: 10px 10px 0 0;
    12541257}
     1258body.no-js #buddypress div#item-header .js-self-profile-button {
     1259        display:none;
     1260}
    12551261#buddypress div#item-header div#message.info {
    12561262        line-height: 80%;
    12571263}
    body.activity-permalink #buddypress ul.item-list li.activity-item { 
    13971403        list-style: none;
    13981404}
    13991405
     1406/*--------------------------------------------------------------
     14073.8.1 - Cover Image
     1408--------------------------------------------------------------*/
     1409
     1410#buddypress #header-cover-image {
     1411        background-color: #c5c5c5;
     1412        background-position: center top;
     1413        background-repeat: no-repeat;
     1414        background-size: cover;
     1415        border: 0;
     1416        display: block;
     1417        left: 0;
     1418        margin: 0;
     1419        padding: 0;
     1420        position: absolute;
     1421        top: 0;
     1422        width: 100%;
     1423        z-index: 1;
     1424}
     1425
     1426#buddypress #item-header-cover-image {
     1427        padding: 0 1em;
     1428        position: relative;
     1429        z-index: 999;
     1430}
    14001431
    14011432/*--------------------------------------------------------------
    140214333.9 - Private Messaging Threads
  • src/bp-templates/bp-legacy/css/twentyfifteen.css

    diff --git src/bp-templates/bp-legacy/css/twentyfifteen.css src/bp-templates/bp-legacy/css/twentyfifteen.css
    index 7c9eabf..2b14228 100644
    http://codex.buddypress.org/themes/buddypress-companion-stylesheets/ 
    955955        width: 100%;
    956956}
    957957
    958 .bp-user #buddypress #item-header #item-header-avatar img.avatar,
    959958.bp-user #buddypress #item-header #item-header-avatar a {
    960959        border-bottom: 0;
    961960        display: inline-block;
  • src/bp-templates/bp-legacy/css/twentyfifteen.scss

    diff --git src/bp-templates/bp-legacy/css/twentyfifteen.scss src/bp-templates/bp-legacy/css/twentyfifteen.scss
    index 22c7eba..267a0d1 100644
    http://codex.buddypress.org/themes/buddypress-companion-stylesheets/ 
    11991199                                text-align: center;
    12001200                                width: 100%;
    12011201
    1202                                 img.avatar,
    12031202                                a {
    12041203                                        border-bottom: 0;
    12051204                                        display: inline-block;
  • src/bp-templates/bp-legacy/css/twentyfourteen.css

    diff --git src/bp-templates/bp-legacy/css/twentyfourteen.css src/bp-templates/bp-legacy/css/twentyfourteen.css
    index b00e3fe..833cbfa 100644
    body.activity-permalink #buddypress { 
    782782                text-align: left;
    783783                width: 20%;
    784784        }
    785         .bp-user #buddypress #item-header #item-header-avatar img {
    786                 margin: 0;
    787         }
    788785        .bp-user #buddypress #item-header #item-header-content {
    789786                float: right;
    790787                width: 78%;
  • src/bp-templates/bp-legacy/css/twentyfourteen.scss

    diff --git src/bp-templates/bp-legacy/css/twentyfourteen.scss src/bp-templates/bp-legacy/css/twentyfourteen.scss
    index 8b9872f..dcf6ed7 100644
    body.activity-permalink { 
    11001100                                overflow: hidden;
    11011101                                text-align: left;
    11021102                                width: 20%;
    1103 
    1104                                 img {margin: 0;}
    11051103                        }
    11061104
    11071105                        #item-header-content {
  • src/bp-templates/bp-legacy/css/twentythirteen.css

    diff --git src/bp-templates/bp-legacy/css/twentythirteen.css src/bp-templates/bp-legacy/css/twentythirteen.css
    index d2eb95e..cec2289 100644
    http://codex.buddypress.org/themes/buddypress-companion-stylesheets/ 
    953953                float: left;
    954954                width: 20%;
    955955        }
    956         .bp-user #buddypress #item-header #item-header-avatar img.avatar,
    957956        .bp-user #buddypress #item-header #item-header-avatar a {
    958957                float: left;
    959                 width: 100%;
    960958        }
    961959        .bp-user #buddypress #item-header #item-header-content {
    962960                float: right;
  • src/bp-templates/bp-legacy/css/twentythirteen.scss

    diff --git src/bp-templates/bp-legacy/css/twentythirteen.scss src/bp-templates/bp-legacy/css/twentythirteen.scss
    index 427a724..17a26f0 100644
    http://codex.buddypress.org/themes/buddypress-companion-stylesheets/ 
    12671267                                        float: left;
    12681268                                        width: 20%;
    12691269
    1270                                         img.avatar,
    12711270                                        a {
    12721271                                                float: left;
    1273                                                 width: 100%;
    12741272                                        }
    12751273                                }
    12761274
  • src/bp-xprofile/bp-xprofile-loader.php

    diff --git src/bp-xprofile/bp-xprofile-loader.php src/bp-xprofile/bp-xprofile-loader.php
    index 034aadf..4104b72 100644
    class BP_XProfile_Component extends BP_Component { 
    227227                        );
    228228                }
    229229
     230                // Change Cover image
     231                if ( bp_displayed_user_use_cover_image_header() ) {
     232                        $sub_nav[] = array(
     233                                'name'            => _x( 'Change Cover Image', 'Profile header sub menu', 'buddypress' ),
     234                                'slug'            => 'change-cover-image',
     235                                'parent_url'      => $profile_link,
     236                                'parent_slug'     => $slug,
     237                                'screen_function' => 'xprofile_screen_change_cover_image',
     238                                'position'        => 40,
     239                                'user_has_access' => $access
     240                        );
     241                }
     242
    230243                // The Settings > Profile nav item can only be set up after
    231244                // the Settings component has run its own nav routine
    232245                add_action( 'bp_settings_setup_nav', array( $this, 'setup_settings_nav' ) );
    class BP_XProfile_Component extends BP_Component { 
    315328                                );
    316329                        }
    317330
     331                        if ( bp_displayed_user_use_cover_image_header() ) {
     332                                $wp_admin_nav[] = array(
     333                                        'parent' => 'my-account-' . $this->id,
     334                                        'id'     => 'my-account-' . $this->id . '-change-cover-image',
     335                                        'title'  => _x( 'Change Cover Image', 'My Account Profile sub nav', 'buddypress' ),
     336                                        'href'   => trailingslashit( $profile_link . 'change-cover-image' )
     337                                );
     338                        }
    318339                }
    319340
    320341                parent::setup_admin_bar( $wp_admin_nav );
  • src/bp-xprofile/bp-xprofile-screens.php

    diff --git src/bp-xprofile/bp-xprofile-screens.php src/bp-xprofile/bp-xprofile-screens.php
    index 556e5ef..fb7d4de 100644
    function xprofile_screen_change_avatar() { 
    296296}
    297297
    298298/**
     299 * Displays the change cover image page.
     300 *
     301 * @package BuddyPress XProfile
     302 *
     303 * @since 2.4.0
     304 */
     305function xprofile_screen_change_cover_image() {
     306
     307        // Bail if not the correct screen
     308        if ( ! bp_is_my_profile() && ! bp_current_user_can( 'bp_moderate' ) ) {
     309                return false;
     310        }
     311
     312        /**
     313         * Fires right before the loading of the XProfile change cover image screen template file.
     314         *
     315         * @since 2.4.0
     316         */
     317        do_action( 'xprofile_screen_change_cover_image' );
     318
     319        /**
     320         * Filters the template to load for the XProfile cover image screen.
     321         *
     322         * @since 2.4.0
     323         *
     324         * @param string $template Path to the XProfile cover image template to load.
     325         */
     326        bp_core_load_template( apply_filters( 'xprofile_template_cover_image', 'members/single/home' ) );
     327}
     328
     329/**
    299330 * Show the xprofile settings template
    300331 *
    301332 * @since 2.0.0
  • tests/phpunit/testcases/core/class-bp-attachment.php

    diff --git tests/phpunit/testcases/core/class-bp-attachment.php tests/phpunit/testcases/core/class-bp-attachment.php
    index f6e7d13..35d0476 100644
    class BP_Tests_BP_Attachment_TestCases extends BP_UnitTestCase { 
    328328                // clean up!
    329329                $this->clean_files();
    330330        }
     331
     332        /**
     333         * @group upload
     334         * @group cover_image
     335         */
     336        public function test_bp_attachment_cover_image_user_upload() {
     337                $reset_files = $_FILES;
     338                $reset_post = $_POST;
     339                $bp = buddypress();
     340                $displayed_user = $bp->displayed_user;
     341                $bp->displayed_user = new stdClass;
     342
     343                $u1 = $this->factory->user->create();
     344                $bp->displayed_user->id = $u1;
     345
     346                // Upload the file
     347                $cover_image_attachment = new BP_Attachment_Cover_Image();
     348                $_POST['action'] = $cover_image_attachment->action;
     349                $_FILES[ $cover_image_attachment->file_input ] = array(
     350                        'tmp_name' => $this->image_file,
     351                        'name'     => 'mystery-man.jpg',
     352                        'type'     => 'image/jpeg',
     353                        'error'    => 0,
     354                        'size'     => filesize( $this->image_file )
     355                );
     356
     357                /* No error */
     358                $cover_image = $cover_image_attachment->upload( $_FILES );
     359                $this->assertEquals( $cover_image['file'], $bp->avatar->upload_path . '/buddypress/members/' . $u1 .'/cover-image/mystery-man.jpg' );
     360
     361                // clean up!
     362                $bp->displayed_user = $displayed_user;
     363                $this->clean_files( 'buddypress' );
     364                $_FILES = $reset_files;
     365                $_POST = $reset_post;
     366        }
    331367}
  • tests/phpunit/testcases/core/functions.php

    diff --git tests/phpunit/testcases/core/functions.php tests/phpunit/testcases/core/functions.php
    index fd36eaf..3a4e413 100644
    class BP_Tests_Core_Functions extends BP_UnitTestCase { 
    684684                // Reset buddypress() vars
    685685                $bp->active_components = $reset_active_components;
    686686        }
     687
     688        /**
     689         * @group bp_attachments
     690         * @ticket BP6570
     691         */
     692        public function test_bp_attachments_get_allowed_types() {
     693                $supported = array( 'jpeg', 'gif', 'png' );
     694
     695                $avatar = bp_attachments_get_allowed_types( 'avatar' );
     696                $this->assertSame( $supported, $avatar );
     697
     698                $cover_image = bp_attachments_get_allowed_types( 'cover_image' );
     699                $this->assertSame( $supported, $cover_image );
     700
     701                $images = bp_attachments_get_allowed_types( 'image/' );
     702
     703                foreach ( $images as $image ) {
     704                        if ( 'image' !== wp_ext2type( $image ) ) {
     705                                $not_image = $image;
     706                        }
     707                }
     708
     709                $this->assertTrue( empty( $not_image ) );
     710        }
    687711}