Skip to:
Content

BuddyPress.org

Ticket #8581: 8581.2.patch

File 8581.2.patch, 61.9 KB (added by imath, 2 years ago)
  • src/bp-activity/bp-activity-functions.php

    diff --git src/bp-activity/bp-activity-functions.php src/bp-activity/bp-activity-functions.php
    index 97a2d5dea..658e916eb 100644
    function bp_activity_type_supports( $activity_type = '', $feature = '' ) { 
    709709                                $retval = true;
    710710                        }
    711711                        break;
     712
     713                /**
     714                 * Does this activity type support `generated-content` ?
     715                 */
     716                case 'generated-content' :
     717                        $retval = in_array( $activity_type, array( 'new_avatar', 'friendship_created', 'created_group', 'joined_group' ), true );
     718                        break;
    712719        }
    713720
    714721        return $retval;
  • src/bp-activity/bp-activity-template.php

    diff --git src/bp-activity/bp-activity-template.php src/bp-activity/bp-activity-template.php
    index 16ee47d86..be3eb6a57 100644
    function bp_activity_action( $args = array() ) { 
    13841384 * Output the activity content body.
    13851385 *
    13861386 * @since 1.2.0
     1387 * @since 10.0.0 Added the `$context` parameter & introduced `type-parts` templating for activity content.
    13871388 *
     1389 * @param string $context The context the template tag is being used. Defaults to 'front'.
    13881390 */
    1389 function bp_activity_content_body() {
     1391function bp_activity_content_body( $context = 'front' ) {
     1392        $located         = '';
     1393        $type            = bp_get_activity_type();
     1394        $allowed_context = false;
     1395
     1396        if ( 'front' === $context ) {
     1397                $allowed_context = ! is_admin() || wp_doing_ajax();
     1398        }
     1399
     1400        /**
     1401         * Filter here to edit whether the use of Activity type parts is allowed.
     1402         *
     1403         * @since 10.0.0
     1404         *
     1405         * @param bool   $allowed_context True if the use of Activity type parts is allowed. False otherwise.
     1406         * @param string $type            The Actvity type.
     1407         */
     1408        $use_type_parts = apply_filters( 'bp_activity_use_type_parts', $allowed_context, $type );
     1409
     1410        if ( $use_type_parts ) {
     1411                $type_part = str_replace( '_', '-', $type ) . '.php';
     1412                $located  = bp_locate_template( array( 'activity/type-parts/' . $type_part ), false, true );
     1413        }
     1414
     1415        if ( $located ) {
     1416                $slug = wp_basename( $located, '.php' );
     1417
     1418                /**
     1419                 * Let plugins adding an action to bp_get_template_part get it from here
     1420                 *
     1421                 * The dynamic portion of the hook is the activity type, eg: `activity_update`.
     1422                 *
     1423                 * @since 10.0.0
     1424                 *
     1425                 * @param string $slug    Template part slug requested.
     1426                 * @param string $context The context the template tag is being used. Defaults to 'front'.
     1427                 */
     1428                do_action( "bp_get_activity_type_part_{$type}", $slug, $context );
     1429
     1430                load_template( $located, false );
     1431        } else {
     1432                echo bp_get_activity_content_body();
     1433        }
     1434}
     1435
     1436/**
     1437 * Template tag to directly output the Activity content body.
     1438 *
     1439 * Unlike `bp_activity_content_body()` this template tag is not
     1440 * checking for potential type parts to output the activity.
     1441 *
     1442 * @since 10.0.0
     1443 */
     1444function bp_activity_the_content_body() {
    13901445        echo bp_get_activity_content_body();
    13911446}
    13921447
    function bp_activity_content_body() { 
    14301485function bp_activity_has_content() {
    14311486        global $activities_template;
    14321487
    1433         if ( ! empty( $activities_template->activity->content ) ) {
    1434                 return true;
     1488        $has_content = ! empty( $activities_template->activity->content );
     1489        if ( ! $has_content ) {
     1490                $activity_type = bp_get_activity_type();
     1491
     1492                if ( bp_activity_type_supports( $activity_type, 'generated-content' ) ) {
     1493                        $bp                = buddypress();
     1494                        $generated_content = new stdClass();
     1495                        $activity          = $activities_template->activity;
     1496                        $user_id           = $activity->user_id;
     1497
     1498                        // Set generated content properties.
     1499                        if ( 'new_avatar' === $activity_type ) {
     1500                                $avatars = bp_avatar_get_version_src( $user_id, bp_get_activity_date_recorded() );
     1501
     1502                                if ( $avatars && 1 === count( $avatars ) ) {
     1503                                        $avatar            = reset( $avatars );
     1504                                        $historical_avatar = trailingslashit( $avatar->parent_dir_url ) . $avatar->name;
     1505
     1506                                        // Add historical avatar to the current activity.
     1507                                        $generated_content->user_profile_photo = array(
     1508                                                'value'             => $historical_avatar,
     1509                                                'sanitize_callback' => 'esc_url',
     1510                                        );
     1511
     1512                                        // Do not use a generated content.
     1513                                } else {
     1514                                        return false;
     1515                                }
     1516                        }
     1517
     1518                        if ( 'friendship_created' === $activity_type ) {
     1519                                $user_id = $activity->secondary_item_id;
     1520
     1521                                if ( isset( $bp->avatar->show_avatars ) && $bp->avatar->show_avatars ) {
     1522                                        $generated_content->user_profile_photo = array(
     1523                                                'value'             => bp_core_fetch_avatar(
     1524                                                        array(
     1525                                                                'item_id' => $user_id,
     1526                                                                'object'  => 'user',
     1527                                                                'type'    => 'full',
     1528                                                                'width'   => bp_core_avatar_full_width(),
     1529                                                                'height'  => bp_core_avatar_full_height(),
     1530                                                                'html'    => false,
     1531                                                        )
     1532                                                ),
     1533                                                'sanitize_callback' => 'esc_url',
     1534                                        );
     1535                                }
     1536                        }
     1537
     1538                        // Set common generated content properties.
     1539                        if ( 'new_avatar' === $activity_type || 'friendship_created' === $activity_type ) {
     1540                                $generated_content->user_url = array(
     1541                                        'value'             => bp_core_get_user_domain( $user_id ),
     1542                                        'sanitize_callback' => 'esc_url',
     1543                                );
     1544
     1545                                $generated_content->user_display_name = array(
     1546                                        'value'             => bp_core_get_user_displayname( $user_id ),
     1547                                        'sanitize_callback' => 'esc_html',
     1548                                );
     1549
     1550                                $generated_content->user_mention_name = array(
     1551                                        'value'             => bp_activity_get_user_mentionname( $user_id ),
     1552                                        'sanitize_callback' => 'esc_html',
     1553                                );
     1554
     1555                                $generated_content->user_mention_url = array(
     1556                                        'value'             => wp_nonce_url(
     1557                                                add_query_arg(
     1558                                                        array(
     1559                                                                'r' => $generated_content->user_mention_name['value'],
     1560                                                        ),
     1561                                                        bp_get_activity_directory_permalink()
     1562                                                )
     1563                                        ),
     1564                                        'sanitize_callback' => 'esc_url',
     1565                                );
     1566
     1567                                if ( bp_displayed_user_use_cover_image_header() ) {
     1568                                        $generated_content->user_cover_image = array(
     1569                                                'value'             => bp_attachments_get_attachment(
     1570                                                        'url',
     1571                                                        array(
     1572                                                                'object_dir' => 'members',
     1573                                                                'item_id'    => $user_id,
     1574                                                        )
     1575                                                ),
     1576                                                'sanitize_callback' => 'esc_url',
     1577                                        );
     1578                                }
     1579                        }
     1580
     1581                        if ( 'created_group' === $activity_type || 'joined_group' === $activity_type ) {
     1582                                $group = bp_get_group( $activity->item_id );
     1583
     1584                                if ( isset( $bp->avatar->show_avatars ) && $bp->avatar->show_avatars && ! bp_disable_group_avatar_uploads() ) {
     1585                                        $generated_content->group_profile_photo = array(
     1586                                                'value'             => bp_core_fetch_avatar(
     1587                                                        array(
     1588                                                                'item_id' => $group->id,
     1589                                                                'object'  => 'group',
     1590                                                                'type'    => 'full',
     1591                                                                'width'   => bp_core_avatar_full_width(),
     1592                                                                'height'  => bp_core_avatar_full_height(),
     1593                                                                'html'    => false,
     1594                                                        )
     1595                                                ),
     1596                                                'sanitize_callback' => 'esc_url',
     1597                                        );
     1598                                }
     1599
     1600                                $generated_content->group_url = array(
     1601                                        'value'             => bp_get_group_permalink( $group ),
     1602                                        'sanitize_callback' => 'esc_url',
     1603                                );
     1604
     1605                                $generated_content->group_name = array(
     1606                                        'value'             => bp_get_group_name( $group ),
     1607                                        'sanitize_callback' => 'esc_html',
     1608                                );
     1609
     1610                                if ( bp_group_use_cover_image_header() ) {
     1611                                        $generated_content->group_cover_image = array(
     1612                                                'value'             => bp_get_group_cover_url( $group ),
     1613                                                'sanitize_callback' => 'esc_url',
     1614                                        );
     1615                                }
     1616                        }
     1617
     1618                        // Update the corresponding entry into the activities template global.
     1619                        if ( get_object_vars( $generated_content ) ) {
     1620                                $activity_id    = $activities_template->activity->id;
     1621                                $activity_index = 0;
     1622
     1623                                // Find the activity index.
     1624                                while ( (int) $activities_template->activities[ $activity_index ]->id !== (int) $activity_id ) {
     1625                                        $activity_index++;
     1626                                }
     1627
     1628                                // Add the generated content object.
     1629                                $activities_template->activities[ $activity_index ]->generated_content = $generated_content;
     1630                                $has_content = true;
     1631                        }
     1632                }
    14351633        }
    14361634
    1437         return false;
     1635        return $has_content;
     1636}
     1637
     1638/**
     1639 * Does this property has been generated?
     1640 *
     1641 * @since 10.0.0
     1642 *
     1643 * @param string $property The name of the property to check into the generated content.
     1644 * @return bool            True if the property is not empty. False otherwise.
     1645 */
     1646function bp_activity_has_generated_content_part( $property = '' ) {
     1647        return bp_activity_get_generated_content_part( $property, 'boolean' );
     1648}
     1649
     1650/**
     1651 * Outputs a property of the activity generated content.
     1652 *
     1653 * @since 10.0.0
     1654 *
     1655 * @param string $property The name of the property to check into the generated content.
     1656 */
     1657function bp_activity_generated_content_part( $property = '' ) {
     1658        echo bp_activity_get_generated_content_part( $property );
    14381659}
    14391660
     1661        /**
     1662         * Returns the property of the activity generated content.
     1663         *
     1664         * @since 10.0.0
     1665         *
     1666         * @param string $property The name of the property to check into the generated content.
     1667         * @param string $return   Whether to return the property value or a boolean to check it exists.
     1668         * @return bool|string     A boolean when requested, false if there is no value, the HTML output otherwise.
     1669         */
     1670        function bp_activity_get_generated_content_part( $property = '', $return = '' ) {
     1671                global $activities_template;
     1672
     1673                if ( ! isset( $activities_template->activity->generated_content->{$property} ) ) {
     1674                        return false;
     1675                }
     1676
     1677                $content_part = $activities_template->activity->generated_content->{$property};
     1678
     1679                if ( ! isset( $content_part['value'] ) || ! $content_part['value'] ) {
     1680                        return false;
     1681                }
     1682
     1683                if ( 'boolean' === $return ) {
     1684                        return true;
     1685                }
     1686
     1687                /**
     1688                 * Filter here to edit the generated content part.
     1689                 *
     1690                 * @since 10.0.0
     1691                 *
     1692                 * @param string $value    The generated content part.
     1693                 * @param string $property The property the content part is attached to.
     1694                 */
     1695                $value = apply_filters( 'bp_activity_get_generated_content_part', $content_part['value'], $property );
     1696
     1697                if ( isset( $content_part['sanitize_callback'] ) && $content_part['sanitize_callback'] ) {
     1698                        return call_user_func( $content_part['sanitize_callback'], $value );
     1699                }
     1700
     1701                return $value;
     1702        }
     1703
    14401704/**
    14411705 * Output the activity content.
    14421706 *
  • src/bp-activity/classes/class-bp-activity-feed.php

    diff --git src/bp-activity/classes/class-bp-activity-feed.php src/bp-activity/classes/class-bp-activity-feed.php
    index bb984c1fa..b474a8f22 100644
    class BP_Activity_Feed { 
    298298         * @since 1.8.0
    299299         */
    300300        protected function feed_content() {
    301                 bp_activity_content_body();
     301                bp_activity_content_body( 'feed' );
    302302
    303303                switch ( $this->id ) {
    304304
  • src/bp-blogs/classes/class-bp-blogs-recent-posts-widget.php

    diff --git src/bp-blogs/classes/class-bp-blogs-recent-posts-widget.php src/bp-blogs/classes/class-bp-blogs-recent-posts-widget.php
    index 16a63af01..5d5a083c0 100644
    class BP_Blogs_Recent_Posts_Widget extends WP_Widget { 
    102102
    103103                                                        <?php if ( bp_get_activity_content_body() ) : ?>
    104104
    105                                                                 <div class="activity-inner"><?php bp_activity_content_body(); ?></div>
     105                                                                <div class="activity-inner"><?php bp_activity_content_body( 'widget' ); ?></div>
    106106
    107107                                                        <?php endif; ?>
    108108
  • src/bp-core/bp-core-attachments.php

    diff --git src/bp-core/bp-core-attachments.php src/bp-core/bp-core-attachments.php
    index e99ed0c14..a74069de5 100644
    function bp_attachments_create_item_type( $type = 'avatar', $args = array() ) { 
    409409
    410410        // It's an avatar, we need to crop it.
    411411        if ( 'avatar' === $type ) {
    412                 $created = bp_core_avatar_handle_crop( array(
    413                         'object'        => $r['object'],
    414                         'avatar_dir'    => trim( dirname( $attachment_data['subdir'] ), '/' ),
    415                         'item_id'       => (int) $r['item_id'],
    416                         'original_file' => trailingslashit( $attachment_data['subdir'] ) . $image_file_name,
    417                         'crop_w'        => $r['crop_w'],
    418                         'crop_h'        => $r['crop_h'],
    419                         'crop_x'        => $r['crop_x'],
    420                         'crop_y'        => $r['crop_y']
    421                 ) );
     412                $created = bp_core_avatar_handle_crop(
     413                        array(
     414                                'object'        => $r['object'],
     415                                'avatar_dir'    => trim( dirname( $attachment_data['subdir'] ), '/' ),
     416                                'item_id'       => (int) $r['item_id'],
     417                                'original_file' => trailingslashit( $attachment_data['subdir'] ) . $image_file_name,
     418                                'crop_w'        => $r['crop_w'],
     419                                'crop_h'        => $r['crop_h'],
     420                                'crop_x'        => $r['crop_x'],
     421                                'crop_y'        => $r['crop_y']
     422                        )
     423                );
    422424
    423425        // It's a cover image we need to fit it to feature's dimensions.
    424426        } elseif ( 'cover_image' === $type ) {
    425                 $cover_image = bp_attachments_cover_image_generate_file( array(
    426                         'file'            => $image_file_path,
    427                         'component'       => $r['component'],
    428                         'cover_image_dir' => $attachment_data['path']
    429                 ) );
     427                $cover_image = bp_attachments_cover_image_generate_file(
     428                        array(
     429                                'file'            => $image_file_path,
     430                                'component'       => $r['component'],
     431                                'cover_image_dir' => $attachment_data['path']
     432                        )
     433                );
    430434
    431435                $created = ! empty( $cover_image['cover_file'] );
    432436        }
    function bp_attachments_cover_image_ajax_delete() { 
    15971601        }
    15981602}
    15991603add_action( 'wp_ajax_bp_cover_image_delete', 'bp_attachments_cover_image_ajax_delete' );
     1604
     1605/**
     1606 * List the files of a directory.
     1607 *
     1608 * @since 10.0.0
     1609 *
     1610 * @param string $directory_path Absolute path of a directory.
     1611 * @return array The list of the files inside the directory.
     1612 */
     1613function bp_attachments_list_directory_files( $directory_path = '' ) {
     1614        if ( ! is_dir( $directory_path ) ) {
     1615                return array();
     1616        }
     1617
     1618        $files    = array();
     1619        $iterator = new FilesystemIterator( $directory_path, FilesystemIterator::SKIP_DOTS );
     1620
     1621        foreach ( $iterator as $file ) {
     1622                $_file = new stdClass();
     1623
     1624                $_file->name               = $file->getfilename();
     1625                $_file->path               = $file->getPathname();
     1626                $_file->size               = $file->getSize();
     1627                $_file->type               = $file->getType();
     1628                $_file->mime_type          = mime_content_type( $_file->path );
     1629                $_file->last_modified      = $file->getMTime();
     1630                $_file->latest_access_date = $file->getATime();
     1631                $_file->id                 = pathinfo( $_file->name, PATHINFO_FILENAME );
     1632                $files[ $_file->id ]       = $_file;
     1633        }
     1634
     1635        return $files;
     1636}
     1637
     1638/**
     1639 * List the files of a directory recursively and eventually find a file using its ID.
     1640 *
     1641 * @since 10.0.0
     1642 *
     1643 * @param string $directory_path Absolute path of a directory.
     1644 * @param string $find           The file ID to find into the directory or its children.
     1645 * @return array The list of the files.
     1646 */
     1647function bp_attachments_list_directory_files_recursively( $directory_path = '', $find = '' ) {
     1648        if ( ! is_dir( $directory_path ) ) {
     1649                return array();
     1650        }
     1651
     1652        $files     = array();
     1653        $directory = new RecursiveDirectoryIterator( $directory_path, FilesystemIterator::SKIP_DOTS );
     1654        $iterator  = new RecursiveIteratorIterator( $directory, RecursiveIteratorIterator::CHILD_FIRST );
     1655        $bp_upload = bp_upload_dir();
     1656
     1657        foreach ( $iterator as $file ) {
     1658                $_file = new stdClass();
     1659
     1660                $_file->name               = $file->getfilename();
     1661                $_file->path               = $file->getPathname();
     1662                $_file->size               = $file->getSize();
     1663                $_file->type               = $file->getType();
     1664                $_file->mime_type          = mime_content_type( $_file->path );
     1665                $_file->last_modified      = $file->getMTime();
     1666                $_file->latest_access_date = $file->getATime();
     1667                $_file->parent_dir_path    = dirname( $_file->path );
     1668                $_file->parent_dir_url     = str_replace( $bp_upload['basedir'], $bp_upload['baseurl'], $_file->parent_dir_path );
     1669                $_file->id                 = pathinfo( $_file->name, PATHINFO_FILENAME );
     1670
     1671                // Ensure URL is https if SSL is set/forced.
     1672                if ( is_ssl() ) {
     1673                        $_file->parent_dir_url = str_replace( 'http://', 'https://', $_file->parent_dir_url );
     1674                }
     1675
     1676                $file_id = $_file->id;
     1677                if ( $_file->parent_dir_path !== $directory_path ) {
     1678                        $file_id = trailingslashit( str_replace( trailingslashit( $directory_path ), '', $_file->parent_dir_path ) ) . $file_id;
     1679                }
     1680
     1681                $files[ $file_id ] = $_file;
     1682        }
     1683
     1684        if ( $find ) {
     1685                return wp_filter_object_list( $files, array( 'id' => $find ) );
     1686        }
     1687
     1688        return $files;
     1689}
  • src/bp-core/bp-core-avatars.php

    diff --git src/bp-core/bp-core-avatars.php src/bp-core/bp-core-avatars.php
    index 301c6bfdc..7336c6d3b 100644
    add_action( 'wp_ajax_bp_avatar_upload', 'bp_avatar_ajax_upload' ); 
    11761176 * Handle avatar webcam capture.
    11771177 *
    11781178 * @since 2.3.0
     1179 * @since 10.0.0 Adds the `$return` param to eventually return the crop result.
    11791180 *
    11801181 * @param string $data    Base64 encoded image.
    11811182 * @param int    $item_id Item to associate.
    1182  * @return bool True on success, false on failure.
     1183 * @param string $return  Whether to get the crop `array` or a `boolean`. Defaults to `boolean`.
     1184 * @return array|bool True on success, false on failure.
    11831185 */
    1184 function bp_avatar_handle_capture( $data = '', $item_id = 0 ) {
     1186function bp_avatar_handle_capture( $data = '', $item_id = 0, $return = 'boolean' ) {
    11851187        if ( empty( $data ) || empty( $item_id ) ) {
    11861188                return false;
    11871189        }
    function bp_avatar_handle_capture( $data = '', $item_id = 0 ) { 
    12371239                // Crop to default values.
    12381240                $crop_args = array( 'item_id' => $item_id, 'original_file' => $avatar_to_crop, 'crop_x' => 0, 'crop_y' => 0 );
    12391241
     1242                if ( 'array' === $return ) {
     1243                        return bp_core_avatar_handle_crop( $crop_args, 'array' );
     1244                }
     1245
    12401246                return bp_core_avatar_handle_crop( $crop_args );
    12411247        } else {
    12421248                return false;
    function bp_avatar_handle_capture( $data = '', $item_id = 0 ) { 
    12471253 * Crop an uploaded avatar.
    12481254 *
    12491255 * @since 1.1.0
     1256 * @since 10.0.0 Adds the `$return` param to eventually return the crop result.
    12501257 *
    12511258 * @param array|string $args {
    12521259 *     Array of function parameters.
    function bp_avatar_handle_capture( $data = '', $item_id = 0 ) { 
    12651272 *     @type int         $crop_x        The horizontal starting point of the crop. Default: 0.
    12661273 *     @type int         $crop_y        The vertical starting point of the crop. Default: 0.
    12671274 * }
    1268  * @return bool True on success, false on failure.
     1275 * @param string       $return Whether to get the crop `array` or a `boolean`. Defaults to `boolean`.
     1276 * @return array|bool True or the crop result on success, false on failure.
    12691277 */
    1270 function bp_core_avatar_handle_crop( $args = '' ) {
     1278function bp_core_avatar_handle_crop( $args = '', $return = 'boolean' ) {
    12711279
    12721280        $r = bp_parse_args(
    12731281                $args,
    function bp_core_avatar_handle_crop( $args = '' ) { 
    13061314                return false;
    13071315        }
    13081316
     1317        if ( 'array' === $return ) {
     1318                return $cropped;
     1319        }
     1320
    13091321        return true;
    13101322}
    13111323
    function bp_avatar_ajax_set() { 
    13521364                        $webcam_avatar = base64_decode( $webcam_avatar );
    13531365                }
    13541366
    1355                 if ( ! bp_avatar_handle_capture( $webcam_avatar, $avatar_data['item_id'] ) ) {
     1367                $cropped_webcam_avatar = bp_avatar_handle_capture( $webcam_avatar, $avatar_data['item_id'], 'array' );
     1368
     1369                if ( ! $cropped_webcam_avatar ) {
    13561370                        wp_send_json_error( array(
    13571371                                'feedback_code' => 1
    13581372                        ) );
    13591373
    13601374                } else {
    13611375                        $return = array(
    1362                                 'avatar' => esc_url( bp_core_fetch_avatar( array(
    1363                                         'object'  => $avatar_data['object'],
    1364                                         'item_id' => $avatar_data['item_id'],
    1365                                         'html'    => false,
    1366                                         'type'    => 'full',
    1367                                 ) ) ),
     1376                                'avatar' => esc_url(
     1377                                        bp_core_fetch_avatar(
     1378                                                array(
     1379                                                        'object'  => $avatar_data['object'],
     1380                                                        'item_id' => $avatar_data['item_id'],
     1381                                                        'html'    => false,
     1382                                                        'type'    => 'full',
     1383                                                )
     1384                                        )
     1385                                ),
    13681386                                'feedback_code' => 2,
    13691387                                'item_id'       => $avatar_data['item_id'],
    13701388                        );
    function bp_avatar_ajax_set() { 
    13761394                         * Fires if the new avatar was successfully captured.
    13771395                         *
    13781396                         * @since 6.0.0
     1397                         * @since 10.0.0 Adds a new param: an array containing the full, thumb avatar and the timestamp.
    13791398                         *
    1380                          * @param string $item_id     Inform about the user id the avatar was set for.
    1381                          * @param string $type        Inform about the way the avatar was set ('camera').
    1382                          * @param array  $avatar_data Array of parameters passed to the avatar handler.
     1399                         * @param string $item_id               Inform about the user id the avatar was set for.
     1400                         * @param string $type                  Inform about the way the avatar was set ('camera').
     1401                         * @param array  $avatar_data           Array of parameters passed to the crop handler.
     1402                         * @param array  $cropped_webcam_avatar Array containing the full, thumb avatar and the timestamp.
    13831403                         */
    1384                         do_action( 'bp_members_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $avatar_data );
     1404                        do_action( 'bp_members_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $avatar_data, $cropped_webcam_avatar );
    13851405
    13861406                        wp_send_json_success( $return );
    13871407                }
    function bp_avatar_ajax_set() { 
    14131433        );
    14141434
    14151435        // Handle crop.
    1416         if ( bp_core_avatar_handle_crop( $r ) ) {
     1436        $cropped_avatar = bp_core_avatar_handle_crop( $r, 'array' );
     1437
     1438        if ( $cropped_avatar ) {
    14171439                $return = array(
    1418                         'avatar' => esc_url( bp_core_fetch_avatar( array(
    1419                                 'object'  => $avatar_data['object'],
    1420                                 'item_id' => $avatar_data['item_id'],
    1421                                 'html'    => false,
    1422                                 'type'    => 'full',
    1423                         ) ) ),
     1440                        'avatar' => esc_url(
     1441                                bp_core_fetch_avatar(
     1442                                        array(
     1443                                                'object'  => $avatar_data['object'],
     1444                                                'item_id' => $avatar_data['item_id'],
     1445                                                'html'    => false,
     1446                                                'type'    => 'full',
     1447                                        )
     1448                                )
     1449                        ),
    14241450                        'feedback_code' => 2,
    14251451                        'item_id'       => $avatar_data['item_id'],
    14261452                );
    function bp_avatar_ajax_set() { 
    14301456                        do_action_deprecated( 'xprofile_avatar_uploaded', array( (int) $avatar_data['item_id'], $avatar_data['type'], $r ), '6.0.0', 'bp_members_avatar_uploaded' );
    14311457
    14321458                        /** This action is documented in bp-core/bp-core-avatars.php */
    1433                         do_action( 'bp_members_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $r );
     1459                        do_action( 'bp_members_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $r, $cropped_avatar );
    14341460                } elseif ( 'group' === $avatar_data['object'] ) {
    14351461                        /** This action is documented in bp-groups/bp-groups-screens.php */
    1436                         do_action( 'groups_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $r );
     1462                        do_action( 'groups_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $r, $cropped_avatar );
    14371463                }
    14381464
    14391465                wp_send_json_success( $return );
    function bp_avatar_template_check() { 
    21222148                bp_attachments_get_template_part( 'avatars/index' );
    21232149        }
    21242150}
     2151
     2152/**
     2153 * Get a specific version of an avatar from its history
     2154 *
     2155 * @since 10.0.0
     2156 *
     2157 * @param int        $user_id   The user ID we need the avatar version for.
     2158 * @param int|string $timestamp An integer Unix timestamp or a date string of the format 'Y-m-d h:i:s'.
     2159 * @param string     $type      The type of avatar we need. Possible values are `thumb` and `full`.
     2160 * @return array                A list of matching results, an empty array if no avatars were found.
     2161 */
     2162function bp_avatar_get_version_src( $user_id = 0, $timestamp = '', $type = 'full' ) {
     2163        if ( ! $user_id || ! $timestamp ) {
     2164                return array();
     2165        }
     2166
     2167        if ( ! is_numeric( $timestamp ) ) {
     2168                $timestamp = strtotime( $timestamp );
     2169        }
     2170
     2171        $avatar_id = $timestamp . '-bpfull';
     2172        if ( 'full' !== $type ) {
     2173                $avatar_id = $timestamp . '-bpthumb';
     2174        }
     2175
     2176        // The user avatar directory we are looking into to get the avatar url.
     2177        $user_avatar_dir = trailingslashit( bp_core_avatar_upload_path() ) . 'avatars/' . $user_id;
     2178
     2179        return bp_attachments_list_directory_files_recursively( $user_avatar_dir, $avatar_id );
     2180}
  • src/bp-core/classes/class-bp-attachment-avatar.php

    diff --git src/bp-core/classes/class-bp-attachment-avatar.php src/bp-core/classes/class-bp-attachment-avatar.php
    index d95ad4c4c..926feda30 100644
    class BP_Attachment_Avatar extends BP_Attachment { 
    199199         * @see  BP_Attachment::crop for the list of parameters
    200200         *
    201201         * @param array $args Array of arguments for the cropping.
    202          * @return array The cropped avatars (full and thumb).
     202         * @return array The cropped avatars (full, thumb and the timestamp).
    203203         */
    204204        public function crop( $args = array() ) {
    205205                // Bail if the original file is missing.
    class BP_Attachment_Avatar extends BP_Attachment { 
    255255
    256256                /**
    257257                 * Check that the new avatar doesn't have the same name as the
    258                  * old one before deleting
     258                 * old one before moving the previous one into history.
    259259                 */
    260260                if ( ! empty( $existing_avatar ) && $existing_avatar !== $this->url . $relative_path ) {
    261                         bp_core_delete_existing_avatar( array( 'object' => $args['object'], 'item_id' => $args['item_id'], 'avatar_path' => $avatar_folder_dir ) );
     261                        // Add a new revision for the existing avatar.
     262                        $avatars = bp_attachments_list_directory_files( $avatar_folder_dir );
     263
     264                        if ( $avatars ) {
     265                                foreach ( $avatars as $avatar_file ) {
     266                                        if ( ! isset( $avatar_file->name, $avatar_file->id, $avatar_file->path ) ) {
     267                                                continue;
     268                                        }
     269
     270                                        $is_full  = preg_match( "/-bpfull/", $avatar_file->name );
     271                                        $is_thumb = preg_match( "/-bpthumb/", $avatar_file->name );
     272
     273                                        if ( $is_full || $is_thumb ) {
     274                                                $revision = $this->add_revision(
     275                                                        'avatar',
     276                                                        array(
     277                                                                'file_abspath' => $avatar_file->path,
     278                                                                'file_id'      => $avatar_file->id,
     279                                                        )
     280                                                );
     281
     282                                                if ( is_wp_error( $revision ) ) {
     283                                                        error_log( $revision->get_error_message() );
     284                                                }
     285                                        }
     286                                }
     287                        }
    262288                }
    263289
    264290                // Make sure we at least have minimal data for cropping.
    class BP_Attachment_Avatar extends BP_Attachment { 
    272298
    273299                // Get the file extension.
    274300                $data = @getimagesize( $absolute_path );
    275                 $ext  = $data['mime'] == 'image/png' ? 'png' : 'jpg';
     301                $ext  = $data['mime'] === 'image/png' ? 'png' : 'jpg';
    276302
    277303                $args['original_file'] = $absolute_path;
    278304                $args['src_abs']       = false;
    279                 $avatar_types = array( 'full' => '', 'thumb' => '' );
     305
     306                $avatar_types = array(
     307                        'full'  => '',
     308                        'thumb' => '',
     309                );
     310                $timestamp   = bp_core_current_time( true, 'timestamp' );
    280311
    281312                foreach ( $avatar_types as $key_type => $type ) {
    282313                        if ( 'thumb' === $key_type ) {
    class BP_Attachment_Avatar extends BP_Attachment { 
    287318                                $args['dst_h'] = bp_core_avatar_full_height();
    288319                        }
    289320
    290                         $filename         = wp_unique_filename( $avatar_folder_dir, uniqid() . "-bp{$key_type}.{$ext}" );
     321                        $filename         = wp_unique_filename( $avatar_folder_dir, $timestamp . "-bp{$key_type}.{$ext}" );
    291322                        $args['dst_file'] = $avatar_folder_dir . '/' . $filename;
    292323
    293324                        $avatar_types[ $key_type ] = parent::crop( $args );
    class BP_Attachment_Avatar extends BP_Attachment { 
    296327                // Remove the original.
    297328                @unlink( $absolute_path );
    298329
    299                 // Return the full and thumb cropped avatars.
    300                 return $avatar_types;
     330                // Return the full, thumb cropped avatars and the timestamp.
     331                return array_merge(
     332                        $avatar_types,
     333                        array(
     334                                'timestamp' => $timestamp,
     335                        )
     336                );
    301337        }
    302338
    303339        /**
  • src/bp-core/classes/class-bp-attachment.php

    diff --git src/bp-core/classes/class-bp-attachment.php src/bp-core/classes/class-bp-attachment.php
    index 9362a6c12..248c44946 100644
    abstract class BP_Attachment { 
    559559                return $script_data;
    560560        }
    561561
     562        /**
     563         * Adds a new revision of a file.
     564         *
     565         * @since 10.0.0
     566         *
     567         * @param string $attachment_type The attachement type (eg: avatar).
     568         * @param array $args {
     569         *     @type string $file_abspath The source file (absolute path) for the attachment.
     570         *     @type string $file_id      Optional. The file ID to use as a suffix for the revision directory.
     571         * }
     572         * @return object|WP_Error An object informing about the URL an Path to a revision file, a WP_Error object on failure.
     573         */
     574        public function add_revision( $attachment_type, $args = array() ) {
     575                $r = bp_parse_args(
     576                        $args,
     577                        array(
     578                                'file_abspath' => '',
     579                                'file_id'      => '',
     580                        ),
     581                        'attachment_' . $attachment_type . '_add_revision'
     582                );
     583
     584                if ( ! $r['file_abspath'] ) {
     585                        return new WP_Error( 'missing_parameter', __( 'The absolute path to your file is missing.', 'buddypress' ) );
     586
     587                        // Make sure it's coming from an uploaded file.
     588                } elseif ( false === strpos( $r['file_abspath'], $this->upload_path ) ) {
     589                        return new WP_Error( 'forbidden_path', __( 'The absolute path to your file is not allowed.', 'buddypress' ) );
     590
     591                } else {
     592                        $filepath = $r['file_abspath'];
     593                }
     594
     595                $dirname  = trailingslashit( dirname( $filepath ) );
     596                $filename = sanitize_file_name( wp_basename( $filepath ) );
     597
     598                if ( ! $r['file_id'] ) {
     599                        $r['file_id'] = $filename;
     600                }
     601
     602                $file_id = wp_hash( $r['file_id'] );
     603
     604                // Set the revision name & dir.
     605                $revision_name = '';
     606                $revision_dir  = $dirname . '._revisions_' . $file_id;
     607
     608                // Avatars and Cover Images are specific attachments.
     609                if ( 'avatar' === $attachment_type || 'cover_image' === $attachment_type ) {
     610                        $revision_dir  = $dirname . 'history';
     611                }
     612
     613                // Create the revision directory if it doesn't exist yet.
     614                if ( ! is_dir( $revision_dir ) ) {
     615                        mkdir( $revision_dir );
     616                }
     617
     618                $revision_name = wp_unique_filename( $revision_dir, $filename );
     619                $revision_path = trailingslashit( $revision_dir ) . $revision_name;
     620
     621                if ( ! rename( $filepath, $revision_path ) ) {
     622                        return new WP_Error( 'missing_parameter', __( 'An unexpected error occured while adding the revision.', 'buddypress' ) );
     623                }
     624
     625                return (object) array(
     626                        'url'  => str_replace( trailingslashit( $this->upload_path ), trailingslashit( $this->url ), $revision_path ),
     627                        'path' => $revision_path,
     628                );
     629        }
     630
    562631        /**
    563632         * Get full data for an image
    564633         *
  • src/bp-groups/actions/create.php

    diff --git src/bp-groups/actions/create.php src/bp-groups/actions/create.php
    index 132429bd1..54e2cc589 100644
    function groups_action_create_group() { 
    270270                                'crop_h'        => $_POST['h']
    271271                        );
    272272
    273                         if ( ! bp_core_avatar_handle_crop( $args ) ) {
     273                        $cropped_avatar = bp_core_avatar_handle_crop( $args, 'array' );
     274
     275                        if ( ! $cropped_avatar ) {
    274276                                bp_core_add_message( __( 'There was an error saving the group profile photo, please try uploading again.', 'buddypress' ), 'error' );
    275277                        } else {
    276278                                /**
    277279                                 * Fires after a group avatar is uploaded.
    278280                                 *
    279281                                 * @since 2.8.0
     282                                 * @since 10.0.0 Adds a new param: an array containing the full, thumb avatar and the timestamp.
    280283                                 *
    281                                  * @param int    $group_id ID of the group.
    282                                  * @param string $type     Avatar type. 'crop' or 'full'.
    283                                  * @param array  $args     Array of parameters passed to the avatar handler.
     284                                 * @param int    $group_id       ID of the group.
     285                                 * @param string $type           Avatar type. 'crop' or 'camera'.
     286                                 * @param array  $args           Array of parameters passed to the crop handler.
     287                                 * @param array  $cropped_avatar Array containing the full, thumb avatar and the timestamp.
    284288                                 */
    285                                 do_action( 'groups_avatar_uploaded', bp_get_current_group_id(), 'crop', $args );
     289                                do_action( 'groups_avatar_uploaded', bp_get_current_group_id(), 'crop', $args, $cropped_avatar );
    286290
    287291                                bp_core_add_message( __( 'The group profile photo was uploaded successfully.', 'buddypress' ) );
    288292                        }
  • src/bp-groups/screens/single/admin/group-avatar.php

    diff --git src/bp-groups/screens/single/admin/group-avatar.php src/bp-groups/screens/single/admin/group-avatar.php
    index 3e2927a1e..57fc59451 100644
    function groups_screen_group_admin_avatar() { 
    7474                        'crop_h'        => $_POST['h']
    7575                );
    7676
    77                 if ( !bp_core_avatar_handle_crop( $args ) ) {
     77                $cropped_avatar = bp_core_avatar_handle_crop( $args, 'array' );
     78
     79                if ( ! $cropped_avatar ) {
    7880                        bp_core_add_message( __( 'There was a problem cropping the group profile photo.', 'buddypress' ), 'error' );
    7981                } else {
    8082                        /**
    8183                         * Fires after a group avatar is uploaded.
    8284                         *
    8385                         * @since 2.8.0
     86                         * @since 10.0.0 Adds a new param: an array containing the full, thumb avatar and the timestamp.
    8487                         *
    85                          * @param int    $group_id ID of the group.
    86                          * @param string $type     Avatar type. 'crop' or 'full'.
    87                          * @param array  $args     Array of parameters passed to the avatar handler.
     88                         * @param int    $group_id       ID of the group.
     89                         * @param string $type           Avatar type. 'crop' or 'camera'.
     90                         * @param array  $args           Array of parameters passed to the avatar handler.
     91                         * @param array  $cropped_avatar Array containing the full, thumb avatar and the timestamp.
    8892                         */
    89                         do_action( 'groups_avatar_uploaded', bp_get_current_group_id(), 'crop', $args );
     93                        do_action( 'groups_avatar_uploaded', bp_get_current_group_id(), 'crop', $args, $cropped_avatar );
    9094                        bp_core_add_message( __( 'The new group profile photo was uploaded successfully.', 'buddypress' ) );
    9195                }
    9296        }
    function groups_screen_group_admin_avatar() { 
    109113         */
    110114        bp_core_load_template( apply_filters( 'groups_template_group_admin_avatar', 'groups/single/home' ) );
    111115}
    112 add_action( 'bp_screens', 'groups_screen_group_admin_avatar' );
    113  No newline at end of file
     116add_action( 'bp_screens', 'groups_screen_group_admin_avatar' );
  • src/bp-members/bp-members-activity.php

    diff --git src/bp-members/bp-members-activity.php src/bp-members/bp-members-activity.php
    index 890ff2317..1645c1542 100644
    add_action( 'bp_core_activated_user', 'bp_core_new_user_activity' ); 
    166166 * Adds an activity stream item when a user has uploaded a new avatar.
    167167 *
    168168 * @since 8.0.0
     169 * @since 10.0.0 Adds the `$type`, `$crop_data` and `$cropped_avatar` parameters.
    169170 *
    170  * @param int $user_id The user id the avatar was set for.
     171 * @param int    $user_id        The user id the avatar was set for.
     172 * @param string $type           The way the avatar was set ('camera' or `crop`).
     173 * @param array  $crop_data      Array of parameters passed to the crop handler.
     174 * @param array  $cropped_avatar Array containing the full, thumb avatar and the timestamp.
    171175 */
    172 function bp_members_new_avatar_activity( $user_id = 0 ) {
     176function bp_members_new_avatar_activity( $user_id = 0, $type = '', $crop_data = array(), $cropped_avatar = array() ) {
    173177
    174178        // Bail if activity component is not active.
    175179        if ( ! bp_is_active( 'activity' ) ) {
    function bp_members_new_avatar_activity( $user_id = 0 ) { 
    230234                }
    231235        }
    232236
     237        $recorded_time = '';
     238        if ( isset( $cropped_avatar['timestamp'] ) && $cropped_avatar['timestamp'] ) {
     239                $recorded_time = date( 'Y-m-d H:i:s', $cropped_avatar['timestamp'] );
     240        }
     241
    233242        // Add the activity.
    234         bp_activity_add(
     243        $activity_id = bp_activity_add(
    235244                array(
    236                         'user_id'   => $user_id,
    237                         'component' => $bp->members->id,
    238                         'type'      => 'new_avatar',
     245                        'user_id'       => $user_id,
     246                        'component'     => $bp->members->id,
     247                        'type'          => 'new_avatar',
     248                        'recorded_time' => $recorded_time,
    239249                )
    240250        );
    241251}
    242 add_action( 'bp_members_avatar_uploaded', 'bp_members_new_avatar_activity' );
     252add_action( 'bp_members_avatar_uploaded', 'bp_members_new_avatar_activity', 10, 4 );
  • src/bp-members/screens/change-avatar.php

    diff --git src/bp-members/screens/change-avatar.php src/bp-members/screens/change-avatar.php
    index 5c4bcf440..6a421ec77 100644
    function bp_members_screen_change_avatar() { 
    6161                        'crop_h'        => $_POST['h']
    6262                );
    6363
    64                 if ( ! bp_core_avatar_handle_crop( $args ) ) {
     64                // Handle crop.
     65                $cropped_avatar = bp_core_avatar_handle_crop( $r, 'array' );
     66
     67                if ( ! $cropped_avatar ) {
    6568                        bp_core_add_message( __( 'There was a problem cropping your profile photo.', 'buddypress' ), 'error' );
    6669                } else {
    6770
    function bp_members_screen_change_avatar() { 
    7275                         * Fires right before the redirect, after processing a new avatar.
    7376                         *
    7477                         * @since 6.0.0
     78                         * @since 10.0.0 Adds a new param: an array containing the full, thumb avatar and the timestamp.
    7579                         *
    76                          * @param string $item_id Inform about the user id the avatar was set for.
    77                          * @param string $value   Inform about the way the avatar was set ('crop').
     80                         * @param string $item_id        Inform about the user id the avatar was set for.
     81                         * @param string $type           Inform about the way the avatar was set ('camera').
     82                         * @param array  $args           Array of parameters passed to the crop handler.
     83                         * @param array  $cropped_avatar Array containing the full, thumb avatar and the timestamp.
    7884                         */
    79                         do_action( 'bp_members_avatar_uploaded', (int) $args['item_id'], 'crop' );
     85                        do_action( 'bp_members_avatar_uploaded', (int) $args['item_id'], 'crop', $args, $cropped_avatar );
    8086
    8187                        bp_core_add_message( __( 'Your new profile photo was uploaded successfully.', 'buddypress' ) );
    8288                        bp_core_redirect( bp_displayed_user_domain() );
  • new file src/bp-templates/bp-legacy/buddypress/activity/type-parts/created-group.php

    diff --git src/bp-templates/bp-legacy/buddypress/activity/type-parts/created-group.php src/bp-templates/bp-legacy/buddypress/activity/type-parts/created-group.php
    new file mode 100644
    index 000000000..af25c0b34
    - +  
     1<?php
     2/**
     3 * BuddyPress - `created_group` activity type content part.
     4 *
     5 * This template is only used to display the `created_group` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10?>
     11<div class="bp-group-activity-preview">
     12
     13        <?php if ( bp_activity_has_generated_content_part( 'group_cover_image' ) ) : ?>
     14                <div class="bp-group-preview-cover">
     15                        <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>">
     16                                <img src="<?php bp_activity_generated_content_part( 'group_cover_image' ); ?>" alt=""/>
     17                        </a>
     18                </div>
     19        <?php endif; ?>
     20
     21        <div class="bp-group-short-description">
     22                <?php if ( bp_activity_has_generated_content_part( 'group_profile_photo' ) ) : ?>
     23                        <div class="bp-group-avatar-content <?php echo bp_activity_has_generated_content_part( 'group_cover_image' ) ? 'has-cover-image' : ''; ?>">
     24                                <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>">
     25                                        <img src="<?php bp_activity_generated_content_part( 'group_profile_photo' ); ?>" class="profile-photo avatar" alt=""/>
     26                                </a>
     27                        </div>
     28                <?php endif; ?>
     29
     30                <p class="bp-group-short-description-title">
     31                        <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>"><?php bp_activity_generated_content_part( 'group_name' ); ?></a>
     32                </p>
     33
     34                <div class="bp-profile-button">
     35                        <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>" class="button large primary button-primary" role="button"><?php esc_html_e( 'Visit group', 'buddypress'); ?></a>
     36                </div>
     37        </div>
     38</div>
  • new file src/bp-templates/bp-legacy/buddypress/activity/type-parts/friendship-created.php

    diff --git src/bp-templates/bp-legacy/buddypress/activity/type-parts/friendship-created.php src/bp-templates/bp-legacy/buddypress/activity/type-parts/friendship-created.php
    new file mode 100644
    index 000000000..b4ba00655
    - +  
     1<?php
     2/**
     3 * BuddyPress - `friendship_created` activity type content part.
     4 *
     5 * This template is only used to display the `friendship_created` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10
     11bp_get_template_part( 'activity/type-parts/new-avatar' );
  • new file src/bp-templates/bp-legacy/buddypress/activity/type-parts/joined-group.php

    diff --git src/bp-templates/bp-legacy/buddypress/activity/type-parts/joined-group.php src/bp-templates/bp-legacy/buddypress/activity/type-parts/joined-group.php
    new file mode 100644
    index 000000000..c83469b9d
    - +  
     1<?php
     2/**
     3 * BuddyPress - `joined_group` activity type content part.
     4 *
     5 * This template is only used to display the `joined_group` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10
     11bp_get_template_part( 'activity/type-parts/created-group' );
  • new file src/bp-templates/bp-legacy/buddypress/activity/type-parts/new-avatar.php

    diff --git src/bp-templates/bp-legacy/buddypress/activity/type-parts/new-avatar.php src/bp-templates/bp-legacy/buddypress/activity/type-parts/new-avatar.php
    new file mode 100644
    index 000000000..c4976130b
    - +  
     1<?php
     2/**
     3 * BuddyPress - `new_avatar` activity type content part.
     4 *
     5 * This template is only used to display the `new_avatar` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10?>
     11<div class="bp-member-activity-preview">
     12
     13        <?php if ( bp_activity_has_generated_content_part( 'user_cover_image' ) ) : ?>
     14                <div class="bp-member-preview-cover">
     15                        <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>">
     16                                <img src="<?php bp_activity_generated_content_part( 'user_cover_image' ); ?>" alt=""/>
     17                        </a>
     18                </div>
     19        <?php endif; ?>
     20
     21        <div class="bp-member-short-description">
     22                <?php if ( bp_activity_has_generated_content_part( 'user_profile_photo' ) ) : ?>
     23                        <div class="bp-member-avatar-content <?php echo bp_activity_has_generated_content_part( 'user_cover_image' ) ? 'has-cover-image' : ''; ?>">
     24                                <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>">
     25                                        <img src="<?php bp_activity_generated_content_part( 'user_profile_photo' ); ?>" class="profile-photo avatar" alt=""/>
     26                                </a>
     27                        </div>
     28                <?php endif; ?>
     29
     30                <p class="bp-member-short-description-title">
     31                        <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>"><?php bp_activity_generated_content_part( 'user_display_name' ); ?></a>
     32                </p>
     33
     34                <p class="bp-member-nickname">
     35                        <a href="<?php is_user_logged_in() ? bp_activity_generated_content_part( 'user_mention_url' ) : bp_activity_generated_content_part( 'user_url' ); ?>">@<?php bp_activity_generated_content_part( 'user_mention_name' ); ?></a>
     36                </p>
     37
     38                <div class="bp-profile-button">
     39                        <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>" class="button large primary button-primary" role="button"><?php esc_html_e( 'View Profile', 'buddypress'); ?></a>
     40                </div>
     41        </div>
     42</div>
  • src/bp-templates/bp-legacy/css/buddypress-rtl.css

    diff --git src/bp-templates/bp-legacy/css/buddypress-rtl.css src/bp-templates/bp-legacy/css/buddypress-rtl.css
    index d99591d63..5e889c519 100644
    Hello, this is the BuddyPress Legacy stylesheet. 
    3030        4.1 - Smartphones Landscape
    3131        4.2 - Smartphones Portrait
    3232        4.3 - Smartphones - smaller screen sizes
     335.0 - Activity Types.
    3334--------------------------------------------------------------*/
    3435
    3536/*--------------------------------------------------------------
    body.register #buddypress div.page ul { 
    22812282                margin: 10px 0 20px;
    22822283        }
    22832284}
     2285
     2286/*--------------------------------------------------------------
     22875.0 - Activity Types
     2288--------------------------------------------------------------*/
     2289.bp-member-preview-cover,
     2290.bp-group-preview-cover {
     2291        position: relative;
     2292        min-height: 150px;
     2293        background: #c5c5c5;
     2294}
     2295
     2296.bp-member-preview-cover img,
     2297.bp-group-preview-cover img {
     2298        background: #c5c5c5;
     2299        -o-object-fit: cover;
     2300        object-fit: cover;
     2301        border: 0;
     2302        display: block;
     2303        margin: 0;
     2304        padding: 0;
     2305        width: 100%;
     2306        z-index: 1;
     2307        height: 150px;
     2308}
     2309
     2310.bp-member-avatar-content,
     2311.bp-group-avatar-content {
     2312        float: right;
     2313        width: 120px;
     2314        position: relative;
     2315        z-index: 2;
     2316}
     2317
     2318.bp-member-avatar-content.has-cover-image,
     2319.bp-group-avatar-content.has-cover-image {
     2320        width: 200px;
     2321        margin-top: -75px;
     2322}
     2323
     2324.bp-member-avatar-content img.profile-photo,
     2325.bp-group-avatar-content img.group-photo {
     2326        border: solid 2px #fff;
     2327        background: rgba(255, 255, 255, 0.8);
     2328        margin-right: 20px;
     2329        height: 80px;
     2330        width: 80px;
     2331}
     2332
     2333.bp-member-avatar-content.has-cover-image img.profile-photo,
     2334.bp-member-avatar-content.has-cover-image img.group-photo,
     2335.bp-group-avatar-content.has-cover-image img.profile-photo,
     2336.bp-group-avatar-content.has-cover-image img.group-photo {
     2337        height: inherit;
     2338        width: inherit;
     2339}
     2340
     2341.bp-member-short-description-title a,
     2342.bp-group-short-description-title a {
     2343        font-weight: 600;
     2344}
     2345
     2346@media screen and (max-width: 46.8em) {
     2347
     2348        .bp-member-short-description,
     2349        .bp-group-short-description {
     2350                text-align: center;
     2351        }
     2352
     2353        .bp-member-avatar-content,
     2354        .bp-group-avatar-content {
     2355                float: none;
     2356                width: 100%;
     2357                margin-right: auto;
     2358                margin-left: auto;
     2359                margin-bottom: 15px;
     2360        }
     2361
     2362        .bp-member-avatar-content img.profile-photo,
     2363        .bp-group-avatar-content img.group-photo {
     2364                margin: auto;
     2365        }
     2366
     2367        .bp-profile-button {
     2368                margin-top: 15px;
     2369        }
     2370}
     2371
     2372@media screen and (min-width: 46.8em) {
     2373
     2374        .bp-profile-button {
     2375                text-align: left;
     2376        }
     2377}
  • 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 be7270d71..e7efa2db9 100644
    Hello, this is the BuddyPress Legacy stylesheet. 
    3030        4.1 - Smartphones Landscape
    3131        4.2 - Smartphones Portrait
    3232        4.3 - Smartphones - smaller screen sizes
     335.0 - Activity Types.
    3334--------------------------------------------------------------*/
    3435
    3536/*--------------------------------------------------------------
    body.register #buddypress div.page ul { 
    22812282                margin: 10px 0 20px;
    22822283        }
    22832284}
     2285
     2286/*--------------------------------------------------------------
     22875.0 - Activity Types
     2288--------------------------------------------------------------*/
     2289.bp-member-preview-cover,
     2290.bp-group-preview-cover {
     2291        position: relative;
     2292        min-height: 150px;
     2293        background: #c5c5c5;
     2294}
     2295
     2296.bp-member-preview-cover img,
     2297.bp-group-preview-cover img {
     2298        background: #c5c5c5;
     2299        -o-object-fit: cover;
     2300        object-fit: cover;
     2301        border: 0;
     2302        display: block;
     2303        margin: 0;
     2304        padding: 0;
     2305        width: 100%;
     2306        z-index: 1;
     2307        height: 150px;
     2308}
     2309
     2310.bp-member-avatar-content,
     2311.bp-group-avatar-content {
     2312        float: left;
     2313        width: 120px;
     2314        position: relative;
     2315        z-index: 2;
     2316}
     2317
     2318.bp-member-avatar-content.has-cover-image,
     2319.bp-group-avatar-content.has-cover-image {
     2320        width: 200px;
     2321        margin-top: -75px;
     2322}
     2323
     2324.bp-member-avatar-content img.profile-photo,
     2325.bp-group-avatar-content img.group-photo {
     2326        border: solid 2px #fff;
     2327        background: rgba(255, 255, 255, 0.8);
     2328        margin-left: 20px;
     2329        height: 80px;
     2330        width: 80px;
     2331}
     2332
     2333.bp-member-avatar-content.has-cover-image img.profile-photo,
     2334.bp-member-avatar-content.has-cover-image img.group-photo,
     2335.bp-group-avatar-content.has-cover-image img.profile-photo,
     2336.bp-group-avatar-content.has-cover-image img.group-photo {
     2337        height: inherit;
     2338        width: inherit;
     2339}
     2340
     2341.bp-member-short-description-title a,
     2342.bp-group-short-description-title a {
     2343        font-weight: 600;
     2344}
     2345
     2346@media screen and (max-width: 46.8em) {
     2347
     2348        .bp-member-short-description,
     2349        .bp-group-short-description {
     2350                text-align: center;
     2351        }
     2352
     2353        .bp-member-avatar-content,
     2354        .bp-group-avatar-content {
     2355                float: none;
     2356                width: 100%;
     2357                margin-left: auto;
     2358                margin-right: auto;
     2359                margin-bottom: 15px;
     2360        }
     2361
     2362        .bp-member-avatar-content img.profile-photo,
     2363        .bp-group-avatar-content img.group-photo {
     2364                margin: auto;
     2365        }
     2366
     2367        .bp-profile-button {
     2368                margin-top: 15px;
     2369        }
     2370}
     2371
     2372@media screen and (min-width: 46.8em) {
     2373
     2374        .bp-profile-button {
     2375                text-align: right;
     2376        }
     2377}
  • new file src/bp-templates/bp-nouveau/buddypress/activity/type-parts/created-group.php

    diff --git src/bp-templates/bp-nouveau/buddypress/activity/type-parts/created-group.php src/bp-templates/bp-nouveau/buddypress/activity/type-parts/created-group.php
    new file mode 100644
    index 000000000..af25c0b34
    - +  
     1<?php
     2/**
     3 * BuddyPress - `created_group` activity type content part.
     4 *
     5 * This template is only used to display the `created_group` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10?>
     11<div class="bp-group-activity-preview">
     12
     13        <?php if ( bp_activity_has_generated_content_part( 'group_cover_image' ) ) : ?>
     14                <div class="bp-group-preview-cover">
     15                        <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>">
     16                                <img src="<?php bp_activity_generated_content_part( 'group_cover_image' ); ?>" alt=""/>
     17                        </a>
     18                </div>
     19        <?php endif; ?>
     20
     21        <div class="bp-group-short-description">
     22                <?php if ( bp_activity_has_generated_content_part( 'group_profile_photo' ) ) : ?>
     23                        <div class="bp-group-avatar-content <?php echo bp_activity_has_generated_content_part( 'group_cover_image' ) ? 'has-cover-image' : ''; ?>">
     24                                <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>">
     25                                        <img src="<?php bp_activity_generated_content_part( 'group_profile_photo' ); ?>" class="profile-photo avatar" alt=""/>
     26                                </a>
     27                        </div>
     28                <?php endif; ?>
     29
     30                <p class="bp-group-short-description-title">
     31                        <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>"><?php bp_activity_generated_content_part( 'group_name' ); ?></a>
     32                </p>
     33
     34                <div class="bp-profile-button">
     35                        <a href="<?php bp_activity_generated_content_part( 'group_url' ); ?>" class="button large primary button-primary" role="button"><?php esc_html_e( 'Visit group', 'buddypress'); ?></a>
     36                </div>
     37        </div>
     38</div>
  • new file src/bp-templates/bp-nouveau/buddypress/activity/type-parts/friendship-created.php

    diff --git src/bp-templates/bp-nouveau/buddypress/activity/type-parts/friendship-created.php src/bp-templates/bp-nouveau/buddypress/activity/type-parts/friendship-created.php
    new file mode 100644
    index 000000000..b4ba00655
    - +  
     1<?php
     2/**
     3 * BuddyPress - `friendship_created` activity type content part.
     4 *
     5 * This template is only used to display the `friendship_created` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10
     11bp_get_template_part( 'activity/type-parts/new-avatar' );
  • new file src/bp-templates/bp-nouveau/buddypress/activity/type-parts/joined-group.php

    diff --git src/bp-templates/bp-nouveau/buddypress/activity/type-parts/joined-group.php src/bp-templates/bp-nouveau/buddypress/activity/type-parts/joined-group.php
    new file mode 100644
    index 000000000..c83469b9d
    - +  
     1<?php
     2/**
     3 * BuddyPress - `joined_group` activity type content part.
     4 *
     5 * This template is only used to display the `joined_group` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10
     11bp_get_template_part( 'activity/type-parts/created-group' );
  • new file src/bp-templates/bp-nouveau/buddypress/activity/type-parts/new-avatar.php

    diff --git src/bp-templates/bp-nouveau/buddypress/activity/type-parts/new-avatar.php src/bp-templates/bp-nouveau/buddypress/activity/type-parts/new-avatar.php
    new file mode 100644
    index 000000000..c4976130b
    - +  
     1<?php
     2/**
     3 * BuddyPress - `new_avatar` activity type content part.
     4 *
     5 * This template is only used to display the `new_avatar` activity type content.
     6 *
     7 * @since 1O.0.0
     8 * @version 10.0.0
     9 */
     10?>
     11<div class="bp-member-activity-preview">
     12
     13        <?php if ( bp_activity_has_generated_content_part( 'user_cover_image' ) ) : ?>
     14                <div class="bp-member-preview-cover">
     15                        <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>">
     16                                <img src="<?php bp_activity_generated_content_part( 'user_cover_image' ); ?>" alt=""/>
     17                        </a>
     18                </div>
     19        <?php endif; ?>
     20
     21        <div class="bp-member-short-description">
     22                <?php if ( bp_activity_has_generated_content_part( 'user_profile_photo' ) ) : ?>
     23                        <div class="bp-member-avatar-content <?php echo bp_activity_has_generated_content_part( 'user_cover_image' ) ? 'has-cover-image' : ''; ?>">
     24                                <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>">
     25                                        <img src="<?php bp_activity_generated_content_part( 'user_profile_photo' ); ?>" class="profile-photo avatar" alt=""/>
     26                                </a>
     27                        </div>
     28                <?php endif; ?>
     29
     30                <p class="bp-member-short-description-title">
     31                        <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>"><?php bp_activity_generated_content_part( 'user_display_name' ); ?></a>
     32                </p>
     33
     34                <p class="bp-member-nickname">
     35                        <a href="<?php is_user_logged_in() ? bp_activity_generated_content_part( 'user_mention_url' ) : bp_activity_generated_content_part( 'user_url' ); ?>">@<?php bp_activity_generated_content_part( 'user_mention_name' ); ?></a>
     36                </p>
     37
     38                <div class="bp-profile-button">
     39                        <a href="<?php bp_activity_generated_content_part( 'user_url' ); ?>" class="button large primary button-primary" role="button"><?php esc_html_e( 'View Profile', 'buddypress'); ?></a>
     40                </div>
     41        </div>
     42</div>
  • src/bp-templates/bp-nouveau/buddypress/activity/widget.php

    diff --git src/bp-templates/bp-nouveau/buddypress/activity/widget.php src/bp-templates/bp-nouveau/buddypress/activity/widget.php
    index 70cd0da60..6ff93a9e0 100644
     
    2121                                <?php if ( bp_activity_has_content() ) : ?>
    2222
    2323                                        <div class="<?php bp_activity_css_class(); ?>">
    24                                                 <?php bp_activity_content_body(); ?>
     24                                                <?php bp_activity_content_body( 'widget' ); ?>
    2525                                        </div>
    2626
    2727                                        <footer>
  • src/bp-templates/bp-nouveau/common-styles/_bp_activity_entries.scss

    diff --git src/bp-templates/bp-nouveau/common-styles/_bp_activity_entries.scss src/bp-templates/bp-nouveau/common-styles/_bp_activity_entries.scss
    index edd598f92..68fc4eaea 100644
    body.activity-permalink { 
    436436
    437437        }
    438438}
     439
     440// Activity Types Entry View
     441.bp-member-preview-cover,
     442.bp-group-preview-cover {
     443        position: relative;
     444        min-height: 150px;
     445        background: #c5c5c5;
     446
     447        img {
     448                background: #c5c5c5;
     449                object-fit: cover;
     450                border: 0;
     451                display: block;
     452                margin: 0;
     453                padding: 0;
     454                width: 100%;
     455                z-index: 1;
     456                height: 150px;
     457        }
     458}
     459
     460.bp-member-avatar-content,
     461.bp-group-avatar-content {
     462        float: left;
     463        width: 120px;
     464        position: relative;
     465        z-index: 2;
     466
     467        img.profile-photo,
     468        img.group-photo {
     469                border: solid 2px #fff;
     470                background: rgba(255, 255, 255, 0.8);
     471                margin-left: 20px;
     472                height: 80px;
     473                width: 80px;
     474        }
     475
     476        &.has-cover-image {
     477                width: 200px;
     478                margin-top: -75px;
     479
     480                img.profile-photo,
     481                img.group-photo {
     482                        height: inherit;
     483                        width: inherit;
     484                }
     485        }
     486}
     487
     488.bp-member-short-description-title a,
     489.bp-group-short-description-title a {
     490        font-weight: 600;
     491}
     492
     493@include medium-max() {
     494
     495        .bp-member-short-description,
     496        .bp-group-short-description {
     497                text-align: center;
     498        }
     499
     500        .bp-member-avatar-content,
     501        .bp-group-avatar-content {
     502                float: none;
     503                width: 100%;
     504                margin-left: auto;
     505                margin-right: auto;
     506                margin-bottom: 15px;
     507
     508                img.profile-photo,
     509                img.group-photo {
     510                        margin: auto;
     511                }
     512        }
     513
     514        .bp-profile-button {
     515                margin-top: 15px;
     516        }
     517
     518} // close @media
     519
     520@include medium-up {
     521
     522        .bp-profile-button {
     523                text-align: right;
     524        }
     525
     526} // close @media
  • src/bp-templates/bp-nouveau/css/buddypress-rtl.css

    diff --git src/bp-templates/bp-nouveau/css/buddypress-rtl.css src/bp-templates/bp-nouveau/css/buddypress-rtl.css
    index e67c2b8f0..809cee962 100644
    body.activity-permalink .activity-list .activity-comments { 
    15871587        }
    15881588}
    15891589
     1590.bp-member-preview-cover,
     1591.bp-group-preview-cover {
     1592        position: relative;
     1593        min-height: 150px;
     1594        background: #c5c5c5;
     1595}
     1596
     1597.bp-member-preview-cover img,
     1598.bp-group-preview-cover img {
     1599        background: #c5c5c5;
     1600        -o-object-fit: cover;
     1601        object-fit: cover;
     1602        border: 0;
     1603        display: block;
     1604        margin: 0;
     1605        padding: 0;
     1606        width: 100%;
     1607        z-index: 1;
     1608        height: 150px;
     1609}
     1610
     1611.bp-member-avatar-content,
     1612.bp-group-avatar-content {
     1613        float: right;
     1614        width: 120px;
     1615        position: relative;
     1616        z-index: 2;
     1617}
     1618
     1619.bp-member-avatar-content img.profile-photo,
     1620.bp-member-avatar-content img.group-photo,
     1621.bp-group-avatar-content img.profile-photo,
     1622.bp-group-avatar-content img.group-photo {
     1623        border: solid 2px #fff;
     1624        background: rgba(255, 255, 255, 0.8);
     1625        margin-right: 20px;
     1626        height: 80px;
     1627        width: 80px;
     1628}
     1629
     1630.bp-member-avatar-content.has-cover-image,
     1631.bp-group-avatar-content.has-cover-image {
     1632        width: 200px;
     1633        margin-top: -75px;
     1634}
     1635
     1636.bp-member-avatar-content.has-cover-image img.profile-photo,
     1637.bp-member-avatar-content.has-cover-image img.group-photo,
     1638.bp-group-avatar-content.has-cover-image img.profile-photo,
     1639.bp-group-avatar-content.has-cover-image img.group-photo {
     1640        height: inherit;
     1641        width: inherit;
     1642}
     1643
     1644.bp-member-short-description-title a,
     1645.bp-group-short-description-title a {
     1646        font-weight: 600;
     1647}
     1648
     1649@media screen and (max-width: 46.8em) {
     1650        .bp-member-short-description,
     1651        .bp-group-short-description {
     1652                text-align: center;
     1653        }
     1654        .bp-member-avatar-content,
     1655        .bp-group-avatar-content {
     1656                float: none;
     1657                width: 100%;
     1658                margin-right: auto;
     1659                margin-left: auto;
     1660                margin-bottom: 15px;
     1661        }
     1662        .bp-member-avatar-content img.profile-photo,
     1663        .bp-member-avatar-content img.group-photo,
     1664        .bp-group-avatar-content img.profile-photo,
     1665        .bp-group-avatar-content img.group-photo {
     1666                margin: auto;
     1667        }
     1668        .bp-profile-button {
     1669                margin-top: 15px;
     1670        }
     1671}
     1672
     1673@media screen and (min-width: 46.8em) {
     1674        .bp-profile-button {
     1675                text-align: left;
     1676        }
     1677}
     1678
    15901679/**
    15911680*-----------------------------------------------------
    15921681* @section 3.1.3 - Activity Comments
  • src/bp-templates/bp-nouveau/css/buddypress.css

    diff --git src/bp-templates/bp-nouveau/css/buddypress.css src/bp-templates/bp-nouveau/css/buddypress.css
    index 526ff907e..31ae2f545 100644
    body.activity-permalink .activity-list .activity-comments { 
    15871587        }
    15881588}
    15891589
     1590.bp-member-preview-cover,
     1591.bp-group-preview-cover {
     1592        position: relative;
     1593        min-height: 150px;
     1594        background: #c5c5c5;
     1595}
     1596
     1597.bp-member-preview-cover img,
     1598.bp-group-preview-cover img {
     1599        background: #c5c5c5;
     1600        -o-object-fit: cover;
     1601        object-fit: cover;
     1602        border: 0;
     1603        display: block;
     1604        margin: 0;
     1605        padding: 0;
     1606        width: 100%;
     1607        z-index: 1;
     1608        height: 150px;
     1609}
     1610
     1611.bp-member-avatar-content,
     1612.bp-group-avatar-content {
     1613        float: left;
     1614        width: 120px;
     1615        position: relative;
     1616        z-index: 2;
     1617}
     1618
     1619.bp-member-avatar-content img.profile-photo,
     1620.bp-member-avatar-content img.group-photo,
     1621.bp-group-avatar-content img.profile-photo,
     1622.bp-group-avatar-content img.group-photo {
     1623        border: solid 2px #fff;
     1624        background: rgba(255, 255, 255, 0.8);
     1625        margin-left: 20px;
     1626        height: 80px;
     1627        width: 80px;
     1628}
     1629
     1630.bp-member-avatar-content.has-cover-image,
     1631.bp-group-avatar-content.has-cover-image {
     1632        width: 200px;
     1633        margin-top: -75px;
     1634}
     1635
     1636.bp-member-avatar-content.has-cover-image img.profile-photo,
     1637.bp-member-avatar-content.has-cover-image img.group-photo,
     1638.bp-group-avatar-content.has-cover-image img.profile-photo,
     1639.bp-group-avatar-content.has-cover-image img.group-photo {
     1640        height: inherit;
     1641        width: inherit;
     1642}
     1643
     1644.bp-member-short-description-title a,
     1645.bp-group-short-description-title a {
     1646        font-weight: 600;
     1647}
     1648
     1649@media screen and (max-width: 46.8em) {
     1650        .bp-member-short-description,
     1651        .bp-group-short-description {
     1652                text-align: center;
     1653        }
     1654        .bp-member-avatar-content,
     1655        .bp-group-avatar-content {
     1656                float: none;
     1657                width: 100%;
     1658                margin-left: auto;
     1659                margin-right: auto;
     1660                margin-bottom: 15px;
     1661        }
     1662        .bp-member-avatar-content img.profile-photo,
     1663        .bp-member-avatar-content img.group-photo,
     1664        .bp-group-avatar-content img.profile-photo,
     1665        .bp-group-avatar-content img.group-photo {
     1666                margin: auto;
     1667        }
     1668        .bp-profile-button {
     1669                margin-top: 15px;
     1670        }
     1671}
     1672
     1673@media screen and (min-width: 46.8em) {
     1674        .bp-profile-button {
     1675                text-align: right;
     1676        }
     1677}
     1678
    15901679/**
    15911680*-----------------------------------------------------
    15921681* @section 3.1.3 - Activity Comments
  • new file tests/phpunit/testcases/core/attachments.php

    diff --git tests/phpunit/testcases/core/attachments.php tests/phpunit/testcases/core/attachments.php
    new file mode 100644
    index 000000000..4acbf496a
    - +  
     1<?php
     2
     3/**
     4 * @group core
     5 */
     6
     7class BP_Tests_Core_Attachments extends BP_UnitTestCase {
     8        /**
     9         * @group bp_attachments_list_directory_files_recursively
     10         */
     11        public function test_bp_attachments_list_directory_files_recursively() {
     12                $files = bp_attachments_list_directory_files_recursively( BP_TESTS_DIR . 'assets', 'index' );
     13
     14                $this->assertTrue( 1 === count( $files ) );
     15                $this->assertTrue( isset( $files['templates/index'] ) );
     16        }
     17}
  • 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 fae4e150d..6bb1c308b 100644
    class BP_Tests_BP_Attachment_TestCases extends BP_UnitTestCase { 
    406406                $this->clean_files( 'shrink' );
    407407        }
    408408
     409        /**
     410         * @group add_revision
     411         */
     412        public function test_bp_attachment_add_revision() {
     413                if ( false === _wp_image_editor_choose() || version_compare( phpversion(), '7.0' , '<' ) ) {
     414                        $this->markTestSkipped( 'This test requires PHP >= 7.0 and to have a valid image editor that is compatible with WordPress.' );
     415                }
     416
     417                $image = BP_TESTS_DIR . 'assets/upside-down.jpg';
     418
     419                $attachment = new BPTest_Attachment_Extension(
     420                        array(
     421                                'base_dir'   => 'add_revision',
     422                                'action'     => 'attachment_action',
     423                                'file_input' => 'attachment_file_input',
     424                        )
     425                );
     426
     427                $abs_path_copy = $attachment->upload_path . '/upside-down.jpg';
     428                copy( $image, $abs_path_copy );
     429
     430                $revision = $attachment->add_revision(
     431                        'media',
     432                        array(
     433                                'file_abspath' => $abs_path_copy,
     434                                'file_id'      => 'media',
     435                        )
     436                );
     437
     438                $this->assertFalse( file_exists( $abs_path_copy ) );
     439                $this->assertTrue( file_exists( $revision->path ) );
     440
     441                // Cleanup
     442                @unlink( $revision->path );
     443                @rmdir( dirname( $revision->path ) );
     444                $this->clean_files( 'add_revision' );
     445        }
     446
     447        /**
     448         * @group add_revision
     449         * @group avatars
     450         */
     451        public function test_bp_attachment_add_avatar_history() {
     452                if ( false === _wp_image_editor_choose() || version_compare( phpversion(), '7.0' , '<' ) ) {
     453                        $this->markTestSkipped( 'This test requires PHP >= 7.0 and to have a valid image editor that is compatible with WordPress.' );
     454                }
     455
     456                $image = BP_TESTS_DIR . 'assets/upside-down.jpg';
     457
     458                $attachment = new BPTest_Attachment_Extension(
     459                        array(
     460                                'base_dir'   => 'add_history',
     461                                'action'     => 'attachment_action',
     462                                'file_input' => 'attachment_file_input',
     463                        )
     464                );
     465
     466                $abs_path_copy = $attachment->upload_path . '/upside-down.jpg';
     467                copy( $image, $abs_path_copy );
     468
     469                $revision = $attachment->add_revision(
     470                        'avatar',
     471                        array(
     472                                'file_abspath' => $abs_path_copy,
     473                                'file_id'      => 'avatar',
     474                        )
     475                );
     476
     477                $this->assertFalse( file_exists( $abs_path_copy ) );
     478                $this->assertTrue( file_exists( $revision->path ) );
     479                $this->assertSame( $attachment->url . '/history/upside-down.jpg', $revision->url );
     480
     481                // Cleanup
     482                @unlink( $revision->path );
     483                @rmdir( dirname( $revision->path ) );
     484                $this->clean_files( 'add_history' );
     485        }
     486
    409487        public function limit_to_50px( $max_width ) {
    410488                return 50;
    411489        }