[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-core/ -> bp-core-attachments.php (source)

   1  <?php
   2  /**
   3   * BuddyPress Attachments functions.
   4   *
   5   * @package BuddyPress
   6   * @subpackage Attachments
   7   * @since 2.3.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /**
  14   * Get the Attachments Uploads dir data.
  15   *
  16   * @since 2.4.0
  17   *
  18   * @param string $data The data to get. Possible values are: 'dir', 'basedir' & 'baseurl'.
  19   *                     Leave empty to get all datas.
  20   * @return string|array The needed Upload dir data.
  21   */
  22  function bp_attachments_uploads_dir_get( $data = '' ) {
  23      $attachments_dir = 'buddypress';
  24      $retval          = '';
  25  
  26      if ( 'dir' === $data ) {
  27          $retval = $attachments_dir;
  28      } else {
  29          $upload_data = bp_upload_dir();
  30  
  31          // Return empty string, if Uploads data are not available.
  32          if ( ! $upload_data ) {
  33              return $retval;
  34          }
  35  
  36          // Build the Upload data array for BuddyPress attachments.
  37          foreach ( $upload_data as $key => $value ) {
  38              if ( 'basedir' === $key || 'baseurl' === $key ) {
  39                  $upload_data[ $key ] = trailingslashit( $value ) . $attachments_dir;
  40  
  41                  // Fix for HTTPS.
  42                  if ( 'baseurl' === $key && is_ssl() ) {
  43                      $upload_data[ $key ] = str_replace( 'http://', 'https://', $upload_data[ $key ] );
  44                  }
  45              } else {
  46                  unset( $upload_data[ $key ] );
  47              }
  48          }
  49  
  50          // Add the dir to the array.
  51          $upload_data['dir'] = $attachments_dir;
  52  
  53          if ( empty( $data ) ) {
  54              $retval = $upload_data;
  55          } elseif ( isset( $upload_data[ $data ] ) ) {
  56              $retval = $upload_data[ $data ];
  57          }
  58      }
  59  
  60      /**
  61       * Filter here to edit the Attachments upload dir data.
  62       *
  63       * @since 2.4.0
  64       *
  65       * @param string|array $retval The needed Upload dir data or the full array of data
  66       * @param string       $data   The data requested
  67       */
  68      return apply_filters( 'bp_attachments_uploads_dir_get', $retval, $data );
  69  }
  70  
  71  /**
  72   * Gets the upload dir array for cover images.
  73   *
  74   * @since 3.0.0
  75   *
  76   * @return array See wp_upload_dir().
  77   */
  78  function bp_attachments_cover_image_upload_dir( $args = array() ) {
  79      // Default values are for members.
  80      $object_id = bp_displayed_user_id();
  81  
  82      if ( empty( $object_id ) ) {
  83          $object_id = bp_loggedin_user_id();
  84      }
  85  
  86      $object_directory = 'members';
  87  
  88      // We're in a group, edit default values.
  89      if ( bp_is_group() || bp_is_group_create() ) {
  90          $object_id        = bp_get_current_group_id();
  91          $object_directory = 'groups';
  92      }
  93  
  94      $r = bp_parse_args( $args, array(
  95          'object_id' => $object_id,
  96          'object_directory' => $object_directory,
  97      ), 'cover_image_upload_dir' );
  98  
  99  
 100      // Set the subdir.
 101      $subdir  = '/' . $r['object_directory'] . '/' . $r['object_id'] . '/cover-image';
 102  
 103      $upload_dir = bp_attachments_uploads_dir_get();
 104  
 105      /**
 106       * Filters the cover image upload directory.
 107       *
 108       * @since 2.4.0
 109       *
 110       * @param array $value      Array containing the path, URL, and other helpful settings.
 111       * @param array $upload_dir The original Uploads dir.
 112       */
 113      return apply_filters( 'bp_attachments_cover_image_upload_dir', array(
 114          'path'    => $upload_dir['basedir'] . $subdir,
 115          'url'     => set_url_scheme( $upload_dir['baseurl'] ) . $subdir,
 116          'subdir'  => $subdir,
 117          'basedir' => $upload_dir['basedir'],
 118          'baseurl' => set_url_scheme( $upload_dir['baseurl'] ),
 119          'error'   => false,
 120      ), $upload_dir );
 121  }
 122  
 123  /**
 124   * Get the max upload file size for any attachment.
 125   *
 126   * @since 2.4.0
 127   *
 128   * @param string $type A string to inform about the type of attachment
 129   *                     we wish to get the max upload file size for.
 130   * @return int Max upload file size for any attachment.
 131   */
 132  function bp_attachments_get_max_upload_file_size( $type = '' ) {
 133      $fileupload_maxk = bp_core_get_root_option( 'fileupload_maxk' );
 134  
 135      if ( '' === $fileupload_maxk ) {
 136          $fileupload_maxk = 5120000; // 5mb;
 137      } else {
 138          $fileupload_maxk = $fileupload_maxk * 1024;
 139      }
 140  
 141      /**
 142       * Filter here to edit the max upload file size.
 143       *
 144       * @since 2.4.0
 145       *
 146       * @param int    $fileupload_maxk Max upload file size for any attachment.
 147       * @param string $type            The attachment type (eg: 'avatar' or 'cover_image').
 148       */
 149      return apply_filters( 'bp_attachments_get_max_upload_file_size', $fileupload_maxk, $type );
 150  }
 151  
 152  /**
 153   * Get allowed types for any attachment.
 154   *
 155   * @since 2.4.0
 156   *
 157   * @param string $type The extension types to get.
 158   *                     Default: 'avatar'.
 159   * @return array The list of allowed extensions for attachments.
 160   */
 161  function bp_attachments_get_allowed_types( $type = 'avatar' ) {
 162      // Defaults to BuddyPress supported image extensions.
 163      $exts = array( 'jpeg', 'gif', 'png' );
 164  
 165      /**
 166       * It's not a BuddyPress feature, get the allowed extensions
 167       * matching the $type requested.
 168       */
 169      if ( 'avatar' !== $type && 'cover_image' !== $type ) {
 170          // Reset the default exts.
 171          $exts = array();
 172  
 173          switch ( $type ) {
 174              case 'video' :
 175                  $exts = wp_get_video_extensions();
 176              break;
 177  
 178              case 'audio' :
 179                  $exts = wp_get_video_extensions();
 180              break;
 181  
 182              default:
 183                  $allowed_mimes = get_allowed_mime_types();
 184  
 185                  /**
 186                   * Search for allowed mimes matching the type.
 187                   *
 188                   * Eg: using 'application/vnd.oasis' as the $type
 189                   * parameter will get all OpenOffice extensions supported
 190                   * by WordPress and allowed for the current user.
 191                   */
 192                  if ( '' !== $type ) {
 193                      $allowed_mimes = preg_grep( '/' . addcslashes( $type, '/.+-' ) . '/', $allowed_mimes );
 194                  }
 195  
 196                  $allowed_types = array_keys( $allowed_mimes );
 197  
 198                  // Loop to explode keys using '|'.
 199                  foreach ( $allowed_types as $allowed_type ) {
 200                      $t = explode( '|', $allowed_type );
 201                      $exts = array_merge( $exts, (array) $t );
 202                  }
 203              break;
 204          }
 205      }
 206  
 207      /**
 208       * Filter here to edit the allowed extensions by attachment type.
 209       *
 210       * @since 2.4.0
 211       *
 212       * @param array  $exts List of allowed extensions.
 213       * @param string $type The requested file type.
 214       */
 215      return apply_filters( 'bp_attachments_get_allowed_types', $exts, $type );
 216  }
 217  
 218  /**
 219   * Get allowed attachment mime types.
 220   *
 221   * @since 2.4.0
 222   *
 223   * @param string $type          The extension types to get (Optional).
 224   * @param array  $allowed_types List of allowed extensions.
 225   * @return array List of allowed mime types.
 226   */
 227  function bp_attachments_get_allowed_mimes( $type = '', $allowed_types = array() ) {
 228      if ( empty( $allowed_types ) ) {
 229          $allowed_types = bp_attachments_get_allowed_types( $type );
 230      }
 231  
 232      $validate_mimes = wp_match_mime_types( join( ',', $allowed_types ), wp_get_mime_types() );
 233      $allowed_mimes  = array_map( 'implode', $validate_mimes );
 234  
 235      /**
 236       * Include jpg type if jpeg is set
 237       */
 238      if ( isset( $allowed_mimes['jpeg'] ) && ! isset( $allowed_mimes['jpg'] ) ) {
 239          $allowed_mimes['jpg'] = $allowed_mimes['jpeg'];
 240      }
 241  
 242      return $allowed_mimes;
 243  }
 244  
 245  /**
 246   * Check the uploaded attachment type is allowed.
 247   *
 248   * @since 2.4.0
 249   *
 250   * @param string $file          Full path to the file.
 251   * @param string $filename      The name of the file (may differ from $file due to $file being
 252   *                              in a tmp directory).
 253   * @param array  $allowed_mimes The attachment allowed mimes (Required).
 254   * @return bool True if the attachment type is allowed. False otherwise
 255   */
 256  function bp_attachments_check_filetype( $file, $filename, $allowed_mimes ) {
 257      $filetype = wp_check_filetype_and_ext( $file, $filename, $allowed_mimes );
 258  
 259      if ( ! empty( $filetype['ext'] ) && ! empty( $filetype['type'] ) ) {
 260          return true;
 261      }
 262  
 263      return false;
 264  }
 265  
 266  /**
 267   * Use the absolute path to an image to set an attachment type for a given item.
 268   *
 269   * @since 2.4.0
 270   *
 271   * @param string $type The attachment type to create (avatar or cover_image). Default: avatar.
 272   * @param array  $args {
 273   *     @type int    $item_id   The ID of the object (Required). Default: 0.
 274   *     @type string $object    The object type (eg: group, user, blog) (Required). Default: 'user'.
 275   *     @type string $component The component for the object (eg: groups, members, blogs). Default: ''.
 276   *     @type string $image     The absolute path to the image (Required). Default: ''.
 277   *     @type int    $crop_w    Crop width. Default: 0.
 278   *     @type int    $crop_h    Crop height. Default: 0.
 279   *     @type int    $crop_x    The horizontal starting point of the crop. Default: 0.
 280   *     @type int    $crop_y    The vertical starting point of the crop. Default: 0.
 281   * }
 282   * @return bool True on success, false otherwise.
 283   */
 284  function bp_attachments_create_item_type( $type = 'avatar', $args = array() ) {
 285      if ( empty( $type ) || ( $type !== 'avatar' && $type !== 'cover_image' ) ) {
 286          return false;
 287      }
 288  
 289      $r = bp_parse_args( $args, array(
 290          'item_id'   => 0,
 291          'object'    => 'user',
 292          'component' => '',
 293          'image'     => '',
 294          'crop_w'    => 0,
 295          'crop_h'    => 0,
 296          'crop_x'    => 0,
 297          'crop_y'    => 0
 298      ), 'create_item_' . $type );
 299  
 300      if ( empty( $r['item_id'] ) || empty( $r['object'] ) || ! file_exists( $r['image'] ) || ! @getimagesize( $r['image'] ) ) {
 301          return false;
 302      }
 303  
 304      // Make sure the file path is safe.
 305      if ( 1 === validate_file( $r['image'] ) ) {
 306          return false;
 307      }
 308  
 309      // Set the component if not already done.
 310      if ( empty( $r['component'] ) ) {
 311          if ( 'user' === $r['object'] ) {
 312              $r['component'] = 'members';
 313          } else {
 314              $r['component'] = $r['object'] . 's';
 315          }
 316      }
 317  
 318      // Get allowed mimes for the Attachment type and check the image one is.
 319      $allowed_mimes = bp_attachments_get_allowed_mimes( $type );
 320      $is_allowed    = wp_check_filetype( $r['image'], $allowed_mimes );
 321  
 322      // It's not an image.
 323      if ( ! $is_allowed['ext'] ) {
 324          return false;
 325      }
 326  
 327      // Init the Attachment data.
 328      $attachment_data = array();
 329  
 330      if ( 'avatar' === $type ) {
 331          // Set crop width for the avatar if not given.
 332          if ( empty( $r['crop_w'] ) ) {
 333              $r['crop_w'] = bp_core_avatar_full_width();
 334          }
 335  
 336          // Set crop height for the avatar if not given.
 337          if ( empty( $r['crop_h'] ) ) {
 338              $r['crop_h'] = bp_core_avatar_full_height();
 339          }
 340  
 341          if ( is_callable( $r['component'] . '_avatar_upload_dir' ) ) {
 342              $dir_args = array( $r['item_id'] );
 343  
 344              // In case  of members, we need an extra argument.
 345              if ( 'members' === $r['component'] ) {
 346                  $dir_args = array( false, $r['item_id'] );
 347              }
 348  
 349              $attachment_data = call_user_func_array( $r['component'] . '_avatar_upload_dir', $dir_args );
 350          }
 351      } elseif ( 'cover_image' === $type ) {
 352          $attachment_data = bp_attachments_cover_image_upload_dir();
 353  
 354          // The BP Attachments Uploads Dir is not set, stop.
 355          if ( ! $attachment_data ) {
 356              return false;
 357          }
 358  
 359          // Default to members for xProfile.
 360          $object_subdir = 'members';
 361  
 362          if ( 'members' !== $r['component'] ) {
 363              $object_subdir = sanitize_key( $r['component'] );
 364          }
 365  
 366          // Set Subdir.
 367          $attachment_data['subdir'] = $object_subdir . '/' . $r['item_id'] . '/cover-image';
 368  
 369          // Set Path.
 370          $attachment_data['path'] = trailingslashit( $attachment_data['basedir'] ) . $attachment_data['subdir'];
 371      }
 372  
 373      if ( ! isset( $attachment_data['path'] ) || ! isset( $attachment_data['subdir'] ) ) {
 374          return false;
 375      }
 376  
 377      // It's not a regular upload, we may need to create some folders.
 378      if ( ! is_dir( $attachment_data['path'] ) ) {
 379          if ( ! wp_mkdir_p( $attachment_data['path'] ) ) {
 380              return false;
 381          }
 382      }
 383  
 384      // Set the image name and path.
 385      $image_file_name = wp_unique_filename( $attachment_data['path'], basename( $r['image'] ) );
 386      $image_file_path = $attachment_data['path'] . '/' . $image_file_name;
 387  
 388      // Copy the image file into the avatar dir.
 389      if ( ! copy( $r['image'], $image_file_path ) ) {
 390          return false;
 391      }
 392  
 393      // Init the response.
 394      $created = false;
 395  
 396      // It's an avatar, we need to crop it.
 397      if ( 'avatar' === $type ) {
 398          $created = bp_core_avatar_handle_crop( array(
 399              'object'        => $r['object'],
 400              'avatar_dir'    => trim( dirname( $attachment_data['subdir'] ), '/' ),
 401              'item_id'       => (int) $r['item_id'],
 402              'original_file' => trailingslashit( $attachment_data['subdir'] ) . $image_file_name,
 403              'crop_w'        => $r['crop_w'],
 404              'crop_h'        => $r['crop_h'],
 405              'crop_x'        => $r['crop_x'],
 406              'crop_y'        => $r['crop_y']
 407          ) );
 408  
 409      // It's a cover image we need to fit it to feature's dimensions.
 410      } elseif ( 'cover_image' === $type ) {
 411          $cover_image = bp_attachments_cover_image_generate_file( array(
 412              'file'            => $image_file_path,
 413              'component'       => $r['component'],
 414              'cover_image_dir' => $attachment_data['path']
 415          ) );
 416  
 417          $created = ! empty( $cover_image['cover_file'] );
 418      }
 419  
 420      // Remove copied file if it fails.
 421      if ( ! $created ) {
 422          @unlink( $image_file_path );
 423      }
 424  
 425      // Return the response.
 426      return $created;
 427  }
 428  
 429  /**
 430   * Get the url or the path for a type of attachment.
 431   *
 432   * @since 2.4.0
 433   *
 434   * @param string $data whether to get the url or the path.
 435   * @param array  $args {
 436   *     @type string $object_dir  The object dir (eg: members/groups). Defaults to members.
 437   *     @type int    $item_id     The object id (eg: a user or a group id). Defaults to current user.
 438   *     @type string $type        The type of the attachment which is also the subdir where files are saved.
 439   *                               Defaults to 'cover-image'
 440   *     @type string $file        The name of the file.
 441   * }
 442   * @return string|bool The url or the path to the attachment, false otherwise
 443   */
 444  function bp_attachments_get_attachment( $data = 'url', $args = array() ) {
 445      // Default value.
 446      $attachment_data = false;
 447  
 448      $r = bp_parse_args( $args, array(
 449          'object_dir' => 'members',
 450          'item_id'    => bp_loggedin_user_id(),
 451          'type'       => 'cover-image',
 452          'file'       => '',
 453      ), 'attachments_get_attachment_src' );
 454  
 455      /**
 456       * Filters whether or not to handle fetching a BuddyPress image attachment.
 457       *
 458       * If you want to override this function, make sure you return false.
 459       *
 460       * @since 2.5.1
 461       *
 462       * @param null|string $value If null is returned, proceed with default behaviour. Otherwise, value returned verbatim.
 463       * @param array $r {
 464       *     @type string $object_dir The object dir (eg: members/groups). Defaults to members.
 465       *     @type int    $item_id    The object id (eg: a user or a group id). Defaults to current user.
 466       *     @type string $type       The type of the attachment which is also the subdir where files are saved.
 467       *                              Defaults to 'cover-image'
 468       *     @type string $file       The name of the file.
 469       * }
 470       */
 471      $pre_filter = apply_filters( 'bp_attachments_pre_get_attachment', null, $r );
 472      if ( $pre_filter !== null ) {
 473          return $pre_filter;
 474      }
 475  
 476      // Get BuddyPress Attachments Uploads Dir datas.
 477      $bp_attachments_uploads_dir = bp_attachments_uploads_dir_get();
 478  
 479      // The BP Attachments Uploads Dir is not set, stop.
 480      if ( ! $bp_attachments_uploads_dir ) {
 481          return $attachment_data;
 482      }
 483  
 484      $type_subdir = $r['object_dir'] . '/' . $r['item_id'] . '/' . $r['type'];
 485      $type_dir    = trailingslashit( $bp_attachments_uploads_dir['basedir'] ) . $type_subdir;
 486  
 487      if ( 1 === validate_file( $type_dir ) || ! is_dir( $type_dir ) ) {
 488          return $attachment_data;
 489      }
 490  
 491      if ( ! empty( $r['file'] ) ) {
 492          if ( ! file_exists( trailingslashit( $type_dir ) . $r['file'] ) ) {
 493              return $attachment_data;
 494          }
 495  
 496          if ( 'url' === $data ) {
 497              $attachment_data = trailingslashit( $bp_attachments_uploads_dir['baseurl'] ) . $type_subdir . '/' . $r['file'];
 498          } else {
 499              $attachment_data = trailingslashit( $type_dir ) . $r['file'];
 500          }
 501  
 502      } else {
 503          $file = false;
 504  
 505          // Open the directory and get the first file.
 506          if ( $att_dir = opendir( $type_dir ) ) {
 507  
 508              while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
 509                  // Look for the first file having the type in its name.
 510                  if ( false !== strpos( $attachment_file, $r['type'] ) && empty( $file ) ) {
 511                      $file = $attachment_file;
 512                      break;
 513                  }
 514              }
 515          }
 516  
 517          if ( empty( $file ) ) {
 518              return $attachment_data;
 519          }
 520  
 521          if ( 'url' === $data ) {
 522              $attachment_data = trailingslashit( $bp_attachments_uploads_dir['baseurl'] ) . $type_subdir . '/' . $file;
 523          } else {
 524              $attachment_data = trailingslashit( $type_dir ) . $file;
 525          }
 526      }
 527  
 528      return $attachment_data;
 529  }
 530  
 531  /**
 532   * Delete an attachment for the given arguments
 533   *
 534   * @since 2.4.0
 535   *
 536   * @see bp_attachments_get_attachment() For more information on accepted arguments.
 537   *
 538   * @param array $args Array of arguments for the attachment deletion.
 539   * @return bool True if the attachment was deleted, false otherwise.
 540   */
 541  function bp_attachments_delete_file( $args = array() ) {
 542      $attachment_path = bp_attachments_get_attachment( 'path', $args );
 543  
 544      /**
 545       * Filters whether or not to handle deleting an existing BuddyPress attachment.
 546       *
 547       * If you want to override this function, make sure you return false.
 548       *
 549       * @since 2.5.1
 550       *
 551       * @param bool $value Whether or not to delete the BuddyPress attachment.
 552       * @param array $args Array of arguments for the attachment deletion.
 553       */
 554      if ( ! apply_filters( 'bp_attachments_pre_delete_file', true, $args ) ) {
 555          return true;
 556      }
 557  
 558      if ( empty( $attachment_path ) ) {
 559          return false;
 560      }
 561  
 562      @unlink( $attachment_path );
 563      return true;
 564  }
 565  
 566  /**
 567   * Get the BuddyPress Plupload settings.
 568   *
 569   * @since 2.3.0
 570   *
 571   * @return array List of BuddyPress Plupload settings.
 572   */
 573  function bp_attachments_get_plupload_default_settings() {
 574  
 575      $max_upload_size = wp_max_upload_size();
 576  
 577      if ( ! $max_upload_size ) {
 578          $max_upload_size = 0;
 579      }
 580  
 581      $defaults = array(
 582          'runtimes'            => 'html5,flash,silverlight,html4',
 583          'file_data_name'      => 'file',
 584          'multipart_params'    => array(
 585              'action'          => 'bp_upload_attachment',
 586              '_wpnonce'        => wp_create_nonce( 'bp-uploader' ),
 587          ),
 588          'url'                 => admin_url( 'admin-ajax.php', 'relative' ),
 589          'flash_swf_url'       => includes_url( 'js/plupload/plupload.flash.swf' ),
 590          'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
 591          'filters' => array(
 592              'max_file_size'   => $max_upload_size . 'b',
 593          ),
 594          'multipart'           => true,
 595          'urlstream_upload'    => true,
 596      );
 597  
 598      // WordPress is not allowing multi selection for iOs 7 device.. See #29602.
 599      if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false &&
 600          strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) {
 601  
 602          $defaults['multi_selection'] = false;
 603      }
 604  
 605      $settings = array(
 606          'defaults' => $defaults,
 607          'browser'  => array(
 608              'mobile'    => wp_is_mobile(),
 609              'supported' => _device_can_upload(),
 610          ),
 611          'limitExceeded' => is_multisite() && ! is_upload_space_available(),
 612      );
 613  
 614      /**
 615       * Filter the BuddyPress Plupload default settings.
 616       *
 617       * @since 2.3.0
 618       *
 619       * @param array $settings Default Plupload parameters array.
 620       */
 621      return apply_filters( 'bp_attachments_get_plupload_default_settings', $settings );
 622  }
 623  
 624  /**
 625   * Builds localization strings for the BuddyPress Uploader scripts.
 626   *
 627   * @since 2.3.0
 628   *
 629   * @return array Plupload default localization strings.
 630   */
 631  function bp_attachments_get_plupload_l10n() {
 632      /**
 633       * Use this filter to edit localization strings.
 634       *
 635       * @since 2.3.0
 636       *
 637       * @param array $value An associative array of the localization strings.
 638       */
 639      return apply_filters(
 640          'bp_attachments_get_plupload_l10n',
 641          array(
 642              'queue_limit_exceeded'      => __( 'You have attempted to queue too many files.', 'buddypress' ),
 643  
 644              /* translators: %s: File name. */
 645              'file_exceeds_size_limit'   => __( '%s exceeds the maximum upload size for this site.', 'buddypress' ),
 646              'zero_byte_file'            => __( 'This file is empty. Please try another.', 'buddypress' ),
 647              'invalid_filetype'          => __( 'This file type is not allowed. Please try another.', 'buddypress' ),
 648              'not_an_image'              => __( 'This file is not an image. Please try another.', 'buddypress' ),
 649              'image_memory_exceeded'     => __( 'Memory exceeded. Please try another smaller file.', 'buddypress' ),
 650              'image_dimensions_exceeded' => __( 'This is larger than the maximum size. Please try another.', 'buddypress' ),
 651              'default_error'             => __( 'An error occurred. Please try again later.', 'buddypress' ),
 652              'missing_upload_url'        => __( 'There was a configuration error. Please contact the server administrator.', 'buddypress' ),
 653              'upload_limit_exceeded'     => __( 'You may only upload 1 file.', 'buddypress' ),
 654              'http_error'                => __( 'HTTP error.', 'buddypress' ),
 655              'upload_failed'             => __( 'Upload failed.', 'buddypress' ),
 656  
 657              /* translators: 1: Opening link tag, 2: Closing link tag. */
 658              'big_upload_failed'         => __( 'Please try uploading this file with the %1$sbrowser uploader%2$s.', 'buddypress' ),
 659  
 660              /* translators: %s: File name. */
 661              'big_upload_queued'         => __( '%s exceeds the maximum upload size for the multi-file uploader when used in your browser.', 'buddypress' ),
 662              'io_error'                  => __( 'IO error.', 'buddypress' ),
 663              'security_error'            => __( 'Security error.', 'buddypress' ),
 664              'file_cancelled'            => __( 'File canceled.', 'buddypress' ),
 665              'upload_stopped'            => __( 'Upload stopped.', 'buddypress' ),
 666              'dismiss'                   => __( 'Dismiss', 'buddypress' ),
 667              'crunching'                 => __( 'Crunching&hellip;', 'buddypress' ),
 668              'unique_file_warning'       => __( 'Make sure to upload a unique file', 'buddypress' ),
 669  
 670              /* translators: %s: File name. */
 671              'error_uploading'           => __( '&#8220;%s&#8221; has failed to upload.', 'buddypress' ),
 672              'has_avatar_warning'        => __( 'If you&#39;d like to delete the existing profile photo but not upload a new one, please use the delete tab.', 'buddypress' )
 673          )
 674      );
 675  }
 676  
 677  /**
 678   * Enqueues the script needed for the Uploader UI.
 679   *
 680   * @since 2.3.0
 681   *
 682   * @see BP_Attachment::script_data() && BP_Attachment_Avatar::script_data() for examples showing how
 683   * to set specific script data.
 684   *
 685   * @param string $class Name of the class extending BP_Attachment (eg: BP_Attachment_Avatar).
 686   * @return null|WP_Error
 687   */
 688  function bp_attachments_enqueue_scripts( $class = '' ) {
 689      // Enqueue me just once per page, please.
 690      if ( did_action( 'bp_attachments_enqueue_scripts' ) ) {
 691          return;
 692      }
 693  
 694      if ( ! $class || ! class_exists( $class ) ) {
 695          return new WP_Error( 'missing_parameter' );
 696      }
 697  
 698      // Get an instance of the class and get the script data.
 699      $attachment = new $class;
 700      $script_data  = $attachment->script_data();
 701  
 702      $args = bp_parse_args( $script_data, array(
 703          'action'            => '',
 704          'file_data_name'    => '',
 705          'max_file_size'     => 0,
 706          'browse_button'     => 'bp-browse-button',
 707          'container'         => 'bp-upload-ui',
 708          'drop_element'      => 'drag-drop-area',
 709          'bp_params'         => array(),
 710          'extra_css'         => array(),
 711          'extra_js'          => array(),
 712          'feedback_messages' => array(),
 713      ), 'attachments_enqueue_scripts' );
 714  
 715      if ( empty( $args['action'] ) || empty( $args['file_data_name'] ) ) {
 716          return new WP_Error( 'missing_parameter' );
 717      }
 718  
 719      // Get the BuddyPress uploader strings.
 720      $strings = bp_attachments_get_plupload_l10n();
 721  
 722      // Get the BuddyPress uploader settings.
 723      $settings = bp_attachments_get_plupload_default_settings();
 724  
 725      // Set feedback messages.
 726      if ( ! empty( $args['feedback_messages'] ) ) {
 727          $strings['feedback_messages'] = $args['feedback_messages'];
 728      }
 729  
 730      // Use a temporary var to ease manipulation.
 731      $defaults = $settings['defaults'];
 732  
 733      // Set the upload action.
 734      $defaults['multipart_params']['action'] = $args['action'];
 735  
 736      // Set BuddyPress upload parameters if provided.
 737      if ( ! empty( $args['bp_params'] ) ) {
 738          $defaults['multipart_params']['bp_params'] = $args['bp_params'];
 739      }
 740  
 741      // Merge other arguments.
 742      $ui_args = array_intersect_key( $args, array(
 743          'file_data_name' => true,
 744          'browse_button'  => true,
 745          'container'      => true,
 746          'drop_element'   => true,
 747      ) );
 748  
 749      $defaults = array_merge( $defaults, $ui_args );
 750  
 751      if ( ! empty( $args['max_file_size'] ) ) {
 752          $defaults['filters']['max_file_size'] = $args['max_file_size'] . 'b';
 753      }
 754  
 755      // Specific to BuddyPress Avatars.
 756      if ( 'bp_avatar_upload' === $defaults['multipart_params']['action'] ) {
 757  
 758          // Include the cropping informations for avatars.
 759          $settings['crop'] = array(
 760              'full_h'  => bp_core_avatar_full_height(),
 761              'full_w'  => bp_core_avatar_full_width(),
 762          );
 763  
 764          // Avatar only need 1 file and 1 only!
 765          $defaults['multi_selection'] = false;
 766  
 767          // Does the object already has an avatar set.
 768          $has_avatar = $defaults['multipart_params']['bp_params']['has_avatar'];
 769  
 770          // What is the object the avatar belongs to.
 771          $object = $defaults['multipart_params']['bp_params']['object'];
 772  
 773          // Init the Avatar nav.
 774          $avatar_nav = array(
 775              'upload' => array( 'id' => 'upload', 'caption' => __( 'Upload', 'buddypress' ), 'order' => 0  ),
 776  
 777              // The delete view will only show if the object has an avatar.
 778              'delete' => array( 'id' => 'delete', 'caption' => __( 'Delete', 'buddypress' ), 'order' => 100, 'hide' => (int) ! $has_avatar ),
 779          );
 780  
 781          // Create the Camera Nav if the WebCam capture feature is enabled.
 782          if ( bp_avatar_use_webcam() && 'user' === $object ) {
 783              $avatar_nav['camera'] = array( 'id' => 'camera', 'caption' => __( 'Take Photo', 'buddypress' ), 'order' => 10 );
 784  
 785              // Set warning messages.
 786              $strings['camera_warnings'] = array(
 787                  'requesting'  => __( 'Please allow us to access to your camera.', 'buddypress'),
 788                  'loading'     => __( 'Please wait as we access your camera.', 'buddypress' ),
 789                  'loaded'      => __( 'Camera loaded. Click on the "Capture" button to take your photo.', 'buddypress' ),
 790                  'noaccess'    => __( 'It looks like you do not have a webcam or we were unable to get permission to use your webcam. Please upload a photo instead.', 'buddypress' ),
 791                  'errormsg'    => __( 'Your browser is not supported. Please upload a photo instead.', 'buddypress' ),
 792                  'videoerror'  => __( 'Video error. Please upload a photo instead.', 'buddypress' ),
 793                  'ready'       => __( 'Your profile photo is ready. Click on the "Save" button to use this photo.', 'buddypress' ),
 794                  'nocapture'   => __( 'No photo was captured. Click on the "Capture" button to take your photo.', 'buddypress' ),
 795              );
 796          }
 797  
 798          /**
 799           * Use this filter to add a navigation to a custom tool to set the object's avatar.
 800           *
 801           * @since 2.3.0
 802           *
 803           * @param array  $avatar_nav {
 804           *     An associative array of available nav items where each item is an array organized this way:
 805           *     $avatar_nav[ $nav_item_id ].
 806           *     @type string $nav_item_id The nav item id in lower case without special characters or space.
 807           *     @type string $caption     The name of the item nav that will be displayed in the nav.
 808           *     @type int    $order       An integer to specify the priority of the item nav, choose one.
 809           *                               between 1 and 99 to be after the uploader nav item and before the delete nav item.
 810           *     @type int    $hide        If set to 1 the item nav will be hidden
 811           *                               (only used for the delete nav item).
 812           * }
 813           * @param string $object The object the avatar belongs to (eg: user or group).
 814           */
 815          $settings['nav'] = bp_sort_by_key( apply_filters( 'bp_attachments_avatar_nav', $avatar_nav, $object ), 'order', 'num' );
 816  
 817      // Specific to BuddyPress cover images.
 818      } elseif ( 'bp_cover_image_upload' === $defaults['multipart_params']['action'] ) {
 819  
 820          // Cover images only need 1 file and 1 only!
 821          $defaults['multi_selection'] = false;
 822  
 823          // Default cover component is members.
 824          $cover_component = 'members';
 825  
 826          // Get the object we're editing the cover image of.
 827          $object = $defaults['multipart_params']['bp_params']['object'];
 828  
 829          // Set the cover component according to the object.
 830          if ( 'group' === $object ) {
 831              $cover_component = 'groups';
 832          } elseif ( 'user' !== $object ) {
 833              $cover_component = apply_filters( 'bp_attachments_cover_image_ui_component', $cover_component );
 834          }
 835          // Get cover image advised dimensions.
 836          $cover_dimensions = bp_attachments_get_cover_image_dimensions( $cover_component );
 837  
 838          // Set warning messages.
 839          $strings['cover_image_warnings'] = apply_filters( 'bp_attachments_cover_image_ui_warnings', array(
 840              'dimensions'  => sprintf(
 841                  /* translators: 1: the advised width size in pixels. 2: the advised height size in pixels. */
 842                  __( 'For better results, make sure to upload an image that is larger than %1$spx wide, and %2$spx tall.', 'buddypress' ),
 843                  (int) $cover_dimensions['width'],
 844                  (int) $cover_dimensions['height']
 845              ),
 846          ) );
 847      }
 848  
 849      // Set Plupload settings.
 850      $settings['defaults'] = $defaults;
 851  
 852      /**
 853       * Enqueue some extra styles if required
 854       *
 855       * Extra styles need to be registered.
 856       */
 857      if ( ! empty( $args['extra_css'] ) ) {
 858          foreach ( (array) $args['extra_css'] as $css ) {
 859              if ( empty( $css ) ) {
 860                  continue;
 861              }
 862  
 863              wp_enqueue_style( $css );
 864          }
 865      }
 866  
 867      wp_enqueue_script ( 'bp-plupload' );
 868      wp_localize_script( 'bp-plupload', 'BP_Uploader', array( 'strings' => $strings, 'settings' => $settings ) );
 869  
 870      /**
 871       * Enqueue some extra scripts if required
 872       *
 873       * Extra scripts need to be registered.
 874       */
 875      if ( ! empty( $args['extra_js'] ) ) {
 876          foreach ( (array) $args['extra_js'] as $js ) {
 877              if ( empty( $js ) ) {
 878                  continue;
 879              }
 880  
 881              wp_enqueue_script( $js );
 882          }
 883      }
 884  
 885      /**
 886       * Fires at the conclusion of bp_attachments_enqueue_scripts()
 887       * to avoid the scripts to be loaded more than once.
 888       *
 889       * @since 2.3.0
 890       */
 891      do_action( 'bp_attachments_enqueue_scripts' );
 892  }
 893  
 894  /**
 895   * Check the current user's capability to edit an avatar for a given object.
 896   *
 897   * @since 2.3.0
 898   *
 899   * @param string $capability The capability to check.
 900   * @param array  $args       An array containing the item_id and the object to check.
 901   * @return bool
 902   */
 903  function bp_attachments_current_user_can( $capability, $args = array() ) {
 904      $can = false;
 905  
 906      if ( 'edit_avatar' === $capability || 'edit_cover_image' === $capability ) {
 907          /**
 908           * Needed avatar arguments are set.
 909           */
 910          if ( isset( $args['item_id'] ) && isset( $args['object'] ) ) {
 911              // Group profile photo.
 912              if ( bp_is_active( 'groups' ) && 'group' === $args['object'] ) {
 913                  if ( bp_is_group_create() ) {
 914                      $can = (bool) groups_is_user_creator( bp_loggedin_user_id(), $args['item_id'] ) || bp_current_user_can( 'bp_moderate' );
 915                  } else {
 916                      $can = (bool) groups_is_user_admin( bp_loggedin_user_id(), $args['item_id'] ) || bp_current_user_can( 'bp_moderate' );
 917                  }
 918              // User profile photo.
 919              } elseif ( bp_is_active( 'members' ) && 'user' === $args['object'] ) {
 920                  $can = bp_loggedin_user_id() === (int) $args['item_id'] || bp_current_user_can( 'bp_moderate' );
 921              }
 922          /**
 923           * No avatar arguments, fallback to bp_user_can_create_groups()
 924           * or bp_is_item_admin()
 925           */
 926          } else {
 927              if ( bp_is_group_create() ) {
 928                  $can = bp_user_can_create_groups();
 929              } else {
 930                  $can = bp_is_item_admin();
 931              }
 932          }
 933      }
 934  
 935      return apply_filters( 'bp_attachments_current_user_can', $can, $capability, $args );
 936  }
 937  
 938  /**
 939   * Send a JSON response back to an Ajax upload request.
 940   *
 941   * @since 2.3.0
 942   *
 943   * @param bool  $success  True for a success, false otherwise.
 944   * @param bool  $is_html4 True if the Plupload runtime used is html4, false otherwise.
 945   * @param mixed $data     Data to encode as JSON, then print and die.
 946   */
 947  function bp_attachments_json_response( $success, $is_html4 = false, $data = null ) {
 948      $response = array( 'success' => $success );
 949  
 950      if ( isset( $data ) ) {
 951          $response['data'] = $data;
 952      }
 953  
 954      // Send regular json response.
 955      if ( ! $is_html4 ) {
 956          wp_send_json( $response );
 957  
 958      /**
 959       * Send specific json response
 960       * the html4 Plupload handler requires a text/html content-type for older IE.
 961       * See https://core.trac.wordpress.org/ticket/31037
 962       */
 963      } else {
 964          echo wp_json_encode( $response );
 965  
 966          wp_die();
 967      }
 968  }
 969  
 970  /**
 971   * Get an Attachment template part.
 972   *
 973   * @since 2.3.0
 974   *
 975   * @param string $slug Template part slug. eg 'uploader' for 'uploader.php'.
 976   * @return bool
 977   */
 978  function bp_attachments_get_template_part( $slug ) {
 979      $switched = false;
 980  
 981      /*
 982       * Use bp-legacy attachment template part for older bp-default themes or if in
 983       * admin area.
 984       */
 985      if ( ! bp_use_theme_compat_with_current_theme() || ( is_admin() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) ) {
 986          $current = bp_get_theme_compat_id();
 987          if ( 'legacy' !== $current ) {
 988              $switched = true;
 989              bp_setup_theme_compat( 'legacy' );
 990          }
 991      }
 992  
 993      // Load the template part.
 994      bp_get_template_part( 'assets/_attachments/' . $slug );
 995  
 996      if ( $switched ) {
 997          bp_setup_theme_compat( $current );
 998      }
 999  }
