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


Generated: Wed May 22 01:01:45 2019 Cross-referenced by PHPXref 0.7.1