[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * BuddyPress Avatars. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 1.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * Set up the constants we need for avatar support. 15 * 16 * @since 1.2.0 17 */ 18 function bp_core_set_avatar_constants() { 19 20 $bp = buddypress(); 21 22 if ( !defined( 'BP_AVATAR_THUMB_WIDTH' ) ) 23 define( 'BP_AVATAR_THUMB_WIDTH', 50 ); 24 25 if ( !defined( 'BP_AVATAR_THUMB_HEIGHT' ) ) 26 define( 'BP_AVATAR_THUMB_HEIGHT', 50 ); 27 28 if ( !defined( 'BP_AVATAR_FULL_WIDTH' ) ) 29 define( 'BP_AVATAR_FULL_WIDTH', 150 ); 30 31 if ( !defined( 'BP_AVATAR_FULL_HEIGHT' ) ) 32 define( 'BP_AVATAR_FULL_HEIGHT', 150 ); 33 34 if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_WIDTH' ) ) 35 define( 'BP_AVATAR_ORIGINAL_MAX_WIDTH', 450 ); 36 37 if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE' ) ) { 38 define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', bp_attachments_get_max_upload_file_size( 'avatar' ) ); 39 } 40 41 if ( ! defined( 'BP_SHOW_AVATARS' ) ) { 42 define( 'BP_SHOW_AVATARS', bp_get_option( 'show_avatars' ) ); 43 } 44 } 45 add_action( 'bp_init', 'bp_core_set_avatar_constants', 3 ); 46 47 /** 48 * Set up global variables related to avatars. 49 * 50 * @since 1.5.0 51 */ 52 function bp_core_set_avatar_globals() { 53 $bp = buddypress(); 54 55 $bp->avatar = new stdClass; 56 $bp->avatar->thumb = new stdClass; 57 $bp->avatar->full = new stdClass; 58 59 // Dimensions. 60 $bp->avatar->thumb->width = BP_AVATAR_THUMB_WIDTH; 61 $bp->avatar->thumb->height = BP_AVATAR_THUMB_HEIGHT; 62 $bp->avatar->full->width = BP_AVATAR_FULL_WIDTH; 63 $bp->avatar->full->height = BP_AVATAR_FULL_HEIGHT; 64 65 // Upload maximums. 66 $bp->avatar->original_max_width = BP_AVATAR_ORIGINAL_MAX_WIDTH; 67 $bp->avatar->original_max_filesize = BP_AVATAR_ORIGINAL_MAX_FILESIZE; 68 69 // Defaults. 70 $bp->avatar->thumb->default = bp_core_avatar_default_thumb(); 71 $bp->avatar->full->default = bp_core_avatar_default(); 72 73 // These have to be set on page load in order to avoid infinite filter loops at runtime. 74 $bp->avatar->upload_path = bp_core_avatar_upload_path(); 75 $bp->avatar->url = bp_core_avatar_url(); 76 77 // Cache the root blog's show_avatars setting, to avoid unnecessary 78 // calls to switch_to_blog(). 79 $bp->avatar->show_avatars = (bool) BP_SHOW_AVATARS; 80 81 // Backpat for pre-1.5. 82 if ( ! defined( 'BP_AVATAR_UPLOAD_PATH' ) ) 83 define( 'BP_AVATAR_UPLOAD_PATH', $bp->avatar->upload_path ); 84 85 // Backpat for pre-1.5. 86 if ( ! defined( 'BP_AVATAR_URL' ) ) 87 define( 'BP_AVATAR_URL', $bp->avatar->url ); 88 89 /** 90 * Fires at the end of the core avatar globals setup. 91 * 92 * @since 1.5.0 93 */ 94 do_action( 'bp_core_set_avatar_globals' ); 95 } 96 add_action( 'bp_setup_globals', 'bp_core_set_avatar_globals' ); 97 98 /** 99 * Checks whether a given gravatar is one of the default ones. 100 * 101 * @since 8.0.0 102 * 103 * @param string $d The name of the default gravatar. 104 * @return bool True if it's a default gravatar. False otherwise. 105 */ 106 function bp_core_is_default_gravatar( $d = '' ) { 107 if ( ! $d ) { 108 return false; 109 } 110 111 /** this filter is documented in wp-admin/options-discussion.php */ 112 $gravatar_defaults = apply_filters( 113 'avatar_defaults', 114 array_fill_keys( 115 array( 116 'mystery', 117 'blank', 118 'gravatar_default', 119 'identicon', 120 'wavatar', 121 'monsterid', 122 'retro', 123 ), 124 '' 125 ) 126 ); 127 128 return isset( $gravatar_defaults[ $d ] ); 129 } 130 131 /** 132 * Get an avatar for a BuddyPress object. 133 * 134 * Supports avatars for users, groups, and blogs by default, but can be 135 * extended to support custom components as well. 136 * 137 * This function gives precedence to locally-uploaded avatars. When a local 138 * avatar is not found, Gravatar is queried. To disable Gravatar fallbacks 139 * locally: 140 * add_filter( 'bp_core_fetch_avatar_no_grav', '__return_true' ); 141 * 142 * @since 1.1.0 143 * @since 2.4.0 Added 'extra_attr', 'scheme', 'rating' and 'force_default' for $args. 144 * These are inherited from WordPress 4.2.0. See {@link get_avatar()}. 145 * 146 * @param array|string $args { 147 * An array of arguments. All arguments are technically optional; some 148 * will, if not provided, be auto-detected by bp_core_fetch_avatar(). This 149 * auto-detection is described more below, when discussing specific 150 * arguments. 151 * 152 * @type int|bool $item_id The numeric ID of the item for which you're requesting 153 * an avatar (eg, a user ID). If no 'item_id' is present, 154 * the function attempts to infer an ID from the 'object' + the 155 * current context: if 'object' is 'user' and the current page is a 156 * user page, 'item_id' will default to the displayed user ID; if 157 * 'group' and on a group page, to the current group ID; if 'blog', 158 * to the current blog's ID. If no 'item_id' can be determined in 159 * this way, the function returns false. Default: false. 160 * @type string $object The kind of object for which you're getting an 161 * avatar. BuddyPress natively supports three options: 'user', 162 * 'group', 'blog'; a plugin may register more. Default: 'user'. 163 * @type string $type When a new avatar is uploaded to BP, 'thumb' and 164 * 'full' versions are saved. This parameter specifies whether you'd 165 * like the 'full' or smaller 'thumb' avatar. Default: 'thumb'. 166 * @type string|bool $avatar_dir The name of the subdirectory where the 167 * requested avatar should be found. If no value is passed, 168 * 'avatar_dir' is inferred from 'object': 'user' becomes 'avatars', 169 * 'group' becomes 'group-avatars', 'blog' becomes 'blog-avatars'. 170 * Remember that this string denotes a subdirectory of BP's main 171 * avatar directory (usually based on {@link wp_upload_dir()}); it's a 172 * string like 'group-avatars' rather than the full directory path. 173 * Generally, it'll only be necessary to override the default value if 174 * storing avatars in a non-default location. Defaults to false 175 * (auto-detected). 176 * @type int|bool $width Requested avatar width. The unit is px. This value 177 * is used to build the 'width' attribute for the <img> element. If 178 * no value is passed, BP uses the global avatar width for this 179 * avatar type. Default: false (auto-detected). 180 * @type int|bool $height Requested avatar height. The unit is px. This 181 * value is used to build the 'height' attribute for the <img> 182 * element. If no value is passed, BP uses the global avatar height 183 * for this avatar type. Default: false (auto-detected). 184 * @type string $class The CSS class for the <img> element. Note that BP 185 * uses the 'avatar' class fairly extensively in its default styling, 186 * so if you plan to pass a custom value, consider appending it to 187 * 'avatar' (eg 'avatar foo') rather than replacing it altogether. 188 * Default: 'avatar'. 189 * @type string|bool $css_id The CSS id for the <img> element. 190 * Default: false. 191 * @type string $title The title attribute for the <img> element. 192 * Default: false. 193 * @type string $alt The alt attribute for the <img> element. In BP, this 194 * value is generally passed by the wrapper functions, where the data 195 * necessary for concatenating the string is at hand; see 196 * {@link bp_get_activity_avatar()} for an example. Default: ''. 197 * @type string|bool $email An email to use in Gravatar queries. Unless 198 * otherwise configured, BP uses Gravatar as a fallback for avatars 199 * that are not provided locally. Gravatar's API requires using a hash 200 * of the user's email address; this argument provides it. If not 201 * provided, the function will infer it: for users, by getting the 202 * user's email from the database, for groups/blogs, by concatenating 203 * "{$item_id}-{$object}@{bp_get_root_domain()}". The user query adds 204 * overhead, so it's recommended that wrapper functions provide a 205 * value for 'email' when querying user IDs. Default: false. 206 * @type bool $no_grav Whether to disable the default Gravatar fallback. 207 * By default, BP will fall back on Gravatar when it cannot find a 208 * local avatar. In some cases, this may be undesirable, in which 209 * case 'no_grav' should be set to true. To disable Gravatar 210 * fallbacks globally, see the 'bp_core_fetch_avatar_no_grav' filter. 211 * Default: true for groups, otherwise false. 212 * @type bool $html Whether to return an <img> HTML element, vs a raw URL 213 * to an avatar. If false, <img>-specific arguments (like 'css_id') 214 * will be ignored. Default: true. 215 * @type string $extra_attr HTML attributes to insert in the IMG element. Not sanitized. Default: ''. 216 * @type string $scheme URL scheme to use. See set_url_scheme() for accepted values. 217 * Default null. 218 * @type string $rating What rating to display Gravatars for. Accepts 'G', 'PG', 'R', 'X'. 219 * Default is the value of the 'avatar_rating' option. 220 * @type bool $force_default Used when creating the Gravatar URL. Whether to force the default 221 * image regardless if the Gravatar exists. Default: false. 222 * } 223 * @return string Formatted HTML <img> element, or raw avatar URL based on $html arg. 224 */ 225 function bp_core_fetch_avatar( $args = '' ) { 226 $bp = buddypress(); 227 228 // If avatars are disabled for the root site, obey that request and bail. 229 if ( ! $bp->avatar || ! $bp->avatar->show_avatars ) { 230 return; 231 } 232 233 // Set the default variables array and parse it against incoming $args array. 234 $params = bp_parse_args( 235 $args, 236 array( 237 'item_id' => false, 238 'object' => 'user', 239 'type' => 'thumb', 240 'avatar_dir' => false, 241 'width' => false, 242 'height' => false, 243 'class' => 'avatar', 244 'css_id' => false, 245 'alt' => '', 246 'email' => false, 247 'no_grav' => null, 248 'html' => true, 249 'title' => '', 250 'extra_attr' => '', 251 'scheme' => null, 252 'rating' => get_option( 'avatar_rating' ), 253 'force_default' => false, 254 ) 255 ); 256 257 /* Set item_id ***********************************************************/ 258 259 if ( empty( $params['item_id'] ) ) { 260 261 switch ( $params['object'] ) { 262 263 case 'blog' : 264 $params['item_id'] = get_current_blog_id(); 265 break; 266 267 case 'group' : 268 if ( bp_is_active( 'groups' ) ) { 269 $params['item_id'] = $bp->groups->current_group->id; 270 } else { 271 $params['item_id'] = false; 272 } 273 274 break; 275 276 case 'user' : 277 default : 278 $params['item_id'] = bp_displayed_user_id(); 279 break; 280 } 281 282 /** 283 * Filters the ID of the item being requested. 284 * 285 * @since 1.1.0 286 * 287 * @param string $value ID of avatar item being requested. 288 * @param string $value Avatar type being requested. 289 * @param array $params Array of parameters for the request. 290 */ 291 $params['item_id'] = apply_filters( 'bp_core_avatar_item_id', $params['item_id'], $params['object'], $params ); 292 293 if ( empty( $params['item_id'] ) ) { 294 return false; 295 } 296 } 297 298 /* Set avatar_dir ********************************************************/ 299 300 if ( empty( $params['avatar_dir'] ) ) { 301 302 switch ( $params['object'] ) { 303 304 case 'blog' : 305 $params['avatar_dir'] = 'blog-avatars'; 306 break; 307 308 case 'group' : 309 if ( bp_is_active( 'groups' ) ) { 310 $params['avatar_dir'] = 'group-avatars'; 311 } else { 312 $params['avatar_dir'] = false; 313 } 314 315 break; 316 317 case 'user' : 318 default : 319 $params['avatar_dir'] = 'avatars'; 320 break; 321 } 322 323 /** 324 * Filters the avatar directory to use. 325 * 326 * @since 1.1.0 327 * 328 * @param string $value Name of the subdirectory where the requested avatar should be found. 329 * @param string $value Avatar type being requested. 330 * @param array $params Array of parameters for the request. 331 */ 332 $params['avatar_dir'] = apply_filters( 'bp_core_avatar_dir', $params['avatar_dir'], $params['object'], $params ); 333 334 if ( empty( $params['avatar_dir'] ) ) { 335 return false; 336 } 337 } 338 339 /* <img> alt *************************************************************/ 340 341 if ( false !== strpos( $params['alt'], '%s' ) || false !== strpos( $params['alt'], '%1$s' ) ) { 342 343 switch ( $params['object'] ) { 344 345 case 'blog' : 346 $item_name = get_blog_option( $params['item_id'], 'blogname' ); 347 break; 348 349 case 'group' : 350 $item_name = bp_get_group_name( groups_get_group( $params['item_id'] ) ); 351 break; 352 353 case 'user' : 354 default : 355 $item_name = bp_core_get_user_displayname( $params['item_id'] ); 356 break; 357 } 358 359 /** 360 * Filters the alt attribute value to be applied to avatar. 361 * 362 * @since 1.5.0 363 * 364 * @param string $value alt to be applied to avatar. 365 * @param string $value ID of avatar item being requested. 366 * @param string $value Avatar type being requested. 367 * @param array $params Array of parameters for the request. 368 */ 369 $item_name = apply_filters( 'bp_core_avatar_alt', $item_name, $params['item_id'], $params['object'], $params ); 370 $params['alt'] = sprintf( $params['alt'], $item_name ); 371 } 372 373 /* Sanity Checks *********************************************************/ 374 375 // Get a fallback for the 'alt' parameter, create html output. 376 if ( empty( $params['alt'] ) ) { 377 $params['alt'] = __( 'Profile Photo', 'buddypress' ); 378 } 379 $html_alt = ' alt="' . esc_attr( $params['alt'] ) . '"'; 380 381 // Filter image title and create html string. 382 $html_title = ''; 383 384 /** 385 * Filters the title attribute value to be applied to avatar. 386 * 387 * @since 1.5.0 388 * 389 * @param string $value Title to be applied to avatar. 390 * @param string $value ID of avatar item being requested. 391 * @param string $value Avatar type being requested. 392 * @param array $params Array of parameters for the request. 393 */ 394 $params['title'] = apply_filters( 'bp_core_avatar_title', $params['title'], $params['item_id'], $params['object'], $params ); 395 396 if ( ! empty( $params['title'] ) ) { 397 $html_title = ' title="' . esc_attr( $params['title'] ) . '"'; 398 } 399 400 // Extra attributes. 401 $extra_attr = ''; 402 if ( ! empty( $params['extra_attr'] ) ) { 403 $extra_attr = ' ' . $params['extra_attr']; 404 } 405 406 // Set CSS ID and create html string. 407 $html_css_id = ''; 408 409 /** 410 * Filters the ID attribute to be applied to avatar. 411 * 412 * @since 2.2.0 413 * 414 * @param string $value ID to be applied to avatar. 415 * @param string $value ID of avatar item being requested. 416 * @param string $value Avatar type being requested. 417 * @param array $params Array of parameters for the request. 418 */ 419 $params['css_id'] = apply_filters( 'bp_core_css_id', $params['css_id'], $params['item_id'], $params['object'], $params ); 420 421 if ( ! empty( $params['css_id'] ) ) { 422 $html_css_id = ' id="' . esc_attr( $params['css_id'] ) . '"'; 423 } 424 425 // Set image width. 426 if ( false !== $params['width'] ) { 427 // Width has been specified. No modification necessary. 428 } elseif ( 'thumb' == $params['type'] ) { 429 $params['width'] = bp_core_avatar_thumb_width(); 430 } else { 431 $params['width'] = bp_core_avatar_full_width(); 432 } 433 $html_width = ' width="' . $params['width'] . '"'; 434 435 // Set image height. 436 if ( false !== $params['height'] ) { 437 // Height has been specified. No modification necessary. 438 } elseif ( 'thumb' == $params['type'] ) { 439 $params['height'] = bp_core_avatar_thumb_height(); 440 } else { 441 $params['height'] = bp_core_avatar_full_height(); 442 } 443 $html_height = ' height="' . $params['height'] . '"'; 444 445 /** 446 * Filters the classes to be applied to the avatar. 447 * 448 * @since 1.6.0 449 * 450 * @param array|string $value Class(es) to be applied to the avatar. 451 * @param string $value ID of the avatar item being requested. 452 * @param string $value Avatar type being requested. 453 * @param array $params Array of parameters for the request. 454 */ 455 $params['class'] = apply_filters( 'bp_core_avatar_class', $params['class'], $params['item_id'], $params['object'], $params ); 456 457 // Use an alias to leave the param unchanged. 458 $avatar_classes = $params['class']; 459 if ( ! is_array( $avatar_classes ) ) { 460 $avatar_classes = explode( ' ', $avatar_classes ); 461 } 462 463 // Merge classes. 464 $avatar_classes = array_merge( $avatar_classes, array( 465 $params['object'] . '-' . $params['item_id'] . '-avatar', 466 'avatar-' . $params['width'], 467 ) ); 468 469 // Sanitize each class. 470 $avatar_classes = array_map( 'sanitize_html_class', $avatar_classes ); 471 472 // Populate the class attribute. 473 $html_class = ' class="' . join( ' ', $avatar_classes ) . ' photo"'; 474 475 // Set img URL and DIR based on prepopulated constants. 476 $avatar_loc = new stdClass(); 477 $avatar_loc->path = trailingslashit( bp_core_avatar_upload_path() ); 478 $avatar_loc->url = trailingslashit( bp_core_avatar_url() ); 479 480 $avatar_loc->dir = trailingslashit( $params['avatar_dir'] ); 481 482 /** 483 * Filters the avatar folder directory URL. 484 * 485 * @since 1.1.0 486 * 487 * @param string $value Path to the avatar folder URL. 488 * @param int $value ID of the avatar item being requested. 489 * @param string $value Avatar type being requested. 490 * @param string $value Subdirectory where the requested avatar should be found. 491 */ 492 $avatar_folder_url = apply_filters( 'bp_core_avatar_folder_url', ( $avatar_loc->url . $avatar_loc->dir . $params['item_id'] ), $params['item_id'], $params['object'], $params['avatar_dir'] ); 493 494 /** 495 * Filters the avatar folder directory path. 496 * 497 * @since 1.1.0 498 * 499 * @param string $value Path to the avatar folder directory. 500 * @param int $value ID of the avatar item being requested. 501 * @param string $value Avatar type being requested. 502 * @param string $value Subdirectory where the requested avatar should be found. 503 */ 504 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', ( $avatar_loc->path . $avatar_loc->dir . $params['item_id'] ), $params['item_id'], $params['object'], $params['avatar_dir'] ); 505 506 /** 507 * Look for uploaded avatar first. Use it if it exists. 508 * Set the file names to search for, to select the full size 509 * or thumbnail image. 510 */ 511 $avatar_size = ( 'full' == $params['type'] ) ? '-bpfull' : '-bpthumb'; 512 $legacy_user_avatar_name = ( 'full' == $params['type'] ) ? '-avatar2' : '-avatar1'; 513 $legacy_group_avatar_name = ( 'full' == $params['type'] ) ? '-groupavatar-full' : '-groupavatar-thumb'; 514 515 // Check for directory. 516 if ( ! $params['force_default'] && file_exists( $avatar_folder_dir ) ) { 517 518 // Open directory. 519 if ( $av_dir = opendir( $avatar_folder_dir ) ) { 520 521 // Stash files in an array once to check for one that matches. 522 $avatar_files = array(); 523 while ( false !== ( $avatar_file = readdir( $av_dir ) ) ) { 524 // Only add files to the array (skip directories). 525 if ( 2 < strlen( $avatar_file ) ) { 526 $avatar_files[] = $avatar_file; 527 } 528 } 529 530 // Check for array. 531 if ( 0 < count( $avatar_files ) ) { 532 533 // Check for current avatar. 534 foreach( $avatar_files as $key => $value ) { 535 if ( strpos ( $value, $avatar_size )!== false ) { 536 $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key]; 537 } 538 } 539 540 // Legacy avatar check. 541 if ( !isset( $avatar_url ) ) { 542 foreach( $avatar_files as $key => $value ) { 543 if ( strpos ( $value, $legacy_user_avatar_name )!== false ) { 544 $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key]; 545 } 546 } 547 548 // Legacy group avatar check. 549 if ( !isset( $avatar_url ) ) { 550 foreach( $avatar_files as $key => $value ) { 551 if ( strpos ( $value, $legacy_group_avatar_name )!== false ) { 552 $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key]; 553 } 554 } 555 } 556 } 557 } 558 } 559 560 // Close the avatar directory. 561 closedir( $av_dir ); 562 563 // If we found a locally uploaded avatar. 564 if ( isset( $avatar_url ) ) { 565 // Support custom scheme. 566 $avatar_url = set_url_scheme( $avatar_url, $params['scheme'] ); 567 568 // Return it wrapped in an <img> element. 569 if ( true === $params['html'] ) { 570 571 /** 572 * Filters an avatar URL wrapped in an <img> element. 573 * 574 * @since 1.1.0 575 * 576 * @param string $value Full <img> element for an avatar. 577 * @param array $params Array of parameters for the request. 578 * @param string $value ID of the item requested. 579 * @param string $value Subdirectory where the requested avatar should be found. 580 * @param string $html_css_id ID attribute for avatar. 581 * @param string $html_width Width attribute for avatar. 582 * @param string $html_height Height attribute for avatar. 583 * @param string $avatar_folder_url Avatar URL path. 584 * @param string $avatar_folder_dir Avatar DIR path. 585 */ 586 return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $avatar_url . '"' . $html_class . $html_css_id . $html_width . $html_height . $html_alt . $html_title . $extra_attr . ' />', $params, $params['item_id'], $params['avatar_dir'], $html_css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir ); 587 588 // ...or only the URL 589 } else { 590 591 /** 592 * Filters a locally uploaded avatar URL. 593 * 594 * @since 1.2.5 595 * 596 * @param string $avatar_url URL for a locally uploaded avatar. 597 * @param array $params Array of parameters for the request. 598 */ 599 return apply_filters( 'bp_core_fetch_avatar_url', $avatar_url, $params ); 600 } 601 } 602 } 603 604 // By default, Gravatar is not pinged for groups. 605 if ( null === $params['no_grav'] ) { 606 $params['no_grav'] = 'group' === $params['object']; 607 } 608 609 /** 610 * Filters whether or not to skip Gravatar check. 611 * 612 * @since 1.5.0 613 * 614 * @param bool $value Whether or not to skip Gravatar. 615 * @param array $params Array of parameters for the avatar request. 616 */ 617 if ( ! apply_filters( 'bp_core_fetch_avatar_no_grav', $params['no_grav'], $params ) ) { 618 619 // Set gravatar type. 620 if ( empty( $bp->grav_default->{$params['object']} ) ) { 621 $default_grav = 'wavatar'; 622 } elseif ( 'mystery' == $bp->grav_default->{$params['object']} ) { 623 624 /** 625 * Filters the Mystery person avatar src value. 626 * 627 * @since 1.2.0 628 * 629 * @param string $value Avatar value. 630 * @param string $value Width to display avatar at. 631 */ 632 $default_grav = apply_filters( 'bp_core_mysteryman_src', 'mm', $params['width'] ); 633 } else { 634 $default_grav = $bp->grav_default->{$params['object']}; 635 } 636 637 // Set gravatar object. 638 if ( empty( $params['email'] ) ) { 639 if ( 'user' == $params['object'] ) { 640 $params['email'] = bp_core_get_user_email( $params['item_id'] ); 641 } elseif ( 'group' == $params['object'] || 'blog' == $params['object'] ) { 642 $params['email'] = $params['item_id'] . '-' . $params['object'] . '@' . bp_get_root_domain(); 643 } 644 } 645 646 /** 647 * Filters the Gravatar email to use. 648 * 649 * @since 1.1.0 650 * 651 * @param string $value Email to use in Gravatar request. 652 * @param string $value ID of the item being requested. 653 * @param string $value Object type being requested. 654 */ 655 $params['email'] = apply_filters( 'bp_core_gravatar_email', $params['email'], $params['item_id'], $params['object'] ); 656 657 /** 658 * Filters the Gravatar URL host. 659 * 660 * @since 1.0.2 661 * 662 * @param string $value Gravatar URL host. 663 */ 664 $gravatar = apply_filters( 'bp_gravatar_url', '//www.gravatar.com/avatar/' ); 665 666 // Append email hash to Gravatar. 667 $gravatar .= md5( strtolower( $params['email'] ) ); 668 669 // Main Gravatar URL args. 670 $url_args = array( 671 's' => $params['width'] 672 ); 673 674 // Custom Gravatar URL args. 675 if ( ! empty( $params['force_default'] ) ) { 676 $url_args['f'] = 'y'; 677 $url_args['d'] = $params['default']; 678 } 679 if ( ! empty( $params['rating'] ) ) { 680 $url_args['r'] = strtolower( $params['rating'] ); 681 } 682 683 /** This filter is documented in wp-includes/deprecated.php */ 684 $d = apply_filters_deprecated( 685 'bp_core_avatar_default', 686 array( $default_grav, $params ), 687 '8.0.0', 688 'bp_core_avatar_gravatar_default||bp_core_default_avatar', 689 __( 'This filter was used for 2 different purposes. If your goal was to filter the default *Gravatar*, please use `bp_core_avatar_gravatar_default` instead. Otherwise, please use `bp_core_default_avatar` instead.', 'buddypress' ) 690 ); 691 692 if ( bp_core_is_default_gravatar( $d ) ) { 693 $default_grav = $d; 694 } 695 696 /** 697 * Filters the Gravatar "d" parameter. 698 * 699 * @since 2.6.0 700 * @since 8.0.0 The name of the filter was changed to `bp_core_avatar_gravatar_default`. 701 * 702 * @param string $default_grav The avatar default. 703 * @param array $params The avatar's data. 704 */ 705 $default_grav = apply_filters( 'bp_core_avatar_gravatar_default', $default_grav, $params ); 706 707 // Only set default image if 'Gravatar Logo' is not requested. 708 if ( ! $params['force_default'] && 'gravatar_default' !== $default_grav ) { 709 $url_args['d'] = $default_grav; 710 } 711 712 // Set up the Gravatar URL. 713 $gravatar = esc_url( add_query_arg( 714 rawurlencode_deep( array_filter( $url_args ) ), 715 $gravatar 716 ) ); 717 718 // No avatar was found, and we've been told not to use a gravatar. 719 } else { 720 721 /** 722 * Filters the avatar default when Gravatar is not used. 723 * 724 * This is a variable filter dependent on the avatar type being requested. 725 * 726 * @since 1.5.0 727 * 728 * @param string $value Default avatar for non-gravatar requests. 729 * @param array $params Array of parameters for the avatar request. 730 */ 731 $gravatar = apply_filters( 'bp_core_default_avatar_' . $params['object'], bp_core_avatar_default( 'local', $params ), $params ); 732 } 733 734 if ( true === $params['html'] ) { 735 736 /** This filter is documented in bp-core/bp-core-avatars.php */ 737 return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $gravatar . '"' . $html_css_id . $html_class . $html_width . $html_height . $html_alt . $html_title . $extra_attr . ' />', $params, $params['item_id'], $params['avatar_dir'], $html_css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir ); 738 } else { 739 740 /** This filter is documented in bp-core/bp-core-avatars.php */ 741 return apply_filters( 'bp_core_fetch_avatar_url', $gravatar, $params ); 742 } 743 } 744 745 /** 746 * Delete an existing avatar. 747 * 748 * @since 1.1.0 749 * 750 * @param array|string $args { 751 * Array of function parameters. 752 * @type bool|int $item_id ID of the item whose avatar you're deleting. 753 * Defaults to the current item of type $object. 754 * @type string $object Object type of the item whose avatar you're 755 * deleting. 'user', 'group', 'blog', or custom. 756 * Default: 'user'. 757 * @type bool|string $avatar_dir Subdirectory where avatar is located. 758 * Default: false, which falls back on the default location 759 * corresponding to the $object. 760 * } 761 * @return bool True on success, false on failure. 762 */ 763 function bp_core_delete_existing_avatar( $args = '' ) { 764 765 $defaults = array( 766 'item_id' => false, 767 'object' => 'user', // User OR group OR blog OR custom type (if you use filters). 768 'avatar_dir' => false 769 ); 770 771 $args = bp_parse_args( 772 $args, 773 $defaults 774 ); 775 776 /** 777 * Filters whether or not to handle deleting an existing avatar. 778 * 779 * If you want to override this function, make sure you return false. 780 * 781 * @since 2.5.1 782 * 783 * @param bool $value Whether or not to delete the avatar. 784 * @param array $args { 785 * Array of function parameters. 786 * 787 * @type bool|int $item_id ID of the item whose avatar you're deleting. 788 * Defaults to the current item of type $object. 789 * @type string $object Object type of the item whose avatar you're 790 * deleting. 'user', 'group', 'blog', or custom. 791 * Default: 'user'. 792 * @type bool|string $avatar_dir Subdirectory where avatar is located. 793 * Default: false, which falls back on the default location 794 * corresponding to the $object. 795 * } 796 */ 797 if ( ! apply_filters( 'bp_core_pre_delete_existing_avatar', true, $args ) ) { 798 return true; 799 } 800 801 if ( empty( $args['item_id'] ) ) { 802 if ( 'user' === $args['object'] ) { 803 $args['item_id'] = bp_displayed_user_id(); 804 } elseif ( 'group' === $args['object'] ) { 805 $args['item_id'] = buddypress()->groups->current_group->id; 806 } elseif ( 'blog' === $args['object'] ) { 807 $args['item_id'] = get_current_blog_id(); 808 } 809 810 /** This filter is documented in bp-core/bp-core-avatars.php */ 811 $item_id = apply_filters( 'bp_core_avatar_item_id', $args['item_id'], $args['object'] ); 812 } else { 813 $item_id = $args['item_id']; 814 } 815 816 if ( $item_id && ( ctype_digit( $item_id ) || is_int( $item_id ) ) ) { 817 $item_id = (int) $item_id; 818 } else { 819 return false; 820 } 821 822 if ( empty( $args['avatar_dir'] ) ) { 823 if ( 'user' === $args['object'] ) { 824 $args['avatar_dir'] = 'avatars'; 825 } elseif ( 'group' === $args['object'] ) { 826 $args['avatar_dir'] = 'group-avatars'; 827 } elseif ( 'blog' === $args['object'] ) { 828 $args['avatar_dir'] = 'blog-avatars'; 829 } 830 831 /** This filter is documented in bp-core/bp-core-avatars.php */ 832 $avatar_dir = apply_filters( 'bp_core_avatar_dir', $args['avatar_dir'], $args['object'] ); 833 } else { 834 $avatar_dir = $args['avatar_dir']; 835 } 836 837 if ( ! $avatar_dir ) { 838 return false; 839 } 840 841 /** This filter is documented in bp-core/bp-core-avatars.php */ 842 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $args['object'], $avatar_dir ); 843 844 if ( ! is_dir( $avatar_folder_dir ) ) { 845 return false; 846 } 847 848 if ( $av_dir = opendir( $avatar_folder_dir ) ) { 849 while ( false !== ( $avatar_file = readdir( $av_dir ) ) ) { 850 if ( ( preg_match( "/-bpfull/", $avatar_file ) || preg_match( "/-bpthumb/", $avatar_file ) ) && '.' != $avatar_file && '..' != $avatar_file ) { 851 @unlink( $avatar_folder_dir . '/' . $avatar_file ); 852 } 853 } 854 } 855 closedir( $av_dir ); 856 857 @rmdir( $avatar_folder_dir ); 858 859 /** 860 * Fires after deleting an existing avatar. 861 * 862 * @since 1.1.0 863 * 864 * @param array $args Array of arguments used for avatar deletion. 865 */ 866 do_action( 'bp_core_delete_existing_avatar', $args ); 867 868 return true; 869 } 870 871 /** 872 * Ajax delete an avatar for a given object and item id. 873 * 874 * @since 2.3.0 875 * 876 * @return string|null A JSON object containing success data if the avatar was deleted, 877 * error message otherwise. 878 */ 879 function bp_avatar_ajax_delete() { 880 if ( ! bp_is_post_request() ) { 881 wp_send_json_error(); 882 } 883 884 $avatar_data = $_POST; 885 886 if ( empty( $avatar_data['object'] ) || empty( $avatar_data['item_id'] ) ) { 887 wp_send_json_error(); 888 } 889 890 $nonce = 'bp_delete_avatar_link'; 891 if ( 'group' === $avatar_data['object'] ) { 892 $nonce = 'bp_group_avatar_delete'; 893 } 894 895 // Check the nonce. 896 check_admin_referer( $nonce, 'nonce' ); 897 898 // Capability check. 899 if ( ! bp_attachments_current_user_can( 'edit_avatar', $avatar_data ) ) { 900 wp_send_json_error(); 901 } 902 903 // Handle delete. 904 if ( bp_core_delete_existing_avatar( array( 'item_id' => $avatar_data['item_id'], 'object' => $avatar_data['object'] ) ) ) { 905 $return = array( 906 'avatar' => esc_url( bp_core_fetch_avatar( array( 907 'object' => $avatar_data['object'], 908 'item_id' => $avatar_data['item_id'], 909 'html' => false, 910 'type' => 'full', 911 ) ) ), 912 'feedback_code' => 4, 913 'item_id' => $avatar_data['item_id'], 914 ); 915 916 wp_send_json_success( $return ); 917 } else { 918 wp_send_json_error( array( 919 'feedback_code' => 3, 920 ) ); 921 } 922 } 923 add_action( 'wp_ajax_bp_avatar_delete', 'bp_avatar_ajax_delete' ); 924 925 /** 926 * Handle avatar uploading. 927 * 928 * The functions starts off by checking that the file has been uploaded 929 * properly using bp_core_check_avatar_upload(). It then checks that the file 930 * size is within limits, and that it has an accepted file extension (jpg, gif, 931 * png). If everything checks out, crop the image and move it to its real 932 * location. 933 * 934 * @since 1.1.0 935 * 936 * @see bp_core_check_avatar_upload() 937 * @see bp_core_check_avatar_type() 938 * 939 * @param array $file The appropriate entry the from $_FILES superglobal. 940 * @param string $upload_dir_filter A filter to be applied to 'upload_dir'. 941 * @return bool True on success, false on failure. 942 */ 943 function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) { 944 945 /** 946 * Filters whether or not to handle uploading. 947 * 948 * If you want to override this function, make sure you return false. 949 * 950 * @since 1.2.4 951 * 952 * @param bool $value Whether or not to crop. 953 * @param array $file Appropriate entry from $_FILES superglobal. 954 * @parma string $upload_dir_filter A filter to be applied to 'upload_dir'. 955 */ 956 if ( ! apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $upload_dir_filter ) ) { 957 return true; 958 } 959 960 // Setup some variables. 961 $bp = buddypress(); 962 $upload_path = bp_core_avatar_upload_path(); 963 964 // Upload the file. 965 $avatar_attachment = new BP_Attachment_Avatar(); 966 $bp->avatar_admin->original = $avatar_attachment->upload( $file, $upload_dir_filter ); 967 968 // In case of an error, stop the process and display a feedback to the user. 969 if ( ! empty( $bp->avatar_admin->original['error'] ) ) { 970 /* translators: %s: the upload error message */ 971 bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->original['error'] ), 'error' ); 972 return false; 973 } 974 975 // The Avatar UI available width. 976 $ui_available_width = 0; 977 978 // Try to set the ui_available_width using the avatar_admin global. 979 if ( isset( $bp->avatar_admin->ui_available_width ) ) { 980 $ui_available_width = $bp->avatar_admin->ui_available_width; 981 } 982 983 // Maybe resize. 984 $original_file_size = $avatar_attachment->get_image_data( $bp->avatar_admin->original['file'] ); 985 $bp->avatar_admin->resized = $avatar_attachment->shrink( $bp->avatar_admin->original['file'], $ui_available_width ); 986 $bp->avatar_admin->image = new stdClass(); 987 988 // We only want to handle one image after resize. 989 if ( empty( $bp->avatar_admin->resized ) || is_wp_error( $bp->avatar_admin->resized ) ) { 990 $bp->avatar_admin->image->file = $bp->avatar_admin->original['file']; 991 $bp->avatar_admin->image->dir = str_replace( $upload_path, '', $bp->avatar_admin->original['file'] ); 992 } else { 993 $bp->avatar_admin->image->file = $bp->avatar_admin->resized['path']; 994 $bp->avatar_admin->image->dir = str_replace( $upload_path, '', $bp->avatar_admin->resized['path'] ); 995 @unlink( $bp->avatar_admin->original['file'] ); 996 } 997 998 // Check for WP_Error on what should be an image. 999 if ( is_wp_error( $bp->avatar_admin->image->dir ) ) { 1000 /* translators: %s: the upload error message */ 1001 bp_core_add_message( sprintf( __( 'Upload failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->image->dir->get_error_message() ), 'error' ); 1002 return false; 1003 } 1004 1005 // If the uploaded image is smaller than the "full" dimensions, throw a warning. 1006 if ( $avatar_attachment->is_too_small( $bp->avatar_admin->image->file ) ) { 1007 if ( isset( $original_file_size['width'] ) && $original_file_size['width'] > bp_core_avatar_full_width() ) { 1008 $aspect_ratio = number_format_i18n( bp_core_avatar_full_width() / bp_core_avatar_full_height(), 2 ); 1009 1010 /* translators: %s: the value of the aspect ratio. */ 1011 bp_core_add_message( sprintf( __( 'The aspect ratio of the image you selected is too great compared to the profile photo one. For best results, upload a picture having an aspect ratio closer to %s.', 'buddypress' ), $aspect_ratio ), 'error' ); 1012 } else { 1013 1014 /* translators: 1: the advised width size in pixels. 2: the advised height size in pixels. */ 1015 bp_core_add_message( sprintf( __( 'You have selected an image that is smaller than recommended. For best results, upload a picture larger than %1$d x %2$d pixels.', 'buddypress' ), bp_core_avatar_full_width(), bp_core_avatar_full_height() ), 'error' ); 1016 } 1017 } 1018 1019 // Set the url value for the image. 1020 $bp->avatar_admin->image->url = bp_core_avatar_url() . $bp->avatar_admin->image->dir; 1021 1022 return true; 1023 } 1024 1025 /** 1026 * Ajax upload an avatar. 1027 * 1028 * @since 2.3.0 1029 * 1030 * @return string|null A JSON object containing success data if the upload succeeded 1031 * error message otherwise. 1032 */ 1033 function bp_avatar_ajax_upload() { 1034 if ( ! bp_is_post_request() ) { 1035 wp_die(); 1036 } 1037 1038 /** 1039 * Sending the json response will be different if 1040 * the current Plupload runtime is html4. 1041 */ 1042 $is_html4 = false; 1043 if ( ! empty( $_POST['html4' ] ) ) { 1044 $is_html4 = true; 1045 } 1046 1047 // Check the nonce. 1048 check_admin_referer( 'bp-uploader' ); 1049 1050 // Init the BuddyPress parameters. 1051 $bp_params = array(); 1052 1053 // We need it to carry on. 1054 if ( ! empty( $_POST['bp_params' ] ) ) { 1055 $bp_params = $_POST['bp_params' ]; 1056 } else { 1057 bp_attachments_json_response( false, $is_html4 ); 1058 } 1059 1060 // We need the object to set the uploads dir filter. 1061 if ( empty( $bp_params['object'] ) ) { 1062 bp_attachments_json_response( false, $is_html4 ); 1063 } 1064 1065 // Capability check. 1066 if ( ! bp_attachments_current_user_can( 'edit_avatar', $bp_params ) ) { 1067 bp_attachments_json_response( false, $is_html4 ); 1068 } 1069 1070 $bp = buddypress(); 1071 $bp_params['upload_dir_filter'] = ''; 1072 $needs_reset = array(); 1073 1074 if ( 'user' === $bp_params['object'] && bp_is_active( 'members' ) ) { 1075 $bp_params['upload_dir_filter'] = 'bp_members_avatar_upload_dir'; 1076 1077 if ( ! bp_displayed_user_id() && ! empty( $bp_params['item_id'] ) ) { 1078 $needs_reset = array( 'key' => 'displayed_user', 'value' => $bp->displayed_user ); 1079 $bp->displayed_user->id = $bp_params['item_id']; 1080 } 1081 } elseif ( 'group' === $bp_params['object'] && bp_is_active( 'groups' ) ) { 1082 $bp_params['upload_dir_filter'] = 'groups_avatar_upload_dir'; 1083 1084 if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) { 1085 $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group ); 1086 $bp->groups->current_group = groups_get_group( $bp_params['item_id'] ); 1087 } 1088 } else { 1089 /** 1090 * Filter here to deal with other components. 1091 * 1092 * @since 2.3.0 1093 * 1094 * @var array $bp_params the BuddyPress Ajax parameters. 1095 */ 1096 $bp_params = apply_filters( 'bp_core_avatar_ajax_upload_params', $bp_params ); 1097 } 1098 1099 if ( ! isset( $bp->avatar_admin ) ) { 1100 $bp->avatar_admin = new stdClass(); 1101 } 1102 1103 /** 1104 * The BuddyPress upload parameters is including the Avatar UI Available width, 1105 * add it to the avatar_admin global for a later use. 1106 */ 1107 if ( isset( $bp_params['ui_available_width'] ) ) { 1108 $bp->avatar_admin->ui_available_width = (int) $bp_params['ui_available_width']; 1109 } 1110 1111 // Upload the avatar. 1112 $avatar = bp_core_avatar_handle_upload( $_FILES, $bp_params['upload_dir_filter'] ); 1113 1114 // Reset objects. 1115 if ( ! empty( $needs_reset ) ) { 1116 if ( ! empty( $needs_reset['component'] ) ) { 1117 $bp->{$needs_reset['component']}->{$needs_reset['key']} = $needs_reset['value']; 1118 } else { 1119 $bp->{$needs_reset['key']} = $needs_reset['value']; 1120 } 1121 } 1122 1123 // Init the feedback message. 1124 $feedback_message = false; 1125 1126 if ( ! empty( $bp->template_message ) ) { 1127 $feedback_message = $bp->template_message; 1128 1129 // Remove template message. 1130 $bp->template_message = false; 1131 $bp->template_message_type = false; 1132 1133 @setcookie( 'bp-message', false, time() - 1000, COOKIEPATH, COOKIE_DOMAIN, is_ssl() ); 1134 @setcookie( 'bp-message-type', false, time() - 1000, COOKIEPATH, COOKIE_DOMAIN, is_ssl() ); 1135 } 1136 1137 if ( empty( $avatar ) ) { 1138 // Default upload error. 1139 $message = __( 'Upload failed.', 'buddypress' ); 1140 1141 // Use the template message if set. 1142 if ( ! empty( $feedback_message ) ) { 1143 $message = $feedback_message; 1144 } 1145 1146 // Upload error reply. 1147 bp_attachments_json_response( false, $is_html4, array( 1148 'type' => 'upload_error', 1149 'message' => $message, 1150 ) ); 1151 } 1152 1153 if ( empty( $bp->avatar_admin->image->file ) ) { 1154 bp_attachments_json_response( false, $is_html4 ); 1155 } 1156 1157 $uploaded_image = @getimagesize( $bp->avatar_admin->image->file ); 1158 1159 // Set the name of the file. 1160 $name = $_FILES['file']['name']; 1161 $name_parts = pathinfo( $name ); 1162 $name = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) ); 1163 1164 // Finally return the avatar to the editor. 1165 bp_attachments_json_response( true, $is_html4, array( 1166 'name' => $name, 1167 'url' => $bp->avatar_admin->image->url, 1168 'width' => $uploaded_image[0], 1169 'height' => $uploaded_image[1], 1170 'feedback' => $feedback_message, 1171 ) ); 1172 } 1173 add_action( 'wp_ajax_bp_avatar_upload', 'bp_avatar_ajax_upload' ); 1174 1175 /** 1176 * Handle avatar webcam capture. 1177 * 1178 * @since 2.3.0 1179 * @since 10.0.0 Adds the `$return` param to eventually return the crop result. 1180 * 1181 * @param string $data Base64 encoded image. 1182 * @param int $item_id Item to associate. 1183 * @param string $return Whether to get the crop `array` or a `boolean`. Defaults to `boolean`. 1184 * @return array|bool True on success, false on failure. 1185 */ 1186 function bp_avatar_handle_capture( $data = '', $item_id = 0, $return = 'boolean' ) { 1187 if ( empty( $data ) || empty( $item_id ) ) { 1188 return false; 1189 } 1190 1191 /** 1192 * Filters whether or not to handle avatar webcam capture. 1193 * 1194 * If you want to override this function, make sure you return false. 1195 * 1196 * @since 2.5.1 1197 * 1198 * @param bool $value Whether or not to crop. 1199 * @param string $data Base64 encoded image. 1200 * @param int $item_id Item to associate. 1201 */ 1202 if ( ! apply_filters( 'bp_avatar_pre_handle_capture', true, $data, $item_id ) ) { 1203 return true; 1204 } 1205 1206 $avatar_dir = bp_core_avatar_upload_path() . '/avatars'; 1207 1208 // It's not a regular upload, we may need to create this folder. 1209 if ( ! file_exists( $avatar_dir ) ) { 1210 if ( ! wp_mkdir_p( $avatar_dir ) ) { 1211 return false; 1212 } 1213 } 1214 1215 /** 1216 * Filters the Avatar folder directory. 1217 * 1218 * @since 2.3.0 1219 * 1220 * @param string $avatar_dir Directory for storing avatars. 1221 * @param int $item_id ID of the item being acted on. 1222 * @param string $value Avatar type. 1223 * @param string $value Avatars word. 1224 */ 1225 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', $avatar_dir . '/' . $item_id, $item_id, 'user', 'avatars' ); 1226 1227 // It's not a regular upload, we may need to create this folder. 1228 if( ! is_dir( $avatar_folder_dir ) ) { 1229 if ( ! wp_mkdir_p( $avatar_folder_dir ) ) { 1230 return false; 1231 } 1232 } 1233 1234 $original_file = $avatar_folder_dir . '/webcam-capture-' . $item_id . '.png'; 1235 1236 if ( file_put_contents( $original_file, $data ) ) { 1237 $avatar_to_crop = str_replace( bp_core_avatar_upload_path(), '', $original_file ); 1238 1239 // Crop to default values. 1240 $crop_args = array( 'item_id' => $item_id, 'original_file' => $avatar_to_crop, 'crop_x' => 0, 'crop_y' => 0 ); 1241 1242 if ( 'array' === $return ) { 1243 return bp_core_avatar_handle_crop( $crop_args, 'array' ); 1244 } 1245 1246 return bp_core_avatar_handle_crop( $crop_args ); 1247 } else { 1248 return false; 1249 } 1250 } 1251 1252 /** 1253 * Crop an uploaded avatar. 1254 * 1255 * @since 1.1.0 1256 * @since 10.0.0 Adds the `$return` param to eventually return the crop result. 1257 * 1258 * @param array|string $args { 1259 * Array of function parameters. 1260 * 1261 * @type string $object Object type of the item whose avatar you're 1262 * handling. 'user', 'group', 'blog', or custom. 1263 * Default: 'user'. 1264 * @type string $avatar_dir Subdirectory where avatar should be stored. 1265 * Default: 'avatars'. 1266 * @type bool|int $item_id ID of the item that the avatar belongs to. 1267 * @type bool|string $original_file Absolute path to the original avatar file. 1268 * @type int $crop_w Crop width. Default: the global 'full' avatar width, 1269 * as retrieved by bp_core_avatar_full_width(). 1270 * @type int $crop_h Crop height. Default: the global 'full' avatar height, 1271 * as retrieved by bp_core_avatar_full_height(). 1272 * @type int $crop_x The horizontal starting point of the crop. Default: 0. 1273 * @type int $crop_y The vertical starting point of the crop. Default: 0. 1274 * } 1275 * @param string $return Whether to get the crop `array` or a `boolean`. Defaults to `boolean`. 1276 * @return array|bool True or the crop result on success, false on failure. 1277 */ 1278 function bp_core_avatar_handle_crop( $args = '', $return = 'boolean' ) { 1279 1280 $r = bp_parse_args( 1281 $args, 1282 array( 1283 'object' => 'user', 1284 'avatar_dir' => 'avatars', 1285 'item_id' => false, 1286 'original_file' => false, 1287 'crop_w' => bp_core_avatar_full_width(), 1288 'crop_h' => bp_core_avatar_full_height(), 1289 'crop_x' => 0, 1290 'crop_y' => 0, 1291 ) 1292 ); 1293 1294 /** 1295 * Filters whether or not to handle cropping. 1296 * 1297 * If you want to override this function, make sure you return false. 1298 * 1299 * @since 1.2.4 1300 * 1301 * @param bool $value Whether or not to crop. 1302 * @param array $r Array of parsed arguments for function. 1303 */ 1304 if ( ! apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) ) { 1305 return true; 1306 } 1307 1308 // Crop the file. 1309 $avatar_attachment = new BP_Attachment_Avatar(); 1310 $cropped = $avatar_attachment->crop( $r ); 1311 1312 // Check for errors. 1313 if ( empty( $cropped['full'] ) || empty( $cropped['thumb'] ) || is_wp_error( $cropped['full'] ) || is_wp_error( $cropped['thumb'] ) ) { 1314 return false; 1315 } 1316 1317 if ( 'array' === $return ) { 1318 return $cropped; 1319 } 1320 1321 return true; 1322 } 1323 1324 /** 1325 * Ajax set an avatar for a given object and item id. 1326 * 1327 * @since 2.3.0 1328 * 1329 * @return string|null A JSON object containing success data if the crop/capture succeeded 1330 * error message otherwise. 1331 */ 1332 function bp_avatar_ajax_set() { 1333 if ( ! bp_is_post_request() ) { 1334 wp_send_json_error(); 1335 } 1336 1337 // Check the nonce. 1338 check_admin_referer( 'bp_avatar_cropstore', 'nonce' ); 1339 1340 $avatar_data = bp_parse_args( 1341 $_POST, 1342 array( 1343 'crop_w' => bp_core_avatar_full_width(), 1344 'crop_h' => bp_core_avatar_full_height(), 1345 'crop_x' => 0, 1346 'crop_y' => 0, 1347 ) 1348 ); 1349 1350 if ( empty( $avatar_data['object'] ) || empty( $avatar_data['item_id'] ) || empty( $avatar_data['original_file'] ) ) { 1351 wp_send_json_error(); 1352 } 1353 1354 // Capability check. 1355 if ( ! bp_attachments_current_user_can( 'edit_avatar', $avatar_data ) ) { 1356 wp_send_json_error(); 1357 } 1358 1359 if ( ! empty( $avatar_data['type'] ) && 'camera' === $avatar_data['type'] && 'user' === $avatar_data['object'] ) { 1360 $webcam_avatar = false; 1361 1362 if ( ! empty( $avatar_data['original_file'] ) ) { 1363 $webcam_avatar = str_replace( array( 'data:image/png;base64,', ' ' ), array( '', '+' ), $avatar_data['original_file'] ); 1364 $webcam_avatar = base64_decode( $webcam_avatar ); 1365 } 1366 1367 $cropped_webcam_avatar = bp_avatar_handle_capture( $webcam_avatar, $avatar_data['item_id'], 'array' ); 1368 1369 if ( ! $cropped_webcam_avatar ) { 1370 wp_send_json_error( array( 1371 'feedback_code' => 1 1372 ) ); 1373 1374 } else { 1375 $return = array( 1376 'avatar' => esc_url( 1377 bp_core_fetch_avatar( 1378 array( 1379 'object' => $avatar_data['object'], 1380 'item_id' => $avatar_data['item_id'], 1381 'html' => false, 1382 'type' => 'full', 1383 ) 1384 ) 1385 ), 1386 'feedback_code' => 2, 1387 'item_id' => $avatar_data['item_id'], 1388 ); 1389 1390 /** This action is documented in wp-includes/deprecated.php */ 1391 do_action_deprecated( 'xprofile_avatar_uploaded', array( (int) $avatar_data['item_id'], $avatar_data['type'], $avatar_data ), '6.0.0', 'bp_members_avatar_uploaded' ); 1392 1393 /** 1394 * Fires if the new avatar was successfully captured. 1395 * 1396 * @since 6.0.0 1397 * @since 10.0.0 Adds a new param: an array containing the full, thumb avatar and the timestamp. 1398 * 1399 * @param string $item_id Inform about the user id the avatar was set for. 1400 * @param string $type Inform about the way the avatar was set ('camera'). 1401 * @param array $avatar_data Array of parameters passed to the crop handler. 1402 * @param array $cropped_webcam_avatar Array containing the full, thumb avatar and the timestamp. 1403 */ 1404 do_action( 'bp_members_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $avatar_data, $cropped_webcam_avatar ); 1405 1406 wp_send_json_success( $return ); 1407 } 1408 1409 return; 1410 } 1411 1412 $original_file = str_replace( bp_core_avatar_url(), '', $avatar_data['original_file'] ); 1413 1414 // Set avatars dir & feedback part. 1415 if ( 'user' === $avatar_data['object'] ) { 1416 $avatar_dir = 'avatars'; 1417 1418 // Defaults to object-avatars dir. 1419 } else { 1420 $avatar_dir = sanitize_key( $avatar_data['object'] ) . '-avatars'; 1421 } 1422 1423 // Crop args. 1424 $r = array( 1425 'item_id' => $avatar_data['item_id'], 1426 'object' => $avatar_data['object'], 1427 'avatar_dir' => $avatar_dir, 1428 'original_file' => $original_file, 1429 'crop_w' => $avatar_data['crop_w'], 1430 'crop_h' => $avatar_data['crop_h'], 1431 'crop_x' => $avatar_data['crop_x'], 1432 'crop_y' => $avatar_data['crop_y'] 1433 ); 1434 1435 // Handle crop. 1436 $cropped_avatar = bp_core_avatar_handle_crop( $r, 'array' ); 1437 1438 if ( $cropped_avatar ) { 1439 $return = array( 1440 'avatar' => esc_url( 1441 bp_core_fetch_avatar( 1442 array( 1443 'object' => $avatar_data['object'], 1444 'item_id' => $avatar_data['item_id'], 1445 'html' => false, 1446 'type' => 'full', 1447 ) 1448 ) 1449 ), 1450 'feedback_code' => 2, 1451 'item_id' => $avatar_data['item_id'], 1452 ); 1453 1454 if ( 'user' === $avatar_data['object'] ) { 1455 /** This action is documented in wp-includes/deprecated.php */ 1456 do_action_deprecated( 'xprofile_avatar_uploaded', array( (int) $avatar_data['item_id'], $avatar_data['type'], $r ), '6.0.0', 'bp_members_avatar_uploaded' ); 1457 1458 /** This action is documented in bp-core/bp-core-avatars.php */ 1459 do_action( 'bp_members_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $r, $cropped_avatar ); 1460 } elseif ( 'group' === $avatar_data['object'] ) { 1461 /** This action is documented in bp-groups/bp-groups-screens.php */ 1462 do_action( 'groups_avatar_uploaded', (int) $avatar_data['item_id'], $avatar_data['type'], $r, $cropped_avatar ); 1463 } 1464 1465 wp_send_json_success( $return ); 1466 } else { 1467 wp_send_json_error( array( 1468 'feedback_code' => 1, 1469 ) ); 1470 } 1471 } 1472 add_action( 'wp_ajax_bp_avatar_set', 'bp_avatar_ajax_set' ); 1473 1474 /** 1475 * Filter {@link get_avatar_url()} to use the BuddyPress user avatar URL. 1476 * 1477 * @since 2.9.0 1478 * 1479 * @param string $retval The URL of the avatar. 1480 * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash, 1481 * user email, WP_User object, WP_Post object, or WP_Comment object. 1482 * @param array $args Arguments passed to get_avatar_data(), after processing. 1483 * @return string 1484 */ 1485 function bp_core_get_avatar_data_url_filter( $retval, $id_or_email, $args ) { 1486 $user = null; 1487 1488 // Ugh, hate duplicating code; process the user identifier. 1489 if ( is_numeric( $id_or_email ) ) { 1490 $user = get_user_by( 'id', absint( $id_or_email ) ); 1491 } elseif ( $id_or_email instanceof WP_User ) { 1492 // User Object 1493 $user = $id_or_email; 1494 } elseif ( $id_or_email instanceof WP_Post ) { 1495 // Post Object 1496 $user = get_user_by( 'id', (int) $id_or_email->post_author ); 1497 } elseif ( $id_or_email instanceof WP_Comment ) { 1498 if ( ! empty( $id_or_email->user_id ) ) { 1499 $user = get_user_by( 'id', (int) $id_or_email->user_id ); 1500 } 1501 } elseif ( is_email( $id_or_email ) ) { 1502 $user = get_user_by( 'email', $id_or_email ); 1503 } 1504 1505 // No user, so bail. 1506 if ( false === $user instanceof WP_User ) { 1507 return $retval; 1508 } 1509 1510 // Set BuddyPress-specific avatar args. 1511 $args['item_id'] = $user->ID; 1512 $args['html'] = false; 1513 1514 // Use the 'full' type if size is larger than BP's thumb width. 1515 if ( (int) $args['size'] > bp_core_avatar_thumb_width() ) { 1516 $args['type'] = 'full'; 1517 } 1518 1519 // Get the BuddyPress avatar URL. 1520 if ( $bp_avatar = bp_core_fetch_avatar( $args ) ) { 1521 return $bp_avatar; 1522 } 1523 1524 return $retval; 1525 } 1526 add_filter( 'get_avatar_url', 'bp_core_get_avatar_data_url_filter', 10, 3 ); 1527 1528 /** 1529 * Is the current avatar upload error-free? 1530 * 1531 * @since 1.0.0 1532 * 1533 * @param array $file The $_FILES array. 1534 * @return bool True if no errors are found. False if there are errors. 1535 */ 1536 function bp_core_check_avatar_upload( $file ) { 1537 if ( isset( $file['error'] ) && $file['error'] ) 1538 return false; 1539 1540 return true; 1541 } 1542 1543 /** 1544 * Is the file size of the current avatar upload permitted? 1545 * 1546 * @since 1.0.0 1547 * 1548 * @param array $file The $_FILES array. 1549 * @return bool True if the avatar is under the size limit, otherwise false. 1550 */ 1551 function bp_core_check_avatar_size( $file ) { 1552 if ( $file['file']['size'] > bp_core_avatar_original_max_filesize() ) 1553 return false; 1554 1555 return true; 1556 } 1557 1558 /** 1559 * Get allowed avatar types. 1560 * 1561 * @since 2.3.0 1562 * 1563 * @return array 1564 */ 1565 function bp_core_get_allowed_avatar_types() { 1566 $allowed_types = bp_attachments_get_allowed_types( 'avatar' ); 1567 1568 /** 1569 * Filters the list of allowed image types. 1570 * 1571 * @since 2.3.0 1572 * 1573 * @param array $allowed_types List of image types. 1574 */ 1575 $avatar_types = (array) apply_filters( 'bp_core_get_allowed_avatar_types', $allowed_types ); 1576 1577 if ( empty( $avatar_types ) ) { 1578 $avatar_types = $allowed_types; 1579 } else { 1580 $avatar_types = array_intersect( $allowed_types, $avatar_types ); 1581 } 1582 1583 return array_values( $avatar_types ); 1584 } 1585 1586 /** 1587 * Get allowed avatar mime types. 1588 * 1589 * @since 2.3.0 1590 * 1591 * @return array 1592 */ 1593 function bp_core_get_allowed_avatar_mimes() { 1594 $allowed_types = bp_core_get_allowed_avatar_types(); 1595 1596 return bp_attachments_get_allowed_mimes( 'avatar', $allowed_types ); 1597 } 1598 1599 /** 1600 * Does the current avatar upload have an allowed file type? 1601 * 1602 * Permitted file types are JPG, GIF and PNG. 1603 * 1604 * @since 1.0.0 1605 * 1606 * @param array $file The $_FILES array. 1607 * @return bool True if the file extension is permitted, otherwise false. 1608 */ 1609 function bp_core_check_avatar_type( $file ) { 1610 return bp_attachments_check_filetype( $file['file']['tmp_name'], $file['file']['name'], bp_core_get_allowed_avatar_mimes() ); 1611 } 1612 1613 /** 1614 * Fetch data from the BP root blog's upload directory. 1615 * 1616 * @since 1.8.0 1617 * 1618 * @param string $type The variable we want to return from the $bp->avatars object. 1619 * Only 'upload_path' and 'url' are supported. Default: 'upload_path'. 1620 * @return string The avatar upload directory path. 1621 */ 1622 function bp_core_get_upload_dir( $type = 'upload_path' ) { 1623 $bp = buddypress(); 1624 1625 switch ( $type ) { 1626 case 'upload_path' : 1627 $constant = 'BP_AVATAR_UPLOAD_PATH'; 1628 $key = 'basedir'; 1629 1630 break; 1631 1632 case 'url' : 1633 $constant = 'BP_AVATAR_URL'; 1634 $key = 'baseurl'; 1635 1636 break; 1637 1638 default : 1639 return false; 1640 1641 break; 1642 } 1643 1644 // See if the value has already been calculated and stashed in the $bp global. 1645 if ( isset( $bp->avatar->$type ) ) { 1646 $retval = $bp->avatar->$type; 1647 } else { 1648 // If this value has been set in a constant, just use that. 1649 if ( defined( $constant ) ) { 1650 $retval = constant( $constant ); 1651 } else { 1652 1653 // Use cached upload dir data if available. 1654 if ( ! empty( $bp->avatar->upload_dir ) ) { 1655 $upload_dir = $bp->avatar->upload_dir; 1656 1657 // No cache, so query for it. 1658 } else { 1659 1660 // Get upload directory information from current site. 1661 $upload_dir = bp_upload_dir(); 1662 1663 // Stash upload directory data for later use. 1664 $bp->avatar->upload_dir = $upload_dir; 1665 } 1666 1667 // Directory does not exist and cannot be created. 1668 if ( ! empty( $upload_dir['error'] ) ) { 1669 $retval = ''; 1670 1671 } else { 1672 $retval = $upload_dir[$key]; 1673 1674 // If $key is 'baseurl', check to see if we're on SSL 1675 // Workaround for WP13941, WP15928, WP19037. 1676 if ( $key == 'baseurl' && is_ssl() ) { 1677 $retval = str_replace( 'http://', 'https://', $retval ); 1678 } 1679 } 1680 1681 } 1682 1683 // Stash in $bp for later use. 1684 $bp->avatar->$type = $retval; 1685 } 1686 1687 return $retval; 1688 } 1689 1690 /** 1691 * Get the absolute upload path for the WP installation. 1692 * 1693 * @since 1.2.0 1694 * 1695 * @return string Absolute path to WP upload directory. 1696 */ 1697 function bp_core_avatar_upload_path() { 1698 1699 /** 1700 * Filters the absolute upload path for the WP installation. 1701 * 1702 * @since 1.2.0 1703 * 1704 * @param string $value Absolute upload path for the WP installation. 1705 */ 1706 return apply_filters( 'bp_core_avatar_upload_path', bp_core_get_upload_dir() ); 1707 } 1708 1709 /** 1710 * Get the raw base URL for root site upload location. 1711 * 1712 * @since 1.2.0 1713 * 1714 * @return string Full URL to current upload location. 1715 */ 1716 function bp_core_avatar_url() { 1717 1718 /** 1719 * Filters the raw base URL for root site upload location. 1720 * 1721 * @since 1.2.0 1722 * 1723 * @param string $value Raw base URL for the root site upload location. 1724 */ 1725 return apply_filters( 'bp_core_avatar_url', bp_core_get_upload_dir( 'url' ) ); 1726 } 1727 1728 /** 1729 * Check if a given user ID has an uploaded avatar. 1730 * 1731 * @since 1.0.0 1732 * 1733 * @param int $user_id ID of the user whose avatar is being checked. 1734 * @return bool True if the user has uploaded a local avatar. Otherwise false. 1735 */ 1736 function bp_get_user_has_avatar( $user_id = 0 ) { 1737 1738 if ( empty( $user_id ) ) 1739 $user_id = bp_displayed_user_id(); 1740 1741 $retval = false; 1742 if ( bp_core_fetch_avatar( array( 'item_id' => $user_id, 'no_grav' => true, 'html' => false, 'type' => 'full' ) ) != bp_core_avatar_default( 'local' ) ) 1743 $retval = true; 1744 1745 /** 1746 * Filters whether or not a user has an uploaded avatar. 1747 * 1748 * @since 1.6.0 1749 * 1750 * @param bool $retval Whether or not a user has an uploaded avatar. 1751 * @param int $user_id ID of the user being checked. 1752 */ 1753 return (bool) apply_filters( 'bp_get_user_has_avatar', $retval, $user_id ); 1754 } 1755 1756 /** 1757 * Utility function for fetching an avatar dimension setting. 1758 * 1759 * @since 1.5.0 1760 * 1761 * @param string $type Dimension type you're fetching dimensions for. 'thumb' 1762 * or 'full'. Default: 'thumb'. 1763 * @param string $h_or_w Which dimension is being fetched. 'height' or 'width'. 1764 * Default: 'height'. 1765 * @return int|bool $dim The dimension. 1766 */ 1767 function bp_core_avatar_dimension( $type = 'thumb', $h_or_w = 'height' ) { 1768 $bp = buddypress(); 1769 $dim = isset( $bp->avatar->{$type}->{$h_or_w} ) ? (int) $bp->avatar->{$type}->{$h_or_w} : false; 1770 1771 /** 1772 * Filters the avatar dimension setting. 1773 * 1774 * @since 1.5.0 1775 * 1776 * @param int|bool $dim Dimension setting for the type. 1777 * @param string $type The type of avatar whose dimensions are requested. Default 'thumb'. 1778 * @param string $h_or_w The dimension parameter being requested. Default 'height'. 1779 */ 1780 return apply_filters( 'bp_core_avatar_dimension', $dim, $type, $h_or_w ); 1781 } 1782 1783 /** 1784 * Get the 'thumb' avatar width setting. 1785 * 1786 * @since 1.5.0 1787 * 1788 * @return int The 'thumb' width. 1789 */ 1790 function bp_core_avatar_thumb_width() { 1791 1792 /** 1793 * Filters the 'thumb' avatar width setting. 1794 * 1795 * @since 1.5.0 1796 * 1797 * @param int $value Value for the 'thumb' avatar width setting. 1798 */ 1799 return apply_filters( 'bp_core_avatar_thumb_width', bp_core_avatar_dimension( 'thumb', 'width' ) ); 1800 } 1801 1802 /** 1803 * Get the 'thumb' avatar height setting. 1804 * 1805 * @since 1.5.0 1806 * 1807 * @return int The 'thumb' height. 1808 */ 1809 function bp_core_avatar_thumb_height() { 1810 1811 /** 1812 * Filters the 'thumb' avatar height setting. 1813 * 1814 * @since 1.5.0 1815 * 1816 * @param int $value Value for the 'thumb' avatar height setting. 1817 */ 1818 return apply_filters( 'bp_core_avatar_thumb_height', bp_core_avatar_dimension( 'thumb', 'height' ) ); 1819 } 1820 1821 /** 1822 * Get the 'full' avatar width setting. 1823 * 1824 * @since 1.5.0 1825 * 1826 * @return int The 'full' width. 1827 */ 1828 function bp_core_avatar_full_width() { 1829 1830 /** 1831 * Filters the 'full' avatar width setting. 1832 * 1833 * @since 1.5.0 1834 * 1835 * @param int $value Value for the 'full' avatar width setting. 1836 */ 1837 return apply_filters( 'bp_core_avatar_full_width', bp_core_avatar_dimension( 'full', 'width' ) ); 1838 } 1839 1840 /** 1841 * Get the 'full' avatar height setting. 1842 * 1843 * @since 1.5.0 1844 * 1845 * @return int The 'full' height. 1846 */ 1847 function bp_core_avatar_full_height() { 1848 1849 /** 1850 * Filters the 'full' avatar height setting. 1851 * 1852 * @since 1.5.0 1853 * 1854 * @param int $value Value for the 'full' avatar height setting. 1855 */ 1856 return apply_filters( 'bp_core_avatar_full_height', bp_core_avatar_dimension( 'full', 'height' ) ); 1857 } 1858 1859 /** 1860 * Get the max width for original avatar uploads. 1861 * 1862 * @since 1.5.0 1863 * 1864 * @return int The max width for original avatar uploads. 1865 */ 1866 function bp_core_avatar_original_max_width() { 1867 1868 /** 1869 * Filters the max width for original avatar uploads. 1870 * 1871 * @since 1.5.0 1872 * 1873 * @param int $value Value for the max width. 1874 */ 1875 return apply_filters( 'bp_core_avatar_original_max_width', (int) buddypress()->avatar->original_max_width ); 1876 } 1877 1878 /** 1879 * Get the max filesize for original avatar uploads. 1880 * 1881 * @since 1.5.0 1882 * 1883 * @return int The max filesize for original avatar uploads. 1884 */ 1885 function bp_core_avatar_original_max_filesize() { 1886 1887 /** 1888 * Filters the max filesize for original avatar uploads. 1889 * 1890 * @since 1.5.0 1891 * 1892 * @param int $value Value for the max filesize. 1893 */ 1894 return apply_filters( 'bp_core_avatar_original_max_filesize', (int) buddypress()->avatar->original_max_filesize ); 1895 } 1896 1897 /** 1898 * Get the URL of the 'full' default avatar. 1899 * 1900 * @since 1.5.0 1901 * @since 2.6.0 Introduced `$params` and `$object_type` parameters. 1902 * 1903 * @param string $type 'local' if the fallback should be the locally-hosted version 1904 * of the mystery person, 'gravatar' if the fallback should be 1905 * Gravatar's version. Default: 'gravatar'. 1906 * @param array $params Parameters passed to bp_core_fetch_avatar(). 1907 * @return string The URL of the default avatar. 1908 */ 1909 function bp_core_avatar_default( $type = 'gravatar', $params = array() ) { 1910 // Local override. 1911 if ( defined( 'BP_AVATAR_DEFAULT' ) ) { 1912 $avatar = BP_AVATAR_DEFAULT; 1913 1914 // Use the local default image. 1915 } elseif ( 'local' === $type ) { 1916 $size = ''; 1917 if ( 1918 ( isset( $params['type'] ) && 'thumb' === $params['type'] && bp_core_avatar_thumb_width() <= 50 ) || 1919 ( isset( $params['width'] ) && $params['width'] <= 50 ) 1920 ) { 1921 1922 $size = '-50'; 1923 } 1924 1925 $avatar = buddypress()->plugin_url . "bp-core/images/mystery-man{$size}.jpg"; 1926 1927 // Use Gravatar's mystery person as fallback. 1928 } else { 1929 $size = ''; 1930 if ( isset( $params['type'] ) && 'thumb' === $params['type'] ) { 1931 $size = bp_core_avatar_thumb_width(); 1932 } else { 1933 $size = bp_core_avatar_full_width(); 1934 } 1935 $avatar = '//www.gravatar.com/avatar/00000000000000000000000000000000?d=mm&s=' . $size; 1936 } 1937 1938 /** This filter is documented in wp-includes/deprecated.php */ 1939 $a = apply_filters_deprecated( 1940 'bp_core_avatar_default', 1941 array( $avatar, $params ), 1942 '8.0.0', 1943 'bp_core_avatar_gravatar_default||bp_core_default_avatar', 1944 __( 'This filter was used for 2 different purposes. If your goal was to filter the default *Gravatar*, please use `bp_core_avatar_gravatar_default` instead. Otherwise, please use `bp_core_default_avatar` instead.', 'buddypress' ) 1945 ); 1946 1947 if ( ! bp_core_is_default_gravatar( $a ) && false !== strpos( $avatar, '//' ) ) { 1948 $avatar = $a; 1949 } 1950 1951 /** 1952 * Filters the URL of the 'full' default avatar. 1953 * 1954 * @since 1.5.0 1955 * @since 2.6.0 Added `$params`. 1956 * @since 8.0.0 The name of the filter was changed to `bp_core_default_avatar`. 1957 * 1958 * @param string $avatar URL of the default avatar. 1959 * @param array $params Params provided to bp_core_fetch_avatar(). 1960 */ 1961 return apply_filters( 'bp_core_default_avatar', $avatar, $params ); 1962 } 1963 1964 /** 1965 * Get the URL of the 'thumb' default avatar. 1966 * 1967 * Uses Gravatar's mystery-person avatar, unless BP_AVATAR_DEFAULT_THUMB has been 1968 * defined. 1969 * 1970 * @since 1.5.0 1971 * @since 2.6.0 Introduced `$object_type` parameter. 1972 * 1973 * @param string $type 'local' if the fallback should be the locally-hosted version 1974 * of the mystery person, 'gravatar' if the fallback should be 1975 * Gravatar's version. Default: 'gravatar'. 1976 * @param array $params Parameters passed to bp_core_fetch_avatar(). 1977 * @return string The URL of the default avatar thumb. 1978 */ 1979 function bp_core_avatar_default_thumb( $type = 'gravatar', $params = array() ) { 1980 // Local override. 1981 if ( defined( 'BP_AVATAR_DEFAULT_THUMB' ) ) { 1982 $avatar = BP_AVATAR_DEFAULT_THUMB; 1983 1984 // Use the local default image. 1985 } elseif ( 'local' === $type ) { 1986 $avatar = buddypress()->plugin_url . 'bp-core/images/mystery-man-50.jpg'; 1987 1988 // Use Gravatar's mystery person as fallback. 1989 } else { 1990 $avatar = '//www.gravatar.com/avatar/00000000000000000000000000000000?d=mm&s=' . bp_core_avatar_thumb_width(); 1991 } 1992 1993 /** 1994 * Filters the URL of the 'thumb' default avatar. 1995 * 1996 * @since 1.5.0 1997 * @since 2.6.0 Added `$params`. 1998 * 1999 * @param string $avatar URL of the default avatar. 2000 * @param string $params Params provided to bp_core_fetch_avatar(). 2001 */ 2002 return apply_filters( 'bp_core_avatar_thumb', $avatar, $params ); 2003 } 2004 2005 /** 2006 * Reset the week parameter of the WordPress main query if needed. 2007 * 2008 * When cropping an avatar, a $_POST['w'] var is sent, setting the 'week' 2009 * parameter of the WordPress main query to this posted var. To avoid 2010 * notices, we need to make sure this 'week' query var is reset to 0. 2011 * 2012 * @since 2.2.0 2013 * 2014 * @param WP_Query|null $posts_query The main query object. 2015 */ 2016 function bp_core_avatar_reset_query( $posts_query = null ) { 2017 $reset_w = false; 2018 2019 // Group's avatar edit screen. 2020 if ( bp_is_group_admin_page() ) { 2021 $reset_w = bp_is_group_admin_screen( 'group-avatar' ); 2022 2023 // Group's avatar create screen. 2024 } elseif ( bp_is_group_create() ) { 2025 /** 2026 * We can't use bp_get_groups_current_create_step(). 2027 * as it's not set yet 2028 */ 2029 $reset_w = 'group-avatar' === bp_action_variable( 1 ); 2030 2031 // User's change avatar screen. 2032 } else { 2033 $reset_w = bp_is_user_change_avatar(); 2034 } 2035 2036 // A user or a group is cropping an avatar. 2037 if ( true === $reset_w && isset( $_POST['avatar-crop-submit'] ) ) { 2038 $posts_query->set( 'w', 0 ); 2039 } 2040 } 2041 add_action( 'bp_parse_query', 'bp_core_avatar_reset_query', 10, 1 ); 2042 2043 /** 2044 * Checks whether Avatar UI should be loaded. 2045 * 2046 * @since 2.3.0 2047 * 2048 * @return bool True if Avatar UI should load, false otherwise. 2049 */ 2050 function bp_avatar_is_front_edit() { 2051 $retval = false; 2052 2053 if ( bp_is_user_change_avatar() && 'crop-image' !== bp_get_avatar_admin_step() ) { 2054 $retval = ! bp_core_get_root_option( 'bp-disable-avatar-uploads' ); 2055 } 2056 2057 if ( bp_is_active( 'groups' ) ) { 2058 // Group creation. 2059 if ( bp_is_group_create() && bp_is_group_creation_step( 'group-avatar' ) && 'crop-image' !== bp_get_avatar_admin_step() ) { 2060 $retval = ! bp_disable_group_avatar_uploads(); 2061 2062 // Group Manage. 2063 } elseif ( bp_is_group_admin_page() && bp_is_group_admin_screen( 'group-avatar' ) && 'crop-image' !== bp_get_avatar_admin_step() ) { 2064 $retval = ! bp_disable_group_avatar_uploads(); 2065 } 2066 } 2067 2068 /** 2069 * Use this filter if you need to : 2070 * - Load the avatar UI for a component that is !groups or !user (return true regarding your conditions) 2071 * - Completely disable the avatar UI introduced in 2.3 (eg: __return_false()) 2072 * 2073 * @since 2.3.0 2074 * 2075 * @param bool $retval Whether or not to load the Avatar UI. 2076 */ 2077 return apply_filters( 'bp_avatar_is_front_edit', $retval ); 2078 } 2079 2080 /** 2081 * Checks whether the Webcam Avatar UI part should be loaded. 2082 * 2083 * @since 2.3.0 2084 * 2085 * @global $is_safari 2086 * @global $is_IE 2087 * 2088 * @return bool True to load the Webcam Avatar UI part. False otherwise. 2089 */ 2090 function bp_avatar_use_webcam() { 2091 global $is_safari, $is_IE, $is_chrome; 2092 2093 /** 2094 * Do not use the webcam feature for mobile devices 2095 * to avoid possible confusions. 2096 */ 2097 if ( wp_is_mobile() ) { 2098 return false; 2099 } 2100 2101 /** 2102 * Bail when the browser does not support getUserMedia. 2103 * 2104 * @see http://caniuse.com/#feat=stream 2105 */ 2106 if ( $is_safari || $is_IE || ( $is_chrome && ! is_ssl() ) ) { 2107 return false; 2108 } 2109 2110 /** 2111 * Use this filter if you need to disable the webcam capture feature 2112 * by returning false. 2113 * 2114 * @since 2.3.0 2115 * 2116 * @param bool $value Whether or not to load Webcam Avatar UI part. 2117 */ 2118 return apply_filters( 'bp_avatar_use_webcam', true ); 2119 } 2120 2121 /** 2122 * Template function to load the Avatar UI javascript templates. 2123 * 2124 * @since 2.3.0 2125 */ 2126 function bp_avatar_get_templates() { 2127 if ( ! bp_avatar_is_front_edit() ) { 2128 return; 2129 } 2130 2131 bp_attachments_get_template_part( 'avatars/index' ); 2132 } 2133 2134 /** 2135 * Trick to check if the theme's BuddyPress templates are up to date. 2136 * 2137 * If the "avatar templates" are not including the new template tag, this will 2138 * help users to get the avatar UI. 2139 * 2140 * @since 2.3.0 2141 */ 2142 function bp_avatar_template_check() { 2143 if ( ! bp_avatar_is_front_edit() ) { 2144 return; 2145 } 2146 2147 if ( ! did_action( 'bp_attachments_avatar_check_template' ) ) { 2148 bp_attachments_get_template_part( 'avatars/index' ); 2149 } 2150 } 2151 2152 /** 2153 * Informs about whether avatar history is disabled or not. 2154 * 2155 * @since 10.0.0 2156 * 2157 * @return bool True if avatar history is disabled. False otherwise. 2158 * Default: `false`. 2159 */ 2160 function bp_avatar_history_is_disabled() { 2161 /** 2162 * Filter here returning `true` to disable avatar history. 2163 * 2164 * @since 10.0.0 2165 * 2166 * @param bool $value True to disable avatar history. False otherwise. 2167 * Default: `false`. 2168 */ 2169 return apply_filters( 'bp_disable_avatar_history', false ); 2170 } 2171 2172 /** 2173 * Get a specific version of an avatar from its history. 2174 * 2175 * @since 10.0.0 2176 * 2177 * @param int $item_id The item ID we need the avatar version for. 2178 * @param string $object The object the item ID relates to. 2179 * @param int|string $timestamp An integer Unix timestamp or a date string of the format 'Y-m-d h:i:s'. 2180 * @param string $type The type of avatar we need. Possible values are `thumb` and `full`. 2181 * @return array A list of matching results, an empty array if no avatars were found. 2182 */ 2183 function bp_avatar_get_version( $item_id = 0, $object = 'user', $timestamp = '', $type = 'full' ) { 2184 if ( ! $item_id || ! $timestamp ) { 2185 return array(); 2186 } 2187 2188 if ( ! is_numeric( $timestamp ) ) { 2189 $timestamp = strtotime( $timestamp ); 2190 } 2191 2192 $avatar_id = $timestamp . '-bpfull'; 2193 if ( 'full' !== $type ) { 2194 $avatar_id = $timestamp . '-bpthumb'; 2195 } 2196 2197 $avatar_dir = 'avatars'; 2198 if ( 'user' !== $object ) { 2199 $avatar_dir = sanitize_key( $object ) . '-avatars'; 2200 } 2201 2202 // The object avatar directory we are looking into to get the avatar url. 2203 $object_avatar_dir = trailingslashit( bp_core_avatar_upload_path() ) . $avatar_dir . '/' . $item_id; 2204 2205 return bp_attachments_list_directory_files_recursively( $object_avatar_dir, $avatar_id ); 2206 } 2207 2208 /** 2209 * Get the list of previous avatars in history 2210 * 2211 * @since 10.0.0 2212 * 2213 * @param int $item_id The item ID we need the avatar version for. 2214 * @param string $object The object the item ID relates to. 2215 * @param string $type Get the `full`, `thumb` or `both` versions. 2216 * @return array The list of previous uploaded avatars. 2217 */ 2218 function bp_avatar_get_avatars_history( $item_id = 0, $object = 'user', $type = 'full' ) { 2219 if ( ! $item_id ) { 2220 return array(); 2221 } 2222 2223 $avatar_dir = 'avatars'; 2224 if ( 'user' !== $object ) { 2225 $avatar_dir = sanitize_key( $object ) . '-avatars'; 2226 } 2227 2228 // The user avatar directory we are looking into to get the avatar url. 2229 $history_dir = trailingslashit( bp_core_avatar_upload_path() ) . $avatar_dir . '/' . $item_id . '/history'; 2230 $historic_avatars = bp_attachments_list_directory_files( $history_dir ); 2231 2232 if ( ! $historic_avatars ) { 2233 return array(); 2234 } 2235 2236 $avatars = array(); 2237 $history_url = trailingslashit( bp_core_avatar_url() ) . $avatar_dir . '/' . $item_id . '/history'; 2238 2239 foreach ( $historic_avatars as $historic_avatar ) { 2240 $prefix = str_replace( array( '-bpfull', '-bpthumb' ), '', $historic_avatar->id ); 2241 $gmdate = gmdate( 'Y-m-d H:i:s', $historic_avatar->last_modified ); 2242 $date = strtotime( get_date_from_gmt( $gmdate ) ); 2243 2244 $avatars[ $historic_avatar->id ] = (object) array( 2245 'id' => $historic_avatar->id, 2246 'name' => $historic_avatar->name, 2247 'date' => sprintf( 2248 '%1$s (%2$s)', 2249 date_i18n( get_option( 'date_format' ), $date ), 2250 date_i18n( get_option( 'time_format' ), $date ) 2251 ), 2252 'type' => str_replace( $prefix . '-bp', '', $historic_avatar->id ), 2253 'url' => $history_url . '/' . $historic_avatar->name, 2254 ); 2255 } 2256 2257 if ( 'both' === $type ) { 2258 return $avatars; 2259 } 2260 2261 return wp_filter_object_list( $avatars, array( 'type' => $type ) ); 2262 } 2263 2264 /** 2265 * Recycle a previously uploaded avatar as the current avatar. 2266 * 2267 * @since 10.0.0 2268 */ 2269 function bp_avatar_ajax_recycle_previous_avatar() { 2270 if ( ! bp_is_post_request() ) { 2271 wp_send_json_error(); 2272 } 2273 2274 $avatar_data = bp_parse_args( 2275 $_POST, 2276 array( 2277 'object' => '', 2278 'item_id' => 0, 2279 'avatar_id' => '', 2280 ) 2281 ); 2282 2283 if ( ! $avatar_data['object'] || ! $avatar_data['item_id'] || ! $avatar_data['avatar_id'] ) { 2284 wp_send_json_error(); 2285 } 2286 2287 // Check the nonce. 2288 check_admin_referer( 'bp_avatar_recycle_previous', 'nonce' ); 2289 2290 // Capability check. 2291 if ( ! bp_attachments_current_user_can( 'edit_avatar', $avatar_data ) ) { 2292 wp_send_json_error(); 2293 } 2294 2295 // Set the Avatar Attachment Instance. 2296 $avatar_attachment = new BP_Attachment_Avatar(); 2297 $object = sanitize_key( $avatar_data['object'] ); 2298 2299 if ( 'user' === $object ) { 2300 $avatar_dir = 'avatars'; 2301 } else { 2302 $avatar_dir = $object . '-avatars'; 2303 } 2304 2305 $item_id = (int) $avatar_data['item_id']; 2306 $avatar_dir_path = $avatar_attachment->upload_path . '/' . $avatar_dir . '/' . $item_id; 2307 $current_avatars = bp_attachments_list_directory_files( $avatar_dir_path ); 2308 $revision_errors = array(); 2309 2310 // This path will be needed to get the avatar revision object. 2311 $avatar_full_revision_path = ''; 2312 2313 // Add a revision of the current avatar if it's not a mystery man! 2314 if ( $current_avatars ) { 2315 foreach( $current_avatars as $current_avatar ) { 2316 if ( ! isset( $current_avatar->name, $current_avatar->id, $current_avatar->path ) ) { 2317 continue; 2318 } 2319 2320 $is_full = preg_match( "/-bpfull/", $current_avatar->name ); 2321 $is_thumb = preg_match( "/-bpthumb/", $current_avatar->name ); 2322 2323 if ( $is_full || $is_thumb ) { 2324 // Add a revision of the current avatar. 2325 $revision = $avatar_attachment->add_revision( 2326 'avatar', 2327 array( 2328 'file_abspath' => $current_avatar->path, 2329 'file_id' => $current_avatar->id, 2330 ) 2331 ); 2332 2333 if ( is_wp_error( $revision ) ) { 2334 $revision_errors[] = $revision->get_error_message(); 2335 } elseif ( $is_full ) { 2336 $avatar_full_revision_path = $revision->path; 2337 } 2338 } 2339 } 2340 } 2341 2342 // No errors, let's recycle the previous avatar. 2343 if ( ! $revision_errors ) { 2344 $avatar_id = sanitize_file_name( $avatar_data['avatar_id'] ); 2345 $suffix = '-bpfull'; 2346 $history_dir = trailingslashit( bp_core_avatar_upload_path() ) . $avatar_dir . '/' . $item_id . '/history'; 2347 $avatars = bp_attachments_list_directory_files( $history_dir ); 2348 2349 if ( ! isset( $avatars[ $avatar_id ] ) ) { 2350 wp_send_json_error( 2351 array( 2352 'message' => __( 'The profile photo you want to recycle cannot be found.', 'buddypress' ), 2353 ) 2354 ); 2355 } 2356 2357 // Init recycle vars. 2358 $recycle_timestamp = bp_core_current_time( true, 'timestamp' ); 2359 $recycle_errors = array(); 2360 $avatar_types = array( 2361 'full' => '', 2362 'thumb' => '', 2363 ); 2364 2365 // Use the found previous avatar. 2366 $avatar = $avatars[ $avatar_id ]; 2367 $avatar_types['full'] = $avatar->path; 2368 $avatar_types['thumb'] = str_replace( $suffix, '-bpthumb', $avatar->path ); 2369 $historical_types = $avatar_types; 2370 2371 // It's a legacy avatar, we need to crop it again and remove the thumb file that is not using a timestamp in its name. 2372 if ( ! file_exists( $avatar_types['thumb'] ) ) { 2373 $full_avatar_path = $avatar_dir_path . '/' . str_replace( 'bpfull', 'original-file', wp_basename( $avatar->path ) ); 2374 2375 // Move the full version back to avatar dir. 2376 rename( $avatar->path, $full_avatar_path ); 2377 2378 $avatar_types = $avatar_attachment->crop( 2379 array( 2380 'original_file' => $full_avatar_path, 2381 'avatar_dir' => $avatar_dir, 2382 'object' => $object, 2383 'item_id' => $item_id, 2384 ) 2385 ); 2386 2387 // loop into the history directory to delete the legacy thumb version file. 2388 foreach ( $avatars as $avatar_object ) { 2389 $timestamp = str_replace( array( '-bpthumb', '-bpfull' ), '', $avatar_object->id ); 2390 2391 if ( ! is_numeric( $timestamp ) && false !== strpos( $avatar_object->id, '-bpthumb' ) ) { 2392 @unlink( $avatar_object->path ); 2393 } 2394 } 2395 } else { 2396 foreach( $avatar_types as $type_key => $avatar_path ) { 2397 $filename = wp_basename( $avatar_path ); 2398 $avatar_id = pathinfo( $filename, PATHINFO_FILENAME ); 2399 $recycle_path = $avatar_dir_path . '/' . str_replace( $avatar_id, $recycle_timestamp . '-bp' . $type_key, $filename ); 2400 2401 if ( ! rename( $avatar_path, $recycle_path ) ) { 2402 $recycle_errors[] = __( 'An unexpected error occured while recycling the previous profile photo.', 'buddypress' ); 2403 } else { 2404 $avatar_types[ $type_key ] = $recycle_path; 2405 } 2406 } 2407 2408 $avatar_types = array_merge( 2409 $avatar_types, 2410 array( 2411 'timestamp' => $recycle_timestamp, 2412 ) 2413 ); 2414 } 2415 2416 // No errors, fire the hook used when an avatar is set. 2417 if ( ! $recycle_errors && $historical_types['full'] !== $avatar_types['full'] ) { 2418 $r = array( 2419 'item_id' => $item_id, 2420 'object' => $object, 2421 'avatar_dir' => $avatar_dir, 2422 ); 2423 2424 $action_hook = 'bp_members_avatar_uploaded'; 2425 if ( 'group' === $object ) { 2426 $action_hook = 'groups_avatar_uploaded'; 2427 } 2428 2429 /** This action is documented in bp-core/bp-core-avatars.php */ 2430 do_action( $action_hook, $item_id, 'recycle', $r, $avatar_types ); 2431 } else { 2432 $recycle_error = reset( $recycle_errors ); 2433 2434 wp_send_json_error( 2435 array( 2436 'message' => join( "\n", $recycle_error ), 2437 ) 2438 ); 2439 } 2440 } else { 2441 wp_send_json_error( 2442 array( 2443 'message' => join( "\n", $revision_errors ), 2444 ) 2445 ); 2446 } 2447 2448 $return = array( 2449 'avatar' => esc_url( 2450 bp_core_fetch_avatar( 2451 array( 2452 'object' => $object, 2453 'item_id' => $item_id, 2454 'html' => false, 2455 'type' => 'full', 2456 ) 2457 ) 2458 ), 2459 'feedback_code' => 5, 2460 'item_id' => $item_id, 2461 ); 2462 2463 // Get the created revision object if it exists. 2464 if ( $avatar_full_revision_path ) { 2465 $history_dir = dirname( $avatar_full_revision_path ); 2466 $avatars_history = bp_attachments_list_directory_files( $history_dir ); 2467 $latest_id = pathinfo( wp_basename( $avatar_full_revision_path ), PATHINFO_FILENAME ); 2468 2469 if ( isset( $avatars_history[ $latest_id ] ) ) { 2470 $gmdate = gmdate( 'Y-m-d H:i:s', $avatars_history[ $latest_id ]->last_modified ); 2471 $date = strtotime( get_date_from_gmt( $gmdate ) ); 2472 $history_url = trailingslashit( bp_core_avatar_url() ) . $avatar_dir . '/' . $item_id . '/history'; 2473 2474 // Prepare the avatar object for JavaScript. 2475 $avatars_history[ $latest_id ]->date = sprintf( 2476 '%1$s (%2$s)', 2477 date_i18n( get_option( 'date_format' ), $date ), 2478 date_i18n( get_option( 'time_format' ), $date ) 2479 ); 2480 $avatars_history[ $latest_id ]->type = 'full'; 2481 $avatars_history[ $latest_id ]->url = $history_url . '/' . $avatars_history[ $latest_id ]->name; 2482 2483 // Remove the path. 2484 unset( $avatars_history[ $latest_id ]->path ); 2485 2486 // Set the new object to add to the revision list. 2487 $return['historicalAvatar'] = $avatars_history[ $latest_id ]; 2488 } 2489 } 2490 2491 wp_send_json_success( $return ); 2492 } 2493 add_action( 'wp_ajax_bp_avatar_recycle_previous', 'bp_avatar_ajax_recycle_previous_avatar' ); 2494 2495 /** 2496 * Delete a previously uploaded avatar from avatars history. 2497 * 2498 * @since 10.0.0 2499 */ 2500 function bp_avatar_ajax_delete_previous_avatar() { 2501 if ( ! bp_is_post_request() ) { 2502 wp_send_json_error(); 2503 } 2504 2505 $avatar_data = bp_parse_args( 2506 $_POST, 2507 array( 2508 'object' => '', 2509 'item_id' => 0, 2510 'avatar_id' => '', 2511 ) 2512 ); 2513 2514 if ( ! $avatar_data['object'] || ! $avatar_data['item_id'] || ! $avatar_data['avatar_id'] ) { 2515 wp_send_json_error(); 2516 } 2517 2518 // Check the nonce. 2519 check_admin_referer( 'bp_avatar_delete_previous', 'nonce' ); 2520 2521 // Capability check. 2522 if ( ! bp_attachments_current_user_can( 'edit_avatar', $avatar_data ) ) { 2523 wp_send_json_error(); 2524 } 2525 2526 $object = sanitize_key( $avatar_data['object'] ); 2527 if ( 'user' === $object ) { 2528 $avatar_dir = 'avatars'; 2529 } else { 2530 $avatar_dir = $object . '-avatars'; 2531 } 2532 2533 $item_id = (int) $avatar_data['item_id']; 2534 $avatar_id = sanitize_file_name( $avatar_data['avatar_id'] ); 2535 $suffix = '-bpfull'; 2536 $history_dir = trailingslashit( bp_core_avatar_upload_path() ) . $avatar_dir . '/' . $item_id . '/history'; 2537 $avatars = bp_attachments_list_directory_files( $history_dir ); 2538 2539 if ( ! isset( $avatars[ $avatar_id ] ) ) { 2540 wp_send_json_error( 2541 array( 2542 'message' => __( 'The profile photo you want to delete cannot be found.', 'buddypress' ), 2543 ) 2544 ); 2545 } 2546 2547 $avatar_types = array( 2548 'full' => '', 2549 'thumb' => '', 2550 ); 2551 2552 // Use the found previous avatar. 2553 $avatar = $avatars[ $avatar_id ]; 2554 $avatar_types['full'] = $avatar->path; 2555 $avatar_types['thumb'] = str_replace( $suffix, '-bpthumb', $avatar->path ); 2556 2557 // It's a legacy avatar, we need to find the thumb version using file last modified date. 2558 if ( ! file_exists( $avatar_types['thumb'] ) ) { 2559 $avatar_types['thumb'] = ''; 2560 $possible_thumb_avatars = wp_list_pluck( $avatars, 'last_modified', 'id' ); 2561 2562 foreach ( $possible_thumb_avatars as $type_id => $modified_date ) { 2563 $timediff = $avatar->last_modified - $modified_date; 2564 if ( 1000 >= absint( $timediff ) && $avatar_id !== $type_id ) { 2565 $avatar_types['thumb'] = $avatars[ $type_id ]->path; 2566 break; 2567 } 2568 } 2569 } 2570 2571 // Remove the files. 2572 foreach ( $avatar_types as $avatar_path ) { 2573 if ( ! $avatar_path ) { 2574 continue; 2575 } 2576 2577 @unlink( $avatar_path ); 2578 } 2579 2580 $timestamp = str_replace( '-bpfull', '', $avatar_id ); 2581 if ( ! is_numeric( $timestamp ) ) { 2582 $timestamp = $avatar->last_modified; 2583 } 2584 2585 /** 2586 * Hook here to run custom code once the previous avatar has been deleted. 2587 * 2588 * @since 10.0.0 2589 * 2590 * @param int $item_id The object ID. 2591 * @param int $timestamp The avatar timestamp. 2592 */ 2593 do_action( "bp_previous_{$object}_avatar_deleted", $item_id, $timestamp ); 2594 2595 // Finally inform about the deletion success. 2596 wp_send_json_success( 2597 array( 2598 'feedback_code' => 6, 2599 ) 2600 ); 2601 } 2602 add_action( 'wp_ajax_bp_avatar_delete_previous', 'bp_avatar_ajax_delete_previous_avatar' );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Dec 5 01:00:58 2024 | Cross-referenced by PHPXref 0.7.1 |