1000  
1001  /** Cover Image ***************************************************************/
1002  
1003  /**
1004   * Get the cover image settings
1005   *
1006   * @since 2.4.0
1007   *
1008   * @param string $component The component to get the settings for ("members" for user or "groups").
1009   * @return false|array The cover image settings in array, false on failure.
1010   */
1011  function bp_attachments_get_cover_image_settings( $component = 'members' ) {
1012      // Default parameters.
1013      $args = array();
1014  
1015      // First look in BP Theme Compat.
1016      $cover_image = bp_get_theme_compat_feature( 'cover_image' );
1017  
1018      if ( ! empty( $cover_image ) ) {
1019          $args = (array) $cover_image;
1020      }
1021  
1022      // Set default args.
1023      $default_args = wp_parse_args(
1024          $args,
1025          array(
1026              'components'    => array(),
1027              'width'         => 1300,
1028              'height'        => 225,
1029              'callback'      => '',
1030              'theme_handle'  => '',
1031              'default_cover' => '',
1032          )
1033      );
1034  
1035      // Handle deprecated xProfile fitler.
1036      if ( 'members' === $component ) {
1037          /** This filter is documented in wp-includes/deprecated.php */
1038          $args = apply_filters_deprecated( 'bp_before_xprofile_cover_image_settings_parse_args', array( $default_args ), '6.0.0', 'bp_before_members_cover_image_settings_parse_args' );
1039      }
1040  
1041      /**
1042       * Then let people override/set the feature using this dynamic filter
1043       *
1044       * Eg: for the user's profile cover image use:
1045       * add_filter( 'bp_before_members_cover_image_settings_parse_args', 'your_filter', 10, 1 );
1046       *
1047       * @since 2.4.0
1048       *
1049       * @param array $settings The cover image settings
1050       */
1051      $settings = bp_parse_args( $args, $default_args, $component . '_cover_image_settings' );
1052  
1053      // Handle deprecated xProfile fitler.
1054      if ( 'members' === $component ) {
1055          /** This filter is documented in wp-includes/deprecated.php */
1056          $settings = apply_filters_deprecated( 'bp_after_xprofile_cover_image_settings_parse_args', array( $settings ), '6.0.0', 'bp_after_members_cover_image_settings_parse_args' );
1057      }
1058  
1059      if ( empty( $settings['components'] ) || empty( $settings['callback'] ) || empty( $settings['theme_handle'] ) ) {
1060          return false;
1061      }
1062  
1063      // Current component is not supported.
1064      if ( ! in_array( $component, $settings['components'] ) ) {
1065          return false;
1066      }
1067  
1068      // Finally return the settings.
1069      return $settings;
1070  }
1071  
1072  /**
1073   * Get cover image Width and Height.
1074   *
1075   * @since 2.4.0
1076   *
1077   * @param string $component The BuddyPress component concerned ("members" for user or "groups").
1078   * @return array|bool An associative array containing the advised width and height for the cover image. False if settings are empty.
1079   */
1080  function bp_attachments_get_cover_image_dimensions( $component = 'members' ) {
1081      // Let's prevent notices when setting the warning strings.
1082      $default = array( 'width' => 0, 'height' => 0 );
1083  
1084      $settings = bp_attachments_get_cover_image_settings( $component );
1085  
1086      if ( empty( $settings ) ) {
1087          return false;
1088      }
1089  
1090      // Get width and height.
1091      $wh = array_intersect_key( $settings, $default );
1092  
1093      /**
1094       * Filter here to edit the cover image dimensions if needed.
1095       *
1096       * @since 2.4.0
1097       *
1098       * @param array  $wh       An associative array containing the width and height values.
1099       * @param array  $settings An associative array containing all the feature settings.
1100       * @param string $compnent The requested component.
1101       */
1102      return apply_filters( 'bp_attachments_get_cover_image_dimensions', $wh, $settings, $component );
1103  }
1104  
1105  /**
1106   * Are we on a page to edit a cover image?
1107   *
1108   * @since 2.4.0
1109   *
1110   * @return bool True if on a page to edit a cover image, false otherwise.
1111   */
1112  function bp_attachments_cover_image_is_edit() {
1113      $retval = false;
1114  
1115      $current_component = bp_current_component();
1116      if ( bp_is_user() ) {
1117          $current_component = 'members';
1118      }
1119  
1120      if ( ! bp_is_active( $current_component, 'cover_image' ) ) {
1121          return $retval;
1122      }
1123  
1124      if ( bp_is_user_change_cover_image() ) {
1125          $retval = ! bp_disable_cover_image_uploads();
1126      }
1127  
1128      if ( ( bp_is_group_admin_page() && 'group-cover-image' == bp_get_group_current_admin_tab() )
1129          || ( bp_is_group_create() && bp_is_group_creation_step( 'group-cover-image' ) ) ) {
1130          $retval = ! bp_disable_group_cover_image_uploads();
1131      }
1132  
1133      return apply_filters( 'bp_attachments_cover_image_is_edit', $retval, $current_component );
1134  }
1135  
1136  /**
1137   * Does the user has a cover image?
1138   *
1139   * @since 2.4.0
1140   *
1141   * @param int $user_id User ID to retrieve cover image for.
1142   * @return bool True if the user has a cover image, false otherwise.
1143   */
1144  function bp_attachments_get_user_has_cover_image( $user_id = 0 ) {
1145      if ( empty( $user_id ) ) {
1146          $user_id = bp_displayed_user_id();
1147      }
1148  
1149      $cover_src = bp_attachments_get_attachment( 'url', array(
1150          'item_id'   => $user_id,
1151      ) );
1152  
1153      return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $user_id );
1154  }
1155  
1156  /**
1157   * Does the group has a cover image?
1158   *
1159   * @since 2.4.0
1160   * @since 6.0.0 Renamed the filter coherently.
1161   *
1162   * @param int $group_id Group ID to check cover image existence for.
1163   * @return bool True if the group has a cover image, false otherwise.
1164   */
1165  function bp_attachments_get_group_has_cover_image( $group_id = 0 ) {
1166      if ( empty( $group_id ) ) {
1167          $group_id = bp_get_current_group_id();
1168      }
1169  
1170      $cover_src = bp_attachments_get_attachment( 'url', array(
1171          'object_dir' => 'groups',
1172          'item_id'    => $group_id,
1173      ) );
1174  
1175      return (bool) apply_filters( 'bp_attachments_get_group_has_cover_image', $cover_src, $group_id );
1176  }
1177  
1178  /**
1179   * Generate the cover image file.
1180   *
1181   * @since 2.4.0
1182   *
1183   * @param array                          $args {
1184   *     @type string $file            The absolute path to the image. Required.
1185   *     @type string $component       The component for the object (eg: groups, members). Required.
1186   *     @type string $cover_image_dir The Cover image dir to write the image into. Required.
1187   * }
1188   * @param BP_Attachment_Cover_Image|null $cover_image_class The class to use to fit the cover image.
1189   * @return false|array An array containing cover image data on success, false otherwise.
1190   */
1191  function bp_attachments_cover_image_generate_file( $args = array(), $cover_image_class = null ) {
1192      // Bail if an argument is missing.
1193      if ( empty( $args['file'] ) || empty( $args['component'] ) || empty( $args['cover_image_dir'] ) ) {
1194          return false;
1195      }
1196  
1197      // Get advised dimensions for the cover image.
1198      $dimensions = bp_attachments_get_cover_image_dimensions( $args['component'] );
1199  
1200      // No dimensions or the file does not match with the cover image dir, stop!
1201      if ( false === $dimensions || $args['file'] !== $args['cover_image_dir'] . '/' . wp_basename( $args['file'] ) ) {
1202          return false;
1203      }
1204  
1205      if ( ! is_a( $cover_image_class, 'BP_Attachment_Cover_Image' ) ) {
1206          $cover_image_class = new BP_Attachment_Cover_Image();
1207      }
1208  
1209      $upload_dir = bp_attachments_cover_image_upload_dir();
1210  
1211      // Make sure the file is inside the Cover Image Upload path.
1212      if ( false === strpos( $args['file'], $upload_dir['basedir'] ) ) {
1213          return false;
1214      }
1215  
1216      // Resize the image so that it fit with the cover image dimensions.
1217      $cover_image  = $cover_image_class->fit( $args['file'], $dimensions );
1218      $is_too_small = false;
1219  
1220      // Image is too small in width and height.
1221      if ( empty( $cover_image ) ) {
1222          $cover_file = $cover_image_class->generate_filename( $args['file'] );
1223          @rename( $args['file'], $cover_file );
1224  
1225          // It's too small!
1226          $is_too_small = true;
1227      } elseif ( ! empty( $cover_image['path'] ) ) {
1228          $cover_file = $cover_image['path'];
1229  
1230          // Image is too small in width or height.
1231          if ( $cover_image['width'] < $dimensions['width'] || $cover_image['height'] < $dimensions['height'] ) {
1232              $is_too_small = true;
1233          }
1234      }
1235  
1236      // We were not able to generate the cover image file.
1237      if ( empty( $cover_file ) ) {
1238          return false;
1239      }
1240  
1241      // Do some clean up with old cover image, now a new one is set.
1242      $cover_basename = wp_basename( $cover_file );
1243  
1244      if ( $att_dir = opendir( $args['cover_image_dir'] ) ) {
1245          while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
1246              // Skip directories and the new cover image.
1247              if ( 2 < strlen( $attachment_file ) && 0 !== strpos( $attachment_file, '.' ) && $cover_basename !== $attachment_file ) {
1248                  @unlink( $args['cover_image_dir'] . '/' . $attachment_file );
1249              }
1250          }
1251      }
1252  
1253      // Finally return needed data.
1254      return array(
1255          'cover_file'     => $cover_file,
1256          'cover_basename' => $cover_basename,
1257          'is_too_small'   => $is_too_small
1258      );
1259  }
1260  
1261  /**
1262   * Ajax Upload and set a cover image
1263   *
1264   * @since 2.4.0
1265   *
1266   * @return string|null A json object containing success data if the upload succeeded,
1267   *                     error message otherwise.
1268   */
1269  function bp_attachments_cover_image_ajax_upload() {
1270      if ( ! bp_is_post_request() ) {
1271          wp_die();
1272      }
1273  
1274      check_admin_referer( 'bp-uploader' );
1275  
1276      // Sending the json response will be different if the current Plupload runtime is html4.
1277      $is_html4 = ! empty( $_POST['html4' ] );
1278  
1279      if ( empty( $_POST['bp_params'] ) ) {
1280          bp_attachments_json_response( false, $is_html4 );
1281      }
1282  
1283      $bp_params = bp_parse_args( $_POST['bp_params'], array(
1284          'object'  => 'user',
1285          'item_id' => bp_loggedin_user_id(),
1286      ), 'attachments_cover_image_ajax_upload' );
1287  
1288      $bp_params['item_id'] = (int) $bp_params['item_id'];
1289      $bp_params['object']  = sanitize_text_field( $bp_params['object'] );
1290  
1291      // We need the object to set the uploads dir filter.
1292      if ( empty( $bp_params['object'] ) ) {
1293          bp_attachments_json_response( false, $is_html4 );
1294      }
1295  
1296      // Capability check.
1297      if ( ! bp_attachments_current_user_can( 'edit_cover_image', $bp_params ) ) {
1298          bp_attachments_json_response( false, $is_html4 );
1299      }
1300  
1301      $bp          = buddypress();
1302      $needs_reset = array();
1303  
1304      // Member's cover image.
1305      if ( 'user' === $bp_params['object'] ) {
1306          $object_data = array( 'dir' => 'members', 'component' => 'members' );
1307  
1308          if ( ! bp_displayed_user_id() && ! empty( $bp_params['item_id'] ) ) {
1309              $needs_reset = array( 'key' => 'displayed_user', 'value' => $bp->displayed_user );
1310              $bp->displayed_user->id = $bp_params['item_id'];
1311          }
1312  
1313      // Group's cover image.
1314      } elseif ( 'group' === $bp_params['object'] ) {
1315          $object_data = array( 'dir' => 'groups', 'component' => 'groups' );
1316  
1317          if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) {
1318              $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group );
1319              $bp->groups->current_group = groups_get_group( $bp_params['item_id'] );
1320          }
1321  
1322      // Other object's cover image.
1323      } else {
1324          $object_data = apply_filters( 'bp_attachments_cover_image_object_dir', array(), $bp_params['object'] );
1325      }
1326  
1327      // Stop here in case of a missing parameter for the object.
1328      if ( empty( $object_data['dir'] ) || empty( $object_data['component'] ) ) {
1329          bp_attachments_json_response( false, $is_html4 );
1330      }
1331  
1332      /**
1333       * Filters whether or not to handle cover image uploading.
1334       *
1335       * If you want to override this function, make sure you return an array with the 'result' key set.
1336       *
1337       * @since 2.5.1
1338       *
1339       * @param array $value
1340       * @param array $bp_params
1341       * @param array $needs_reset Stores original value of certain globals we need to revert to later.
1342       * @param array $object_data
1343       */
1344      $pre_filter = apply_filters( 'bp_attachments_pre_cover_image_ajax_upload', array(), $bp_params, $needs_reset, $object_data );
1345      if ( isset( $pre_filter['result'] ) ) {
1346          bp_attachments_json_response( $pre_filter['result'], $is_html4, $pre_filter );
1347      }
1348  
1349      $cover_image_attachment = new BP_Attachment_Cover_Image();
1350      $uploaded = $cover_image_attachment->upload( $_FILES );
1351  
1352      // Reset objects.
1353      if ( ! empty( $needs_reset ) ) {
1354          if ( ! empty( $needs_reset['component'] ) ) {
1355              $bp->{$needs_reset['component']}->{$needs_reset['key']} = $needs_reset['value'];
1356          } else {
1357              $bp->{$needs_reset['key']} = $needs_reset['value'];
1358          }
1359      }
1360  
1361      if ( ! empty( $uploaded['error'] ) ) {
1362          // Upload error response.
1363          bp_attachments_json_response( false, $is_html4, array(
1364              'type'    => 'upload_error',
1365              'message' => sprintf(
1366                  /* translators: %s: the upload error message */
1367                  __( 'Upload Failed! Error was: %s', 'buddypress' ),
1368                  $uploaded['error']
1369              ),
1370          ) );
1371      }
1372  
1373      $error_message = __( 'There was a problem uploading the cover image.', 'buddypress' );
1374  
1375      $bp_attachments_uploads_dir = bp_attachments_cover_image_upload_dir();
1376  
1377      // The BP Attachments Uploads Dir is not set, stop.
1378      if ( ! $bp_attachments_uploads_dir ) {
1379          bp_attachments_json_response( false, $is_html4, array(
1380              'type'    => 'upload_error',
1381              'message' => $error_message,
1382          ) );
1383      }
1384  
1385      $cover_subdir = $object_data['dir'] . '/' . $bp_params['item_id'] . '/cover-image';
1386      $cover_dir    = trailingslashit( $bp_attachments_uploads_dir['basedir'] ) . $cover_subdir;
1387  
1388      if ( 1 === validate_file( $cover_dir ) || ! is_dir( $cover_dir ) ) {
1389          // Upload error response.
1390          bp_attachments_json_response( false, $is_html4, array(
1391              'type'    => 'upload_error',
1392              'message' => $error_message,
1393          ) );
1394      }
1395  
1396      /*
1397       * Generate the cover image so that it fit to feature's dimensions
1398       *
1399       * Unlike the avatar, uploading and generating the cover image is happening during
1400       * the same Ajax request, as we already instantiated the BP_Attachment_Cover_Image
1401       * class, let's use it.
1402       */
1403      $cover = bp_attachments_cover_image_generate_file( array(
1404          'file'            => $uploaded['file'],
1405          'component'       => $object_data['component'],
1406          'cover_image_dir' => $cover_dir
1407      ), $cover_image_attachment );
1408  
1409      if ( ! $cover ) {
1410          bp_attachments_json_response( false, $is_html4, array(
1411              'type'    => 'upload_error',
1412              'message' => $error_message,
1413          ) );
1414      }
1415  
1416      $cover_url = trailingslashit( $bp_attachments_uploads_dir['baseurl'] ) . $cover_subdir . '/' . $cover['cover_basename'];
1417  
1418      // 1 is success.
1419      $feedback_code = 1;
1420  
1421      // 0 is the size warning.
1422      if ( $cover['is_too_small'] ) {
1423          $feedback_code = 0;
1424      }
1425  
1426      // Set the name of the file.
1427      $name       = $_FILES['file']['name'];
1428      $name_parts = pathinfo( $name );
1429      $name       = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) );
1430  
1431      // Set some arguments for filters.
1432      $item_id   = (int) $bp_params['item_id'];
1433      $component = $object_data['component'];
1434  
1435      /**
1436       * Fires if the new cover image was successfully uploaded.
1437       *
1438       * The dynamic portion of the hook will be members in case of a user's
1439       * cover image, groups in case of a group's cover image. For instance:
1440       * Use add_action( 'members_cover_image_uploaded' ) to run your specific
1441       * code once the user has set his cover image.
1442       *
1443       * @since 2.4.0
1444       * @since 3.0.0 Added $cover_url, $name, $feedback_code arguments.
1445       *
1446       * @param int    $item_id       Inform about the item id the cover image was set for.
1447       * @param string $name          Filename.
1448       * @param string $cover_url     URL to the image.
1449       * @param int    $feedback_code If value not 1, an error occured.
1450       */
1451      do_action(
1452          $component . '_cover_image_uploaded',
1453          $item_id,
1454          $name,
1455          $cover_url,
1456          $feedback_code
1457      );
1458  
1459      // Handle deprecated xProfile action.
1460      if ( 'members' === $component ) {
1461          /** This filter is documented in wp-includes/deprecated.php */
1462          do_action_deprecated(
1463              'xprofile_cover_image_uploaded',
1464              array(
1465                  $item_id,
1466                  $name,
1467                  $cover_url,
1468                  $feedback_code,
1469              ),
1470              '6.0.0',
1471              'members_cover_image_deleted'
1472          );
1473      }
1474  
1475      // Finally return the cover image url to the UI.
1476      bp_attachments_json_response( true, $is_html4, array(
1477          'name'          => $name,
1478          'url'           => $cover_url,
1479          'feedback_code' => $feedback_code,
1480      ) );
1481  }
1482  add_action( 'wp_ajax_bp_cover_image_upload', 'bp_attachments_cover_image_ajax_upload' );
1483  
1484  /**
1485   * Ajax delete a cover image for a given object and item id.
1486   *
1487   * @since 2.4.0
1488   *
1489   * @return string|null A json object containing success data if the cover image was deleted
1490   *                     error message otherwise.
1491   */
1492  function bp_attachments_cover_image_ajax_delete() {
1493      if ( ! bp_is_post_request() ) {
1494          wp_send_json_error();
1495      }
1496  
1497      if ( empty( $_POST['object'] ) || empty( $_POST['item_id'] ) || ( ! ctype_digit( $_POST['item_id'] ) && ! is_int( $_POST['item_id'] ) ) ) {
1498          wp_send_json_error();
1499      }
1500  
1501      $args = array(
1502          'object'  => sanitize_text_field( $_POST['object'] ),
1503          'item_id' => (int) $_POST['item_id'],
1504      );
1505  
1506      // Check permissions.
1507      check_admin_referer( 'bp_delete_cover_image', 'nonce' );
1508      if ( ! bp_attachments_current_user_can( 'edit_cover_image', $args ) ) {
1509          wp_send_json_error();
1510      }
1511  
1512      // Set object for the user's case.
1513      if ( 'user' === $args['object'] ) {
1514          $component = 'members';
1515          $dir       = 'members';
1516  
1517      // Set it for any other cases.
1518      } else {
1519          $component = $args['object'] . 's';
1520          $dir       = $component;
1521      }
1522  
1523      // Handle delete.
1524      if ( bp_attachments_delete_file( array( 'item_id' => $args['item_id'], 'object_dir' => $dir, 'type' => 'cover-image' ) ) ) {
1525          $item_id = (int) $args['item_id'];
1526  
1527          /**
1528           * Fires if the cover image was successfully deleted.
1529           *
1530           * The dynamic portion of the hook will be members in case of a user's
1531           * cover image, groups in case of a group's cover image. For instance:
1532           * Use add_action( 'members_cover_image_deleted' ) to run your specific
1533           * code once the user has deleted his cover image.
1534           *
1535           * @since 2.8.0
1536           *
1537           * @param int $item_id Inform about the item id the cover image was deleted for.
1538           */
1539          do_action( "{$component}_cover_image_deleted", $item_id );
1540  
1541          // Handle deprecated xProfile action.
1542          if ( 'members' === $component ) {
1543              /** This filter is documented in wp-includes/deprecated.php */
1544              do_action_deprecated( 'xprofile_cover_image_deleted', array( $item_id ), '6.0.0', 'members_cover_image_deleted' );
1545          }
1546  
1547          $response = array(
1548              'reset_url'     => '',
1549              'feedback_code' => 3,
1550          );
1551  
1552          // Get cover image settings in case there's a default header.
1553          $cover_params = bp_attachments_get_cover_image_settings( $component );
1554  
1555          // Check if there's a default cover.
1556          if ( ! empty( $cover_params['default_cover'] ) ) {
1557              $response['reset_url'] = $cover_params['default_cover'];
1558          }
1559  
1560          wp_send_json_success( $response );
1561  
1562      } else {
1563          wp_send_json_error( array(
1564              'feedback_code' => 2,
1565          ) );
1566      }
1567  }
1568  add_action( 'wp_ajax_bp_cover_image_delete', 'bp_attachments_cover_image_ajax_delete' );


Generated: Fri Sep 25 01:01:33 2020 Cross-referenced by PHPXref 0.7.1