Skip to:
Content

BuddyPress.org

Ticket #6570: 6570.02.patch

File 6570.02.patch, 57.8 KB (added by imath, 10 years ago)
  • src/bp-core/bp-core-attachments.php

    diff --git src/bp-core/bp-core-attachments.php src/bp-core/bp-core-attachments.php
    index 1fadb11..a652386 100644
    function bp_attachments_enqueue_scripts( $class = '' ) { 
    257257                 * @param string $object the object the avatar belongs to (eg: user or group)
    258258                 */
    259259                $settings['nav'] = bp_sort_by_key( apply_filters( 'bp_attachments_avatar_nav', $avatar_nav, $object ), 'order', 'num' );
     260
     261        // Specific to BuddyPress cover images
     262        } elseif ( 'bp_cover_image_upload' === $defaults['multipart_params']['action'] ) {
     263
     264                // Cover images only need 1 file and 1 only!
     265                $defaults['multi_selection'] = false;
     266
     267                // Default cover component is xprofile
     268                $cover_component = 'xprofile';
     269
     270                // Get the object we're editing the cover image of
     271                $object = $defaults['multipart_params']['bp_params']['object'];
     272
     273                // Set the cover component according to the object
     274                if ( 'group' === $object ) {
     275                        $cover_component = 'groups';
     276                } elseif ( 'user' !== $object ) {
     277                        $cover_component = apply_filters( 'bp_attachments_cover_image_ui_component', $cover_component );
     278                }
     279                // Get cover image advised dimensions
     280                $cover_dimensions = bp_attachments_get_cover_image_dimensions( $cover_component );
     281
     282                // Set warning messages
     283                $strings['cover_image_warnings'] = apply_filters( 'bp_attachments_cover_image_ui_warnings', array(
     284                        'dimensions'  => sprintf(
     285                                        __( 'For better results, make sure to upload an image having a width >= %1$s px and a height >= %2$s px.', 'buddypress' ),
     286                                        (int) $cover_dimensions['width'],
     287                                        (int) $cover_dimensions['height']
     288                                ),
     289                ) );
    260290        }
    261291
    262292        // Set Plupload settings
    function bp_attachments_enqueue_scripts( $class = '' ) { 
    317347function bp_attachments_current_user_can( $capability, $args = array() ) {
    318348        $can = false;
    319349
    320         if ( 'edit_avatar' === $capability ) {
     350        if ( 'edit_avatar' === $capability || 'edit_cover_image' === $capability ) {
    321351                /**
    322352                 * Needed avatar arguments are set.
    323353                 */
    function bp_attachments_get_template_part( $slug ) { 
    410440                bp_get_template_part( $attachment_template_part );
    411441        }
    412442}
     443
     444/** Cover Image ***************************************************************/
     445
     446/**
     447 * Get the cover image settings
     448 *
     449 * @since  BuddyPress (2.4.0)
     450 *
     451 * @param  string $component the component to get the settings for ("xprofile" for user or "groups")
     452 * @return array            the cover image settings
     453 */
     454function bp_attachments_get_cover_image_settings( $component = 'xprofile' ) {
     455        // Default parameters
     456        $args = array();
     457
     458        // First look in BP Theme Compat
     459        $cover_image = bp_get_theme_compat_feature( 'cover_image' );
     460
     461        if ( ! empty( $cover_image ) ) {
     462                $args = (array) $cover_image;
     463        }
     464
     465        /**
     466         * Then let people override/set the feature using this dynamic filter
     467         *
     468         * eg: for the user's profile cover image use :
     469         * add_filter( 'bp_before_xprofile_cover_image_settings_parse_args', 'your_filter', 10, 1 );
     470         *
     471         * @since  BuddyPress (2.4.0)
     472         *
     473         * @param array $settings the cover image settings
     474         */
     475        $settings = bp_parse_args( $args, array(
     476                'components'    => array(),
     477                'width'         => 1300,
     478                'height'        => 225,
     479                'callback'      => '',
     480                'theme_handle'  => '',
     481                'default_cover' => '',
     482        ), $component . '_cover_image_settings' );
     483
     484        if ( empty( $settings['components'] ) || empty( $settings['callback'] ) || empty( $settings['theme_handle'] ) ) {
     485                return false;
     486        }
     487
     488        // Current component is not supported
     489        if ( ! in_array( $component, $settings['components'] ) ) {
     490                return false;
     491        }
     492
     493        // Finally return the settings
     494        return $settings;
     495}
     496
     497/**
     498 * Get cover image Width and Height
     499 *
     500 * @since  BuddyPress (2.4.0)
     501 *
     502 * @param  string $component the BuddyPress component concerned ("xprofile" for user or "groups")
     503 * @return array             an associative array containing the advised width and height for the cover image
     504 */
     505function bp_attachments_get_cover_image_dimensions( $component = 'xprofile' ) {
     506        // Let's prevent notices when setting the warning strings
     507        $default = array( 'width' => 0, 'height' => 0 );
     508
     509        $settings = bp_attachments_get_cover_image_settings( $component );
     510
     511        if ( empty( $settings ) ) {
     512                return false;
     513        }
     514
     515        // Get width and height
     516        $wh = array_intersect_key( $settings, $default );
     517
     518        /**
     519         * Filter here to edit the cover image dimensions if needed.
     520         *
     521         * @since  BuddyPress (2.4.0)
     522         *
     523         * @param  array  $wh        an associative array containing the width and height values
     524         * @param  array  $settings  an associative array containing all the feature settings
     525         * @param  string $compnent  the requested component
     526         */
     527        return apply_filters( 'bp_attachments_get_cover_image_dimensions', $wh, $settings, $component );
     528}
     529
     530/**
     531 * Are we on a page to edit a cover image ?
     532 *
     533 * @since  BuddyPress (2.4.0)
     534 *
     535 * @todo  The Groups single item part
     536 * @return bool True if on a page to edit a cover image, false otherwise
     537 */
     538function bp_attachments_cover_image_is_edit() {
     539        $retval = false;
     540
     541        $current_component = bp_current_component();
     542        if ( 'profile' === $current_component ) {
     543                $current_component = 'xprofile';
     544        }
     545
     546        if ( ! bp_is_active( $current_component, 'cover_image' ) ) {
     547                return $retval;
     548        }
     549
     550        if ( bp_is_user_change_cover_image() ) {
     551                $retval = ! bp_disable_avatar_uploads();
     552        }
     553
     554        /**
     555         * @todo
     556         * if ( bp_is_group_change_cover_image() ) $retval = ! bp_disable_group_avatar_uploads();
     557         */
     558
     559        return apply_filters( 'bp_attachments_cover_image_is_edit', $retval, $current_component );
     560}
     561
     562/**
     563 * Get the url or the path for a type of attachment
     564 *
     565 * @since  BuddyPress (2.4.0)
     566 *
     567 * @param  string $data whether to get the url or the path
     568 * @param  array  $args {
     569 *     @type string $object_dir  The object dir (eg: members/groups). Defaults to members.
     570 *     @type int    $item_id     The object id (eg: a user or a group id). Defaults to current user.
     571 *     @type string $type        The type of the attachment which is also the subdir where files are saved.
     572 *                               Defaults to 'cover-image'
     573 *     @type string $file        The name of the file.
     574 * }
     575 * @return string|bool the url or the path to the attachment, false otherwise
     576 */
     577function bp_attachments_get_attachment( $data = 'url', $args = array() ) {
     578        // Default value
     579        $attachment_data = false;
     580
     581        $r = bp_parse_args( $args, array(
     582                'object_dir' => 'members',
     583                'item_id'    => bp_loggedin_user_id(),
     584                'type'       => 'cover-image',
     585                'file'       => '',
     586        ), 'attachments_get_attachment_src' );
     587
     588        // Get BuddyPress Upload Dir
     589        $bp_upload_dir = bp_upload_dir();
     590
     591        $type_subdir = 'buddypress/' . $r['object_dir'] . '/' . $r['item_id'] . '/' . $r['type'];
     592        $type_dir    = trailingslashit( $bp_upload_dir['basedir'] ) . $type_subdir;
     593
     594        if ( ! is_dir( $type_dir ) ) {
     595                return $attachment_data;
     596        }
     597
     598        if ( ! empty( $r['file'] ) ) {
     599                if ( ! file_exists( trailingslashit( $type_dir ) . $r['file'] ) ) {
     600                        return $attachment_data;
     601                }
     602
     603                if ( 'url' === $data ) {
     604                        $attachment_data = trailingslashit( $bp_upload_dir['baseurl'] ) . $type_subdir . '/' . $r['file'];
     605                } else {
     606                        $attachment_data = trailingslashit( $type_dir ) . $r['file'];
     607                }
     608
     609        } else {
     610                $file = false;
     611
     612                // Open the directory and get the first file
     613                if ( $att_dir = opendir( $type_dir ) ) {
     614
     615                        while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
     616                                // Look for the first file having the type in its name
     617                                if ( false !== strpos( $attachment_file, $r['type'] ) && empty( $file ) ) {
     618                                        $file = $attachment_file;
     619                                        break;
     620                                }
     621                        }
     622                }
     623
     624                if ( empty( $file ) ) {
     625                        return $attachment_data;
     626                }
     627
     628                if ( 'url' === $data ) {
     629                        $attachment_data = trailingslashit( $bp_upload_dir['baseurl'] ) . $type_subdir . '/' . $file;
     630                } else {
     631                        $attachment_data = trailingslashit( $type_dir ) . $file;
     632                }
     633        }
     634
     635        return $attachment_data;
     636}
     637
     638/**
     639 * Does the user has a cover image ?
     640 *
     641 * @since  BuddyPress (2.4.0)
     642 *
     643 * @param  int $user_id
     644 * @return bool True if the user has a cover image, false otherwise
     645 */
     646function bp_attachments_get_user_has_cover_image( $user_id = 0 ) {
     647        if ( empty( $user_id ) ) {
     648                $user_id = bp_displayed_user_id();
     649        }
     650
     651        $cover_src = bp_attachments_get_attachment( 'url', array(
     652                'item_id'   => $user_id,
     653        ) );
     654
     655        return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $user_id );
     656}
     657
     658/**
     659 * Does the group has a cover image ?
     660 *
     661 * @since  BuddyPress (2.4.0)
     662 *
     663 * @param  int $group_id
     664 * @return bool True if the group has a cover image, false otherwise
     665 */
     666function bp_attachments_get_group_has_cover_image( $group_id = 0 ) {
     667        if ( empty( $group_id ) ) {
     668                $group_id = bp_get_current_group_id();
     669        }
     670
     671        $cover_src = bp_attachments_get_attachment( 'url', array(
     672                'object_dir' => 'groups',
     673                'item_id'    => $group_id,
     674        ) );
     675
     676        return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $group_id );
     677}
     678
     679/**
     680 * Delete an attachment for the given arguments
     681 *
     682 * @since  BuddyPress (2.4.0)
     683 *
     684 * @param  array $args
     685 * @see    bp_attachments_get_attachment() For more information on accepted arguments.
     686 * @return bool True if the attachment was deleted, false otherwise
     687 */
     688function bp_attachments_delete_file( $args = array() ) {
     689        $cover_path = bp_attachments_get_attachment( 'path', $args );
     690
     691        if ( empty( $cover_path ) ) {
     692                return false;
     693        }
     694
     695        @unlink( $cover_path );
     696        return true;
     697}
     698
     699/**
     700 * Ajax Upload and set a cover image
     701 *
     702 * @since  BuddyPress (2.4.0)
     703 *
     704 * @return  string|null A json object containing success data if the upload succeeded
     705 *                      error message otherwise.
     706 */
     707function bp_attachments_cover_image_ajax_upload() {
     708        // Bail if not a POST action
     709        if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
     710                wp_die();
     711        }
     712
     713        /**
     714         * Sending the json response will be different if
     715         * the current Plupload runtime is html4
     716         */
     717        $is_html4 = false;
     718        if ( ! empty( $_POST['html4' ] ) ) {
     719                $is_html4 = true;
     720        }
     721
     722        // Check the nonce
     723        check_admin_referer( 'bp-uploader' );
     724
     725        // Init the BuddyPress parameters
     726        $bp_params = array();
     727
     728        // We need it to carry on
     729        if ( ! empty( $_POST['bp_params' ] ) ) {
     730                $bp_params = bp_parse_args( $_POST['bp_params' ], array(
     731                        'object'  => 'user',
     732                        'item_id' => bp_loggedin_user_id(),
     733                ), 'attachments_cover_image_ajax_upload' );
     734        } else {
     735                bp_attachments_json_response( false, $is_html4 );
     736        }
     737
     738        // We need the object to set the uploads dir filter
     739        if ( empty( $bp_params['object'] ) ) {
     740                bp_attachments_json_response( false, $is_html4 );
     741        }
     742
     743        // Capability check
     744        if ( ! bp_attachments_current_user_can( 'edit_cover_image', $bp_params ) ) {
     745                bp_attachments_json_response( false, $is_html4 );
     746        }
     747
     748        $cover_image_attachment = new BP_Attachment_Cover_Image();
     749        $uploaded = $cover_image_attachment->upload( $_FILES );
     750
     751        if ( ! empty( $uploaded['error'] ) ) {
     752                // Upload error response
     753                bp_attachments_json_response( false, $is_html4, array(
     754                        'type'    => 'upload_error',
     755                        'message' => sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $uploaded['error'] ),
     756                ) );
     757        }
     758
     759        // Default object data
     760        $object_data = array( 'dir' => 'members', 'component' => 'xprofile' );
     761        if ( 'group' === $bp_params['object'] ) {
     762                $object_data = array( 'dir' => 'groups', 'component' => 'groups' );
     763        } elseif ( 'user' !== $bp_params['object'] ) {
     764                $object_data = apply_filters( 'bp_attachments_cover_image_object_dir', $object_data, $bp_params['object'] );
     765        }
     766
     767        // Get advised dimensions for the cover image
     768        $dimensions = bp_attachments_get_cover_image_dimensions( $object_data['component'] );
     769
     770        // Resize the image so that it fit with the cover image dimensions
     771        $cover_image  = $cover_image_attachment->fit( $uploaded['file'], $dimensions );
     772        $is_too_small = false;
     773
     774        // Image is too small in width and height
     775        if ( empty( $cover_image ) ) {
     776                $cover_file = $cover_image_attachment->generate_filename( $uploaded['file'] );
     777                @rename( $uploaded['file'], $cover_file );
     778
     779                // It's too small!
     780                $is_too_small = true;
     781        } elseif ( ! empty( $cover_image['path'] ) ) {
     782                $cover_file   = $cover_image['path'];
     783
     784                if ( $cover_image['width'] < $dimensions['width'] || $cover_image['height'] < $dimensions['height'] ) {
     785                        $is_too_small = true;
     786                }
     787        }
     788
     789        // Default error message
     790        $error_message = __( 'There was a problem uploading the cover image.', 'buddypress' );
     791
     792        if ( empty( $cover_file ) ) {
     793                // Upload error response
     794                bp_attachments_json_response( false, $is_html4, array(
     795                        'type'    => 'upload_error',
     796                        'message' => __( 'There was a problem uploading the cover image.', 'buddypress' ),
     797                ) );
     798        }
     799
     800        // Set the basename for the cover file
     801        $cover_basename = wp_basename( $cover_file );
     802
     803        // Get BuddyPress Upload Dir
     804        $bp_upload_dir = bp_upload_dir();
     805
     806        $cover_subdir = 'buddypress/' . $object_data['dir'] . '/' . $bp_params['item_id'] . '/cover-image';
     807        $cover_dir    = trailingslashit( $bp_upload_dir['basedir'] ) . $cover_subdir;
     808
     809        if ( ! is_dir( $cover_dir ) ) {
     810                // Upload error response
     811                bp_attachments_json_response( false, $is_html4, array(
     812                        'type'    => 'upload_error',
     813                        'message' => $error_message,
     814                ) );
     815        }
     816
     817        // Clean up the cover dir to only keep the uploaded cover image
     818        if ( $att_dir = opendir( $cover_dir ) ) {
     819                while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
     820                        // skip directories and the new cover image
     821                        if ( 2 < strlen( $attachment_file ) && 0 !== strpos( $attachment_file, '.' ) && $cover_basename !== $attachment_file ) {
     822                                @unlink( $cover_dir . '/' . $attachment_file );
     823                        }
     824                }
     825        }
     826
     827        // Build the url to the file
     828        $cover_url = trailingslashit( $bp_upload_dir['baseurl'] ) . $cover_subdir . '/' . $cover_basename;
     829
     830        // Init Feedback code, 1 is success
     831        $feedback_code = 1;
     832
     833        // 0 is the size warning
     834        if ( $is_too_small ) {
     835                $feedback_code = 0;
     836        }
     837
     838        // Set the name of the file
     839        $name = $_FILES['file']['name'];
     840        $name_parts = pathinfo( $name );
     841        $name = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) );
     842
     843        // Build the successful response
     844        $response = array(
     845                'name'          => $name,
     846                'url'           => $cover_url,
     847                'feedback_code' => $feedback_code,
     848        );
     849
     850        // User already has a cover image
     851        if ( "true" === $bp_params['has_cover_image'] ) {
     852                $response['had_cover_image'] = true;
     853
     854        // Get the style in case it's not already loaded
     855        } else {
     856                $response['header']       = bp_buffer_template_part( 'members/single/cover-image-header', null, false );
     857                $response['inline_style'] = bp_add_cover_image_inline_css( true );
     858        }
     859
     860        // Finally return the cover image to the UI
     861        bp_attachments_json_response( true, $is_html4, $response );
     862}
     863add_action( 'wp_ajax_bp_cover_image_upload', 'bp_attachments_cover_image_ajax_upload' );
     864
     865/**
     866 * Ajax delete a cover image for a given object and item id.
     867 *
     868 * @since BuddyPress (2.4.0)
     869 *
     870 * @return string|null A json object containing success data if the cover image was deleted
     871 *                     error message otherwise.
     872 */
     873function bp_attachments_cover_image_ajax_delete() {
     874        // Bail if not a POST action.
     875        if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
     876                wp_send_json_error();
     877        }
     878
     879        $cover_image_data = $_POST;
     880
     881        if ( empty( $cover_image_data['object'] ) || empty( $cover_image_data['item_id'] ) ) {
     882                wp_send_json_error();
     883        }
     884
     885        // Check the nonce
     886        check_admin_referer( 'bp_delete_cover_image', 'nonce' );
     887
     888        // Capability check
     889        if ( ! bp_attachments_current_user_can( 'edit_cover_image', $cover_image_data ) ) {
     890                wp_send_json_error();
     891        }
     892
     893        // Set object for the user's case
     894        if ( 'user' === $cover_image_data['object'] ) {
     895                $object = 'member';
     896
     897        // Set it for any other cases
     898        } else {
     899                $object = $cover_image_data['object'];
     900        }
     901
     902        // Set the object dir
     903        $dir = $object . 's';
     904
     905        // Handle delete
     906        if ( bp_attachments_delete_file( array( 'item_id' => $cover_image_data['item_id'], 'object_dir' => $dir, 'type' => 'cover-image' ) ) ) {
     907
     908                wp_send_json_success( array(
     909                        'header'        => bp_buffer_template_part( $dir . '/single/' . $object . '-header', null, false ),
     910                        'feedback_code' => 3,
     911                ) );
     912        } else {
     913                wp_send_json_error( array(
     914                        'feedback_code' => 2,
     915                ) );
     916        }
     917}
     918add_action( 'wp_ajax_bp_cover_image_delete', 'bp_attachments_cover_image_ajax_delete' );
  • src/bp-core/bp-core-classes.php

    diff --git src/bp-core/bp-core-classes.php src/bp-core/bp-core-classes.php
    index 41be065..76aba5e 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 392f926..af1cdad 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  BuddyPress (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 BuddyPress (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                // No user uploads, no need to carry on
     375                if ( bp_disable_avatar_uploads() ) {
     376                        return;
     377                }
     378
     379                $cover_image_object = array(
     380                        'component' => 'xprofile',
     381                        'object' => $bp->displayed_user
     382                );
     383        } elseif ( bp_is_group() ) {
     384
     385                // No user uploads, no need to carry on
     386                if ( bp_disable_group_avatar_uploads() ) {
     387                        return;
     388                }
     389
     390                $cover_image_object = array(
     391                        'component' =>'groups',
     392                        'object' => $bp->groups->current_group
     393                );
     394        } else {
     395                $cover_image_object = apply_filters( 'bp_current_cover_image_object_inline_css', array() );
     396        }
     397
     398        // Bail if no component were found.
     399        if ( empty( $cover_image_object['component'] ) || empty( $cover_image_object['object'] ) || ! bp_is_active( $cover_image_object['component'], 'cover_image' ) ) {
     400                return;
     401        }
     402
     403        // Get the settings of the cover image feature for the current component
     404        $params = bp_attachments_get_cover_image_settings( $cover_image_object['component'] );
     405
     406        // Bail if no params.
     407        if ( empty( $params ) ) {
     408                return;
     409        }
     410
     411        // Try to call the callback
     412        if ( is_callable( $params['callback'] ) ) {
     413
     414                $object_dir = $cover_image_object['component'];
     415
     416                if ( 'xprofile' === $object_dir ) {
     417                        $object_dir = 'members';
     418                }
     419
     420                $cover_image = bp_attachments_get_attachment( 'url', array(
     421                        'object_dir' => $object_dir,
     422                        'item_id'    => $cover_image_object['object']->id,
     423                ) );
     424
     425                if ( empty( $cover_image ) ) {
     426                        if ( ! empty( $params['default_cover'] ) ) {
     427                                $cover_image = $params['default_cover'];
     428                        } else {
     429                                return;
     430                        }
     431                }
     432
     433                // Object has a cover so update it!
     434                $cover_image_object['object']->has_cover_image = true;
     435
     436                $inline_css = call_user_func_array( $params['callback'], array( array(
     437                        'cover_image' => esc_url( $cover_image ),
     438                        'component'   => sanitize_key( $cover_image_object['component'] ),
     439                        'object_id'   => (int) $cover_image_object['object']->id,
     440                        'width'       => (int) $params['width'],
     441                        'height'      => (int) $params['height'],
     442                ) ) );
     443
     444                // Finally add the inline css to the handle
     445                if ( ! empty( $inline_css ) ) {
     446
     447                        // Used to get the css when Ajax setting the cover image
     448                        if ( true === $return ) {
     449                                return array(
     450                                        'css_rules' => '<style type="text/css">' . "\n" . $inline_css . "\n" . '</style>',
     451                                        'handle'    => $params['theme_handle'],
     452                                );
     453                        }
     454
     455                        wp_add_inline_style( $params['theme_handle'], $inline_css );
     456                } else {
     457                        return false;
     458                }
     459        }
     460}
     461add_action( 'bp_enqueue_scripts', 'bp_add_cover_image_inline_css', 11 );
  • src/bp-core/bp-core-template.php

    diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php
    index 52bae24..ef740f5 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  BuddyPress (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 897b775..9240936 100644
    function bp_set_theme_compat_original_template( $template = '' ) { 
    437437}
    438438
    439439/**
     440 * Set a theme compat feature
     441 *
     442 * @since BuddyPress (2.4.0)
     443 *
     444 * @param  string $theme_id the theme id (eg: legacy)
     445 * @param  array  $feature  an associative array (eg: array( name => 'feature_name', 'settings' => array() ))
     446 */
     447function bp_set_theme_compat_feature( $theme_id, $feature = array() ) {
     448        if ( empty( $theme_id ) || empty( $feature['name'] ) ) {
     449                return;
     450        }
     451
     452        // Get BuddyPress instance
     453        $bp = buddypress();
     454
     455        // Get current theme compat theme
     456        $theme_compat_theme = $bp->theme_compat->theme;
     457
     458        // Bail if theme is not in use
     459        if ( $theme_id !== $theme_compat_theme->id ) {
     460                return;
     461        }
     462
     463        $features = $theme_compat_theme->__get( 'features' );
     464        if ( empty( $features ) ) {
     465                $features = array();
     466        }
     467
     468        // Bail if the feature is already registered or no settings were provided
     469        if ( isset( $features[ $feature['name'] ] ) || empty( $feature['settings'] ) ) {
     470                return;
     471        }
     472
     473        // Add the feature
     474        $features[ $feature['name'] ] = (object) $feature['settings'];
     475
     476        // The feature is attached to components
     477        if ( isset( $features[ $feature['name'] ]->components ) ) {
     478                // Set the feature for each concerned component
     479                foreach ( (array) $features[ $feature['name'] ]->components as $component ) {
     480                        // The xProfile component is specific
     481                        if ( 'xprofile' === $component ) {
     482                                $component = 'profile';
     483                        }
     484
     485                        if ( isset( $bp->{$component} ) ) {
     486                                if ( isset( $bp->{$component}->features ) ) {
     487                                        $bp->{$component}->features[] = $feature['name'];
     488                                } else {
     489                                        $bp->{$component}->features = array( $feature['name'] );
     490                                }
     491                        }
     492                }
     493        }
     494
     495        // Finally update the theme compat features
     496        $theme_compat_theme->__set( 'features', $features );
     497}
     498
     499/**
     500 * Get a theme compat feature
     501 *
     502 * @since BuddyPress (2.4.0)
     503 *
     504 * @param  string $feature the feature (eg: cover_image)
     505 * @return object          the feature settings.
     506 */
     507function bp_get_theme_compat_feature( $feature = '' ) {
     508        // Get current theme compat theme
     509        $theme_compat_theme = buddypress()->theme_compat->theme;
     510
     511        // Get features
     512        $features = $theme_compat_theme->__get( 'features' );
     513
     514        if ( ! isset( $features[ $feature ] ) ) {
     515                return false;
     516        }
     517
     518        return $features[ $feature ];
     519}
     520
     521/**
    440522 * Check whether a given template is the one that WP originally selected to display current page.
    441523 *
    442524 * @since BuddyPress (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..0b8a741 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 BuddyPress (2.4.0)
     18 */
     19class BP_Attachment_Cover_Image extends BP_Attachment {
     20        /**
     21         * The constuctor
     22         *
     23         * @since BuddyPress (2.4.0)
     24         */
     25        public function __construct() {
     26                parent::__construct( array(
     27                        'action'             => 'bp_cover_image_upload',
     28                        'file_input'         => 'file',
     29                        'base_dir'           => 'buddypress',
     30                        'required_wp_files'  => array( 'file', 'image' ),
     31
     32                        /* @todo use a custom error, like we are doing for avatars */
     33                        'allowed_mime_types' => array( 'jpg', 'png', 'gif' ),
     34                ) );
     35        }
     36
     37        /**
     38         * Set the directory when uploading a file
     39         *
     40         * @since BuddyPress (2.4.0)
     41         *
     42         * @return array upload data (path, url, basedir...)
     43         */
     44        public function upload_dir_filter() {
     45                // Default values are for profiles
     46                $object_id = bp_displayed_user_id();
     47
     48                if ( empty( $object_id ) ) {
     49                        $object_id = bp_loggedin_user_id();
     50                }
     51
     52                $object_directory = 'members';
     53
     54                // We're in a group, edit default values
     55                if ( bp_is_group() ) {
     56                        $object_id        = bp_get_current_group_id();
     57                        $object_directory = 'groups';
     58                }
     59
     60                // Set the subdir
     61                $subdir  = '/' . $object_directory . '/' . $object_id . '/cover-image';
     62
     63                return apply_filters( 'bp_attachments_cover_image_upload_datas', array(
     64                        'path'    => $this->upload_path . $subdir,
     65                        'url'     => $this->url . $subdir,
     66                        'subdir'  => $subdir,
     67                        'basedir' => $this->upload_path,
     68                        'baseurl' => $this->url,
     69                        'error'   => false
     70                ) );
     71        }
     72
     73        /**
     74         * Adjust the cover image to fit with advised width & height.
     75         *
     76         * @since BuddyPress (2.4.0)
     77         *
     78         * @param string $file the absolute path to the file.
     79         * @return mixed
     80         */
     81        public function fit( $file = '', $dimensions = array() ) {
     82                if ( empty( $dimensions['width'] ) || empty( $dimensions['height'] ) ) {
     83                        return false;
     84                }
     85
     86                // Get image size
     87                $size   = @getimagesize( $file );
     88                $retval = false;
     89
     90                // Check image size and shrink if too large
     91                if ( $size[0] > $dimensions['width'] || $size[1] > $dimensions['height'] ) {
     92                        $editor = wp_get_image_editor( $file );
     93
     94                        if ( ! is_wp_error( $editor ) ) {
     95                                $editor->set_quality( 100 );
     96
     97                                $resized = $editor->resize( $dimensions['width'], $dimensions['height'], true );
     98                                if ( ! is_wp_error( $resized ) ) {
     99                                        $cover   = $editor->save( $this->generate_filename( $file ) );
     100                                } else {
     101                                        $retval = $resized;
     102                                }
     103
     104                                // Check for cover creation errors
     105                                if ( ( false === $retval ) && is_wp_error( $cover ) ) {
     106                                        $retval = $cover;
     107                                }
     108
     109                                // Cover is good so proceed
     110                                if ( false === $retval ) {
     111                                        $retval = $cover;
     112                                }
     113
     114                        } else {
     115                                $retval = $editor;
     116                        }
     117                }
     118
     119                return $retval;
     120        }
     121
     122        /**
     123         * Generate a filename for the cover image
     124         *
     125         * @since BuddyPress (2.4.0)
     126         *
     127         * @param  string $file the absolute path to the file.
     128         * @return string       the absolute path to the new file name
     129         */
     130        public function generate_filename( $file = '' ) {
     131                if ( empty( $file ) || ! file_exists( $file ) ) {
     132                        return false;
     133                }
     134
     135                $info    = pathinfo( $file );
     136                $dir     = $info['dirname'];
     137                $ext     = strtolower( $info['extension'] );
     138                $name    = wp_hash( $file . time() ) . '-bp-cover-image';
     139
     140                return trailingslashit( $dir ) . "{$name}.{$ext}";
     141        }
     142
     143        /**
     144         * Build script datas for the Uploader UI
     145         *
     146         * @since BuddyPress (2.4.0)
     147         *
     148         * @return array the javascript localization data
     149         */
     150        public function script_data() {
     151                // Get default script data
     152                $script_data = parent::script_data();
     153
     154                if ( bp_is_user() ) {
     155                        $item_id = bp_displayed_user_id();
     156
     157                        $script_data['bp_params'] = array(
     158                                'object'          => 'user',
     159                                'item_id'         => $item_id,
     160                                'has_cover_image' => bp_attachments_get_user_has_cover_image( $item_id ),
     161                                'nonces'  => array(
     162                                        'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
     163                                ),
     164                        );
     165
     166                        // Set feedback messages
     167                        $script_data['feedback_messages'] = array(
     168                                1 => __( 'Your new cover image was uploaded successfully.', 'buddypress' ),
     169                                2 => __( 'There was a problem deleting your cover image. Please try again.', 'buddypress' ),
     170                                3 => __( 'Your cover image was deleted successfully!', 'buddypress' ),
     171                        );
     172                } elseif ( bp_is_group() ) {
     173                        $item_id = bp_get_current_group_id();
     174
     175                        $script_data['bp_params'] = array(
     176                                'object'          => 'group',
     177                                'item_id'         => bp_get_current_group_id(),
     178                                'has_cover_image' => bp_attachments_get_group_has_cover_image( $item_id ),
     179                                'nonces'  => array(
     180                                        'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
     181                                ),
     182                        );
     183
     184                        // Set feedback messages
     185                        $script_data['feedback_messages'] = array(
     186                                1 => __( 'The group cover image was uploaded successfully.', 'buddypress' ),
     187                                2 => __( 'There was a problem deleting the group cover image. Please try again.', 'buddypress' ),
     188                                3 => __( 'The group cover image was deleted successfully!', 'buddypress' ),
     189                        );
     190                } else {
     191                        /**
     192                         * Use this filter to include specific BuddyPress params for your object.
     193                         * e.g. Cover image for blogs single item.
     194                         *
     195                         * @since BuddyPress (2.4.0)
     196                         *
     197                         * @param array $value The cover image specific BuddyPress parameters.
     198                         */
     199                        $script_data['bp_params'] = apply_filters( 'bp_attachment_cover_image_params', array() );
     200                }
     201
     202                // Include our specific js & css
     203                $script_data['extra_js']  = array( 'bp-cover-image' );
     204                $script_data['extra_css'] = array( 'bp-avatar' );
     205
     206                return apply_filters( 'bp_attachments_cover_image_script_data', $script_data );
     207        }
     208}
  • 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..0e367c4 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 item header
     117                                $( '#item-header' ).html( response.header );
     118
     119                                // Reset the has_cover_image bp_param
     120                                BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image = false;
     121
     122                        } ).fail( function( response ) {
     123                                var feedback = BP_Uploader.strings.default_error;
     124                                if ( ! _.isUndefined( response ) ) {
     125                                        feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ];
     126                                }
     127
     128                                var coverImageStatus = new bp.Views.CoverImageStatus( {
     129                                        value : feedback,
     130                                        type : 'error'
     131                                } );
     132
     133                                self.views.add( {
     134                                        id   : 'status',
     135                                        view : coverImageStatus
     136                                } );
     137
     138                                coverImageStatus.inject( '.bp-cover-image-status' );
     139
     140                                // Put back the delete view
     141                                bp.CoverImage.deleteView();
     142                        } );
     143                },
     144
     145                removeWarning: function() {
     146                        if ( ! _.isNull( this.warning ) ) {
     147                                this.warning.remove();
     148                        }
     149                },
     150
     151                displayWarning: function( message ) {
     152                        this.removeWarning();
     153
     154                        this.warning = new bp.Views.uploaderWarning( {
     155                                value: message
     156                        } );
     157
     158                        this.warning.inject( '.bp-cover-image-status' );
     159                },
     160
     161                // Dynamically set the cover without a page reload
     162                setCover: function( cover ) {
     163                        if ( ! _.isUndefined( cover.had_cover_image ) ) {
     164                                $( '#item-header-cover-image' ).css( {
     165                                        'background-image': 'url( ' + cover.url + ' )'
     166                                } );
     167                        } else if ( ! _.isUndefined( cover.header ) ) {
     168                                if ( ! $( '#item-header-cover-image' ).length ) {
     169                                        $( '#item-header' ).html( cover.header );
     170
     171                                        // Check we have everything we need
     172                                        if ( ! _.isUndefined( cover.inline_style.handle ) && ! _.isUndefined( cover.inline_style.css_rules ) ) {
     173                                                if ( ! $( '#' + cover.inline_style.handle + '-inline-css').length ) {
     174                                                        $( '#item-header' ).prepend( cover.inline_style.css_rules );
     175                                                }
     176                                        }
     177
     178                                } else {
     179                                        $( '#item-header-cover-image' ).css( {
     180                                                'background-image': 'url( ' + cover.url + ' )'
     181                                        } );
     182                                }
     183                        }
     184                }
     185        };
     186
     187        // Custom Uploader Files view
     188        bp.Views.coverImageUploadProgress = bp.Views.uploaderStatus.extend( {
     189                className: 'files',
     190
     191                initialize: function() {
     192                        bp.Views.uploaderStatus.prototype.initialize.apply( this, arguments );
     193
     194                        this.collection.on( 'change:url', this.uploadResult, this );
     195                },
     196
     197                uploadResult: function( model ) {
     198                        var message, type;
     199
     200                        if ( ! _.isUndefined( model.get( 'url' ) ) ) {
     201
     202                                // Image is too small
     203                                if ( 0 === model.get( 'feedback_code' ) ) {
     204                                        message = BP_Uploader.strings.cover_image_warnings.dimensions;
     205                                        type    = 'warning';
     206
     207                                // Success, Rock n roll!
     208                                } else {
     209                                        message = BP_Uploader.strings.feedback_messages[ model.get( 'feedback_code' ) ];
     210                                        type = 'success';
     211                                }
     212
     213                                this.views.set( '.bp-uploader-progress', new bp.Views.CoverImageStatus( {
     214                                        value : message,
     215                                        type  : type
     216                                } ) );
     217
     218                                // Update the header
     219                                bp.CoverImage.setCover( _.pick( model.attributes, 'url', 'had_cover_image', 'inline_style', 'header' ) );
     220
     221                                // Add the delete view
     222                                bp.CoverImage.deleteView();
     223                        }
     224                }
     225        } );
     226
     227        // BuddyPress Cover Image Feedback view
     228        bp.Views.CoverImageStatus = bp.View.extend( {
     229                tagName: 'p',
     230                className: 'updated',
     231                id: 'bp-cover-image-feedback',
     232
     233                initialize: function() {
     234                        this.el.className += ' ' + this.options.type;
     235                        this.value = this.options.value;
     236                },
     237
     238                render: function() {
     239                        this.$el.html( this.value );
     240                        return this;
     241                }
     242        } );
     243
     244        // BuddyPress Cover Image Delete view
     245        bp.Views.DeleteCoverImage = bp.View.extend( {
     246                tagName: 'div',
     247                id: 'bp-delete-cover-image-container',
     248                template: bp.template( 'bp-cover-image-delete' ),
     249
     250                events: {
     251                        'click #bp-delete-cover-image': 'deleteCoverImage'
     252                },
     253
     254                deleteCoverImage: function( event ) {
     255                        event.preventDefault();
     256
     257                        bp.CoverImage.deleteCoverImage( this.model );
     258                }
     259        } );
     260
     261        bp.CoverImage.start();
     262
     263})( bp, jQuery );
  • src/bp-members/bp-members-template.php

    diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
    index f4d482f..ee11912 100644
    function bp_get_displayed_user_nav() { 
    14671467        }
    14681468}
    14691469
     1470/** Cover image ***************************************************************/
     1471
     1472/**
     1473 * Does the displayed user has a cover image
     1474 *
     1475 * @since BuddyPress (2.4.0)
     1476 *
     1477 * @return bool True if the displayed user has a cover image,
     1478 *              False otherwise
     1479 */
     1480function bp_displayed_user_has_cover_image() {
     1481        $bp = buddypress();
     1482
     1483        /**
     1484         * Filters the displayed user's check about his cover image.
     1485         *
     1486         * @since BuddyPress (2.4.0)
     1487         *
     1488         * @param bool $value whether the user has a cover image or not.
     1489         */
     1490        return (bool) apply_filters( 'bp_displayed_user_has_cover_image', ! empty( $bp->displayed_user->has_cover_image ) );
     1491}
     1492
    14701493/** Avatars *******************************************************************/
    14711494
    14721495/**
  • 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 fb7cdb4..6bf3f13 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' );
     67
     68                // Set Up theme features
     69                $this->setup_features();
     70        }
     71
     72        /**
     73         * Setup the theme's features
     74         *
     75         * @since BuddyPress (2.4.0)
     76         * @access public
     77         *
     78         * @global $content_width the content width of the theme
     79         */
     80        public function setup_features() {
     81                global $content_width;
     82
     83                // Get the theme
     84                $current_theme = wp_get_theme();
     85                $theme_handle  = $current_theme->get_stylesheet();
     86                $parent        = $current_theme->parent();
     87
     88                if ( $parent ) {
     89                        $theme_handle = $parent->get_stylesheet();
     90                }
     91
     92                /**
     93                 * Since Companion stylesheets, the $content_width is smaller
     94                 * than the width used by BuddyPress, so we need to manually set the
     95                 * content width for the concerned themes.
     96                 *
     97                 * array( stylesheet => content width used by BuddyPress )
     98                 */
     99                $bp_content_widths = array(
     100                        'twentyfifteen'  => 1300,
     101                        'twentyfourteen' => 955,
     102                        'twentythirteen' => 890,
     103                );
     104
     105                // Default values
     106                $bp_content_width = (int) $content_width;
     107                $bp_handle        = 'bp-legacy-css';
     108
     109                // Specific to themes having companion stylesheets
     110                if ( isset( $bp_content_widths[ $theme_handle ] ) ) {
     111                        $bp_content_width = $bp_content_widths[ $theme_handle ];
     112                        $bp_handle        = 'bp-' . $theme_handle;
     113                }
     114
     115                if ( is_rtl() ) {
     116                        $bp_handle .= '-rtl';
     117                }
     118
     119                $top_offset    = 150;
     120                $avatar_height = apply_filters( 'bp_core_avatar_full_height', $top_offset );
     121
     122                if ( $avatar_height > $top_offset ) {
     123                        $top_offset = $avatar_height;
     124                }
     125
     126                bp_set_theme_compat_feature( $this->id, array(
     127                        'name'     => 'cover_image',
     128                        'settings' => array(
     129                                'components'   => array( 'xprofile', 'groups' ),
     130                                'width'        => $bp_content_width,
     131                                'height'       => $top_offset + round( $avatar_height / 2 ),
     132                                'callback'     => 'bp_legacy_theme_cover_image',
     133                                'theme_handle' => $bp_handle,
     134                        ),
     135                ) );
    67136        }
    68137
    69138        /**
    function bp_legacy_theme_ajax_messages_star_handler() { 
    17171786        echo '-1';
    17181787        die();
    17191788}
     1789
     1790/**
     1791 * BP Legacy's callback for the cover image feature
     1792 *
     1793 * @since  BuddyPress (2.4.0)
     1794 *
     1795 * @param  array  $params the current component's feature parameters
     1796 * @return array          an array to inform about the css handle to attach the css rules to
     1797 */
     1798function bp_legacy_theme_cover_image( $params = array() ) {
     1799        if ( empty( $params ) ) {
     1800                return;
     1801        }
     1802
     1803        // Bail if the single item has no cover images
     1804        if ( ! isset( $params['cover_image'] ) ) {
     1805                return;
     1806        }
     1807
     1808        // feature's height - padding - 1/2 avatar height
     1809        $top_offset = $params['height'] - 5 - round( (int) bp_core_avatar_full_height() / 2 );
     1810        $left_offset = bp_core_avatar_full_height() + 20;
     1811
     1812        /**
     1813         * @todo groups single item rules, most of the css should be in companion stylesheets..
     1814         */
     1815        return '
     1816                /* Cover image */
     1817                #buddypress #item-header-cover-image {
     1818                        background: #FFF url(' . $params['cover_image'] . ') no-repeat center top;
     1819                        padding:5px;
     1820                        overflow:hidden;
     1821                }
     1822
     1823                #buddypress #item-header-cover-image #item-header-avatar,
     1824                .bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar {
     1825                        margin-top: '. $top_offset .'px;
     1826                        float: none;
     1827                        overflow:visible;
     1828                        width:auto;
     1829                }
     1830
     1831                #buddypress div#item-header #item-header-cover-image #item-header-content {
     1832                        float: left;
     1833                        margin-left: 15px;
     1834                        width:auto;
     1835                }
     1836
     1837                #buddypress #item-header-cover-image #item-header-avatar img,
     1838                .bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar img {
     1839                        float: left;
     1840                }
     1841
     1842                #buddypress #item-header-cover-image #item-header-avatar a,
     1843                .bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar a {
     1844                        width:auto;
     1845                }
     1846
     1847                /* This should only happen on regular screens */
     1848                #buddypress div#item-header-cover-image h2 a,
     1849                #buddypress div#item-header-cover-image h2 {
     1850                        color: #FFF;
     1851                        text-rendering: optimizelegibility;
     1852                        text-shadow: 0px 0px 3px rgba( 0, 0, 0, 0.8 );
     1853                        margin:25px 0 0;
     1854                        font-size:200%;
     1855                }
     1856
     1857                #buddypress #item-header-cover-image #item-header-avatar img.avatar,
     1858                .bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar img.avatar {
     1859                        border: solid 2px #FFF;
     1860                        background: rgba( 255, 255, 255, 0.8 );
     1861                        width:auto;
     1862                }
     1863
     1864                #buddypress #item-header-cover-image #item-buttons {
     1865                        overflow:hidden;
     1866                        margin: 25px 0;
     1867                        padding: 0 0 5px;
     1868                }
     1869
     1870                #buddypress #item-header-cover-image #item-buttons:before {
     1871                        content:"\00a0";
     1872                }
     1873
     1874                #buddypress div#item-header #item-header-cover-image #item-meta {
     1875                        width:100%;
     1876                        padding-top:25px;
     1877                        clear:both;
     1878                }
     1879
     1880                @media screen and (max-width: 782px) {
     1881                        #buddypress #item-header-cover-image #item-header-avatar,
     1882                        .bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar,
     1883                        #buddypress div#item-header #item-header-cover-image #item-header-content {
     1884                                width:100%;
     1885                                text-align:center;
     1886                        }
     1887
     1888                        #buddypress #item-header-cover-image #item-header-avatar a {
     1889                                display:inline-block;
     1890                        }
     1891
     1892                        #buddypress #item-header-cover-image #item-header-avatar img {
     1893                                margin:0;
     1894                        }
     1895
     1896                        #buddypress div#item-header #item-header-cover-image #item-header-content {
     1897                                margin:0;
     1898                        }
     1899
     1900                        #buddypress div#item-header-cover-image h2 a,
     1901                        #buddypress div#item-header-cover-image h2 {
     1902                                color: inherit;
     1903                                text-shadow: none;
     1904                                margin:25px 0 0;
     1905                                font-size:200%;
     1906                        }
     1907
     1908                        #buddypress #item-header-cover-image #item-buttons div {
     1909                                float:none;
     1910                                display:inline-block;
     1911                        }
     1912
     1913                        #buddypress #item-header-cover-image #item-buttons:before {
     1914                                content:"";
     1915                        }
     1916
     1917                        #buddypress #item-header-cover-image #item-buttons {
     1918                                margin: 5px 0;
     1919                        }
     1920                }
     1921        ';
     1922}
  • 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..a552682 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
     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/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..9a636af 100644
     
     1<?php
     2
     3/**
     4 * BuddyPress - Users Cover Image Header
     5 *
     6 * @package BuddyPress
     7 * @subpackage bp-legacy
     8 */
     9
     10?>
     11
     12<?php
     13
     14/**
     15 * Fires before the display of a member's header.
     16 *
     17 * @since BuddyPress (1.2.0)
     18 */
     19do_action( 'bp_before_member_header' ); ?>
     20
     21<div id="item-header-cover-image">
     22
     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 BuddyPress (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        </div><!-- #item-header-content -->
     53
     54        <?php
     55
     56        /**
     57         * Fires before the display of the member's header meta.
     58         *
     59         * @since BuddyPress (1.2.0)
     60         */
     61        do_action( 'bp_before_member_header_meta' ); ?>
     62
     63        <div id="item-meta">
     64
     65                <?php if ( bp_is_active( 'activity' ) ) : ?>
     66
     67                        <div id="latest-update">
     68
     69                                <?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
     70
     71                        </div>
     72
     73                <?php endif; ?>
     74
     75                <?php
     76
     77                 /**
     78                  * Fires after the group header actions section.
     79                  *
     80                  * If you'd like to show specific profile fields here use:
     81                  * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
     82                  *
     83                  * @since BuddyPress (1.2.0)
     84                  */
     85                 do_action( 'bp_profile_header_meta' );
     86
     87                 ?>
     88
     89        </div><!-- #item-meta -->
     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 BuddyPress (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 6b9f04c..57914db 100644
     
    1111
    1212        <div id="item-header" role="complementary">
    1313
    14                 <?php bp_get_template_part( 'members/single/member-header' ) ?>
     14                <?php
     15                /**
     16                 * Since 2.4.0, we display the cover image header if the displayed user
     17                 * has a cover image.
     18                 */
     19                if ( bp_displayed_user_has_cover_image() ) :
     20                        bp_get_template_part( 'members/single/cover-image-header' );
     21                else :
     22                        bp_get_template_part( 'members/single/member-header' );
     23                endif;
     24                ?>
    1525
    1626        </div><!-- #item-header -->
    1727
  • 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 165cd17..f419718 100644
    do_action( 'bp_before_profile_content' ); ?> 
    3838                bp_get_template_part( 'members/single/profile/change-avatar' );
    3939                break;
    4040
     41        // Change Cover Image
     42        case 'change-cover-image' :
     43                bp_get_template_part( 'members/single/profile/change-cover-image' );
     44                break;
     45
    4146        // Compose
    4247        case 'public' :
    4348
  • 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..a114aee 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 BuddyPress (2.4.0)
     9 */
     10do_action( 'bp_before_profile_cover_image_upload_content' ); ?>
     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 BuddyPress (2.4.0)
     22 */
     23do_action( 'bp_after_profile_cover_image_upload_content' ); ?>
  • src/bp-xprofile/bp-xprofile-loader.php

    diff --git src/bp-xprofile/bp-xprofile-loader.php src/bp-xprofile/bp-xprofile-loader.php
    index a38b21b..79364d3 100644
    class BP_XProfile_Component extends BP_Component { 
    226226                                'position'        => 30,
    227227                                'user_has_access' => $access
    228228                        );
     229
     230                        // Change Cover image
     231                        if ( ! bp_disable_avatar_uploads() && bp_is_active( $this->id, 'cover_image' ) ) {
     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                        }
    229242                }
    230243
    231244                // The Settings > Profile nav item can only be set up after
    class BP_XProfile_Component extends BP_Component { 
    314327                                        'title'  => _x( 'Change Profile Photo', 'My Account Profile sub nav', 'buddypress' ),
    315328                                        'href'   => trailingslashit( $profile_link . 'change-avatar' )
    316329                                );
    317                         }
    318330
     331                                if ( ! bp_disable_avatar_uploads() && bp_is_active( $this->id, 'cover_image' ) ) {
     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                                }
     339                        }
    319340                }
    320341
    321342                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 afb4604..6650f00 100644
    function xprofile_screen_change_avatar() { 
    292292}
    293293
    294294/**
     295 * Displays the change cover image page.
     296 *
     297 * @package BuddyPress XProfile
     298 *
     299 * @since BuddyPress (2.4.0)
     300 */
     301function xprofile_screen_change_cover_image() {
     302
     303        // Bail if not the correct screen
     304        if ( ! bp_is_my_profile() && ! bp_current_user_can( 'bp_moderate' ) ) {
     305                return false;
     306        }
     307
     308        /**
     309         * Fires right before the loading of the XProfile change cover image screen template file.
     310         *
     311         * @since BuddyPress (2.4.0)
     312         */
     313        do_action( 'xprofile_screen_change_cover_image' );
     314
     315        /**
     316         * Filters the template to load for the XProfile cover image screen.
     317         *
     318         * @since BuddyPress (2.4.0)
     319         *
     320         * @param string $template Path to the XProfile cover image template to load.
     321         */
     322        bp_core_load_template( apply_filters( 'xprofile_template_cover_image', 'members/single/home' ) );
     323}
     324
     325/**
    295326 * Show the xprofile settings template
    296327 *
    297328 * @since BuddyPress (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}